]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
add support for the RTA_VIA attribute
authorEric W. Biederman <ebiederm@xmission.com>
Sun, 15 Mar 2015 19:52:06 +0000 (14:52 -0500)
committerStephen Hemminger <shemming@brocade.com>
Tue, 24 Mar 2015 22:45:23 +0000 (15:45 -0700)
Add support for the RTA_VIA attribute that specifies an address family
as well as an address for the next hop gateway.

To make it easy to pass this reorder inet_prefix so that it's tail
is a proper RTA_VIA attribute.

Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
include/utils.h
ip/iproute.c
man/man8/ip-route.8.in

index 79c1da19188d4295e25ff60d40753f2780c46772..ff4c417d8e5e5c04678a3aebcf241c437890820f 100644 (file)
@@ -50,10 +50,11 @@ extern void incomplete_command(void) __attribute__((noreturn));
 
 typedef struct
 {
-       __u8 family;
-       __u8 bytelen;
+       __u16 flags;
+       __u16 bytelen;
        __s16 bitlen;
-       __u32 flags;
+       /* These next two fields match rtvia */
+       __u16 family;
        __u32 data[8];
 } inet_prefix;
 
index c73a36433436966c545e8bf9d720918daf18474f..214aaac9a17af5527feff34b48a1e334b686c1a1 100644 (file)
@@ -75,7 +75,8 @@ static void usage(void)
        fprintf(stderr, "             [ table TABLE_ID ] [ proto RTPROTO ]\n");
        fprintf(stderr, "             [ scope SCOPE ] [ metric METRIC ]\n");
        fprintf(stderr, "INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]...\n");
-       fprintf(stderr, "NH := [ via ADDRESS ] [ dev STRING ] [ weight NUMBER ] NHFLAGS\n");
+       fprintf(stderr, "NH := [ via [ FAMILY ] ADDRESS ] [ dev STRING ] [ weight NUMBER ] NHFLAGS\n");
+       fprintf(stderr, "FAMILY := [ inet | inet6 | ipx | dnet | bridge | link ]");
        fprintf(stderr, "OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ]\n");
        fprintf(stderr, "           [ rtt TIME ] [ rttvar TIME ] [ reordering NUMBER ]\n");
        fprintf(stderr, "           [ window NUMBER] [ cwnd NUMBER ] [ initcwnd NUMBER ]\n");
@@ -185,8 +186,15 @@ static int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
            (r->rtm_family != filter.msrc.family ||
             (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len)))
                return 0;
-       if (filter.rvia.family && r->rtm_family != filter.rvia.family)
-               return 0;
+       if (filter.rvia.family) {
+               int family = r->rtm_family;
+               if (tb[RTA_VIA]) {
+                       struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
+                       family = via->rtvia_family;
+               }
+               if (family != filter.rvia.family)
+                       return 0;
+       }
        if (filter.rprefsrc.family && r->rtm_family != filter.rprefsrc.family)
                return 0;
 
@@ -205,6 +213,12 @@ static int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
                via.family = r->rtm_family;
                if (tb[RTA_GATEWAY])
                        memcpy(&via.data, RTA_DATA(tb[RTA_GATEWAY]), host_len/8);
+               if (tb[RTA_VIA]) {
+                       size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
+                       struct rtvia *rtvia = RTA_DATA(tb[RTA_VIA]);
+                       via.family = rtvia->rtvia_family;
+                       memcpy(&via.data, rtvia->rtvia_addr, len);
+               }
        }
        if (filter.rprefsrc.bitlen>0) {
                memset(&prefsrc, 0, sizeof(prefsrc));
@@ -386,6 +400,14 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                                    RTA_DATA(tb[RTA_GATEWAY]),
                                    abuf, sizeof(abuf)));
        }
+       if (tb[RTA_VIA]) {
+               size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
+               struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
+               fprintf(fp, "via %s %s ",
+                       family_name(via->rtvia_family),
+                       format_host(via->rtvia_family, len, via->rtvia_addr,
+                                   abuf, sizeof(abuf)));
+       }
        if (tb[RTA_OIF] && filter.oifmask != -1)
                fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
 
@@ -603,6 +625,14 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                                                            RTA_DATA(tb[RTA_GATEWAY]),
                                                            abuf, sizeof(abuf)));
                                }
