iproute: support onelink route option and print route flags
[oweals/busybox.git] / networking / libiproute / iproute.c
index d771a609b24b21abfc868379af7b39ed2f461790..170c67b30d470857e739d8ad1834c39b1f113c31 100644 (file)
@@ -1,19 +1,16 @@
 /* vi: set sw=4 ts=4: */
 /*
- * iproute.c           "ip route".
- *
- * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
- *
- * Authors:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
  * Changes:
  *
- * Rani Assaf <rani@magic.metawire.com> 980929:        resolve addresses
+ * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
  * Kunihiro Ishiguro <kunihiro@zebra.org> 001102: rtnh_ifindex was not initialized
  */
 
-#include "ip_common.h" /* #include "libbb.h" is inside */
+#include "ip_common.h"  /* #include "libbb.h" is inside */
 #include "rt_names.h"
 #include "utils.h"
 
@@ -34,8 +31,8 @@ struct filter_t {
        //int type; - read-only
        //int typemask; - unused
        //int tos, tosmask; - unused
-       int iif, iifmask;
-       int oif, oifmask;
+       int iif;
+       int oif;
        //int realm, realmmask; - unused
        //inet_prefix rprefsrc; - read-only
        inet_prefix rvia;
@@ -76,7 +73,7 @@ static unsigned get_hz(void)
                fclose(fp);
        }
        if (!hz_internal)
-               hz_internal = sysconf(_SC_CLK_TCK);
+               hz_internal = bb_clk_tck();
        return hz_internal;
 }
 
@@ -85,7 +82,7 @@ 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];
+       struct rtattr *tb[RTA_MAX+1];
        char abuf[256];
        inet_prefix dst;
        inet_prefix src;
@@ -162,8 +159,21 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
        }
 
        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;
+               src.bytelen = (r->rtm_family == AF_INET6 ? 16 : 4);
+               memcpy(src.data, RTA_DATA(tb[RTA_SRC]), src.bytelen);
+       }
+       if (tb[RTA_DST]) {
+               dst.bitlen = r->rtm_dst_len;
+               dst.bytelen = (r->rtm_family == AF_INET6 ? 16 : 4);
+               memcpy(dst.data, RTA_DATA(tb[RTA_DST]), dst.bytelen);
+       }
+
        if (G_filter.rdst.family
         && inet_addr_match(&dst, &G_filter.rdst, G_filter.rdst.bitlen)
        ) {
@@ -185,23 +195,32 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
        ) {
                return 0;
        }
-       if (G_filter.flushb
-        && r->rtm_family == AF_INET6
-        && r->rtm_dst_len == 0
-        && r->rtm_type == RTN_UNREACHABLE
-        && tb[RTA_PRIORITY]
-        && *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1
-       ) {
-               return 0;
+       if (G_filter.oif != 0) {
+               if (!tb[RTA_OIF])
+                       return 0;
+               if (G_filter.oif != *(int*)RTA_DATA(tb[RTA_OIF]))
+                       return 0;
        }
 
        if (G_filter.flushb) {
                struct nlmsghdr *fn;
+
+               /* We are creating route flush commands */
+
+               if (r->rtm_family == AF_INET6
+                && r->rtm_dst_len == 0
+                && r->rtm_type == RTN_UNREACHABLE
+                && tb[RTA_PRIORITY]
+                && *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1
+               ) {
+                       return 0;
+               }
+
                if (NLMSG_ALIGN(G_filter.flushp) + n->nlmsg_len > G_filter.flushe) {
                        if (flush_update())
                                bb_error_msg_and_die("flush");
                }
-               fn = (struct nlmsghdr*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp));
+               fn = (void*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp));
                memcpy(fn, n, n->nlmsg_len);
                fn->nlmsg_type = RTM_DELROUTE;
                fn->nlmsg_flags = NLM_F_REQUEST;
@@ -211,6 +230,8 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
                return 0;
        }
 
+       /* We are printing routes */
+
        if (n->nlmsg_type == RTM_DELROUTE) {
                printf("Deleted ");
        }
@@ -260,10 +281,12 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
                                        RTA_DATA(tb[RTA_GATEWAY]),
                                        abuf, sizeof(abuf)));
        }
