]> git.proxmox.com Git - mirror_iproute2.git/blobdiff - bridge/mdb.c
utils: Introduce and use nodev() helper routine
[mirror_iproute2.git] / bridge / mdb.c
index 600596c94969b91d8db4432d3264168494f10df1..f38dc67c849a333c01a6b25c5e33c0144c629aad 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Get mdb table with netlink
  */
 #include "br_common.h"
 #include "rt_names.h"
 #include "utils.h"
+#include "json_print.h"
 
 #ifndef MDBA_RTA
 #define MDBA_RTA(r) \
-       ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct br_port_msg))))
+       ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct br_port_msg))))
 #endif
 
-static unsigned int filter_index;
+static unsigned int filter_index, filter_vlan;
 
 static void usage(void)
 {
        fprintf(stderr, "Usage: bridge mdb { add | del } dev DEV port PORT grp GROUP [permanent | temp] [vid VID]\n");
-       fprintf(stderr, "       bridge mdb {show} [ dev DEV ]\n");
+       fprintf(stderr, "       bridge mdb {show} [ dev DEV ] [ vid VID ]\n");
        exit(-1);
 }
 
-static void br_print_router_ports(FILE *f, struct rtattr *attr)
+static bool is_temp_mcast_rtr(__u8 type)
 {
-       uint32_t *port_ifindex;
+       return type == MDB_RTR_TYPE_TEMP_QUERY || type == MDB_RTR_TYPE_TEMP;
+}
+
+static const char *format_timer(__u32 ticks)
+{
+       struct timeval tv;
+       static char tbuf[32];
+
+       __jiffies_to_tv(&tv, ticks);
+       snprintf(tbuf, sizeof(tbuf), "%4lu.%.2lu",
+                (unsigned long)tv.tv_sec,
+                (unsigned long)tv.tv_usec / 10000);
+
+       return tbuf;
+}
+
+static void __print_router_port_stats(FILE *f, struct rtattr *pattr)
+{
+       struct rtattr *tb[MDBA_ROUTER_PATTR_MAX + 1];
+
+       parse_rtattr(tb, MDBA_ROUTER_PATTR_MAX, MDB_RTR_RTA(RTA_DATA(pattr)),
+                    RTA_PAYLOAD(pattr) - RTA_ALIGN(sizeof(uint32_t)));
+
+       if (tb[MDBA_ROUTER_PATTR_TIMER]) {
+               __u32 timer = rta_getattr_u32(tb[MDBA_ROUTER_PATTR_TIMER]);
+
+               print_string(PRINT_ANY, "timer", " %s",
+                            format_timer(timer));
+       }
+
+       if (tb[MDBA_ROUTER_PATTR_TYPE]) {
+               __u8 type = rta_getattr_u8(tb[MDBA_ROUTER_PATTR_TYPE]);
+
+               print_string(PRINT_ANY, "type", " %s",
+                            is_temp_mcast_rtr(type) ? "temp" : "permanent");
+       }
+}
+
+static void br_print_router_ports(FILE *f, struct rtattr *attr,
+                                 const char *brifname)
+{
+       int rem = RTA_PAYLOAD(attr);
        struct rtattr *i;
-       int rem;
 
-       rem = RTA_PAYLOAD(attr);
+       if (is_json_context())
+               open_json_array(PRINT_JSON, brifname);
+       else if (!show_stats)
+               fprintf(f, "router ports on %s: ", brifname);
+
        for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
-               port_ifindex = RTA_DATA(i);
-               fprintf(f, "%s ", ll_index_to_name(*port_ifindex));
+               uint32_t *port_ifindex = RTA_DATA(i);
+               const char *port_ifname = ll_index_to_name(*port_ifindex);
+
+               if (is_json_context()) {
+                       open_json_object(NULL);
+                       print_string(PRINT_JSON, "port", NULL, port_ifname);
+
+                       if (show_stats)
+                               __print_router_port_stats(f, i);
+                       close_json_object();
+               } else if (show_stats) {
+                       fprintf(f, "router ports on %s: %s",
+                               brifname, port_ifname);
+
+                       __print_router_port_stats(f, i);
+                       fprintf(f, "\n");
+               } else {
+                       fprintf(f, "%s ", port_ifname);
+               }
        }
-
-       fprintf(f, "\n");
+       close_json_array(PRINT_JSON, NULL);
 }
 
