libiproute: handle table ids larger than 255
[oweals/busybox.git] / networking / libiproute / iproute.c
index 0d291440547dfb5e30ec7b5f4137bef98e511abd..0f2b89682d2e92b50bec8bce1327aceeb2d78ae7 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include "ip_common.h"  /* #include "libbb.h" is inside */
+#include "common_bufsiz.h"
 #include "rt_names.h"
 #include "utils.h"
 
@@ -43,7 +44,8 @@ struct filter_t {
 } FIX_ALIASING;
 typedef struct filter_t filter_t;
 
-#define G_filter (*(filter_t*)&bb_common_bufsiz1)
+#define G_filter (*(filter_t*)bb_common_bufsiz1)
+#define INIT_G() do { setup_common_bufsiz(); } while (0)
 
 static int flush_update(void)
 {
@@ -61,10 +63,10 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
        struct rtmsg *r = NLMSG_DATA(n);
        int len = n->nlmsg_len;
        struct rtattr *tb[RTA_MAX+1];
-       char abuf[256];
        inet_prefix dst;
        inet_prefix src;
        int host_len = -1;
+       uint32_t tid;
 
        if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
                fprintf(stderr, "Not a route: %08x %08x %08x\n",
@@ -77,6 +79,14 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
        if (len < 0)
                bb_error_msg_and_die("wrong nlmsg len %d", len);
 
+       memset(tb, 0, sizeof(tb));
+       parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
+
+       if (tb[RTA_TABLE])
+               tid = *(uint32_t *)RTA_DATA(tb[RTA_TABLE]);
+       else
+               tid = r->rtm_table;
+
        if (r->rtm_family == AF_INET6)
                host_len = 128;
        else if (r->rtm_family == AF_INET)
@@ -106,7 +116,7 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
                        }
                }
        } else {
-               if (G_filter.tb > 0 && G_filter.tb != r->rtm_table) {
+               if (G_filter.tb > 0 && G_filter.tb != tid) {
                        return 0;
                }
        }
@@ -135,10 +145,8 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
                return 0;
        }
 
-       memset(tb, 0, sizeof(tb));
        memset(&src, 0, sizeof(src));
        memset(&dst, 0, sizeof(dst));