-       if (tb[RTA_OIF] && G_filter.oifmask != -1) {
+       if (tb[RTA_OIF]) {
                printf("dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
        }
 
+       /* Todo: parse & show "proto kernel", "scope link" here */
+
        if (tb[RTA_PREFSRC] && /*G_filter.rprefsrc.bitlen - always 0*/ 0 != host_len) {
                /* Do not use format_host(). It is our local addr
                   and symbolic name will not be useful.
@@ -275,6 +298,19 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
        if (tb[RTA_PRIORITY]) {
                printf(" metric %d ", *(uint32_t*)RTA_DATA(tb[RTA_PRIORITY]));
        }
+       if (r->rtm_flags & RTNH_F_DEAD) {
+               printf("dead ");
+       }
+       if (r->rtm_flags & RTNH_F_ONLINK) {
+               printf("onlink ");
+       }
+       if (r->rtm_flags & RTNH_F_PERVASIVE) {
+               printf("pervasive ");
+       }
+       if (r->rtm_flags & RTM_F_NOTIFY) {
+               printf("notify ");
+       }
+
        if (r->rtm_family == AF_INET6) {
                struct rta_cacheinfo *ci = NULL;
                if (tb[RTA_CACHEINFO]) {
@@ -295,7 +331,7 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
                                printf(" error %d", ci->rta_error);
                }
        }
-       if (tb[RTA_IIF] && G_filter.iifmask != -1) {
+       if (tb[RTA_IIF] && G_filter.iif == 0) {
                printf(" iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
        }
        bb_putchar('\n');
@@ -307,7 +343,7 @@ 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")
-               "dev\0""oif\0""to\0""metric\0";
+               "dev\0""oif\0""to\0""metric\0""onlink\0";
        enum {
                ARG_src,
                ARG_via,
@@ -318,6 +354,7 @@ IF_FEATURE_IP_RULE(ARG_table,)
                ARG_oif,
                ARG_to,
                ARG_metric,
+               ARG_onlink,
        };
        enum {
                gw_ok = 1 << 0,
@@ -327,9 +364,9 @@ IF_FEATURE_IP_RULE(ARG_table,)
        };
        struct rtnl_handle rth;
        struct {
-               struct nlmsghdr         n;
-               struct rtmsg            r;
-               char                    buf[1024];
+               struct nlmsghdr n;
+               struct rtmsg    r;
+               char            buf[1024];
        } req;
        char mxbuf[256];
        struct rtattr * mxrta = (void*)mxbuf;
@@ -408,6 +445,8 @@ IF_FEATURE_IP_RULE(ARG_table,)
                        NEXT_ARG();
                        metric = get_u32(*argv, "metric");
                        addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric);
+               } else if (arg == ARG_onlink) {
+                       req.r.rtm_flags |= RTNH_F_ONLINK;
                } else {
                        int type;
                        inet_prefix dst;
@@ -416,7 +455,8 @@ IF_FEATURE_IP_RULE(ARG_table,)
                                NEXT_ARG();
                        }
                        if ((**argv < '0' || **argv > '9')
-                        && rtnl_rtntype_a2n(&type, *argv) == 0) {
+                        && rtnl_rtntype_a2n(&type, *argv) == 0
+                       ) {
                                NEXT_ARG();
                                req.r.rtm_type = type;
                                ok |= type_ok;
@@ -665,12 +705,10 @@ static int iproute_list_or_flush(char **argv, int flush)
                if (id) {
                        idx = xll_name_to_index(id);
                        G_filter.iif = idx;
-                       G_filter.iifmask = -1;
                }
                if (od) {
                        idx = xll_name_to_index(od);
                        G_filter.oif = idx;
-                       G_filter.oifmask = -1;
                }
        }
 
@@ -791,8 +829,8 @@ static int iproute_get(char **argv)
                                }
                                req.r.rtm_dst_len = addr.bitlen;
                        }
-                       argv++;
                }
+               argv++;
        }
 
        if (req.r.rtm_dst_len == 0) {
@@ -869,7 +907,7 @@ static int iproute_get(char **argv)
 }
 
 /* Return value becomes exitcode. It's okay to not return at all */
-int do_iproute(char **argv)
+int FAST_FUNC do_iproute(char **argv)
 {
        static const char ip_route_commands[] ALIGN1 =
        /*0-3*/ "add\0""append\0""change\0""chg\0"