aboutsummaryrefslogtreecommitdiff
path: root/sbin/route
diff options
context:
space:
mode:
authorDavid E. O'Brien <obrien@FreeBSD.org>2013-02-08 16:10:16 +0000
committerDavid E. O'Brien <obrien@FreeBSD.org>2013-02-08 16:10:16 +0000
commitd9a447559bc04121f7c6682e64abe67efa154864 (patch)
treeb2f038222ff8a70f687652441df00d2b564c8abe /sbin/route
parent3cbf5f97aafc2b249c509ee1162c47c9b28e591e (diff)
parentfbda3d5daeeb730a49d025b614b35a32f0319718 (diff)
downloadsrc-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/keywords1
-rw-r--r--sbin/route/route.853
-rw-r--r--sbin/route/route.c635
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);