-static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e,
+static void print_mdb_entry(FILE *f, int ifindex, const struct br_mdb_entry *e,
                            struct nlmsghdr *n, struct rtattr **tb)
 {
        SPRINT_BUF(abuf);
+       const char *dev;
        const void *src;
        int af;
 
+       if (filter_vlan && e->vid != filter_vlan)
+               return;
+
        af = e->addr.proto == htons(ETH_P_IP) ? AF_INET : AF_INET6;
        src = af == AF_INET ? (const void *)&e->addr.u.ip4 :
                              (const void *)&e->addr.u.ip6;
+       dev = ll_index_to_name(ifindex);
+
+       open_json_object(NULL);
+
        if (n->nlmsg_type == RTM_DELMDB)
-               fprintf(f, "Deleted ");
-       fprintf(f, "dev %s port %s grp %s %s %s", ll_index_to_name(ifindex),
-               ll_index_to_name(e->ifindex),
-               inet_ntop(af, src, abuf, sizeof(abuf)),
-               (e->state & MDB_PERMANENT) ? "permanent" : "temp",
-               (e->flags & MDB_FLAGS_OFFLOAD) ? "offload" : "");
+               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
+
+
+       if (is_json_context()) {
+               print_int(PRINT_JSON, "index", NULL, ifindex);
+               print_string(PRINT_JSON, "dev", NULL, dev);
+       } else {
+               fprintf(f, "%u: ", ifindex);
+               color_fprintf(f, COLOR_IFNAME, "%s ", dev);
+       }
+
+       print_string(PRINT_ANY, "port", " %s ",
+                    ll_index_to_name(e->ifindex));
+
+       print_color_string(PRINT_ANY, ifa_family_color(af),
+                           "grp", " %s ",
+                           inet_ntop(af, src, abuf, sizeof(abuf)));
+
+       print_string(PRINT_ANY, "state", " %s ",
+                          (e->state & MDB_PERMANENT) ? "permanent" : "temp");
+
+       open_json_array(PRINT_JSON, "flags");
+       if (e->flags & MDB_FLAGS_OFFLOAD)
+               print_string(PRINT_ANY, NULL, "%s ", "offload");
+       close_json_array(PRINT_JSON, NULL);
+
        if (e->vid)
-               fprintf(f, " vid %hu", e->vid);
+               print_uint(PRINT_ANY, "vid", " vid %u", e->vid);
+
        if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) {
-               struct timeval tv;
+               __u32 timer = rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER]);
 
-               __jiffies_to_tv(&tv, rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER]));
-               fprintf(f, "%4i.%.2i", (int)tv.tv_sec, (int)tv.tv_usec/10000);
+               print_string(PRINT_ANY, "timer", " %s",
+                            format_timer(timer));
        }
-       fprintf(f, "\n");
+       close_json_object();
 }
 
 static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr,
@@ -93,15 +184,60 @@ static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr,
        }
 }
 
