]> git.proxmox.com Git - mirror_iproute2.git/blobdiff - ip/ipmroute.c
mroute: fix up family handling
[mirror_iproute2.git] / ip / ipmroute.c
index 8f4b0612c5d78525f7d54cb2bd2afebc12a89963..b8f0bc49b92e31aec527a515670cedbca58ad5e4 100644 (file)
@@ -13,8 +13,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
-#include <syslog.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <linux/if_arp.h>
 #include <linux/sockios.h>
 
+#include <rt_names.h>
 #include "utils.h"
-
-char filter_dev[16];
-int  filter_family;
+#include "ip_common.h"
+#include "json_print.h"
 
 static void usage(void) __attribute__((noreturn));
 
 static void usage(void)
 {
-       fprintf(stderr, "Usage: ip mroute show [ PREFIX ] [ from PREFIX ] [ iif DEVICE ]\n");
+       fprintf(stderr, "Usage: ip mroute show [ [ to ] PREFIX ] [ from PREFIX ] [ iif DEVICE ]\n");
+       fprintf(stderr, "                      [ table TABLE_ID ]\n");
+       fprintf(stderr, "TABLE_ID := [ local | main | default | all | NUMBER ]\n");
 #if 0
        fprintf(stderr, "Usage: ip mroute [ add | del ] DESTINATION from SOURCE [ iif DEVICE ] [ oif DEVICE ]\n");
 #endif
        exit(-1);
 }
 