+                               if (tb[RTA_VIA]) {
+                                       size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
+                                       struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
+                                       fprintf(fp, "via %s %s ",
+                                               family_name(via->rtvia_family),
+                                               format_host(via->rtvia_family, len, via->rtvia_addr,
+                                                           abuf, sizeof(abuf)));
+                               }
                                if (tb[RTA_FLOW]) {
                                        __u32 to = rta_getattr_u32(tb[RTA_FLOW]);
                                        __u32 from = to>>16;
@@ -650,12 +680,23 @@ static int parse_one_nh(struct rtmsg *r, struct rtattr *rta,
        while (++argv, --argc > 0) {
                if (strcmp(*argv, "via") == 0) {
                        inet_prefix addr;
+                       int family;
                        NEXT_ARG();
-                       get_addr(&addr, *argv, r->rtm_family);
+                       family = read_family(*argv);
+                       if (family == AF_UNSPEC)
+                               family = r->rtm_family;
+                       else
+                               NEXT_ARG();
+                       get_addr(&addr, *argv, family);
                        if (r->rtm_family == AF_UNSPEC)
                                r->rtm_family = addr.family;
-                       rta_addattr_l(rta, 4096, RTA_GATEWAY, &addr.data, addr.bytelen);
-                       rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen;
+                       if (addr.family == r->rtm_family) {
+                               rta_addattr_l(rta, 4096, RTA_GATEWAY, &addr.data, addr.bytelen);
+                               rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen;
+                       } else {
+                               rta_addattr_l(rta, 4096, RTA_VIA, &addr.family, addr.bytelen+2);
+                               rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen+2;
+                       }
                } else if (strcmp(*argv, "dev") == 0) {
                        NEXT_ARG();
                        if ((rtnh->rtnh_ifindex = ll_name_to_index(*argv)) == 0) {
@@ -763,12 +804,21 @@ static int iproute_modify(int cmd, unsigned flags, int argc, char **argv)
                        addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen);
                } else if (strcmp(*argv, "via") == 0) {
                        inet_prefix addr;
+                       int family;
                        gw_ok = 1;
                        NEXT_ARG();
-                       get_addr(&addr, *argv, req.r.rtm_family);
+                       family = read_family(*argv);
+                       if (family == AF_UNSPEC)
+                               family = req.r.rtm_family;
+                       else
+                               NEXT_ARG();
+                       get_addr(&addr, *argv, family);
                        if (req.r.rtm_family == AF_UNSPEC)
                                req.r.rtm_family = addr.family;
-                       addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen);
+                       if (addr.family == req.r.rtm_family)
+                               addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen);
+                       else
+                               addattr_l(&req.n, sizeof(req), RTA_VIA, &addr.family, addr.bytelen+2);
                } else if (strcmp(*argv, "from") == 0) {
                        inet_prefix addr;
                        NEXT_ARG();
@@ -1253,8 +1303,14 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
                        get_unsigned(&mark, *argv, 0);
                        filter.markmask = -1;
                } else if (strcmp(*argv, "via") == 0) {
+                       int family;
                        NEXT_ARG();
-                       get_prefix(&filter.rvia, *argv, do_ipv6);
+                       family = read_family(*argv);
+                       if (family == AF_UNSPEC)
+                               family = do_ipv6;
+                       else
+                               NEXT_ARG();
+                       get_prefix(&filter.rvia, *argv, family);
                } else if (strcmp(*argv, "src") == 0) {
                        NEXT_ARG();
                        get_prefix(&filter.rprefsrc, *argv, do_ipv6);
@@ -1556,6 +1612,8 @@ static int iproute_get(int argc, char **argv)
                        tb[RTA_OIF]->rta_type = 0;
                if (tb[RTA_GATEWAY])
                        tb[RTA_GATEWAY]->rta_type = 0;
+               if (tb[RTA_VIA])
+                       tb[RTA_VIA]->rta_type = 0;
                if (!idev && tb[RTA_IIF])
                        tb[RTA_IIF]->rta_type = 0;
                req.n.nlmsg_flags = NLM_F_REQUEST;
index 2b1583d5a30c50fa576cfa1326f55baf8452a449..906cfea0cd6bb535e38b4967ab5d1783a8875378 100644 (file)
@@ -81,12 +81,17 @@ replace " } "
 .ti -8
 .IR NH " := [ "
 .B  via
-.IR ADDRESS " ] [ "
+[
+.IR FAMILY " ] " ADDRESS " ] [ "
 .B  dev
 .IR STRING " ] [ "
 .B  weight
 .IR NUMBER " ] " NHFLAGS
 
+.ti -8
+.IR FAMILY " := [ "
+.BR inet " | " inet6 " | " ipx " | " dnet " | " bridge " | " link " ]"
+
 .ti -8
 .IR OPTIONS " := " FLAGS " [ "
 .B  mtu
@@ -333,9 +338,10 @@ table by default.
 the output device name.
 
 .TP
-.BI via " ADDRESS"
-the address of the nexthop router.  Actually, the sense of this field
-depends on the route type.  For normal
+.BI via " [ FAMILY ] ADDRESS"
+the address of the nexthop router, in the address family FAMILY.
+Actually, the sense of this field depends on the route type.  For
+normal
 .B unicast
 routes it is either the true next hop router or, if it is a direct
 route installed in BSD compatibility mode, it can be a local address
@@ -472,7 +478,7 @@ is a complex value with its own syntax similar to the top level
 argument lists:
 
 .in +8
-.BI via " ADDRESS"
+.BI via " [ FAMILY ] ADDRESS"
 - is the nexthop router.
 .sp
 
@@ -669,7 +675,7 @@ only list routes of this type.
 only list routes going via this device.
 
 .TP
-.BI via " PREFIX"
+.BI via " [ FAMILY ] PREFIX"
 only list routes going via the nexthop routers selected by
 .IR PREFIX "."