+static void print_mdb_entries(FILE *fp, struct nlmsghdr *n,
+                             int ifindex,  struct rtattr *mdb)
+{
+       int rem = RTA_PAYLOAD(mdb);
+       struct rtattr *i;
+
+       open_json_array(PRINT_JSON, "mdb");
+       for (i = RTA_DATA(mdb); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
+               br_print_mdb_entry(fp, ifindex, i, n);
+       close_json_array(PRINT_JSON, NULL);
+}
+
+static void print_router_entries(FILE *fp, struct nlmsghdr *n,
+                                int ifindex, struct rtattr *router)
+{
+       const char *brifname = ll_index_to_name(ifindex);
+
+       open_json_array(PRINT_JSON, "router");
+       if (n->nlmsg_type == RTM_GETMDB) {
+               if (show_details)
+                       br_print_router_ports(fp, router, brifname);
+       } else {
+               struct rtattr *i = RTA_DATA(router);
+               uint32_t *port_ifindex = RTA_DATA(i);
+
+               if (is_json_context()) {
+                       open_json_array(PRINT_JSON, brifname);
+                       open_json_object(NULL);
+
+                       print_string(PRINT_JSON, "port", NULL,
+                                    ll_index_to_name(*port_ifindex));
+                       close_json_object();
+                       close_json_array(PRINT_JSON, NULL);
+               } else {
+                       fprintf(fp, "router port dev %s master %s\n",
+                               ll_index_to_name(*port_ifindex),
+                               brifname);
+               }
+       }
+       close_json_array(PRINT_JSON, NULL);
+}
+
 int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
        FILE *fp = arg;
        struct br_port_msg *r = NLMSG_DATA(n);
        int len = n->nlmsg_len;
-       struct rtattr *tb[MDBA_MAX+1], *i;
+       struct rtattr *tb[MDBA_MAX+1];
 
-       if (n->nlmsg_type != RTM_GETMDB && n->nlmsg_type != RTM_NEWMDB && n->nlmsg_type != RTM_DELMDB) {
-               fprintf(stderr, "Not RTM_GETMDB, RTM_NEWMDB or RTM_DELMDB: %08x %08x %08x\n",
+       if (n->nlmsg_type != RTM_GETMDB &&
+           n->nlmsg_type != RTM_NEWMDB &&
+           n->nlmsg_type != RTM_DELMDB) {
+               fprintf(stderr,
+                       "Not RTM_GETMDB, RTM_NEWMDB or RTM_DELMDB: %08x %08x %08x\n",
                        n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
 
                return 0;
@@ -118,34 +254,14 @@ int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 
        parse_rtattr(tb, MDBA_MAX, MDBA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
 
-       if (tb[MDBA_MDB]) {
-               int rem = RTA_PAYLOAD(tb[MDBA_MDB]);
-
-               for (i = RTA_DATA(tb[MDBA_MDB]); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
-                       br_print_mdb_entry(fp, r->ifindex, i, n);
-       }
-
-       if (tb[MDBA_ROUTER]) {
-               if (n->nlmsg_type == RTM_GETMDB) {
-                       if (show_details) {
-                               fprintf(fp, "router ports on %s: ",
-                                       ll_index_to_name(r->ifindex));
-                               br_print_router_ports(fp, tb[MDBA_ROUTER]);
-                       }
-               } else {
-                       uint32_t *port_ifindex;
+       if (n->nlmsg_type == RTM_DELMDB)
+               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 
-                       i = RTA_DATA(tb[MDBA_ROUTER]);
-                       port_ifindex = RTA_DATA(i);
-                       if (n->nlmsg_type == RTM_DELMDB)
-                               fprintf(fp, "Deleted ");
-                       fprintf(fp, "router port dev %s master %s\n",
-                               ll_index_to_name(*port_ifindex),
-                               ll_index_to_name(r->ifindex));
-               }
-       }
+       if (tb[MDBA_MDB])
+               print_mdb_entries(fp, n, r->ifindex, tb[MDBA_MDB]);
 
-       fflush(fp);
+       if (tb[MDBA_ROUTER])
+               print_router_entries(fp, n, r->ifindex, tb[MDBA_ROUTER]);
 
        return 0;
 }
@@ -160,19 +276,24 @@ static int mdb_show(int argc, char **argv)
                        if (filter_dev)
                                duparg("dev", *argv);
                        filter_dev = *argv;
+               } else if (strcmp(*argv, "vid") == 0) {
+                       NEXT_ARG();
+                       if (filter_vlan)
+                               duparg("vid", *argv);
+                       filter_vlan = atoi(*argv);
                }
                argc--; argv++;
        }
 
        if (filter_dev) {
-               filter_index = if_nametoindex(filter_dev);
-               if (filter_index == 0) {
-                       fprintf(stderr, "Cannot find device \"%s\"\n",
-                               filter_dev);
-                       return -1;
-               }
+               filter_index = ll_name_to_index(filter_dev);
+               if (!filter_index)
+                       return nodev(filter_dev);
        }
 
+       new_json_obj(json);
+
+       /* get mdb entries*/
        if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) {
                perror("Cannot send dump request");
                return -1;
@@ -183,28 +304,28 @@ static int mdb_show(int argc, char **argv)
                return -1;
        }
 
+       delete_json_obj();
+       fflush(stdout);
+
        return 0;
 }
 
 static int mdb_modify(int cmd, int flags, int argc, char **argv)
 {
        struct {
-               struct nlmsghdr         n;
+               struct nlmsghdr n;
                struct br_port_msg      bpm;
-               char                    buf[1024];
-       } req;
-       struct br_mdb_entry entry;
+               char                    buf[1024];
+       } req = {
+               .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_port_msg)),
+               .n.nlmsg_flags = NLM_F_REQUEST | flags,
+               .n.nlmsg_type = cmd,
+               .bpm.family = PF_BRIDGE,
+       };
+       struct br_mdb_entry entry = {};
        char *d = NULL, *p = NULL, *grp = NULL;
        short vid = 0;
 
-       memset(&req, 0, sizeof(req));
-       memset(&entry, 0, sizeof(entry));
-
-       req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_port_msg));
-       req.n.nlmsg_flags = NLM_F_REQUEST|flags;
-       req.n.nlmsg_type = cmd;
-       req.bpm.family = PF_BRIDGE;
-
        while (argc > 0) {
                if (strcmp(*argv, "dev") == 0) {
                        NEXT_ARG();
@@ -236,16 +357,12 @@ static int mdb_modify(int cmd, int flags, int argc, char **argv)
        }
 
        req.bpm.ifindex = ll_name_to_index(d);
-       if (req.bpm.ifindex == 0) {
-               fprintf(stderr, "Cannot find device \"%s\"\n", d);
-               return -1;
-       }
+       if (!req.bpm.ifindex)
+               return nodev(d);
 
        entry.ifindex = ll_name_to_index(p);
-       if (entry.ifindex == 0) {
-               fprintf(stderr, "Cannot find device \"%s\"\n", p);
-               return -1;
-       }
+       if (!entry.ifindex)
+               return nodev(p);
 
        if (!inet_pton(AF_INET, grp, &entry.addr.u.ip4)) {
                if (!inet_pton(AF_INET6, grp, &entry.addr.u.ip6)) {
@@ -259,7 +376,7 @@ static int mdb_modify(int cmd, int flags, int argc, char **argv)
        entry.vid = vid;
        addattr_l(&req.n, sizeof(req), MDBA_SET_ENTRY, &entry, sizeof(entry));
 
-       if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
+       if (rtnl_talk(&rth, &req.n, NULL) < 0)
                return -1;
 
        return 0;