-static char *viftable[32];
-
-struct rtfilter
-{
+struct rtfilter {
+       int tb;
+       int af;
+       int iif;
        inet_prefix mdst;
        inet_prefix msrc;
 } filter;
 
-static void read_viftable(void)
+int print_mroute(struct nlmsghdr *n, void *arg)
 {
-       char buf[256];
-       FILE *fp = fopen("/proc/net/ip_mr_vif", "r");
+       struct rtmsg *r = NLMSG_DATA(n);
+       int len = n->nlmsg_len;
+       struct rtattr *tb[RTA_MAX+1];
+       const char *src, *dst;
+       SPRINT_BUF(b1);
+       SPRINT_BUF(b2);
+       __u32 table;
+       int iif = 0;
+       int family;
+
+       if ((n->nlmsg_type != RTM_NEWROUTE &&
+            n->nlmsg_type != RTM_DELROUTE)) {
+               fprintf(stderr, "Not a multicast route: %08x %08x %08x\n",
+                       n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+               return 0;
+       }
+       len -= NLMSG_LENGTH(sizeof(*r));
+       if (len < 0) {
+               fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+               return -1;
+       }
 
-       if (!fp)
-               return;
+       if (r->rtm_type != RTN_MULTICAST) {
+               fprintf(stderr,
+                       "Non multicast route received, kernel does support IP multicast?\n");
+               return -1;
+       }
 
-       fgets(buf, sizeof(buf), fp);
+       parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
+       table = rtm_get_table(r, tb);
 
-       while (fgets(buf, sizeof(buf), fp)) {
-               int vifi;
-               char dev[256];
+       if (filter.tb > 0 && filter.tb != table)
+               return 0;
 
-               if (sscanf(buf, "%d%s", &vifi, dev) < 2)
-                       continue;
+       if (tb[RTA_IIF])
+               iif = rta_getattr_u32(tb[RTA_IIF]);
+       if (filter.iif && filter.iif != iif)
+               return 0;
 
-               if (vifi<0 || vifi>31)
-                       continue;
+       if (filter.af && filter.af != r->rtm_family)
+               return 0;
 
-               viftable[vifi] = strdup(dev);
-       }
-       fclose(fp);
-}
+       if (inet_addr_match_rta(&filter.mdst, tb[RTA_DST]))
+               return 0;
 
-static void read_mroute_list(FILE *ofp)
-{
-       char buf[256];
-       FILE *fp = fopen("/proc/net/ip_mr_cache", "r");
+       if (inet_addr_match_rta(&filter.msrc, tb[RTA_SRC]))
+               return 0;
+
+       family = get_real_family(r->rtm_type, r->rtm_family);
+
+       open_json_object(NULL);
+       if (n->nlmsg_type == RTM_DELROUTE)
+               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 
-       if (!fp)
-               return;
+       if (tb[RTA_SRC])
+               src = rt_addr_n2a_r(family, RTA_PAYLOAD(tb[RTA_SRC]),
+                                   RTA_DATA(tb[RTA_SRC]), b1, sizeof(b1));
+       else
+               src = "unknown";
 
-       fgets(buf, sizeof(buf), fp);
+       if (tb[RTA_DST])
+               dst = rt_addr_n2a_r(family, RTA_PAYLOAD(tb[RTA_DST]),
+                                   RTA_DATA(tb[RTA_DST]), b2, sizeof(b2));
+       else
+               dst = "unknown";
 
-       while (fgets(buf, sizeof(buf), fp)) {
-               inet_prefix maddr, msrc;
-               unsigned pkts, b, w;
-               int vifi;
-               char oiflist[256];
-               char sbuf[256];
-               char mbuf[256];
+       if (is_json_context()) {
+               print_string(PRINT_JSON, "src", NULL, src);
+               print_string(PRINT_JSON, "dst", NULL, dst);
+       } else {
                char obuf[256];
 
-               oiflist[0] = 0;
-               if (sscanf(buf, "%x%x%d%u%u%u%s", maddr.data, msrc.data, &vifi,
-                          &pkts, &b, &w, oiflist) < 6)
-                       continue;
+               snprintf(obuf, sizeof(obuf), "(%s,%s)", src, dst);
+               print_string(PRINT_FP, NULL,
+                            "%-32s Iif: ", obuf);
+       }
 
-               if (vifi!=-1 && (vifi < 0 || vifi>31))
-                       continue;
+       if (iif)
+               print_color_string(PRINT_ANY, COLOR_IFNAME,
+                                  "iif", "%-10s ", ll_index_to_name(iif));
+       else
+               print_string(PRINT_ANY,"iif", "%s ", "unresolved");
+
+       if (tb[RTA_MULTIPATH]) {
+               struct rtnexthop *nh = RTA_DATA(tb[RTA_MULTIPATH]);
+               int first = 1;
+
+               open_json_array(PRINT_JSON, "multipath");
+               len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
+
+               for (;;) {
+                       if (len < sizeof(*nh))
+                               break;
+                       if (nh->rtnh_len > len)
+                               break;
+
+                       open_json_object(NULL);
+                       if (first) {
+                               print_string(PRINT_FP, NULL, "Oifs: ", NULL);
+                               first = 0;
+                       }
 
-               if (filter_dev[0] && (vifi<0 || strcmp(filter_dev, viftable[vifi])))
-                       continue;
-               if (filter.mdst.family && inet_addr_match(&maddr, &filter.mdst, filter.mdst.bitlen))
-                       continue;
-               if (filter.msrc.family && inet_addr_match(&msrc, &filter.msrc, filter.msrc.bitlen))
-                       continue;
+                       print_color_string(PRINT_ANY, COLOR_IFNAME,
+                                          "oif", "%s", ll_index_to_name(nh->rtnh_ifindex));
 
-               snprintf(obuf, sizeof(obuf), "(%s, %s)",
-                        format_host(AF_INET, 4, &msrc.data[0], sbuf, sizeof(sbuf)),
-                        format_host(AF_INET, 4, &maddr.data[0], mbuf, sizeof(mbuf)));
+                       if (nh->rtnh_hops > 1)
+                               print_uint(PRINT_ANY,
+                                          "ttl", "(ttl %u) ", nh->rtnh_hops);
+                       else
+                               print_string(PRINT_FP, NULL, " ", NULL);
 
-               fprintf(ofp, "%-32s Iif: ", obuf);
+                       close_json_object();
+                       len -= NLMSG_ALIGN(nh->rtnh_len);
+                       nh = RTNH_NEXT(nh);
+               }
+               close_json_array(PRINT_JSON, NULL);
+       }
 
-               if (vifi == -1)
-                       fprintf(ofp, "unresolved ");
-               else
-                       fprintf(ofp, "%-10s ", viftable[vifi]);
+       print_string(PRINT_ANY, "state", " State: %s",
+                    (r->rtm_flags & RTNH_F_UNRESOLVED) ? "unresolved" : "resolved");
 
-               if (oiflist[0]) {
-                       char *next = NULL;
-                       char *p = oiflist;
-                       int ovifi, ottl;
+       if (r->rtm_flags & RTNH_F_OFFLOAD)
+               print_null(PRINT_ANY, "offload", " offload", NULL);
 
-                       fprintf(ofp, "Oifs: ");
+       if (show_stats && tb[RTA_MFC_STATS]) {
+               struct rta_mfc_stats *mfcs = RTA_DATA(tb[RTA_MFC_STATS]);
 
-                       while (p) {
-                               next = strchr(p, ' ');
-                               if (next) {
-                                       *next = 0;
-                                       next++;
-                               }
-                               if (sscanf(p, "%d:%d", &ovifi, &ottl)<2) {
-                                       p = next;
-                                       continue;
-                               }
-                               p = next;
+               print_nl();
+               print_u64(PRINT_ANY, "packets", "  %"PRIu64" packets,",
+                          mfcs->mfcs_packets);
+               print_u64(PRINT_ANY, "bytes", " %"PRIu64" bytes", mfcs->mfcs_bytes);
 
-                               fprintf(ofp, "%s", viftable[ovifi]);
-                               if (ottl>1)
-                                       fprintf(ofp, "(ttl %d) ", ovifi);
-                               else
-                                       fprintf(ofp, " ");
-                       }
-               }
+               if (mfcs->mfcs_wrong_if)
+                       print_u64(PRINT_ANY, "wrong_if",
+                                  ", %"PRIu64" arrived on wrong iif.",
+                                  mfcs->mfcs_wrong_if);
+       }
 
-               if (show_stats && b) {
-                       fprintf(ofp, "%s  %u packets, %u bytes", _SL_, pkts, b);
-                       if (w)
-                               fprintf(ofp, ", %u arrived on wrong iif.", w);
-               }
-               fprintf(ofp, "\n");
+       if (show_stats && tb[RTA_EXPIRES]) {
+               struct timeval tv;
+               double age;
+
+               __jiffies_to_tv(&tv, rta_getattr_u64(tb[RTA_EXPIRES]));
+               age = tv.tv_sec;
+               age += tv.tv_usec / 1000000.;
+               print_float(PRINT_ANY, "expires",
+                           ", Age %.2f", age);
        }
-       fclose(fp);
+
+       if (table && (table != RT_TABLE_MAIN || show_details > 0) && !filter.tb)
+               print_string(PRINT_ANY, "table", " Table: %s",
+                            rtnl_rttable_n2a(table, b1, sizeof(b1)));
+
+       print_string(PRINT_FP, NULL, "\n", NULL);
+       close_json_object();
+       return 0;
 }
 
+void ipmroute_reset_filter(int ifindex)
+{
+       memset(&filter, 0, sizeof(filter));
+       filter.mdst.bitlen = -1;
+       filter.msrc.bitlen = -1;
+       filter.iif = ifindex;
+}
 
 static int mroute_list(int argc, char **argv)
 {
+       char *id = NULL;
+       int family = preferred_family;
+
+       ipmroute_reset_filter(0);
+       if (family == AF_INET || family == AF_UNSPEC) {
+               family = RTNL_FAMILY_IPMR;
+               filter.af = RTNL_FAMILY_IPMR;
+               filter.tb = RT_TABLE_DEFAULT;  /* for backward compatibility */
+       } else if (family == AF_INET6) {
+               family = RTNL_FAMILY_IP6MR;
+               filter.af = RTNL_FAMILY_IP6MR;
+       } else {
+               /* family does not have multicast routing */
+               return 0;
+       }
+
+       filter.msrc.family = filter.mdst.family = family;
+
        while (argc > 0) {
-               if (strcmp(*argv, "iif") == 0) {
+               if (matches(*argv, "table") == 0) {
+                       __u32 tid;
+
                        NEXT_ARG();
-                       strncpy(filter_dev, *argv, sizeof(filter_dev)-1);
+                       if (rtnl_rttable_a2n(&tid, *argv)) {
+                               if (strcmp(*argv, "all") == 0) {
+                                       filter.tb = 0;
+                               } else if (strcmp(*argv, "help") == 0) {
+                                       usage();
+                               } else {
+                                       invarg("table id value is invalid\n", *argv);
+                               }
+                       } else
+                               filter.tb = tid;
+               } else if (strcmp(*argv, "iif") == 0) {
+                       NEXT_ARG();
+                       id = *argv;
                } else if (matches(*argv, "from") == 0) {
                        NEXT_ARG();
-                       get_prefix(&filter.msrc, *argv, AF_INET);
+                       if (get_prefix(&filter.msrc, *argv, family))
+                               invarg("from value is invalid\n", *argv);
                } else {
                        if (strcmp(*argv, "to") == 0) {
                                NEXT_ARG();
                        }
                        if (matches(*argv, "help") == 0)
                                usage();
-                       get_prefix(&filter.mdst, *argv, AF_INET);
+                       if (get_prefix(&filter.mdst, *argv, family))
+                               invarg("to value is invalid\n", *argv);
                }
-               argv++; argc--;
+               argc--; argv++;
+       }
+
+       ll_init_map(&rth);
+
+       if (id)  {
+               int idx;
+
+               idx = ll_name_to_index(id);
+               if (!idx)
+                       return nodev(id);
+               filter.iif = idx;
+       }
+
+       if (rtnl_routedump_req(&rth, filter.af, NULL) < 0) {
+               perror("Cannot send dump request");
+               return 1;
+       }
+
+       new_json_obj(json);
+       if (rtnl_dump_filter(&rth, print_mroute, stdout) < 0) {
+               delete_json_obj();
+               fprintf(stderr, "Dump terminated\n");
+               exit(1);
        }
+       delete_json_obj();
 
-       read_viftable();
-       read_mroute_list(stdout);
        return 0;
 }