-       parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
 
        if (tb[RTA_SRC]) {
                src.bitlen = r->rtm_src_len;
@@ -218,17 +226,15 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
 
        if (tb[RTA_DST]) {
                if (r->rtm_dst_len != host_len) {
-                       printf("%s/%u ", rt_addr_n2a(r->rtm_family,
-                                               RTA_DATA(tb[RTA_DST]),
-                                               abuf, sizeof(abuf)),
-                                       r->rtm_dst_len
-                                       );
+                       printf("%s/%u ",
+                               rt_addr_n2a(r->rtm_family, RTA_DATA(tb[RTA_DST])),
+                               r->rtm_dst_len
+                       );
                } else {
                        printf("%s ", format_host(r->rtm_family,
                                                RTA_PAYLOAD(tb[RTA_DST]),
-                                               RTA_DATA(tb[RTA_DST]),
-                                               abuf, sizeof(abuf))
-                                       );
+                                               RTA_DATA(tb[RTA_DST]))
+                       );
                }
        } else if (r->rtm_dst_len) {
                printf("0/%d ", r->rtm_dst_len);
@@ -237,17 +243,15 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
        }
        if (tb[RTA_SRC]) {
                if (r->rtm_src_len != host_len) {
-                       printf("from %s/%u ", rt_addr_n2a(r->rtm_family,
-                                               RTA_DATA(tb[RTA_SRC]),
-                                               abuf, sizeof(abuf)),
-                                       r->rtm_src_len
-                                       );
+                       printf("from %s/%u ",
+                               rt_addr_n2a(r->rtm_family, RTA_DATA(tb[RTA_SRC])),
+                               r->rtm_src_len
+                       );
                } else {
                        printf("from %s ", format_host(r->rtm_family,
                                                RTA_PAYLOAD(tb[RTA_SRC]),
-                                               RTA_DATA(tb[RTA_SRC]),
-                                               abuf, sizeof(abuf))
-                                       );
+                                               RTA_DATA(tb[RTA_SRC]))
+                       );
                }
        } else if (r->rtm_src_len) {
                printf("from 0/%u ", r->rtm_src_len);
@@ -255,12 +259,16 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
        if (tb[RTA_GATEWAY] && G_filter.rvia.bitlen != host_len) {
                printf("via %s ", format_host(r->rtm_family,
                                        RTA_PAYLOAD(tb[RTA_GATEWAY]),
-                                       RTA_DATA(tb[RTA_GATEWAY]),
-                                       abuf, sizeof(abuf)));
+                                       RTA_DATA(tb[RTA_GATEWAY]))
+               );
        }
        if (tb[RTA_OIF]) {
                printf("dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
        }
+#if ENABLE_FEATURE_IP_RULE
+       if (tid && tid != RT_TABLE_MAIN && !G_filter.tb)
+               printf("table %s ", rtnl_rttable_n2a(tid));
+#endif
 
        /* Todo: parse & show "proto kernel", "scope link" here */
 
@@ -269,8 +277,7 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
                   and symbolic name will not be useful.
                 */
                printf(" src %s ", rt_addr_n2a(r->rtm_family,
-                                       RTA_DATA(tb[RTA_PREFSRC]),
-                                       abuf, sizeof(abuf)));
+                                       RTA_DATA(tb[RTA_PREFSRC])));
        }
        if (tb[RTA_PRIORITY]) {
                printf(" metric %d ", *(uint32_t*)RTA_DATA(tb[RTA_PRIORITY]));
@@ -319,12 +326,13 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
 static int iproute_modify(int cmd, unsigned flags, char **argv)
 {
        static const char keywords[] ALIGN1 =
-               "src\0""via\0""mtu\0""lock\0""protocol\0"IF_FEATURE_IP_RULE("table\0")
+               "src\0""via\0""mtu\0""lock\0""scope\0""protocol\0"IF_FEATURE_IP_RULE("table\0")
                "dev\0""oif\0""to\0""metric\0""onlink\0";
        enum {
                ARG_src,
                ARG_via,
                ARG_mtu, PARM_lock,
+               ARG_scope,
                ARG_protocol,
 IF_FEATURE_IP_RULE(ARG_table,)
                ARG_dev,
@@ -350,6 +358,7 @@ IF_FEATURE_IP_RULE(ARG_table,)
        unsigned mxlock = 0;
        char *d = NULL;
        smalluint ok = 0;
+       smalluint scope_ok = 0;
        int arg;
 
        memset(&req, 0, sizeof(req));
@@ -358,15 +367,17 @@ IF_FEATURE_IP_RULE(ARG_table,)
        req.n.nlmsg_flags = NLM_F_REQUEST | flags;
        req.n.nlmsg_type = cmd;
        req.r.rtm_family = preferred_family;
-       if (RT_TABLE_MAIN) /* if it is zero, memset already did it */
+       if (RT_TABLE_MAIN != 0) /* if it is zero, memset already did it */
                req.r.rtm_table = RT_TABLE_MAIN;
-       if (RT_SCOPE_NOWHERE)
+       if (RT_SCOPE_NOWHERE != 0)
                req.r.rtm_scope = RT_SCOPE_NOWHERE;
 
        if (cmd != RTM_DELROUTE) {
-               req.r.rtm_protocol = RTPROT_BOOT;
                req.r.rtm_scope = RT_SCOPE_UNIVERSE;
-               req.r.rtm_type = RTN_UNICAST;
+               if (RTPROT_BOOT != 0)
+                       req.r.rtm_protocol = RTPROT_BOOT;
+               if (RTN_UNICAST != 0)
+                       req.r.rtm_type = RTN_UNICAST;
        }
 
        mxrta->rta_type = RTA_METRICS;
@@ -399,6 +410,13 @@ IF_FEATURE_IP_RULE(ARG_table,)
                        }
                        mtu = get_unsigned(*argv, "mtu");
                        rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
+               } else if (arg == ARG_scope) {
+                       uint32_t scope;
+                       NEXT_ARG();
+                       if (rtnl_rtscope_a2n(&scope, *argv))
+                               invarg_1_to_2(*argv, "scope");
+                       req.r.rtm_scope = scope;
+                       scope_ok = 1;
                } else if (arg == ARG_protocol) {
                        uint32_t prot;
                        NEXT_ARG();
@@ -412,7 +430,12 @@ IF_FEATURE_IP_RULE(ARG_table,)
                        NEXT_ARG();
                        if (rtnl_rttable_a2n(&tid, *argv))
                                invarg_1_to_2(*argv, "table");
-                       req.r.rtm_table = tid;
+                       if (tid < 256)
+                               req.r.rtm_table = tid;
+                       else {
+                               req.r.rtm_table = RT_TABLE_UNSPEC;
+                               addattr32(&req.n, sizeof(req), RTA_TABLE, tid);
+                       }
 #endif
                } else if (arg == ARG_dev || arg == ARG_oif) {
                        NEXT_ARG();
@@ -475,20 +498,22 @@ IF_FEATURE_IP_RULE(ARG_table,)
                addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
        }
 
-       if (req.r.rtm_type == RTN_LOCAL || req.r.rtm_type == RTN_NAT)
-               req.r.rtm_scope = RT_SCOPE_HOST;
-       else
-       if (req.r.rtm_type == RTN_BROADCAST
-        || req.r.rtm_type == RTN_MULTICAST
-        || req.r.rtm_type == RTN_ANYCAST
-       ) {
-               req.r.rtm_scope = RT_SCOPE_LINK;
-       }
-       else if (req.r.rtm_type == RTN_UNICAST || req.r.rtm_type == RTN_UNSPEC) {
-               if (cmd == RTM_DELROUTE)
-                       req.r.rtm_scope = RT_SCOPE_NOWHERE;
-               else if (!(ok & gw_ok))
+       if (!scope_ok) {
+               if (req.r.rtm_type == RTN_LOCAL || req.r.rtm_type == RTN_NAT)
+                       req.r.rtm_scope = RT_SCOPE_HOST;
+               else
+               if (req.r.rtm_type == RTN_BROADCAST
+                || req.r.rtm_type == RTN_MULTICAST
+                || req.r.rtm_type == RTN_ANYCAST
+               ) {
                        req.r.rtm_scope = RT_SCOPE_LINK;
+               }
+               else if (req.r.rtm_type == RTN_UNICAST || req.r.rtm_type == RTN_UNSPEC) {
+                       if (cmd == RTM_DELROUTE)
+                               req.r.rtm_scope = RT_SCOPE_NOWHERE;
+                       else if (!(ok & gw_ok))
+                               req.r.rtm_scope = RT_SCOPE_LINK;
+               }
        }
 
        if (req.r.rtm_family == AF_UNSPEC) {
@@ -894,6 +919,8 @@ int FAST_FUNC do_iproute(char **argv)
        unsigned flags = 0;
        int cmd = RTM_NEWROUTE;
 
+       INIT_G();
+
        if (!*argv)
                return iproute_list_or_flush(argv, 0);