diff options
author | David E. O'Brien <obrien@FreeBSD.org> | 2013-02-08 16:10:16 +0000 |
---|---|---|
committer | David E. O'Brien <obrien@FreeBSD.org> | 2013-02-08 16:10:16 +0000 |
commit | d9a447559bc04121f7c6682e64abe67efa154864 (patch) | |
tree | b2f038222ff8a70f687652441df00d2b564c8abe /sbin/route | |
parent | 3cbf5f97aafc2b249c509ee1162c47c9b28e591e (diff) | |
parent | fbda3d5daeeb730a49d025b614b35a32f0319718 (diff) | |
download | src-d9a447559bc04121f7c6682e64abe67efa154864.tar.gz src-d9a447559bc04121f7c6682e64abe67efa154864.zip |
Sync with HEAD.
Notes
Notes:
svn path=/projects/bmake/; revision=246555
Diffstat (limited to 'sbin/route')
-rw-r--r-- | sbin/route/keywords | 1 | ||||
-rw-r--r-- | sbin/route/route.8 | 53 | ||||
-rw-r--r-- | sbin/route/route.c | 635 |
3 files changed, 486 insertions, 203 deletions
diff --git a/sbin/route/keywords b/sbin/route/keywords index 8817f3055b80..adfba7cf111b 100644 --- a/sbin/route/keywords +++ b/sbin/route/keywords @@ -10,6 +10,7 @@ del delete dst expire +fib flush gateway genmask diff --git a/sbin/route/route.8 b/sbin/route/route.8 index 6bf65b4ac55f..b7861068bacb 100644 --- a/sbin/route/route.8 +++ b/sbin/route/route.8 @@ -28,7 +28,7 @@ .\" @(#)route.8 8.3 (Berkeley) 3/19/94 .\" $FreeBSD$ .\" -.Dd March 24, 2012 +.Dd November 17, 2012 .Dt ROUTE 8 .Os .Sh NAME @@ -118,16 +118,14 @@ The monitor command has the syntax: .Bd -ragged -offset indent -compact .Nm .Op Fl n -.Cm monitor +.Cm monitor Op Fl fib Ar number .Ed .Pp The flush command has the syntax: .Pp .Bd -ragged -offset indent -compact .Nm -.Op Fl n -.Cm flush -.Op Ar family +.Oo Fl n Cm flush Oc Oo Ar family Oc Op Fl fib Ar number .Ed .Pp If the @@ -144,6 +142,11 @@ or .Fl inet modifiers, only routes having destinations with addresses in the delineated family will be deleted. +When a +.Fl fib +option is specified, the operation will be applied to +the specified FIB +.Pq routing table . .Pp The other commands have the following syntax: .Pp @@ -154,6 +157,7 @@ The other commands have the following syntax: .Op Fl net No \&| Fl host .Ar destination gateway .Op Ar netmask +.Op Fl fib Ar number .Ed .Pp where @@ -210,9 +214,15 @@ A .Ar destination of .Ar default -is a synonym for -.Fl net Li 0.0.0.0 , -which is the default route. +is a synonym for the default route. +For +.Li IPv4 +it is +.Fl net Fl inet Li 0.0.0.0 , +and for +.Li IPv6 +it is +.Fl net Fl inet6 Li :: . .Pp If the destination is directly reachable via an interface requiring @@ -314,6 +324,33 @@ specify that all ensuing metrics may be locked by the .Fl lockrest meta-modifier. .Pp +The optional modifier +.Fl fib Ar number +specifies that the command will be applied to a non-default FIB. +The +.Ar number +must be smaller than the +.Va net.fibs +.Xr sysctl 8 +MIB. +When this modifier is not specified, +or a negative number is specified, +the default FIB shown in the +.Va net.my_fibnum +.Xr sysctl 8 +MIB will be used. +.Pp +The +.Ar number +allows multiple FIBs by a comma-separeted list and/or range +specification. +The +.Qq Fl fib Li 2,4,6 +means the FIB number 2, 4, and 6. +The +.Qq Fl fib Li 1,3-5,6 +means the 1, 3, 4, 5, and 6. +.Pp In a .Cm change or diff --git a/sbin/route/route.c b/sbin/route/route.c index 717a09ad2a8b..48f90a768d23 100644 --- a/sbin/route/route.c +++ b/sbin/route/route.c @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include <sys/ioctl.h> #include <sys/sysctl.h> #include <sys/types.h> +#include <sys/queue.h> #include <net/if.h> #include <net/route.h> @@ -77,7 +78,6 @@ struct keytab { {0, 0} }; -struct ortentry route; union sockunion { struct sockaddr sa; struct sockaddr_in sin; @@ -86,7 +86,6 @@ union sockunion { #endif struct sockaddr_at sat; struct sockaddr_dl sdl; - struct sockaddr_inarp sinarp; struct sockaddr_storage ss; /* added to avoid memory overrun */ } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp; @@ -94,17 +93,20 @@ typedef union sockunion *sup; int pid, rtm_addrs; int s; int forcehost, forcenet, doflush, nflag, af, qflag, tflag; -int iflag, verbose, aflen = sizeof (struct sockaddr_in); +int verbose, aflen = sizeof (struct sockaddr_in); int locking, lockrest, debugonly; struct rt_metrics rt_metrics; u_long rtm_inits; uid_t uid; +static int defaultfib; +static int numfibs; static int atalk_aton(const char *, struct at_addr *); static char *atalk_ntoa(struct at_addr); static void bprintf(FILE *, int, u_char *); static void flushroutes(int argc, char *argv[]); -static int getaddr(int, char *, struct hostent **); +static int flushroutes_fib(int); +static int getaddr(int, char *, struct hostent **, int); static int keyword(const char *); static void inet_makenetandmask(u_long, struct sockaddr_in *, u_long); #ifdef INET6 @@ -112,21 +114,36 @@ static int inet6_makenetandmask(struct sockaddr_in6 *, const char *); #endif static void interfaces(void); static void mask_addr(void); -static void monitor(void); +static void monitor(int, char*[]); static const char *netname(struct sockaddr *); static void newroute(int, char **); +static int newroute_fib(int, char *, int); static void pmsg_addrs(char *, int, size_t); static void pmsg_common(struct rt_msghdr *, size_t); static int prefixlen(const char *); -static void print_getmsg(struct rt_msghdr *, int); +static void print_getmsg(struct rt_msghdr *, int, int); static void print_rtmsg(struct rt_msghdr *, size_t); static const char *routename(struct sockaddr *); -static int rtmsg(int, int); +static int rtmsg(int, int, int); static void set_metric(char *, int); +static int set_sofib(int); +static int set_procfib(int); static void sockaddr(char *, struct sockaddr *); static void sodump(sup, const char *); extern char *iso_ntoa(void); +struct fibl { + TAILQ_ENTRY(fibl) fl_next; + + int fl_num; + int fl_error; + int fl_errno; +}; +TAILQ_HEAD(fibl_head_t, fibl) fibl_head; + +static int fiboptlist_csv(const char *, struct fibl_head_t *); +static int fiboptlist_range(const char *, struct fibl_head_t *); + static void usage(const char *) __dead2; void @@ -144,6 +161,7 @@ int main(int argc, char **argv) { int ch; + size_t len; if (argc < 2) usage(NULL); @@ -180,6 +198,17 @@ main(int argc, char **argv) s = socket(PF_ROUTE, SOCK_RAW, 0); if (s < 0) err(EX_OSERR, "socket"); + + len = sizeof(numfibs); + if (sysctlbyname("net.fibs", (void *)&numfibs, &len, NULL, 0) == -1) + numfibs = -1; + + len = sizeof(defaultfib); + if (numfibs != -1 && + sysctlbyname("net.my_fibnum", (void *)&defaultfib, &len, NULL, + 0) == -1) + defaultfib = -1; + if (*argv != NULL) switch (keyword(*argv)) { case K_GET: @@ -195,7 +224,7 @@ main(int argc, char **argv) /* NOTREACHED */ case K_MONITOR: - monitor(); + monitor(argc, argv); /* NOTREACHED */ case K_FLUSH: @@ -207,6 +236,136 @@ main(int argc, char **argv) /* NOTREACHED */ } +static int +set_sofib(int fib) +{ + + if (fib < 0) + return (0); + return (setsockopt(s, SOL_SOCKET, SO_SETFIB, (void *)&fib, + sizeof(fib))); +} + +static int +set_procfib(int fib) +{ + + if (fib < 0) + return (0); + return (setfib(fib)); +} + +static int +fiboptlist_range(const char *arg, struct fibl_head_t *flh) +{ + struct fibl *fl; + char *str0, *str, *token, *endptr; + int fib[2], i, error; + + str0 = str = strdup(arg); + error = 0; + i = 0; + while ((token = strsep(&str, "-")) != NULL) { + switch (i) { + case 0: + case 1: + errno = 0; + fib[i] = strtol(token, &endptr, 0); + if (errno == 0) { + if (*endptr != '\0' || + fib[i] < 0 || + (numfibs != -1 && fib[i] > numfibs - 1)) + errno = EINVAL; + } + if (errno) + error = 1; + break; + default: + error = 1; + } + if (error) + goto fiboptlist_range_ret; + i++; + } + if (fib[0] >= fib[1]) { + error = 1; + goto fiboptlist_range_ret; + } + for (i = fib[0]; i <= fib[1]; i++) { + fl = calloc(1, sizeof(*fl)); + if (fl == NULL) { + error = 1; + goto fiboptlist_range_ret; + } + fl->fl_num = i; + TAILQ_INSERT_TAIL(flh, fl, fl_next); + } +fiboptlist_range_ret: + free(str0); + return (error); +} + +#define ALLSTRLEN 64 +static int +fiboptlist_csv(const char *arg, struct fibl_head_t *flh) +{ + struct fibl *fl; + char *str0, *str, *token, *endptr; + int fib, error; + + if (strcmp("all", arg) == 0) { + str = calloc(1, ALLSTRLEN); + if (str == NULL) { + error = 1; + goto fiboptlist_csv_ret; + } + if (numfibs > 1) + snprintf(str, ALLSTRLEN - 1, "%d-%d", 0, numfibs - 1); + else + snprintf(str, ALLSTRLEN - 1, "%d", 0); + } else if (strcmp("default", arg) == 0) { + str0 = str = calloc(1, ALLSTRLEN); + if (str == NULL) { + error = 1; + goto fiboptlist_csv_ret; + } + snprintf(str, ALLSTRLEN - 1, "%d", defaultfib); + } else + str0 = str = strdup(arg); + + error = 0; + while ((token = strsep(&str, ",")) != NULL) { + if (*token != '-' && strchr(token, '-') != NULL) { + error = fiboptlist_range(token, flh); + if (error) + goto fiboptlist_csv_ret; + } else { + errno = 0; + fib = strtol(token, &endptr, 0); + if (errno == 0) { + if (*endptr != '\0' || + fib < 0 || + (numfibs != -1 && fib > numfibs - 1)) + errno = EINVAL; + } + if (errno) { + error = 1; + goto fiboptlist_csv_ret; + } + fl = calloc(1, sizeof(*fl)); + if (fl == NULL) { + error = 1; + goto fiboptlist_csv_ret; + } + fl->fl_num = fib; + TAILQ_INSERT_TAIL(flh, fl, fl_next); + } + } +fiboptlist_csv_ret: + free(str0); + return (error); +} + /* * Purge all entries in the routing tables not * associated with network interfaces. @@ -214,38 +373,71 @@ main(int argc, char **argv) static void flushroutes(int argc, char *argv[]) { - size_t needed; - int mib[6], rlen, seqno, count = 0; - char *buf, *next, *lim; - struct rt_msghdr *rtm; + struct fibl *fl; + int error; - if (uid != 0 && !debugonly) { + if (uid != 0 && !debugonly && !tflag) { errx(EX_NOPERM, "must be root to alter routing table"); } shutdown(s, SHUT_RD); /* Don't want to read back our messages */ - if (argc > 1) { + + TAILQ_INIT(&fibl_head); + while (argc > 1) { + argc--; argv++; - if (argc == 2 && **argv == '-') - switch (keyword(*argv + 1)) { - case K_INET: - af = AF_INET; - break; + if (**argv != '-') + usage(*argv); + switch (keyword(*argv + 1)) { + case K_INET: + af = AF_INET; + break; #ifdef INET6 - case K_INET6: - af = AF_INET6; - break; + case K_INET6: + af = AF_INET6; + break; #endif - case K_ATALK: - af = AF_APPLETALK; - break; - case K_LINK: - af = AF_LINK; - break; - default: - goto bad; - } else -bad: usage(*argv); + case K_ATALK: + af = AF_APPLETALK; + break; + case K_LINK: + af = AF_LINK; + break; + case K_FIB: + if (!--argc) + usage(*argv); + error = fiboptlist_csv(*++argv, &fibl_head); + if (error) + errx(EX_USAGE, "invalid fib number: %s", *argv); + break; + default: + usage(*argv); + } } + if (TAILQ_EMPTY(&fibl_head)) { + error = fiboptlist_csv("default", &fibl_head); + if (error) + errx(EX_OSERR, "fiboptlist_csv failed."); + } + TAILQ_FOREACH(fl, &fibl_head, fl_next) + flushroutes_fib(fl->fl_num); +} + +static int +flushroutes_fib(int fib) +{ + struct rt_msghdr *rtm; + size_t needed; + char *buf, *next, *lim; + int mib[6], rlen, seqno, count = 0; + int error; + + error = set_sofib(fib); + error += set_procfib(fib); + if (error) { + warn("fib number %d is ignored", fib); + return (error); + } + retry: mib[0] = CTL_NET; mib[1] = PF_ROUTE; @@ -303,13 +495,17 @@ retry: print_rtmsg(rtm, rlen); else { struct sockaddr *sa = (struct sockaddr *)(rtm + 1); - (void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ? + + printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ? routename(sa) : netname(sa)); sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa); - (void) printf("%-20.20s ", routename(sa)); - (void) printf("done\n"); + printf("%-20.20s ", routename(sa)); + if (fib >= 0) + printf("-fib %-3d ", fib); + printf("done\n"); } } + return (error); } const char * @@ -372,18 +568,6 @@ routename(struct sockaddr *sa) memcpy(&sin6, sa, sa->sa_len); sin6.sin6_len = sizeof(struct sockaddr_in6); sin6.sin6_family = AF_INET6; -#ifdef __KAME__ - if (sa->sa_len == sizeof(struct sockaddr_in6) && - (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) || - IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr) || - IN6_IS_ADDR_MC_NODELOCAL(&sin6.sin6_addr)) && - sin6.sin6_scope_id == 0) { - sin6.sin6_scope_id = - ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); - sin6.sin6_addr.s6_addr[2] = 0; - sin6.sin6_addr.s6_addr[3] = 0; - } -#endif if (nflag) niflags |= NI_NUMERICHOST; if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, @@ -422,7 +606,7 @@ routename(struct sockaddr *sa) /* * Return the name of the network whose address is given. - * The address is assumed to be that of a net or subnet, not a host. + * The address is assumed to be that of a net, not a host. */ const char * netname(struct sockaddr *sa) @@ -430,9 +614,8 @@ netname(struct sockaddr *sa) const char *cp = NULL; static char line[MAXHOSTNAMELEN + 1]; struct netent *np = NULL; - u_long net, mask; u_long i; - int n, subnetshift; + int n; switch (sa->sa_family) { @@ -444,28 +627,7 @@ netname(struct sockaddr *sa) if (in.s_addr == 0) cp = "default"; else if (!nflag) { - if (IN_CLASSA(i)) { - mask = IN_CLASSA_NET; - subnetshift = 8; - } else if (IN_CLASSB(i)) { - mask = IN_CLASSB_NET; - subnetshift = 8; - } else { - mask = IN_CLASSC_NET; - subnetshift = 4; - } - /* - * If there are more bits than the standard mask - * would suggest, subnets must be in use. - * Guess at the subnet mask, assuming reasonable - * width subnet fields. - */ - while (in.s_addr & ~mask) - mask |= mask >> subnetshift; - net = in.s_addr & mask; - while ((mask & 1) == 0) - mask >>= 1, net >>= 1; - np = getnetbyaddr(net, AF_INET); + np = getnetbyaddr(i, AF_INET); if (np != NULL) cp = np->n_name; } @@ -498,18 +660,6 @@ netname(struct sockaddr *sa) memcpy(&sin6, sa, sa->sa_len); sin6.sin6_len = sizeof(struct sockaddr_in6); sin6.sin6_family = AF_INET6; -#ifdef __KAME__ - if (sa->sa_len == sizeof(struct sockaddr_in6) && - (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) || - IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr) || - IN6_IS_ADDR_MC_NODELOCAL(&sin6.sin6_addr)) && - sin6.sin6_scope_id == 0) { - sin6.sin6_scope_id = - ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); - sin6.sin6_addr.s6_addr[2] = 0; - sin6.sin6_addr.s6_addr[3] = 0; - } -#endif if (nflag) niflags |= NI_NUMERICHOST; if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, @@ -573,18 +723,32 @@ set_metric(char *value, int key) *valp = atoi(value); } +#define F_ISHOST 0x01 +#define F_FORCENET 0x02 +#define F_FORCEHOST 0x04 +#define F_PROXY 0x08 +#define F_INTERFACE 0x10 + static void newroute(int argc, char **argv) { + struct hostent *hp; + struct fibl *fl; char *cmd; - const char *dest = "", *gateway = "", *errmsg; - int ishost = 0, proxy = 0, ret, attempts, oerrno, flags = RTF_STATIC; - int key; - struct hostent *hp = 0; + const char *dest, *gateway, *errmsg; + int key, error, flags, nrflags, fibnum; - if (uid != 0) { + if (uid != 0 && !debugonly && !tflag) { errx(EX_NOPERM, "must be root to alter routing table"); } + + dest = NULL; + gateway = NULL; + flags = RTF_STATIC; + nrflags = 0; + hp = NULL; + TAILQ_INIT(&fibl_head); + cmd = argv[0]; if (*cmd != 'g' && *cmd != 's') shutdown(s, SHUT_RD); /* Don't want to read back our messages */ @@ -616,7 +780,7 @@ newroute(int argc, char **argv) break; case K_IFACE: case K_INTERFACE: - iflag++; + nrflags |= F_INTERFACE; break; case K_NOSTATIC: flags &= ~RTF_STATIC; @@ -628,7 +792,7 @@ newroute(int argc, char **argv) lockrest = 1; break; case K_HOST: - forcehost++; + nrflags |= F_FORCEHOST; break; case K_REJECT: flags |= RTF_REJECT; @@ -643,7 +807,7 @@ newroute(int argc, char **argv) flags |= RTF_PROTO2; break; case K_PROXY: - proxy = 1; + nrflags |= F_PROXY; break; case K_XRESOLVE: flags |= RTF_XRESOLVE; @@ -657,49 +821,58 @@ newroute(int argc, char **argv) case K_NOSTICK: flags &= ~RTF_STICKY; break; + case K_FIB: + if (!--argc) + usage(NULL); + error = fiboptlist_csv(*++argv, &fibl_head); + if (error) + errx(EX_USAGE, + "invalid fib number: %s", *argv); + break; case K_IFA: if (!--argc) usage(NULL); - (void) getaddr(RTA_IFA, *++argv, 0); + getaddr(RTA_IFA, *++argv, 0, nrflags); break; case K_IFP: if (!--argc) usage(NULL); - (void) getaddr(RTA_IFP, *++argv, 0); + getaddr(RTA_IFP, *++argv, 0, nrflags); break; case K_GENMASK: if (!--argc) usage(NULL); - (void) getaddr(RTA_GENMASK, *++argv, 0); + getaddr(RTA_GENMASK, *++argv, 0, nrflags); break; case K_GATEWAY: if (!--argc) usage(NULL); - (void) getaddr(RTA_GATEWAY, *++argv, 0); + getaddr(RTA_GATEWAY, *++argv, 0, nrflags); break; case K_DST: if (!--argc) usage(NULL); - ishost = getaddr(RTA_DST, *++argv, &hp); + if (getaddr(RTA_DST, *++argv, &hp, nrflags)) + nrflags |= F_ISHOST; dest = *argv; break; case K_NETMASK: if (!--argc) usage(NULL); - (void) getaddr(RTA_NETMASK, *++argv, 0); + getaddr(RTA_NETMASK, *++argv, 0, nrflags); /* FALLTHROUGH */ case K_NET: - forcenet++; + nrflags |= F_FORCENET; break; case K_PREFIXLEN: if (!--argc) usage(NULL); if (prefixlen(*++argv) == -1) { - forcenet = 0; - ishost = 1; + nrflags &= ~F_FORCENET; + nrflags |= F_ISHOST; } else { - forcenet = 1; - ishost = 0; + nrflags |= F_FORCENET; + nrflags &= ~F_ISHOST; } break; case K_MTU: @@ -721,18 +894,20 @@ newroute(int argc, char **argv) } else { if ((rtm_addrs & RTA_DST) == 0) { dest = *argv; - ishost = getaddr(RTA_DST, *argv, &hp); + if (getaddr(RTA_DST, *argv, &hp, nrflags)) + nrflags |= F_ISHOST; } else if ((rtm_addrs & RTA_GATEWAY) == 0) { gateway = *argv; - (void) getaddr(RTA_GATEWAY, *argv, &hp); + getaddr(RTA_GATEWAY, *argv, &hp, nrflags); } else { - (void) getaddr(RTA_NETMASK, *argv, 0); - forcenet = 1; + getaddr(RTA_NETMASK, *argv, 0, nrflags); + nrflags |= F_FORCENET; } } } - if (forcehost) { - ishost = 1; + + if (nrflags & F_FORCEHOST) { + nrflags |= F_ISHOST; #ifdef INET6 if (af == AF_INET6) { rtm_addrs &= ~RTA_NETMASK; @@ -740,100 +915,148 @@ newroute(int argc, char **argv) } #endif } - if (forcenet) - ishost = 0; + if (nrflags & F_FORCENET) + nrflags &= ~F_ISHOST; flags |= RTF_UP; - if (ishost) + if (nrflags & F_ISHOST) flags |= RTF_HOST; - if (iflag == 0) + if ((nrflags & F_INTERFACE) == 0) flags |= RTF_GATEWAY; - if (proxy) { - so_dst.sinarp.sin_other = SIN_PROXY; + if (nrflags & F_PROXY) flags |= RTF_ANNOUNCE; + if (dest == NULL) + dest = ""; + if (gateway == NULL) + gateway = ""; + + if (TAILQ_EMPTY(&fibl_head)) { + error = fiboptlist_csv("default", &fibl_head); + if (error) + errx(EX_OSERR, "fiboptlist_csv failed."); } - for (attempts = 1; ; attempts++) { - errno = 0; - if ((ret = rtmsg(*cmd, flags)) == 0) - break; - if (errno != ENETUNREACH && errno != ESRCH) - break; - if (af == AF_INET && *gateway != '\0' && - hp != NULL && hp->h_addr_list[1] != NULL) { - hp->h_addr_list++; - memmove(&so_gate.sin.sin_addr, hp->h_addr_list[0], - MIN((size_t)hp->h_length, - sizeof(so_gate.sin.sin_addr))); - } else - break; + error = 0; + TAILQ_FOREACH(fl, &fibl_head, fl_next) { + fl->fl_error = newroute_fib(fl->fl_num, cmd, flags); + if (fl->fl_error) + fl->fl_errno = errno; + error += fl->fl_error; } if (*cmd == 'g' || *cmd == 's') - exit(ret != 0); + exit(error); + + error = 0; if (!qflag) { - oerrno = errno; - (void) printf("%s %s %s", cmd, ishost? "host" : "net", dest); - if (*gateway) { - (void) printf(": gateway %s", gateway); - if (attempts > 1 && ret == 0 && af == AF_INET) - (void) printf(" (%s)", - inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr)); + fibnum = 0; + TAILQ_FOREACH(fl, &fibl_head, fl_next) { + if (fl->fl_error == 0) + fibnum++; } - if (ret == 0) { - (void) printf("\n"); - } else { - switch (oerrno) { - case ESRCH: - errmsg = "not in table"; - break; - case EBUSY: - errmsg = "entry in use"; - break; - case ENOBUFS: - errmsg = "not enough memory"; - break; - case EADDRINUSE: - /* handle recursion avoidance in rt_setgate() */ - errmsg = "gateway uses the same route"; - break; - case EEXIST: - errmsg = "route already in table"; - break; - default: - errmsg = strerror(oerrno); - break; + if (fibnum > 0) { + int firstfib = 1; + + printf("%s %s %s", cmd, + (nrflags & F_ISHOST) ? "host" : "net", dest); + if (*gateway) + printf(": gateway %s", gateway); + + if (numfibs > 1) { + TAILQ_FOREACH(fl, &fibl_head, fl_next) { + if (fl->fl_error == 0 + && fl->fl_num >= 0) { + if (firstfib) { + printf(" fib "); + firstfib = 0; + } + printf("%d", fl->fl_num); + if (fibnum-- > 1) + printf(","); + } + } + } + printf("\n"); + } + + fibnum = 0; + TAILQ_FOREACH(fl, &fibl_head, fl_next) { + if (fl->fl_error != 0) { + printf("%s %s %s", cmd, (nrflags & F_ISHOST) + ? "host" : "net", dest); + if (*gateway) + printf(": gateway %s", gateway); + + if (fl->fl_num >= 0) + printf(" fib %d", fl->fl_num); + + switch (fl->fl_errno) { + case ESRCH: + errmsg = "not in table"; + break; + case EBUSY: + errmsg = "entry in use"; + break; + case ENOBUFS: + errmsg = "not enough memory"; + break; + case EADDRINUSE: + /* + * handle recursion avoidance + * in rt_setgate() + */ + errmsg = "gateway uses the same route"; + break; + case EEXIST: + errmsg = "route already in table"; + break; + default: + errmsg = strerror(fl->fl_errno); + break; + } + printf(": %s\n", errmsg); + error = 1; } - (void) printf(": %s\n", errmsg); } } - exit(ret != 0); + exit(error); +} + +static int +newroute_fib(int fib, char *cmd, int flags) +{ + int error; + + error = set_sofib(fib); + if (error) { + warn("fib number %d is ignored", fib); + return (error); + } + + error = rtmsg(*cmd, flags, fib); + return (error); } static void inet_makenetandmask(u_long net, struct sockaddr_in *sin, u_long bits) { - u_long addr, mask = 0; + u_long mask = 0; char *cp; rtm_addrs |= RTA_NETMASK; + /* - * XXX: This approach unable to handle 0.0.0.1/32 correctly - * as inet_network() converts 0.0.0.1 and 1 equally. + * MSB of net should be meaningful. 0/0 is exception. */ - if (net <= 0xff) - addr = net << IN_CLASSA_NSHIFT; - else if (net <= 0xffff) - addr = net << IN_CLASSB_NSHIFT; - else if (net <= 0xffffff) - addr = net << IN_CLASSC_NSHIFT; - else - addr = net; + if (net > 0) + while ((net & 0xff000000) == 0) + net <<= 8; + /* * If no /xx was specified we must calculate the * CIDR address. */ - if ((bits == 0) && (addr != 0)) { + if ((bits == 0) && (net != 0)) { u_long i, j; for(i=0,j=0xff; i<4; i++) { - if (addr & j) { + if (net & j) { break; } j <<= 8; @@ -844,7 +1067,7 @@ inet_makenetandmask(u_long net, struct sockaddr_in *sin, u_long bits) if (bits != 0) mask = 0xffffffff << (32 - bits); - sin->sin_addr.s_addr = htonl(addr); + sin->sin_addr.s_addr = htonl(net); sin = &so_mask.sin; sin->sin_addr.s_addr = htonl(mask); sin->sin_len = 0; @@ -890,7 +1113,7 @@ inet6_makenetandmask(struct sockaddr_in6 *sin6, const char *plen) * returning 1 if a host address, 0 if a network address. */ static int -getaddr(int which, char *str, struct hostent **hpp) +getaddr(int which, char *str, struct hostent **hpp, int nrflags) { sup su; struct hostent *hp; @@ -911,7 +1134,7 @@ getaddr(int which, char *str, struct hostent **hpp) break; case RTA_GATEWAY: su = &so_gate; - if (iflag) { + if (nrflags & F_INTERFACE) { struct ifaddrs *ifap, *ifa; struct sockaddr_dl *sdl = NULL; @@ -971,7 +1194,7 @@ getaddr(int which, char *str, struct hostent **hpp) #if 0 bzero(su, sizeof(*su)); /* for readability */ #endif - getaddr(RTA_NETMASK, str, 0); + getaddr(RTA_NETMASK, str, 0, nrflags); break; #if 0 case RTA_NETMASK: @@ -1002,16 +1225,6 @@ getaddr(int which, char *str, struct hostent **hpp) exit(1); } memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6)); -#ifdef __KAME__ - if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) || - IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr) || - IN6_IS_ADDR_MC_NODELOCAL(&su->sin6.sin6_addr)) && - su->sin6.sin6_scope_id) { - *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] = - htons(su->sin6.sin6_scope_id); - su->sin6.sin6_scope_id = 0; - } -#endif freeaddrinfo(res); if (q != NULL) *q++ = '/'; @@ -1165,10 +1378,39 @@ retry2: } static void -monitor(void) +monitor(int argc, char *argv[]) { - int n; - char msg[2048]; + int n, fib, error; + char msg[2048], *endptr; + + fib = defaultfib; + while (argc > 1) { + argc--; + argv++; + if (**argv != '-') + usage(*argv); + switch (keyword(*argv + 1)) { + case K_FIB: + if (!--argc) + usage(*argv); + errno = 0; + fib = strtol(*++argv, &endptr, 0); + if (errno == 0) { + if (*endptr != '\0' || + fib < 0 || + (numfibs != -1 && fib > numfibs - 1)) + errno = EINVAL; + } + if (errno) + errx(EX_USAGE, "invalid fib number: %s", *argv); + break; + default: + usage(*argv); + } + } + error = set_sofib(fib); + if (error) + errx(EX_USAGE, "invalid fib number: %d", fib); verbose = 1; if (debugonly) { @@ -1190,7 +1432,7 @@ struct { } m_rtmsg; static int -rtmsg(int cmd, int flags) +rtmsg(int cmd, int flags, int fib) { static int seq; int rlen; @@ -1253,7 +1495,7 @@ rtmsg(int cmd, int flags) if (l < 0) warn("read from routing socket"); else - print_getmsg(&rtm, l); + print_getmsg(&rtm, l, fib); } #undef rtm return (0); @@ -1413,6 +1655,7 @@ print_rtmsg(struct rt_msghdr *rtm, size_t msglen) break; } printf("\n"); + fflush(stdout); break; default: @@ -1430,7 +1673,7 @@ badlen: } static void -print_getmsg(struct rt_msghdr *rtm, int msglen) +print_getmsg(struct rt_msghdr *rtm, int msglen, int fib) { struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL; struct sockaddr_dl *ifp = NULL; @@ -1490,6 +1733,8 @@ print_getmsg(struct rt_msghdr *rtm, int msglen) } if (gate && rtm->rtm_flags & RTF_GATEWAY) (void)printf(" gateway: %s\n", routename(gate)); + if (fib >= 0) + (void)printf(" fib: %u\n", (unsigned int)fib); if (ifp) (void)printf(" interface: %.*s\n", ifp->sdl_nlen, ifp->sdl_data); |