]> git.proxmox.com Git - mirror_iproute2.git/commitdiff
Merge branch 'iproute2-master' into iproute2-next
authorDavid Ahern <dsahern@gmail.com>
Tue, 27 Mar 2018 19:33:02 +0000 (12:33 -0700)
committerDavid Ahern <dsahern@gmail.com>
Tue, 27 Mar 2018 19:33:02 +0000 (12:33 -0700)
Signed-off-by: David Ahern <dsahern@gmail.com>
138 files changed:
Makefile
bridge/br_common.h
bridge/bridge.c
bridge/fdb.c
bridge/link.c
bridge/mdb.c
bridge/vlan.c
etc/iproute2/ematch_map
include/ll_map.h
include/uapi/linux/bpf.h
include/uapi/linux/fib_rules.h
include/uapi/linux/if_ether.h
include/uapi/linux/if_link.h
include/uapi/linux/pkt_cls.h
include/uapi/linux/sctp.h
include/uapi/linux/tc_ematch/tc_em_ipt.h [new file with mode: 0644]
include/uapi/linux/tcp.h
include/uapi/rdma/rdma_netlink.h [deleted file]
include/utils.h
ip/ip.c
ip/ip6tunnel.c
ip/ip_common.h
ip/ipaddress.c
ip/ipaddrlabel.c
ip/ipfou.c
ip/iplink.c
ip/iplink_bond.c
ip/iplink_bridge.c
ip/iplink_bridge_slave.c
ip/iplink_geneve.c
ip/iplink_vlan.c
ip/iplink_vxcan.c
ip/iplink_vxlan.c
ip/iplink_xdp.c
ip/ipmacsec.c
ip/ipmaddr.c
ip/ipmroute.c
ip/ipneigh.c
ip/ipnetconf.c
ip/ipnetns.c
ip/ipntable.c
ip/iproute.c
ip/iproute_lwtunnel.c
ip/iproute_lwtunnel.h [deleted file]
ip/iprule.c
ip/ipseg6.c
ip/iptoken.c
ip/iptunnel.c
ip/iptuntap.c
ip/link_gre.c
ip/link_gre6.c
ip/link_ip6tnl.c
ip/link_iptnl.c
ip/link_veth.c
ip/link_vti.c
ip/link_vti6.c
ip/tcp_metrics.c
ip/tunnel.c
ip/tunnel.h
ip/xdp.h [deleted file]
lib/Makefile
lib/json_print.c
lib/json_writer.c
lib/ll_map.c
lib/utils.c
man/man8/bridge.8
man/man8/ip-link.8.in
man/man8/ip-rule.8
man/man8/ip.8
man/man8/rdma.8
man/man8/tc-codel.8
man/man8/tc-ematch.8
man/man8/tc-flower.8
man/man8/tc-fq_codel.8
man/man8/tc.8
misc/ifstat.c
misc/nstat.c
misc/ss.c
rdma/Makefile
rdma/dev.c
rdma/include/uapi/rdma/rdma_netlink.h [new file with mode: 0644]
rdma/rdma.c
tc/Makefile
tc/em_ipt.c [new file with mode: 0644]
tc/f_flow.c
tc/f_flower.c
tc/f_fw.c
tc/f_route.c
tc/f_rsvp.c
tc/f_tcindex.c
tc/f_u32.c
tc/m_action.c
tc/m_bpf.c
tc/m_connmark.c
tc/m_csum.c
tc/m_ematch.c
tc/m_ematch.h
tc/m_gact.c
tc/m_ife.c
tc/m_ipt.c
tc/m_mirred.c
tc/m_nat.c
tc/m_pedit.c
tc/m_police.c
tc/m_sample.c
tc/m_simple.c
tc/m_skbedit.c
tc/m_skbmod.c
tc/m_tunnel_key.c
tc/m_vlan.c
tc/m_xt.c
tc/m_xt_old.c
tc/q_atm.c
tc/q_cbq.c
tc/q_cbs.c
tc/q_choke.c
tc/q_codel.c
tc/q_drr.c
tc/q_dsmark.c
tc/q_fq.c
tc/q_fq_codel.c
tc/q_gred.c
tc/q_hfsc.c
tc/q_hhf.c
tc/q_htb.c
tc/q_mqprio.c
tc/q_netem.c
tc/q_pie.c
tc/q_qfq.c
tc/q_red.c
tc/q_sfb.c
tc/q_tbf.c
tc/tc.c
tc/tc_class.c
tc/tc_filter.c
tc/tc_qdisc.c
tc/tc_util.c
tc/tc_util.h

index 32587db3be70598aef5bcff1025fe9e0ff90153e..b526d3b5b5c4e4ec013f8f7d601ad02ff0dbfa03 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -59,7 +59,7 @@ YACCFLAGS = -d -t -v
 
 SUBDIRS=lib ip tc bridge misc netem genl tipc devlink rdma man
 
-LIBNETLINK=../lib/libnetlink.a ../lib/libutil.a
+LIBNETLINK=../lib/libutil.a ../lib/libnetlink.a
 LDLIBS += $(LIBNETLINK)
 
 all: config.mk
index f07c7d1c9090b032ff5e2ae1d0660e1fcd6381aa..2f1cb8fd9f3d02c890c9fdb4ba82a50c01355f11 100644 (file)
@@ -6,7 +6,7 @@
 #define MDB_RTR_RTA(r) \
                ((struct rtattr *)(((char *)(r)) + RTA_ALIGN(sizeof(__u32))))
 
-extern void print_vlan_info(FILE *fp, struct rtattr *tb, int ifindex);
+extern void print_vlan_info(FILE *fp, struct rtattr *tb);
 extern int print_linkinfo(const struct sockaddr_nl *who,
                          struct nlmsghdr *n,
                          void *arg);
@@ -26,5 +26,5 @@ extern int show_stats;
 extern int show_details;
 extern int timestamp;
 extern int compress_vlans;
-extern int json_output;
+extern int json;
 extern struct rtnl_handle rth;
index 48fe1c8b2ef10b90857664530a0ab902f2c208e3..7fcfe1116f6e5a204151fd468adf662ef3670550 100644 (file)
 #include "utils.h"
 #include "br_common.h"
 #include "namespace.h"
+#include "color.h"
 
 struct rtnl_handle rth = { .fd = -1 };
 int preferred_family = AF_UNSPEC;
 int oneline;
 int show_stats;
 int show_details;
+int show_pretty;
+int color;
 int compress_vlans;
-int json_output;
+int json;
 int timestamp;
 char *batch_file;
 int force;
@@ -39,7 +42,7 @@ static void usage(void)
 "where OBJECT := { link | fdb | mdb | vlan | monitor }\n"
 "      OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n"
 "                   -o[neline] | -t[imestamp] | -n[etns] name |\n"
-"                   -c[ompressvlans] -j{son} }\n");
+"                   -c[ompressvlans] -color -p[retty] -j{son} }\n");
        exit(-1);
 }
 
@@ -170,12 +173,16 @@ main(int argc, char **argv)
                        NEXT_ARG();
                        if (netns_switch(argv[1]))
                                exit(-1);
+               } else if (matches(opt, "-color") == 0) {
+                       enable_color();
                } else if (matches(opt, "-compressvlans") == 0) {
                        ++compress_vlans;
                } else if (matches(opt, "-force") == 0) {
                        ++force;
                } else if (matches(opt, "-json") == 0) {
-                       ++json_output;
+                       ++json;
+               } else if (matches(opt, "-pretty") == 0) {
+                       ++pretty;
                } else if (matches(opt, "-batch") == 0) {
                        argc--;
                        argv++;
@@ -193,6 +200,9 @@ main(int argc, char **argv)
 
        _SL_ = oneline ? "\\" : "\n";
 
+       if (color && !json)
+               enable_color();
+
        if (batch_file)
                return batch(batch_file);
 
index 8b133f9c1c8da8f01030681f1cb52b4ce081c0b2..4dbc894ceab9396ac53712dc1d55bdbb2589fd90 100644 (file)
@@ -22,9 +22,9 @@
 #include <linux/neighbour.h>
 #include <string.h>
 #include <limits.h>
-#include <json_writer.h>
 #include <stdbool.h>
 
+#include "json_print.h"
 #include "libnetlink.h"
 #include "br_common.h"
 #include "rt_names.h"
 
 static unsigned int filter_index, filter_vlan, filter_state;
 
-json_writer_t *jw_global;
-
 static void usage(void)
 {
        fprintf(stderr,
                "Usage: bridge fdb { add | append | del | replace } ADDR dev DEV\n"
-               "              [ self ] [ master ] [ use ] [ router ]\n"
+               "              [ self ] [ master ] [ use ] [ router ] [ extern_learn ]\n"
                "              [ local | static | dynamic ] [ dst IPADDR ] [ vlan VID ]\n"
                "              [ port PORT] [ vni VNI ] [ via DEV ]\n"
                "       bridge fdb [ show [ br BRDEV ] [ brport DEV ] [ vlan VID ] [ state STATE ] ]\n");
@@ -83,13 +81,46 @@ static int state_a2n(unsigned int *s, const char *arg)
        return 0;
 }
 
-static void start_json_fdb_flags_array(bool *fdb_flags)
+static void fdb_print_flags(FILE *fp, unsigned int flags)
 {
-       if (*fdb_flags)
-               return;
-       jsonw_name(jw_global, "flags");
-       jsonw_start_array(jw_global);
-       *fdb_flags = true;
+       open_json_array(PRINT_JSON,
+                       is_json_context() ?  "flags" : "");
+
+       if (flags & NTF_SELF)
+               print_string(PRINT_ANY, NULL, "%s ", "self");
+
+       if (flags & NTF_ROUTER)
+               print_string(PRINT_ANY, NULL, "%s ", "router");
+
+       if (flags & NTF_EXT_LEARNED)
+               print_string(PRINT_ANY, NULL, "%s ", "extern_learn");
+
+       if (flags & NTF_OFFLOADED)
+               print_string(PRINT_ANY, NULL, "%s ", "offload");
+
+       if (flags & NTF_MASTER)
+               print_string(PRINT_ANY, NULL, "%s ", "master");
+
+       close_json_array(PRINT_JSON, NULL);
+}
+
+static void fdb_print_stats(FILE *fp, const struct nda_cacheinfo *ci)
+{
+       static int hz;
+
+       if (!hz)
+               hz = get_user_hz();
+
+       if (is_json_context()) {
+               print_uint(PRINT_JSON, "used", NULL,
+                                ci->ndm_used / hz);
+               print_uint(PRINT_JSON, "updated", NULL,
+                               ci->ndm_updated / hz);
+       } else {
+               fprintf(fp, "used %d/%d ", ci->ndm_used / hz,
+                                       ci->ndm_updated / hz);
+
+       }
 }
 
 int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
@@ -99,8 +130,6 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
        int len = n->nlmsg_len;
        struct rtattr *tb[NDA_MAX+1];
        __u16 vid = 0;
-       bool fdb_flags = false;
-       const char *state_s;
 
        if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH) {
                fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n",
@@ -132,191 +161,98 @@ int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
        if (filter_vlan && filter_vlan != vid)
                return 0;
 
-       if (jw_global) {
-               jsonw_pretty(jw_global, 1);
-               jsonw_start_object(jw_global);
-       }
-
-       if (n->nlmsg_type == RTM_DELNEIGH) {
-               if (jw_global)
-                       jsonw_string_field(jw_global, "opCode", "deleted");
-               else
-                       fprintf(fp, "Deleted ");
-       }
+       open_json_object(NULL);
+       if (n->nlmsg_type == RTM_DELNEIGH)
+               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 
        if (tb[NDA_LLADDR]) {
+               const char *lladdr;
                SPRINT_BUF(b1);
-               ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
-                           RTA_PAYLOAD(tb[NDA_LLADDR]),
-                           ll_index_to_type(r->ndm_ifindex),
-                           b1, sizeof(b1));
-               if (jw_global)
-                       jsonw_string_field(jw_global, "mac", b1);
-               else
-                       fprintf(fp, "%s ", b1);
+
+               lladdr = ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
+                                    RTA_PAYLOAD(tb[NDA_LLADDR]),
+                                    ll_index_to_type(r->ndm_ifindex),
+                                    b1, sizeof(b1));
+
+               print_color_string(PRINT_ANY, COLOR_MAC,
+                                  "mac", "%s ", lladdr);
        }
 
        if (!filter_index && r->ndm_ifindex) {
-               if (jw_global)
-                       jsonw_string_field(jw_global, "dev",
-                                          ll_index_to_name(r->ndm_ifindex));
-               else
-                       fprintf(fp, "dev %s ",
-                               ll_index_to_name(r->ndm_ifindex));
+               if (!is_json_context())
+                       fprintf(fp, "dev ");
+               print_color_string(PRINT_ANY, COLOR_IFNAME,
+                                  "ifname", "%s ",
+                                  ll_index_to_name(r->ndm_ifindex));
        }
 
        if (tb[NDA_DST]) {
                int family = AF_INET;
-               const char *abuf_s;
+               const char *dst;
 
                if (RTA_PAYLOAD(tb[NDA_DST]) == sizeof(struct in6_addr))
                        family = AF_INET6;
 
-               abuf_s = format_host(family,
-                                    RTA_PAYLOAD(tb[NDA_DST]),
-                                    RTA_DATA(tb[NDA_DST]));
-               if (jw_global)
-                       jsonw_string_field(jw_global, "dst", abuf_s);
-               else
-                       fprintf(fp, "dst %s ", abuf_s);
-       }
+               dst = format_host(family,
+                                 RTA_PAYLOAD(tb[NDA_DST]),
+                                 RTA_DATA(tb[NDA_DST]));
 
-       if (vid) {
-               if (jw_global)
-                       jsonw_uint_field(jw_global, "vlan", vid);
-               else
-                       fprintf(fp, "vlan %hu ", vid);
+               print_color_string(PRINT_ANY,
+                                  ifa_family_color(family),
+                                   "dst", "%s ", dst);
        }
 
-       if (tb[NDA_PORT]) {
-               if (jw_global)
-                       jsonw_uint_field(jw_global, "port",
-                                        rta_getattr_be16(tb[NDA_PORT]));
-               else
-                       fprintf(fp, "port %d ",
-                               rta_getattr_be16(tb[NDA_PORT]));
-       }
+       if (vid)
+               print_uint(PRINT_ANY,
+                                "vlan", "vlan %hu ", vid);
 
-       if (tb[NDA_VNI]) {
-               if (jw_global)
-                       jsonw_uint_field(jw_global, "vni",
-                                        rta_getattr_u32(tb[NDA_VNI]));
-               else
-                       fprintf(fp, "vni %d ",
-                               rta_getattr_u32(tb[NDA_VNI]));
-       }
+       if (tb[NDA_PORT])
+               print_uint(PRINT_ANY,
+                                "port", "port %u ",
+                                rta_getattr_be16(tb[NDA_PORT]));
 
-       if (tb[NDA_SRC_VNI]) {
-               if (jw_global)
-                       jsonw_uint_field(jw_global, "src_vni",
-                                        rta_getattr_u32(tb[NDA_SRC_VNI]));
-               else
-                       fprintf(fp, "src_vni %d ",
+       if (tb[NDA_VNI])
+               print_uint(PRINT_ANY,
+                                "vni", "vni %u ",
+                                rta_getattr_u32(tb[NDA_VNI]));
+
+       if (tb[NDA_SRC_VNI])
+               print_uint(PRINT_ANY,
+                                "src_vni", "src_vni %u ",
                                rta_getattr_u32(tb[NDA_SRC_VNI]));
-       }
 
        if (tb[NDA_IFINDEX]) {
                unsigned int ifindex = rta_getattr_u32(tb[NDA_IFINDEX]);
 
-               if (ifindex) {
-                       if (!tb[NDA_LINK_NETNSID]) {
-                               const char *ifname = ll_index_to_name(ifindex);
-
-                               if (jw_global)
-                                       jsonw_string_field(jw_global, "viaIf",
-                                                          ifname);
-                               else
-                                       fprintf(fp, "via %s ", ifname);
-                       } else {
-                               if (jw_global)
-                                       jsonw_uint_field(jw_global, "viaIfIndex",
-                                                        ifindex);
-                               else
-                                       fprintf(fp, "via ifindex %u ", ifindex);
-                       }
-               }
-       }
-
-       if (tb[NDA_LINK_NETNSID]) {
-               if (jw_global)
-                       jsonw_uint_field(jw_global, "linkNetNsId",
-                                        rta_getattr_u32(tb[NDA_LINK_NETNSID]));
+               if (tb[NDA_LINK_NETNSID])
+                       print_uint(PRINT_ANY,
+                                        "viaIfIndex", "via ifindex %u ",
+                                        ifindex);
                else
-                       fprintf(fp, "link-netnsid %d ",
-                               rta_getattr_u32(tb[NDA_LINK_NETNSID]));
+                       print_string(PRINT_ANY,
+                                          "viaIf", "via %s ",
+                                          ll_index_to_name(ifindex));
        }
 
-       if (show_stats && tb[NDA_CACHEINFO]) {
-               struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
-               int hz = get_user_hz();
+       if (tb[NDA_LINK_NETNSID])
+               print_uint(PRINT_ANY,
+                                "linkNetNsId", "link-netnsid %d ",
+                                rta_getattr_u32(tb[NDA_LINK_NETNSID]));
 
-               if (jw_global) {
-                       jsonw_uint_field(jw_global, "used",
-                               ci->ndm_used/hz);
-                       jsonw_uint_field(jw_global, "updated",
-                               ci->ndm_updated/hz);
-               } else {
-                       fprintf(fp, "used %d/%d ", ci->ndm_used/hz,
-                                       ci->ndm_updated/hz);
-               }
-       }
+       if (show_stats && tb[NDA_CACHEINFO])
+               fdb_print_stats(fp, RTA_DATA(tb[NDA_CACHEINFO]));
 
-       if (jw_global) {
-               if (r->ndm_flags & NTF_SELF) {
-                       start_json_fdb_flags_array(&fdb_flags);
-                       jsonw_string(jw_global, "self");
-               }
-               if (r->ndm_flags & NTF_ROUTER) {
-                       start_json_fdb_flags_array(&fdb_flags);
-                       jsonw_string(jw_global, "router");
-               }
-               if (r->ndm_flags & NTF_EXT_LEARNED) {
-                       start_json_fdb_flags_array(&fdb_flags);
-                       jsonw_string(jw_global, "extern_learn");
-               }
-               if (r->ndm_flags & NTF_OFFLOADED) {
-                       start_json_fdb_flags_array(&fdb_flags);
-                       jsonw_string(jw_global, "offload");
-               }
-               if (r->ndm_flags & NTF_MASTER)
-                       jsonw_string(jw_global, "master");
-               if (fdb_flags)
-                       jsonw_end_array(jw_global);
+       fdb_print_flags(fp, r->ndm_flags);
 
-               if (tb[NDA_MASTER])
-                       jsonw_string_field(jw_global,
-                                          "master",
-                                          ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
 
-       } else {
-               if (r->ndm_flags & NTF_SELF)
-                       fprintf(fp, "self ");
-               if (r->ndm_flags & NTF_ROUTER)
-                       fprintf(fp, "router ");
-               if (r->ndm_flags & NTF_EXT_LEARNED)
-                       fprintf(fp, "extern_learn ");
-               if (r->ndm_flags & NTF_OFFLOADED)
-                       fprintf(fp, "offload ");
-               if (tb[NDA_MASTER]) {
-                       fprintf(fp, "master %s ",
-                               ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
-               } else if (r->ndm_flags & NTF_MASTER) {
-                       fprintf(fp, "master ");
-               }
-       }
-
-       state_s = state_n2a(r->ndm_state);
-       if (jw_global) {
-               if (state_s[0])
-                       jsonw_string_field(jw_global, "state", state_s);
-
-               jsonw_end_object(jw_global);
-       } else {
-               fprintf(fp, "%s\n", state_s);
-
-               fflush(fp);
-       }
+       if (tb[NDA_MASTER])
+               print_string(PRINT_ANY, "master", "%s ",
+                            ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
 
+       print_string(PRINT_ANY, "state", "%s\n",
+                          state_n2a(r->ndm_state));
+       close_json_object();
+       fflush(fp);
        return 0;
 }
 
@@ -375,11 +311,8 @@ static int fdb_show(int argc, char **argv)
        /*we'll keep around filter_dev for older kernels */
        if (filter_dev) {
                filter_index = ll_name_to_index(filter_dev);
-               if (filter_index == 0) {
-                       fprintf(stderr, "Cannot find device \"%s\"\n",
-                               filter_dev);
-                       return -1;
-               }
+               if (!filter_index)
+                       return nodev(filter_dev);
                req.ifm.ifi_index = filter_index;
        }
 
@@ -388,22 +321,13 @@ static int fdb_show(int argc, char **argv)
                exit(1);
        }
 
-       if (json_output) {
-               jw_global = jsonw_new(stdout);
-               if (!jw_global) {
-                       fprintf(stderr, "Error allocation json object\n");
-                       exit(1);
-               }
-               jsonw_start_array(jw_global);
-       }
+       new_json_obj(json);
        if (rtnl_dump_filter(&rth, print_fdb, stdout) < 0) {
                fprintf(stderr, "Dump terminated\n");
                exit(1);
        }
-       if (jw_global) {
-               jsonw_end_array(jw_global);
-               jsonw_destroy(&jw_global);
-       }
+       delete_json_obj();
+       fflush(stdout);
 
        return 0;
 }
@@ -464,8 +388,8 @@ static int fdb_modify(int cmd, int flags, int argc, char **argv)
                } else if (strcmp(*argv, "via") == 0) {
                        NEXT_ARG();
                        via = ll_name_to_index(*argv);
-                       if (via == 0)
-                               invarg("invalid device\n", *argv);
+                       if (!via)
+                               exit(nodev(*argv));
                } else if (strcmp(*argv, "self") == 0) {
                        req.ndm.ndm_flags |= NTF_SELF;
                } else if (matches(*argv, "master") == 0) {
@@ -488,6 +412,8 @@ static int fdb_modify(int cmd, int flags, int argc, char **argv)
                        vid = atoi(*argv);
                } else if (matches(*argv, "use") == 0) {
                        req.ndm.ndm_flags |= NTF_USE;
+               } else if (matches(*argv, "extern_learn") == 0) {
+                       req.ndm.ndm_flags |= NTF_EXT_LEARNED;
                } else {
                        if (strcmp(*argv, "to") == 0)
                                NEXT_ARG();
@@ -540,10 +466,8 @@ static int fdb_modify(int cmd, int flags, int argc, char **argv)
                addattr32(&req.n, sizeof(req), NDA_IFINDEX, via);
 
        req.ndm.ndm_ifindex = ll_name_to_index(d);
-       if (req.ndm.ndm_ifindex == 0) {
-               fprintf(stderr, "Cannot find device \"%s\"\n", d);
-               return -1;
-       }
+       if (!req.ndm.ndm_ifindex)
+               return nodev(d);
 
        if (rtnl_talk(&rth, &req.n, NULL) < 0)
                return -1;
index 870ebe0504777bdede5d55c4cbfb91a6a048f955..579d57e7c072a1b75649eac89b8d89b0e3db3956 100644 (file)
@@ -12,6 +12,7 @@
 #include <string.h>
 #include <stdbool.h>
 
+#include "json_print.h"
 #include "libnetlink.h"
 #include "utils.h"
 #include "br_common.h"
@@ -26,15 +27,21 @@ static const char *port_states[] = {
        [BR_STATE_BLOCKING] = "blocking",
 };
 
-static void print_link_flags(FILE *fp, unsigned int flags)
+static const char *hw_mode[] = {
+       "VEB", "VEPA"
+};
+
+static void print_link_flags(FILE *fp, unsigned int flags, unsigned int mdown)
 {
-       fprintf(fp, "<");
+       open_json_array(PRINT_ANY, is_json_context() ? "flags" : "<");
        if (flags & IFF_UP && !(flags & IFF_RUNNING))
-               fprintf(fp, "NO-CARRIER%s", flags ? "," : "");
+               print_string(PRINT_ANY, NULL,
+                            flags ? "%s," : "%s", "NO-CARRIER");
        flags &= ~IFF_RUNNING;
-#define _PF(f) if (flags&IFF_##f) { \
-                 flags &= ~IFF_##f ; \
-                 fprintf(fp, #f "%s", flags ? "," : ""); }
+
+#define _PF(f) if (flags&IFF_##f) {                                    \
+               flags &= ~IFF_##f ;                                     \
+               print_string(PRINT_ANY, NULL, flags ? "%s," : "%s", #f); }
        _PF(LOOPBACK);
        _PF(BROADCAST);
        _PF(POINTOPOINT);
@@ -55,53 +62,130 @@ static void print_link_flags(FILE *fp, unsigned int flags)
        _PF(ECHO);
 #undef _PF
        if (flags)
-               fprintf(fp, "%x", flags);
-       fprintf(fp, "> ");
+               print_hex(PRINT_ANY, NULL, "%x", flags);
+       if (mdown)
+               print_string(PRINT_ANY, NULL, ",%s", "M-DOWN");
+       close_json_array(PRINT_ANY, "> ");
 }
 
-static const char *oper_states[] = {
-       "UNKNOWN", "NOTPRESENT", "DOWN", "LOWERLAYERDOWN",
-       "TESTING", "DORMANT",    "UP"
-};
-
-static const char *hw_mode[] = {"VEB", "VEPA"};
+static void print_portstate(__u8 state)
+{
+       if (state <= BR_STATE_BLOCKING)
+               print_string(PRINT_ANY, "state",
+                            "state %s ", port_states[state]);
+       else
+               print_uint(PRINT_ANY, "state",
+                            "state (%d) ", state);
+}
 
-static void print_operstate(FILE *f, __u8 state)
+static void print_onoff(FILE *fp, const char *flag, __u8 val)
 {
-       if (state >= ARRAY_SIZE(oper_states))
-               fprintf(f, "state %#x ", state);
+       if (is_json_context())
+               print_bool(PRINT_JSON, flag, NULL, val);
        else
-               fprintf(f, "state %s ", oper_states[state]);
+               fprintf(fp, "%s %s ", flag, val ? "on" : "off");
 }
 
-static void print_portstate(FILE *f, __u8 state)
+static void print_hwmode(__u16 mode)
 {
-       if (state <= BR_STATE_BLOCKING)
-               fprintf(f, "state %s ", port_states[state]);
+       if (mode >= ARRAY_SIZE(hw_mode))
+               print_0xhex(PRINT_ANY, "hwmode",
+                           "hwmode %#hx ", mode);
        else
-               fprintf(f, "state (%d) ", state);
+               print_string(PRINT_ANY, "hwmode",
+                            "hwmode %s ", hw_mode[mode]);
 }
 
-static void print_onoff(FILE *f, char *flag, __u8 val)
+static void print_protinfo(FILE *fp, struct rtattr *attr)
 {
-       fprintf(f, "%s %s ", flag, val ? "on" : "off");
+       if (attr->rta_type & NLA_F_NESTED) {
+               struct rtattr *prtb[IFLA_BRPORT_MAX + 1];
+
+               parse_rtattr_nested(prtb, IFLA_BRPORT_MAX, attr);
+
+               if (prtb[IFLA_BRPORT_STATE])
+                       print_portstate(rta_getattr_u8(prtb[IFLA_BRPORT_STATE]));
+
+               if (prtb[IFLA_BRPORT_PRIORITY])
+                       print_uint(PRINT_ANY, "priority",
+                                  "priority %u ",
+                                  rta_getattr_u16(prtb[IFLA_BRPORT_PRIORITY]));
+
+               if (prtb[IFLA_BRPORT_COST])
+                       print_uint(PRINT_ANY, "cost",
+                                  "cost %u ",
+                                  rta_getattr_u32(prtb[IFLA_BRPORT_COST]));
+
+               if (!show_details)
+                       return;
+
+               if (!is_json_context())
+                       fprintf(fp, "%s    ", _SL_);
+
+               if (prtb[IFLA_BRPORT_MODE])
+                       print_onoff(fp, "hairpin",
+                                   rta_getattr_u8(prtb[IFLA_BRPORT_MODE]));
+               if (prtb[IFLA_BRPORT_GUARD])
+                       print_onoff(fp, "guard",
+                                   rta_getattr_u8(prtb[IFLA_BRPORT_GUARD]));
+               if (prtb[IFLA_BRPORT_PROTECT])
+                       print_onoff(fp, "root_block",
+                                   rta_getattr_u8(prtb[IFLA_BRPORT_PROTECT]));
+               if (prtb[IFLA_BRPORT_FAST_LEAVE])
+                       print_onoff(fp, "fastleave",
+                                   rta_getattr_u8(prtb[IFLA_BRPORT_FAST_LEAVE]));
+               if (prtb[IFLA_BRPORT_LEARNING])
+                       print_onoff(fp, "learning",
+                                   rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING]));
+               if (prtb[IFLA_BRPORT_LEARNING_SYNC])
+                       print_onoff(fp, "learning_sync",
+                                   rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING_SYNC]));
+               if (prtb[IFLA_BRPORT_UNICAST_FLOOD])
+                       print_onoff(fp, "flood",
+                                   rta_getattr_u8(prtb[IFLA_BRPORT_UNICAST_FLOOD]));
+               if (prtb[IFLA_BRPORT_MCAST_FLOOD])
+                       print_onoff(fp, "mcast_flood",
+                                   rta_getattr_u8(prtb[IFLA_BRPORT_MCAST_FLOOD]));
+               if (prtb[IFLA_BRPORT_NEIGH_SUPPRESS])
+                       print_onoff(fp, "neigh_suppress",
+                                   rta_getattr_u8(prtb[IFLA_BRPORT_NEIGH_SUPPRESS]));
+               if (prtb[IFLA_BRPORT_VLAN_TUNNEL])
+                       print_onoff(fp, "vlan_tunnel",
+                                   rta_getattr_u8(prtb[IFLA_BRPORT_VLAN_TUNNEL]));
+       } else
+               print_portstate(rta_getattr_u8(attr));
 }
 
-static void print_hwmode(FILE *f, __u16 mode)
+
+/*
+ * This is reported by HW devices that have some bridging
+ * capabilities.
+ */
+static void print_af_spec(FILE *fp, struct rtattr *attr)
 {
-       if (mode >= ARRAY_SIZE(hw_mode))
-               fprintf(f, "hwmode %#hx ", mode);
-       else
-               fprintf(f, "hwmode %s ", hw_mode[mode]);
+       struct rtattr *aftb[IFLA_BRIDGE_MAX+1];
+
+       parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, attr);
+
+       if (aftb[IFLA_BRIDGE_MODE])
+               print_hwmode(rta_getattr_u16(aftb[IFLA_BRIDGE_MODE]));
+
+       if (!show_details)
+               return;
+
+       if (aftb[IFLA_BRIDGE_VLAN_INFO])
+               print_vlan_info(fp, aftb[IFLA_BRIDGE_VLAN_INFO]);
 }
 
 int print_linkinfo(const struct sockaddr_nl *who,
                   struct nlmsghdr *n, void *arg)
 {
        FILE *fp = arg;
-       int len = n->nlmsg_len;
        struct ifinfomsg *ifi = NLMSG_DATA(n);
        struct rtattr *tb[IFLA_MAX+1];
+       unsigned int m_flag = 0;
+       int len = n->nlmsg_len;
+       const char *name;
 
        len -= NLMSG_LENGTH(sizeof(*ifi));
        if (len < 0) {
@@ -117,114 +201,38 @@ int print_linkinfo(const struct sockaddr_nl *who,
 
        parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(ifi), len, NLA_F_NESTED);
 
-       if (tb[IFLA_IFNAME] == NULL) {
-               fprintf(stderr, "BUG: nil ifname\n");
+       name = get_ifname_rta(ifi->ifi_index, tb[IFLA_IFNAME]);
+       if (!name)
                return -1;
-       }
 
+       open_json_object(NULL);
        if (n->nlmsg_type == RTM_DELLINK)
-               fprintf(fp, "Deleted ");
+               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 
-       fprintf(fp, "%d: %s ", ifi->ifi_index,
-               tb[IFLA_IFNAME] ? rta_getattr_str(tb[IFLA_IFNAME]) : "<nil>");
-
-       if (tb[IFLA_OPERSTATE])
-               print_operstate(fp, rta_getattr_u8(tb[IFLA_OPERSTATE]));
-
-       if (tb[IFLA_LINK]) {
-               int iflink = rta_getattr_u32(tb[IFLA_LINK]);
-
-               fprintf(fp, "@%s: ",
-                       iflink ? ll_index_to_name(iflink) : "NONE");
-       } else
-               fprintf(fp, ": ");
-
-       print_link_flags(fp, ifi->ifi_flags);
+       print_int(PRINT_ANY, "ifindex", "%d: ", ifi->ifi_index);
+       m_flag = print_name_and_link("%s: ", name, tb);
+       print_link_flags(fp, ifi->ifi_flags, m_flag);
 
        if (tb[IFLA_MTU])
-               fprintf(fp, "mtu %u ", rta_getattr_u32(tb[IFLA_MTU]));
+               print_int(PRINT_ANY,
+                         "mtu", "mtu %u ",
+                         rta_getattr_u32(tb[IFLA_MTU]));
 
        if (tb[IFLA_MASTER]) {
                int master = rta_getattr_u32(tb[IFLA_MASTER]);
 
-               fprintf(fp, "master %s ", ll_index_to_name(master));
+               print_string(PRINT_ANY, "master", "master %s ",
+                            ll_index_to_name(master));
        }
 
-       if (tb[IFLA_PROTINFO]) {
-               if (tb[IFLA_PROTINFO]->rta_type & NLA_F_NESTED) {
-                       struct rtattr *prtb[IFLA_BRPORT_MAX+1];
-
-                       parse_rtattr_nested(prtb, IFLA_BRPORT_MAX,
-                                           tb[IFLA_PROTINFO]);
-
-                       if (prtb[IFLA_BRPORT_STATE])
-                               print_portstate(fp,
-                                               rta_getattr_u8(prtb[IFLA_BRPORT_STATE]));
-                       if (prtb[IFLA_BRPORT_PRIORITY])
-                               fprintf(fp, "priority %hu ",
-                                       rta_getattr_u16(prtb[IFLA_BRPORT_PRIORITY]));
-                       if (prtb[IFLA_BRPORT_COST])
-                               fprintf(fp, "cost %u ",
-                                       rta_getattr_u32(prtb[IFLA_BRPORT_COST]));
-
-                       if (show_details) {
-                               fprintf(fp, "%s    ", _SL_);
-
-                               if (prtb[IFLA_BRPORT_MODE])
-                                       print_onoff(fp, "hairpin",
-                                                   rta_getattr_u8(prtb[IFLA_BRPORT_MODE]));
-                               if (prtb[IFLA_BRPORT_GUARD])
-                                       print_onoff(fp, "guard",
-                                                   rta_getattr_u8(prtb[IFLA_BRPORT_GUARD]));
-                               if (prtb[IFLA_BRPORT_PROTECT])
-                                       print_onoff(fp, "root_block",
-                                                   rta_getattr_u8(prtb[IFLA_BRPORT_PROTECT]));
-                               if (prtb[IFLA_BRPORT_FAST_LEAVE])
-                                       print_onoff(fp, "fastleave",
-                                                   rta_getattr_u8(prtb[IFLA_BRPORT_FAST_LEAVE]));
-                               if (prtb[IFLA_BRPORT_LEARNING])
-                                       print_onoff(fp, "learning",
-                                                   rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING]));
-                               if (prtb[IFLA_BRPORT_LEARNING_SYNC])
-                                       print_onoff(fp, "learning_sync",
-                                                   rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING_SYNC]));
-                               if (prtb[IFLA_BRPORT_UNICAST_FLOOD])
-                                       print_onoff(fp, "flood",
-                                                   rta_getattr_u8(prtb[IFLA_BRPORT_UNICAST_FLOOD]));
-                               if (prtb[IFLA_BRPORT_MCAST_FLOOD])
-                                       print_onoff(fp, "mcast_flood",
-                                                   rta_getattr_u8(prtb[IFLA_BRPORT_MCAST_FLOOD]));
-                               if (prtb[IFLA_BRPORT_NEIGH_SUPPRESS])
-                                       print_onoff(fp, "neigh_suppress",
-                                                   rta_getattr_u8(prtb[IFLA_BRPORT_NEIGH_SUPPRESS]));
-                               if (prtb[IFLA_BRPORT_VLAN_TUNNEL])
-                                       print_onoff(fp, "vlan_tunnel",
-                                                   rta_getattr_u8(prtb[IFLA_BRPORT_VLAN_TUNNEL]));
-                       }
-               } else
-                       print_portstate(fp, rta_getattr_u8(tb[IFLA_PROTINFO]));
-       }
+       if (tb[IFLA_PROTINFO])
+               print_protinfo(fp, tb[IFLA_PROTINFO]);
 
-       if (tb[IFLA_AF_SPEC]) {
-               /* This is reported by HW devices that have some bridging
-                * capabilities.
-                */
-               struct rtattr *aftb[IFLA_BRIDGE_MAX+1];
-
-               parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, tb[IFLA_AF_SPEC]);
-
-               if (aftb[IFLA_BRIDGE_MODE])
-                       print_hwmode(fp, rta_getattr_u16(aftb[IFLA_BRIDGE_MODE]));
-               if (show_details) {
-                       if (aftb[IFLA_BRIDGE_VLAN_INFO]) {
-                               fprintf(fp, "\n");
-                               print_vlan_info(fp, tb[IFLA_AF_SPEC],
-                                               ifi->ifi_index);
-                       }
-               }
-       }
+       if (tb[IFLA_AF_SPEC])
+               print_af_spec(fp, tb[IFLA_AF_SPEC]);
 
-       fprintf(fp, "\n");
+       print_string(PRINT_FP, NULL, "%s", "\n");
+       close_json_object();
        fflush(fp);
        return 0;
 }
@@ -477,11 +485,9 @@ static int brlink_show(int argc, char **argv)
        }
 
        if (filter_dev) {
-               if ((filter_index = ll_name_to_index(filter_dev)) == 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);
        }
 
        if (show_details) {
@@ -499,10 +505,14 @@ static int brlink_show(int argc, char **argv)
                }
        }
 
+       new_json_obj(json);
        if (rtnl_dump_filter(&rth, print_linkinfo, stdout) < 0) {
                fprintf(stderr, "Dump terminated\n");
                exit(1);
        }
+
+       delete_json_obj();
+       fflush(stdout);
        return 0;
 }
 
index 58c20b82b8a63b15a16bb79fceafe085e91cc122..f38dc67c849a333c01a6b25c5e33c0144c629aad 100644 (file)
 #include <linux/if_ether.h>
 #include <string.h>
 #include <arpa/inet.h>
-#include <json_writer.h>
 
 #include "libnetlink.h"
 #include "br_common.h"
 #include "rt_names.h"
 #include "utils.h"
+#include "json_print.h"
 
 #ifndef MDBA_RTA
 #define MDBA_RTA(r) \
@@ -27,9 +27,6 @@
 #endif
 
 static unsigned int filter_index, filter_vlan;
-json_writer_t *jw_global;
-static bool print_mdb_entries = true;
-static bool print_mdb_router = true;
 
 static void usage(void)
 {
@@ -43,162 +40,131 @@ static bool is_temp_mcast_rtr(__u8 type)
        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];
-       struct timeval tv;
-       __u8 type;
 
        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]) {
-               __jiffies_to_tv(&tv,
-                               rta_getattr_u32(tb[MDBA_ROUTER_PATTR_TIMER]));
-               if (jw_global) {
-                       char formatted_time[9];
-
-                       snprintf(formatted_time, sizeof(formatted_time),
-                                "%4i.%.2i", (int)tv.tv_sec,
-                                (int)tv.tv_usec/10000);
-                       jsonw_string_field(jw_global, "timer", formatted_time);
-               } else {
-                       fprintf(f, " %4i.%.2i",
-                               (int)tv.tv_sec, (int)tv.tv_usec/10000);
-               }
+               __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]) {
-               type = rta_getattr_u8(tb[MDBA_ROUTER_PATTR_TYPE]);
-               if (jw_global)
-                       jsonw_string_field(jw_global, "type",
-                               is_temp_mcast_rtr(type) ? "temp" : "permanent");
-               else
-                       fprintf(f, " %s",
-                               is_temp_mcast_rtr(type) ? "temp" : "permanent");
+               __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, __u32 brifidx)
+static void br_print_router_ports(FILE *f, struct rtattr *attr,
+                                 const char *brifname)
 {
-       uint32_t *port_ifindex;
+       int rem = RTA_PAYLOAD(attr);
        struct rtattr *i;
-       int rem;
 
-       rem = RTA_PAYLOAD(attr);
-       if (jw_global) {
-               jsonw_name(jw_global, ll_index_to_name(brifidx));
-               jsonw_start_array(jw_global);
-               for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
-                       port_ifindex = RTA_DATA(i);
-                       jsonw_start_object(jw_global);
-                       jsonw_string_field(jw_global,
-                                          "port",
-                                          ll_index_to_name(*port_ifindex));
+       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)) {
+               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);
-                       jsonw_end_object(jw_global);
-               }
-               jsonw_end_array(jw_global);
-       } else {
-               if (!show_stats)
-                       fprintf(f, "router ports on %s: ",
-                               ll_index_to_name(brifidx));
-               for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
-                       port_ifindex = RTA_DATA(i);
-                       if (show_stats) {
-                               fprintf(f, "router ports on %s: %s",
-                                       ll_index_to_name(brifidx),
-                                       ll_index_to_name(*port_ifindex));
-                               __print_router_port_stats(f, i);
-                               fprintf(f, "\n");
-                       } else{
-                               fprintf(f, "%s ",
-                                       ll_index_to_name(*port_ifindex));
-                       }
-               }
-               if (!show_stats)
+                       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);
+               }
        }
+       close_json_array(PRINT_JSON, NULL);
 }
 
-static void start_json_mdb_flags_array(bool *mdb_flags)
-{
-       if (*mdb_flags)
-               return;
-       jsonw_name(jw_global, "flags");
-       jsonw_start_array(jw_global);
-       *mdb_flags = true;
-}
-
-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;
-       bool mdb_flags = false;
 
        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;
-       if (jw_global)
-               jsonw_start_object(jw_global);
-       if (n->nlmsg_type == RTM_DELMDB) {
-               if (jw_global)
-                       jsonw_string_field(jw_global, "opCode", "deleted");
-               else
-                       fprintf(f, "Deleted ");
-       }
-       if (jw_global) {
-               jsonw_string_field(jw_global, "dev", ll_index_to_name(ifindex));
-               jsonw_string_field(jw_global,
-                                  "port",
-                                  ll_index_to_name(e->ifindex));
-               jsonw_string_field(jw_global, "grp", inet_ntop(af, src,
-                       abuf, sizeof(abuf)));
-               jsonw_string_field(jw_global, "state",
-                       (e->state & MDB_PERMANENT) ? "permanent" : "temp");
-               if (e->flags & MDB_FLAGS_OFFLOAD) {
-                       start_json_mdb_flags_array(&mdb_flags);
-                       jsonw_string(jw_global, "offload");
-               }
-               if (mdb_flags)
-                       jsonw_end_array(jw_global);
-       } else{
-               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" : "");
-       }
-       if (e->vid) {
-               if (jw_global)
-                       jsonw_uint_field(jw_global, "vid", e->vid);
-               else
-                       fprintf(f, " vid %hu", e->vid);
+       dev = ll_index_to_name(ifindex);
+
+       open_json_object(NULL);
+
+       if (n->nlmsg_type == RTM_DELMDB)
+               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);
        }
-       if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) {
-               struct timeval tv;
 
-               __jiffies_to_tv(&tv, rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER]));
-               if (jw_global) {
-                       char formatted_time[9];
+       print_string(PRINT_ANY, "port", " %s ",
+                    ll_index_to_name(e->ifindex));
 
-                       snprintf(formatted_time, sizeof(formatted_time),
-                                "%4i.%.2i", (int)tv.tv_sec,
-                                (int)tv.tv_usec/10000);
-                       jsonw_string_field(jw_global, "timer", formatted_time);
-               } else {
-                       fprintf(f, "%4i.%.2i", (int)tv.tv_sec,
-                               (int)tv.tv_usec/10000);
-               }
+       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)
+               print_uint(PRINT_ANY, "vid", " vid %u", e->vid);
+
+       if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) {
+               __u32 timer = rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER]);
+
+               print_string(PRINT_ANY, "timer", " %s",
+                            format_timer(timer));
        }
-       if (jw_global)
-               jsonw_end_object(jw_global);
-       else
-               fprintf(f, "\n");
+       close_json_object();
 }
 
 static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr,
@@ -218,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;
@@ -243,50 +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] && print_mdb_entries) {
-               int rem = RTA_PAYLOAD(tb[MDBA_MDB]);
+       if (n->nlmsg_type == RTM_DELMDB)
+               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 
-               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] && print_mdb_router) {
-               if (n->nlmsg_type == RTM_GETMDB) {
-                       if (show_details)
-                               br_print_router_ports(fp, tb[MDBA_ROUTER],
-                                                     r->ifindex);
-               } else {
-                       uint32_t *port_ifindex;
-
-                       i = RTA_DATA(tb[MDBA_ROUTER]);
-                       port_ifindex = RTA_DATA(i);
-                       if (n->nlmsg_type == RTM_DELMDB) {
-                               if (jw_global)
-                                       jsonw_string_field(jw_global,
-                                                          "opCode",
-                                                          "deleted");
-                               else
-                                       fprintf(fp, "Deleted ");
-                       }
-                       if (jw_global) {
-                               jsonw_name(jw_global,
-                                          ll_index_to_name(r->ifindex));
-                               jsonw_start_array(jw_global);
-                               jsonw_start_object(jw_global);
-                               jsonw_string_field(jw_global, "port",
-                                       ll_index_to_name(*port_ifindex));
-                               jsonw_end_object(jw_global);
-                               jsonw_end_array(jw_global);
-                       } else {
-                               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]);
 
-       if (!jw_global)
-               fflush(fp);
+       if (tb[MDBA_ROUTER])
+               print_router_entries(fp, n, r->ifindex, tb[MDBA_ROUTER]);
 
        return 0;
 }
@@ -312,61 +287,25 @@ static int mdb_show(int argc, char **argv)
 
        if (filter_dev) {
                filter_index = ll_name_to_index(filter_dev);
-               if (filter_index == 0) {
-                       fprintf(stderr, "Cannot find device \"%s\"\n",
-                               filter_dev);
-                       return -1;
-               }
+               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;
        }
 
-       if (!json_output) {
-               /* Normal output */
-               if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
-                       fprintf(stderr, "Dump terminated\n");
-                       return -1;
-               }
-               return 0;
-       }
-       /* Json output */
-       jw_global = jsonw_new(stdout);
-       jsonw_pretty(jw_global, 1);
-       jsonw_start_object(jw_global);
-       jsonw_name(jw_global, "mdb");
-       jsonw_start_array(jw_global);
-
-       /* print mdb entries */
-       print_mdb_entries = true;
-       print_mdb_router = false;
        if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
                fprintf(stderr, "Dump terminated\n");
                return -1;
        }
-       jsonw_end_array(jw_global);
-
-       /* get router ports */
-       if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) {
-               perror("Cannot send dump request");
-               return -1;
-       }
-       jsonw_name(jw_global, "router");
-       jsonw_start_object(jw_global);
 
-       /* print router ports */
-       print_mdb_entries = false;
-       print_mdb_router = true;
-       if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
-               fprintf(stderr, "Dump terminated\n");
-               return -1;
-       }
-       jsonw_end_object(jw_global);
-       jsonw_end_object(jw_global);
-       jsonw_destroy(&jw_global);
+       delete_json_obj();
+       fflush(stdout);
 
        return 0;
 }
@@ -418,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)) {
index f42d7e6ba2441a4970b502fdf3bd92b27d574058..19a36b8040693849907e787ea53fb0e50f7cade5 100644 (file)
@@ -8,19 +8,16 @@
 #include <netinet/in.h>
 #include <linux/if_bridge.h>
 #include <linux/if_ether.h>
-#include <json_writer.h>
 #include <string.h>
 
+#include "json_print.h"
 #include "libnetlink.h"
 #include "br_common.h"
 #include "utils.h"
 
 static unsigned int filter_index, filter_vlan;
-static int last_ifidx = -1;
 static int show_vlan_tunnel_info = 0;
 
-json_writer_t *jw_global;
-
 static void usage(void)
 {
        fprintf(stderr,
@@ -257,39 +254,33 @@ static int filter_vlan_check(__u16 vid, __u16 flags)
 
 static void print_vlan_port(FILE *fp, int ifi_index)
 {
-       if (jw_global) {
-               jsonw_pretty(jw_global, 1);
-               jsonw_name(jw_global,
-                          ll_index_to_name(ifi_index));
-               jsonw_start_array(jw_global);
-       } else {
-               fprintf(fp, "%s",
-                       ll_index_to_name(ifi_index));
-       }
+       print_string(PRINT_ANY, NULL, "%s",
+                    ll_index_to_name(ifi_index));
 }
 
-static void start_json_vlan_flags_array(bool *vlan_flags)
+static void print_range(const char *name, __u16 start, __u16 id)
 {
-       if (*vlan_flags)
-               return;
-       jsonw_name(jw_global, "flags");
-       jsonw_start_array(jw_global);
-       *vlan_flags = true;
+       char end[64];
+
+       snprintf(end, sizeof(end), "%sEnd", name);
+
+       print_hu(PRINT_ANY, name, "\t %hu", start);
+       if (start != id)
+               print_hu(PRINT_ANY, end, "-%hu", id);
+
 }
 
 static void print_vlan_tunnel_info(FILE *fp, struct rtattr *tb, int ifindex)
 {
-       bool jsonw_end_parray = false;
        struct rtattr *i, *list = tb;
        int rem = RTA_PAYLOAD(list);
        __u16 last_vid_start = 0;
        __u32 last_tunid_start = 0;
 
-       if (!filter_vlan) {
+       if (!filter_vlan)
                print_vlan_port(fp, ifindex);
-               jsonw_end_parray = 1;
-       }
 
+       open_json_array(PRINT_JSON, "tunnel");
        for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
                struct rtattr *ttb[IFLA_BRIDGE_VLAN_TUNNEL_MAX+1];
                __u32 tunnel_id = 0;
@@ -321,6 +312,7 @@ static void print_vlan_tunnel_info(FILE *fp, struct rtattr *tb, int ifindex)
                        last_vid_start = tunnel_vid;
                        last_tunid_start = tunnel_id;
                }
+
                vcheck_ret = filter_vlan_check(tunnel_vid, tunnel_flags);
                if (vcheck_ret == -1)
                        break;
@@ -330,52 +322,19 @@ static void print_vlan_tunnel_info(FILE *fp, struct rtattr *tb, int ifindex)
                if (tunnel_flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
                        continue;
 
-               if (filter_vlan) {
+               if (filter_vlan)
                        print_vlan_port(fp, ifindex);
-                       jsonw_end_parray = 1;
-               }
 
-               if (jw_global) {
-                       jsonw_start_object(jw_global);
-                       jsonw_uint_field(jw_global, "vlan",
-                                        last_vid_start);
-               } else {
-                       fprintf(fp, "\t %hu", last_vid_start);
-               }
-               if (last_vid_start != tunnel_vid) {
-                       if (jw_global)
-                               jsonw_uint_field(jw_global, "vlanEnd",
-                                                tunnel_vid);
-                       else
-                               fprintf(fp, "-%hu", tunnel_vid);
-               }
-
-               if (jw_global) {
-                       jsonw_uint_field(jw_global, "tunid",
-                                        last_tunid_start);
-               } else {
-                       fprintf(fp, "\t %hu", last_tunid_start);
-               }
-               if (last_vid_start != tunnel_vid) {
-                       if (jw_global)
-                               jsonw_uint_field(jw_global, "tunidEnd",
-                                                tunnel_id);
-                       else
-                               fprintf(fp, "-%hu", tunnel_id);
-               }
+               open_json_object(NULL);
+               print_range("vlan", last_vid_start, tunnel_vid);
+               print_range("tunid", last_tunid_start, tunnel_id);
+               close_json_object();
 
-               if (jw_global)
-                       jsonw_end_object(jw_global);
-               else
+               if (!is_json_context())
                        fprintf(fp, "\n");
-       }
 
-       if (jsonw_end_parray) {
-               if (jw_global)
-                       jsonw_end_array(jw_global);
-               else
-                       fprintf(fp, "\n");
        }
+       close_json_array(PRINT_JSON, NULL);
 }
 
 static int print_vlan_tunnel(const struct sockaddr_nl *who,
@@ -409,9 +368,11 @@ static int print_vlan_tunnel(const struct sockaddr_nl *who,
 
        /* if AF_SPEC isn't there, vlan table is not preset for this port */
        if (!tb[IFLA_AF_SPEC]) {
-               if (!filter_vlan && !jw_global)
-                       fprintf(fp, "%s\tNone\n",
-                               ll_index_to_name(ifm->ifi_index));
+               if (!filter_vlan && !is_json_context()) {
+                       color_fprintf(fp, COLOR_IFNAME, "%s",
+                                     ll_index_to_name(ifm->ifi_index));
+                       fprintf(fp, "\tNone\n");
+               }
                return 0;
        }
 
@@ -452,48 +413,51 @@ static int print_vlan(const struct sockaddr_nl *who,
 
        /* if AF_SPEC isn't there, vlan table is not preset for this port */
        if (!tb[IFLA_AF_SPEC]) {
-               if (!filter_vlan && !jw_global)
-                       fprintf(fp, "%s\tNone\n",
-                               ll_index_to_name(ifm->ifi_index));
+               if (!filter_vlan && !is_json_context()) {
+                       color_fprintf(fp, COLOR_IFNAME, "%s",
+                                     ll_index_to_name(ifm->ifi_index));
+                       fprintf(fp, "\tNone\n");
+               }
                return 0;
        }
 
-       print_vlan_info(fp, tb[IFLA_AF_SPEC], ifm->ifi_index);
+       print_vlan_port(fp, ifm->ifi_index);
+       print_vlan_info(fp, tb[IFLA_AF_SPEC]);
 
        fflush(fp);
        return 0;
 }
 
-static void print_one_vlan_stats(FILE *fp,
-                                const struct bridge_vlan_xstats *vstats,
-                                int ifindex)
+static void print_vlan_flags(__u16 flags)
 {
-       const char *ifname = "";
+       if (flags & BRIDGE_VLAN_INFO_PVID)
+               print_null(PRINT_ANY, "pvid", " %s", "PVID");
 
-       if (filter_vlan && filter_vlan != vstats->vid)
-               return;
-       /* skip pure port entries, they'll be dumped via the slave stats call */
-       if ((vstats->flags & BRIDGE_VLAN_INFO_MASTER) &&
-           !(vstats->flags & BRIDGE_VLAN_INFO_BRENTRY))
-               return;
+       if (flags & BRIDGE_VLAN_INFO_UNTAGGED)
+               print_null(PRINT_ANY, "untagged", " %s", "untagged");
+}
 
-       if (last_ifidx != ifindex) {
-               ifname = ll_index_to_name(ifindex);
-               last_ifidx = ifindex;
-       }
-       fprintf(fp, "%-16s  %hu", ifname, vstats->vid);
-       if (vstats->flags & BRIDGE_VLAN_INFO_PVID)
-               fprintf(fp, " PVID");
-       if (vstats->flags & BRIDGE_VLAN_INFO_UNTAGGED)
-               fprintf(fp, " Egress Untagged");
-       fprintf(fp, "\n");
-       fprintf(fp, "%-16s    RX: %llu bytes %llu packets\n",
-               "", vstats->rx_bytes, vstats->rx_packets);
-       fprintf(fp, "%-16s    TX: %llu bytes %llu packets\n",
-               "", vstats->tx_bytes, vstats->tx_packets);
+static void print_one_vlan_stats(const struct bridge_vlan_xstats *vstats)
+{
+       open_json_object(NULL);
+       print_hu(PRINT_ANY, "vid", " %hu", vstats->vid);
+
+       print_vlan_flags(vstats->flags);
+
+       print_lluint(PRINT_ANY, "rx_bytes",
+                    "\n                   RX: %llu bytes",
+                    vstats->rx_bytes);
+       print_lluint(PRINT_ANY, "rx_packets", " %llu packets\n",
+               vstats->rx_packets);
+       print_lluint(PRINT_ANY, "tx_bytes",
+                    "                   TX: %llu bytes",
+                    vstats->tx_bytes);
+       print_lluint(PRINT_ANY, "tx_packets", " %llu packets",
+               vstats->tx_packets);
+       close_json_object();
 }
 
-static void print_vlan_stats_attr(FILE *fp, struct rtattr *attr, int ifindex)
+static void print_vlan_stats_attr(struct rtattr *attr, int ifindex)
 {
        struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1];
        struct rtattr *i, *list;
@@ -506,11 +470,33 @@ static void print_vlan_stats_attr(FILE *fp, struct rtattr *attr, int ifindex)
 
        list = brtb[LINK_XSTATS_TYPE_BRIDGE];
        rem = RTA_PAYLOAD(list);
+
+       open_json_object(NULL);
+
+       print_color_string(PRINT_ANY, COLOR_IFNAME,
+                          "dev", "%-16s",
+                          ll_index_to_name(ifindex));
+
+       open_json_array(PRINT_JSON, "xstats");
        for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+               const struct bridge_vlan_xstats *vstats = RTA_DATA(i);
+
                if (i->rta_type != BRIDGE_XSTATS_VLAN)
                        continue;
-               print_one_vlan_stats(fp, RTA_DATA(i), ifindex);
+
+               if (filter_vlan && filter_vlan != vstats->vid)
+                       continue;
+
+               /* skip pure port entries, they'll be dumped via the slave stats call */
+               if ((vstats->flags & BRIDGE_VLAN_INFO_MASTER) &&
+                   !(vstats->flags & BRIDGE_VLAN_INFO_BRENTRY))
+                       continue;
+
+               print_one_vlan_stats(vstats);
        }
+       close_json_array(PRINT_ANY, "\n");
+       close_json_object();
+
 }
 
 static int print_vlan_stats(const struct sockaddr_nl *who,
@@ -535,11 +521,11 @@ static int print_vlan_stats(const struct sockaddr_nl *who,
 
        /* We have to check if any of the two attrs are usable */
        if (tb[IFLA_STATS_LINK_XSTATS])
-               print_vlan_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS],
+               print_vlan_stats_attr(tb[IFLA_STATS_LINK_XSTATS],
                                      ifsm->ifindex);
 
        if (tb[IFLA_STATS_LINK_XSTATS_SLAVE])
-               print_vlan_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS_SLAVE],
+               print_vlan_stats_attr(tb[IFLA_STATS_LINK_XSTATS_SLAVE],
                                      ifsm->ifindex);
 
        fflush(fp);
@@ -568,29 +554,22 @@ static int vlan_show(int argc, char **argv)
 
        if (filter_dev) {
                filter_index = ll_name_to_index(filter_dev);
-               if (filter_index == 0) {
-                       fprintf(stderr, "Cannot find device \"%s\"\n",
-                               filter_dev);
-                       return -1;
-               }
+               if (!filter_index)
+                       return nodev(filter_dev);
        }
 
+       new_json_obj(json);
+
        if (!show_stats) {
                if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK,
                                             (compress_vlans ?
-                                               RTEXT_FILTER_BRVLAN_COMPRESSED :
-                                               RTEXT_FILTER_BRVLAN)) < 0) {
+                                             RTEXT_FILTER_BRVLAN_COMPRESSED :
+                                             RTEXT_FILTER_BRVLAN)) < 0) {
                        perror("Cannont send dump request");
                        exit(1);
                }
-               if (json_output) {
-                       jw_global = jsonw_new(stdout);
-                       if (!jw_global) {
-                               fprintf(stderr, "Error allocation json object\n");
-                               exit(1);
-                       }
-                       jsonw_start_object(jw_global);
-               } else {
+
+               if (!is_json_context()) {
                        if (show_vlan_tunnel_info)
                                printf("port\tvlan ids\ttunnel id\n");
                        else
@@ -602,7 +581,6 @@ static int vlan_show(int argc, char **argv)
                                               stdout);
                else
                        ret = rtnl_dump_filter(&rth, print_vlan, stdout);
-
                if (ret < 0) {
                        fprintf(stderr, "Dump ternminated\n");
                        exit(1);
@@ -618,7 +596,9 @@ static int vlan_show(int argc, char **argv)
                        exit(1);
                }
 
-               printf("%-16s vlan id\n", "port");
+               if (!is_json_context())
+                       printf("%-16s vlan id\n", "port");
+
                if (rtnl_dump_filter(&rth, print_vlan_stats, stdout) < 0) {
                        fprintf(stderr, "Dump terminated\n");
                        exit(1);
@@ -638,26 +618,21 @@ static int vlan_show(int argc, char **argv)
                }
        }
 
-       if (jw_global) {
-               jsonw_end_object(jw_global);
-               jsonw_destroy(&jw_global);
-       }
-
+       delete_json_obj();
+       fflush(stdout);
        return 0;
 }
 
-void print_vlan_info(FILE *fp, struct rtattr *tb, int ifindex)
+void print_vlan_info(FILE *fp, struct rtattr *tb)
 {
        struct rtattr *i, *list = tb;
        int rem = RTA_PAYLOAD(list);
        __u16 last_vid_start = 0;
-       bool vlan_flags = false;
-       bool jsonw_end_parray = false;
 
-       if (!filter_vlan) {
-               print_vlan_port(fp, ifindex);
-               jsonw_end_parray = true;
-       }
+       if (!is_json_context())
+               fprintf(fp, "%s", _SL_);
+
+       open_json_array(PRINT_JSON, "vlan");
 
        for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
                struct bridge_vlan_info *vinfo;
@@ -676,61 +651,14 @@ void print_vlan_info(FILE *fp, struct rtattr *tb, int ifindex)
                else if (vcheck_ret == 0)
                        continue;
 
-               if (filter_vlan) {
-                       print_vlan_port(fp, ifindex);
-                       jsonw_end_parray = true;
-               }
-               if (jw_global) {
-                       jsonw_start_object(jw_global);
-                       jsonw_uint_field(jw_global, "vlan",
-                                        last_vid_start);
-                       if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
-                               continue;
-               } else {
-                       fprintf(fp, "\t %hu", last_vid_start);
-               }
-               if (last_vid_start != vinfo->vid) {
-                       if (jw_global)
-                               jsonw_uint_field(jw_global, "vlanEnd",
-                                                vinfo->vid);
-                       else
-                               fprintf(fp, "-%hu", vinfo->vid);
-               }
-               if (vinfo->flags & BRIDGE_VLAN_INFO_PVID) {
-                       if (jw_global) {
-                               start_json_vlan_flags_array(&vlan_flags);
-                               jsonw_string(jw_global, "PVID");
-                       } else {
-                               fprintf(fp, " PVID");
-                       }
-               }
-               if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED) {
-                       if (jw_global) {
-                               start_json_vlan_flags_array(&vlan_flags);
-                               jsonw_string(jw_global,
-                                            "Egress Untagged");
-                       } else {
-                               fprintf(fp, " Egress Untagged");
-                       }
-               }
-               if (jw_global && vlan_flags) {
-                       jsonw_end_array(jw_global);
-                       vlan_flags = false;
-               }
+               open_json_object(NULL);
+               print_range("vlan", last_vid_start, vinfo->vid);
 
-               if (jw_global)
-                       jsonw_end_object(jw_global);
-               else
-                       fprintf(fp, "\n");
+               print_vlan_flags(vinfo->flags);
+               close_json_object();
        }
 
-       if (jsonw_end_parray) {
-               if (jw_global)
-                       jsonw_end_array(jw_global);
-               else
-                       fprintf(fp, "\n");
-
-       }
+       close_json_array(PRINT_ANY, "\n");
 }
 
 int do_vlan(int argc, char **argv)
index 1823983775168ac320f9948f27e10a6da0c0ae4b..4d6bb2f039789d0666a8788c6de114737eb06b93 100644 (file)
@@ -5,3 +5,4 @@
 4      meta
 7      canid
 8      ipset
+9      ipt
index c8474e6eb542c9ff6a0094e1f5ab47c639ecf544..8546ff928bc0b8b5a424a8806106cd8fb532f93c 100644 (file)
@@ -8,9 +8,11 @@ int ll_remember_index(const struct sockaddr_nl *who,
 void ll_init_map(struct rtnl_handle *rth);
 unsigned ll_name_to_index(const char *name);
 const char *ll_index_to_name(unsigned idx);
-const char *ll_idx_n2a(unsigned idx, char *buf);
 int ll_index_to_type(unsigned idx);
 int ll_index_to_flags(unsigned idx);
 unsigned namehash(const char *str);
 
+const char *ll_idx_n2a(unsigned int idx);
+unsigned int ll_idx_a2n(const char *name);
+
 #endif /* __LL_MAP_H__ */
index 40b08520a369d70fa6262bd339aa4b09d573b101..19817e3d52e8f5bf9926190e0f25bb8e77c30fdf 100644 (file)
@@ -800,6 +800,7 @@ enum bpf_func_id {
 /* BPF_FUNC_skb_set_tunnel_key flags. */
 #define BPF_F_ZERO_CSUM_TX             (1ULL << 1)
 #define BPF_F_DONT_FRAGMENT            (1ULL << 2)
+#define BPF_F_SEQ_NUMBER               (1ULL << 3)
 
 /* BPF_FUNC_perf_event_output, BPF_FUNC_perf_event_read and
  * BPF_FUNC_perf_event_read_value flags.
index 2b642bf9b5a0ab492c06a4c82392200834059cd1..232df14e1287a3297716f0c16a0632194a189d50 100644 (file)
@@ -23,7 +23,7 @@ struct fib_rule_hdr {
        __u8            tos;
 
        __u8            table;
-       __u8            res1;   /* reserved */
+       __u8            res1;   /* reserved */
        __u8            res2;   /* reserved */
        __u8            action;
 
@@ -35,6 +35,11 @@ struct fib_rule_uid_range {
        __u32           end;
 };
 
+struct fib_rule_port_range {
+       __u16           start;
+       __u16           end;
+};
+
 enum {
        FRA_UNSPEC,
        FRA_DST,        /* destination address */
@@ -58,6 +63,10 @@ enum {
        FRA_PAD,
        FRA_L3MDEV,     /* iif or oif is l3mdev goto its table */
        FRA_UID_RANGE,  /* UID range */
+       FRA_PROTOCOL,   /* Originator of the rule */
+       FRA_IP_PROTO,   /* ip proto */
+       FRA_SPORT_RANGE, /* sport */
+       FRA_DPORT_RANGE, /* dport */
        __FRA_MAX
 };
 
index a34b152e3c19683f2acd70a9e3d750897382eb70..c3fafe295f62ad6b6821ed2e84430f1a6f8631c2 100644 (file)
@@ -88,6 +88,7 @@
 #define ETH_P_AOE      0x88A2          /* ATA over Ethernet            */
 #define ETH_P_8021AD   0x88A8          /* 802.1ad Service VLAN         */
 #define ETH_P_802_EX1  0x88B5          /* 802.1 Local Experimental 1.  */
+#define ETH_P_PREAUTH  0x88C7          /* 802.11 Preauthentication */
 #define ETH_P_TIPC     0x88CA          /* TIPC                         */
 #define ETH_P_MACSEC   0x88E5          /* 802.1ae MACsec */
 #define ETH_P_8021AH   0x88E7          /* 802.1ah Backbone Service Tag */
index 7ac1042c0faff68bfa206c241b3e684c95990b36..9c6cedabc91821f3f039607b22e0a11b85ccbca9 100644 (file)
@@ -939,4 +939,22 @@ enum {
        IFLA_EVENT_BONDING_OPTIONS,     /* change in bonding options */
 };
 
+/* tun section */
+
+enum {
+       IFLA_TUN_UNSPEC,
+       IFLA_TUN_OWNER,
+       IFLA_TUN_GROUP,
+       IFLA_TUN_TYPE,
+       IFLA_TUN_PI,
+       IFLA_TUN_VNET_HDR,
+       IFLA_TUN_PERSIST,
+       IFLA_TUN_MULTI_QUEUE,
+       IFLA_TUN_NUM_QUEUES,
+       IFLA_TUN_NUM_DISABLED_QUEUES,
+       __IFLA_TUN_MAX,
+};
+
+#define IFLA_TUN_MAX (__IFLA_TUN_MAX - 1)
+
 #endif /* _LINUX_IF_LINK_H */
index 46c506615f4ad7f103ec7a479bf70911c480fff0..be05e66c167b12a70db409242519a9b1958b1000 100644 (file)
@@ -475,6 +475,7 @@ enum {
 
 enum {
        TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT = (1 << 0),
+       TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST = (1 << 1),
 };
 
 /* Match-all classifier */
@@ -555,7 +556,8 @@ enum {
 #define        TCF_EM_VLAN             6
 #define        TCF_EM_CANID            7
 #define        TCF_EM_IPSET            8
-#define        TCF_EM_MAX              8
+#define        TCF_EM_IPT              9
+#define        TCF_EM_MAX              9
 
 enum {
        TCF_EM_PROG_TC
index 64309a2b73cb326c74200e3ffda62f2ff7f9258e..1e1ed65ccad88a60d0bf8cffe67e01bcbd8ab599 100644 (file)
@@ -260,6 +260,19 @@ struct sctp_nxtinfo {
        sctp_assoc_t nxt_assoc_id;
 };
 
+/* 5.3.7 SCTP PR-SCTP Information Structure (SCTP_PRINFO)
+ *
+ *   This cmsghdr structure specifies SCTP options for sendmsg().
+ *
+ *   cmsg_level    cmsg_type      cmsg_data[]
+ *   ------------  ------------   -------------------
+ *   IPPROTO_SCTP  SCTP_PRINFO    struct sctp_prinfo
+ */
+struct sctp_prinfo {
+       __u16 pr_policy;
+       __u32 pr_value;
+};
+
 /*
  *  sinfo_flags: 16 bits (unsigned integer)
  *
@@ -271,6 +284,8 @@ enum sctp_sinfo_flags {
        SCTP_ADDR_OVER          = (1 << 1), /* Override the primary destination. */
        SCTP_ABORT              = (1 << 2), /* Send an ABORT message to the peer. */
        SCTP_SACK_IMMEDIATELY   = (1 << 3), /* SACK should be sent without delay. */
+       /* 2 bits here have been used by SCTP_PR_SCTP_MASK */
+       SCTP_SENDALL            = (1 << 6),
        SCTP_NOTIFICATION       = MSG_NOTIFICATION, /* Next message is not user msg but notification. */
        SCTP_EOF                = MSG_FIN,  /* Initiate graceful shutdown process. */
 };
@@ -293,6 +308,14 @@ typedef enum sctp_cmsg_type {
 #define SCTP_RCVINFO   SCTP_RCVINFO
        SCTP_NXTINFO,           /* 5.3.6 SCTP Next Receive Information Structure */
 #define SCTP_NXTINFO   SCTP_NXTINFO
+       SCTP_PRINFO,            /* 5.3.7 SCTP PR-SCTP Information Structure */
+#define SCTP_PRINFO    SCTP_PRINFO
+       SCTP_AUTHINFO,          /* 5.3.8 SCTP AUTH Information Structure (RESERVED) */
+#define SCTP_AUTHINFO  SCTP_AUTHINFO
+       SCTP_DSTADDRV4,         /* 5.3.9 SCTP Destination IPv4 Address Structure */
+#define SCTP_DSTADDRV4 SCTP_DSTADDRV4
+       SCTP_DSTADDRV6,         /* 5.3.10 SCTP Destination IPv6 Address Structure */
+#define SCTP_DSTADDRV6 SCTP_DSTADDRV6
 } sctp_cmsg_t;
 
 /*
diff --git a/include/uapi/linux/tc_ematch/tc_em_ipt.h b/include/uapi/linux/tc_ematch/tc_em_ipt.h
new file mode 100644 (file)
index 0000000..49a6553
--- /dev/null
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __LINUX_TC_EM_IPT_H
+#define __LINUX_TC_EM_IPT_H
+
+#include <linux/types.h>
+#include <linux/pkt_cls.h>
+
+enum {
+       TCA_EM_IPT_UNSPEC,
+       TCA_EM_IPT_HOOK,
+       TCA_EM_IPT_MATCH_NAME,
+       TCA_EM_IPT_MATCH_REVISION,
+       TCA_EM_IPT_NFPROTO,
+       TCA_EM_IPT_MATCH_DATA,
+       __TCA_EM_IPT_MAX
+};
+
+#define TCA_EM_IPT_MAX (__TCA_EM_IPT_MAX - 1)
+
+#endif
index 3dc9e4a337f269c732cce692cd9ed7766a77afab..6bf453cf08296e6f7a4da7391bd016e599e76896 100644 (file)
@@ -241,6 +241,8 @@ enum {
        TCP_NLA_MIN_RTT,        /* minimum RTT */
        TCP_NLA_RECUR_RETRANS,  /* Recurring retransmits for the current pkt */
        TCP_NLA_DELIVERY_RATE_APP_LMT, /* delivery rate application limited ? */
+       TCP_NLA_SNDQ_SIZE,      /* Data (bytes) pending in send queue */
+       TCP_NLA_CA_STATE,       /* ca_state of socket */
 
 };
 
diff --git a/include/uapi/rdma/rdma_netlink.h b/include/uapi/rdma/rdma_netlink.h
deleted file mode 100644 (file)
index dbac3b8..0000000
+++ /dev/null
@@ -1,355 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-#ifndef _RDMA_NETLINK_H
-#define _RDMA_NETLINK_H
-
-#include <linux/types.h>
-
-enum {
-       RDMA_NL_RDMA_CM = 1,
-       RDMA_NL_IWCM,
-       RDMA_NL_RSVD,
-       RDMA_NL_LS,     /* RDMA Local Services */
-       RDMA_NL_NLDEV,  /* RDMA device interface */
-       RDMA_NL_NUM_CLIENTS
-};
-
-enum {
-       RDMA_NL_GROUP_CM = 1,
-       RDMA_NL_GROUP_IWPM,
-       RDMA_NL_GROUP_LS,
-       RDMA_NL_NUM_GROUPS
-};
-
-#define RDMA_NL_GET_CLIENT(type) ((type & (((1 << 6) - 1) << 10)) >> 10)
-#define RDMA_NL_GET_OP(type) (type & ((1 << 10) - 1))
-#define RDMA_NL_GET_TYPE(client, op) ((client << 10) + op)
-
-enum {
-       RDMA_NL_RDMA_CM_ID_STATS = 0,
-       RDMA_NL_RDMA_CM_NUM_OPS
-};
-
-enum {
-       RDMA_NL_RDMA_CM_ATTR_SRC_ADDR = 1,
-       RDMA_NL_RDMA_CM_ATTR_DST_ADDR,
-       RDMA_NL_RDMA_CM_NUM_ATTR,
-};
-
-/* iwarp port mapper op-codes */
-enum {
-       RDMA_NL_IWPM_REG_PID = 0,
-       RDMA_NL_IWPM_ADD_MAPPING,
-       RDMA_NL_IWPM_QUERY_MAPPING,
-       RDMA_NL_IWPM_REMOVE_MAPPING,
-       RDMA_NL_IWPM_REMOTE_INFO,
-       RDMA_NL_IWPM_HANDLE_ERR,
-       RDMA_NL_IWPM_MAPINFO,
-       RDMA_NL_IWPM_MAPINFO_NUM,
-       RDMA_NL_IWPM_NUM_OPS
-};
-
-struct rdma_cm_id_stats {
-       __u32   qp_num;
-       __u32   bound_dev_if;
-       __u32   port_space;
-       __s32   pid;
-       __u8    cm_state;
-       __u8    node_type;
-       __u8    port_num;
-       __u8    qp_type;
-};
-
-enum {
-       IWPM_NLA_REG_PID_UNSPEC = 0,
-       IWPM_NLA_REG_PID_SEQ,
-       IWPM_NLA_REG_IF_NAME,
-       IWPM_NLA_REG_IBDEV_NAME,
-       IWPM_NLA_REG_ULIB_NAME,
-       IWPM_NLA_REG_PID_MAX
-};
-
-enum {
-       IWPM_NLA_RREG_PID_UNSPEC = 0,
-       IWPM_NLA_RREG_PID_SEQ,
-       IWPM_NLA_RREG_IBDEV_NAME,
-       IWPM_NLA_RREG_ULIB_NAME,
-       IWPM_NLA_RREG_ULIB_VER,
-       IWPM_NLA_RREG_PID_ERR,
-       IWPM_NLA_RREG_PID_MAX
-
-};
-
-enum {
-       IWPM_NLA_MANAGE_MAPPING_UNSPEC = 0,
-       IWPM_NLA_MANAGE_MAPPING_SEQ,
-       IWPM_NLA_MANAGE_ADDR,
-       IWPM_NLA_MANAGE_MAPPED_LOC_ADDR,
-       IWPM_NLA_RMANAGE_MAPPING_ERR,
-       IWPM_NLA_RMANAGE_MAPPING_MAX
-};
-
-#define IWPM_NLA_MANAGE_MAPPING_MAX 3
-#define IWPM_NLA_QUERY_MAPPING_MAX  4
-#define IWPM_NLA_MAPINFO_SEND_MAX   3
-
-enum {
-       IWPM_NLA_QUERY_MAPPING_UNSPEC = 0,
-       IWPM_NLA_QUERY_MAPPING_SEQ,
-       IWPM_NLA_QUERY_LOCAL_ADDR,
-       IWPM_NLA_QUERY_REMOTE_ADDR,
-       IWPM_NLA_RQUERY_MAPPED_LOC_ADDR,
-       IWPM_NLA_RQUERY_MAPPED_REM_ADDR,
-       IWPM_NLA_RQUERY_MAPPING_ERR,
-       IWPM_NLA_RQUERY_MAPPING_MAX
-};
-
-enum {
-       IWPM_NLA_MAPINFO_REQ_UNSPEC = 0,
-       IWPM_NLA_MAPINFO_ULIB_NAME,
-       IWPM_NLA_MAPINFO_ULIB_VER,
-       IWPM_NLA_MAPINFO_REQ_MAX
-};
-
-enum {
-       IWPM_NLA_MAPINFO_UNSPEC = 0,
-       IWPM_NLA_MAPINFO_LOCAL_ADDR,
-       IWPM_NLA_MAPINFO_MAPPED_ADDR,
-       IWPM_NLA_MAPINFO_MAX
-};
-
-enum {
-       IWPM_NLA_MAPINFO_NUM_UNSPEC = 0,
-       IWPM_NLA_MAPINFO_SEQ,
-       IWPM_NLA_MAPINFO_SEND_NUM,
-       IWPM_NLA_MAPINFO_ACK_NUM,
-       IWPM_NLA_MAPINFO_NUM_MAX
-};
-
-enum {
-       IWPM_NLA_ERR_UNSPEC = 0,
-       IWPM_NLA_ERR_SEQ,
-       IWPM_NLA_ERR_CODE,
-       IWPM_NLA_ERR_MAX
-};
-
-/*
- * Local service operations:
- *   RESOLVE - The client requests the local service to resolve a path.
- *   SET_TIMEOUT - The local service requests the client to set the timeout.
- *   IP_RESOLVE - The client requests the local service to resolve an IP to GID.
- */
-enum {
-       RDMA_NL_LS_OP_RESOLVE = 0,
-       RDMA_NL_LS_OP_SET_TIMEOUT,
-       RDMA_NL_LS_OP_IP_RESOLVE,
-       RDMA_NL_LS_NUM_OPS
-};
-
-/* Local service netlink message flags */
-#define RDMA_NL_LS_F_ERR       0x0100  /* Failed response */
-
-/*
- * Local service resolve operation family header.
- * The layout for the resolve operation:
- *    nlmsg header
- *    family header
- *    attributes
- */
-
-/*
- * Local service path use:
- * Specify how the path(s) will be used.
- *   ALL - For connected CM operation (6 pathrecords)
- *   UNIDIRECTIONAL - For unidirectional UD (1 pathrecord)
- *   GMP - For miscellaneous GMP like operation (at least 1 reversible
- *         pathrecord)
- */
-enum {
-       LS_RESOLVE_PATH_USE_ALL = 0,
-       LS_RESOLVE_PATH_USE_UNIDIRECTIONAL,
-       LS_RESOLVE_PATH_USE_GMP,
-       LS_RESOLVE_PATH_USE_MAX
-};
-
-#define LS_DEVICE_NAME_MAX 64
-
-struct rdma_ls_resolve_header {
-       __u8 device_name[LS_DEVICE_NAME_MAX];
-       __u8 port_num;
-       __u8 path_use;
-};
-
-struct rdma_ls_ip_resolve_header {
-       __u32 ifindex;
-};
-
-/* Local service attribute type */
-#define RDMA_NLA_F_MANDATORY   (1 << 13)
-#define RDMA_NLA_TYPE_MASK     (~(NLA_F_NESTED | NLA_F_NET_BYTEORDER | \
-                                 RDMA_NLA_F_MANDATORY))
-
-/*
- * Local service attributes:
- *   Attr Name       Size                       Byte order
- *   -----------------------------------------------------
- *   PATH_RECORD     struct ib_path_rec_data
- *   TIMEOUT         u32                        cpu
- *   SERVICE_ID      u64                        cpu
- *   DGID            u8[16]                     BE
- *   SGID            u8[16]                     BE
- *   TCLASS          u8
- *   PKEY            u16                        cpu
- *   QOS_CLASS       u16                        cpu
- *   IPV4            u32                        BE
- *   IPV6            u8[16]                     BE
- */
-enum {
-       LS_NLA_TYPE_UNSPEC = 0,
-       LS_NLA_TYPE_PATH_RECORD,
-       LS_NLA_TYPE_TIMEOUT,
-       LS_NLA_TYPE_SERVICE_ID,
-       LS_NLA_TYPE_DGID,
-       LS_NLA_TYPE_SGID,
-       LS_NLA_TYPE_TCLASS,
-       LS_NLA_TYPE_PKEY,
-       LS_NLA_TYPE_QOS_CLASS,
-       LS_NLA_TYPE_IPV4,
-       LS_NLA_TYPE_IPV6,
-       LS_NLA_TYPE_MAX
-};
-
-/* Local service DGID/SGID attribute: big endian */
-struct rdma_nla_ls_gid {
-       __u8            gid[16];
-};
-
-enum rdma_nldev_command {
-       RDMA_NLDEV_CMD_UNSPEC,
-
-       RDMA_NLDEV_CMD_GET, /* can dump */
-
-       /* 2 - 4 are free to use */
-
-       RDMA_NLDEV_CMD_PORT_GET = 5, /* can dump */
-
-       /* 6 - 8 are free to use */
-
-       RDMA_NLDEV_CMD_RES_GET = 9, /* can dump */
-
-       RDMA_NLDEV_CMD_RES_QP_GET, /* can dump */
-
-       RDMA_NLDEV_NUM_OPS
-};
-
-enum rdma_nldev_attr {
-       /* don't change the order or add anything between, this is ABI! */
-       RDMA_NLDEV_ATTR_UNSPEC,
-
-       /* Identifier for ib_device */
-       RDMA_NLDEV_ATTR_DEV_INDEX,              /* u32 */
-
-       RDMA_NLDEV_ATTR_DEV_NAME,               /* string */
-       /*
-        * Device index together with port index are identifiers
-        * for port/link properties.
-        *
-        * For RDMA_NLDEV_CMD_GET commamnd, port index will return number
-        * of available ports in ib_device, while for port specific operations,
-        * it will be real port index as it appears in sysfs. Port index follows
-        * sysfs notation and starts from 1 for the first port.
-        */
-       RDMA_NLDEV_ATTR_PORT_INDEX,             /* u32 */
-
-       /*
-        * Device and port capabilities
-        */
-       RDMA_NLDEV_ATTR_CAP_FLAGS,              /* u64 */
-
-       /*
-        * FW version
-        */
-       RDMA_NLDEV_ATTR_FW_VERSION,             /* string */
-
-       /*
-        * Node GUID (in host byte order) associated with the RDMA device.
-        */
-       RDMA_NLDEV_ATTR_NODE_GUID,                      /* u64 */
-
-       /*
-        * System image GUID (in host byte order) associated with
-        * this RDMA device and other devices which are part of a
-        * single system.
-        */
-       RDMA_NLDEV_ATTR_SYS_IMAGE_GUID,         /* u64 */
-
-       /*
-        * Subnet prefix (in host byte order)
-        */
-       RDMA_NLDEV_ATTR_SUBNET_PREFIX,          /* u64 */
-
-       /*
-        * Local Identifier (LID),
-        * According to IB specification, It is 16-bit address assigned
-        * by the Subnet Manager. Extended to be 32-bit for OmniPath users.
-        */
-       RDMA_NLDEV_ATTR_LID,                    /* u32 */
-       RDMA_NLDEV_ATTR_SM_LID,                 /* u32 */
-
-       /*
-        * LID mask control (LMC)
-        */
-       RDMA_NLDEV_ATTR_LMC,                    /* u8 */
-
-       RDMA_NLDEV_ATTR_PORT_STATE,             /* u8 */
-       RDMA_NLDEV_ATTR_PORT_PHYS_STATE,        /* u8 */
-
-       RDMA_NLDEV_ATTR_DEV_NODE_TYPE,          /* u8 */
-
-       RDMA_NLDEV_ATTR_RES_SUMMARY,            /* nested table */
-       RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY,      /* nested table */
-       RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME, /* string */
-       RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR, /* u64 */
-
-       RDMA_NLDEV_ATTR_RES_QP,                 /* nested table */
-       RDMA_NLDEV_ATTR_RES_QP_ENTRY,           /* nested table */
-       /*
-        * Local QPN
-        */
-       RDMA_NLDEV_ATTR_RES_LQPN,               /* u32 */
-       /*
-        * Remote QPN,
-        * Applicable for RC and UC only IBTA 11.2.5.3 QUERY QUEUE PAIR
-        */
-       RDMA_NLDEV_ATTR_RES_RQPN,               /* u32 */
-       /*
-        * Receive Queue PSN,
-        * Applicable for RC and UC only 11.2.5.3 QUERY QUEUE PAIR
-        */
-       RDMA_NLDEV_ATTR_RES_RQ_PSN,             /* u32 */
-       /*
-        * Send Queue PSN
-        */
-       RDMA_NLDEV_ATTR_RES_SQ_PSN,             /* u32 */
-       RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE,     /* u8 */
-       /*
-        * QP types as visible to RDMA/core, the reserved QPT
-        * are not exported through this interface.
-        */
-       RDMA_NLDEV_ATTR_RES_TYPE,               /* u8 */
-       RDMA_NLDEV_ATTR_RES_STATE,              /* u8 */
-       /*
-        * Process ID which created object,
-        * in case of kernel origin, PID won't exist.
-        */
-       RDMA_NLDEV_ATTR_RES_PID,                /* u32 */
-       /*
-        * The name of process created following resource.
-        * It will exist only for kernel objects.
-        * For user created objects, the user is supposed
-        * to read /proc/PID/comm file.
-        */
-       RDMA_NLDEV_ATTR_RES_KERN_NAME,          /* string */
-
-       RDMA_NLDEV_ATTR_MAX
-};
-#endif /* _RDMA_NETLINK_H */
index e7bffe8acbda405234e06a55078ee8af978636fa..8cb4349e8a89f6f2ae3eb8818af804ef38da2c8c 100644 (file)
@@ -12,6 +12,7 @@
 #include "libnetlink.h"
 #include "ll_map.h"
 #include "rtm_map.h"
+#include "json_print.h"
 
 extern int preferred_family;
 extern int human_readable;
@@ -23,6 +24,7 @@ extern int resolve_hosts;
 extern int oneline;
 extern int brief;
 extern int json;
+extern int pretty;
 extern int timestamp;
 extern int timestamp_short;
 extern const char * _SL_;
@@ -64,6 +66,11 @@ enum {
        ADDRTYPE_INET_MULTI     = ADDRTYPE_INET | ADDRTYPE_MULTI
 };
 
+static inline void inet_prefix_reset(inet_prefix *p)
+{
+       p->flags = 0;
+}
+
 static inline bool is_addrtype_inet(const inet_prefix *p)
 {
        return p->flags & ADDRTYPE_INET;
@@ -155,6 +162,10 @@ int af_byte_len(int af);
 
 const char *format_host_r(int af, int len, const void *addr,
                               char *buf, int buflen);
+#define format_host_rta_r(af, rta, buf, buflen)        \
+       format_host_r(af, RTA_PAYLOAD(rta), RTA_DATA(rta), \
+                     buf, buflen)
+
 const char *format_host(int af, int lne, const void *addr);
 #define format_host_rta(af, rta) \
        format_host(af, RTA_PAYLOAD(rta), RTA_DATA(rta))
@@ -171,8 +182,10 @@ void missarg(const char *) __attribute__((noreturn));
 void invarg(const char *, const char *) __attribute__((noreturn));
 void duparg(const char *, const char *) __attribute__((noreturn));
 void duparg2(const char *, const char *) __attribute__((noreturn));
+int nodev(const char *dev);
 int check_ifname(const char *);
 int get_ifname(char *, const char *);
+const char *get_ifname_rta(int ifindex, const struct rtattr *rta);
 int matches(const char *arg, const char *pattern);
 int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits);
 int inet_addr_match_rta(const inet_prefix *m, const struct rtattr *rta);
@@ -239,6 +252,9 @@ void print_escape_buf(const __u8 *buf, size_t len, const char *escape);
 int print_timestamp(FILE *fp);
 void print_nlmsg_timestamp(FILE *fp, const struct nlmsghdr *n);
 
+unsigned int print_name_and_link(const char *fmt,
+                                const char *name, struct rtattr *tb[]);
+
 #define BIT(nr)                 (1UL << (nr))
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
@@ -272,16 +288,6 @@ extern int cmdlineno;
 ssize_t getcmdline(char **line, size_t *len, FILE *in);
 int makeargs(char *line, char *argv[], int maxargs);
 
-struct iplink_req {
-       struct nlmsghdr         n;
-       struct ifinfomsg        i;
-       char                    buf[1024];
-};
-
-int iplink_parse(int argc, char **argv, struct iplink_req *req,
-               char **name, char **type, char **link, char **dev,
-               int *group, int *index);
-
 int do_each_netns(int (*func)(char *nsname, void *arg), void *arg,
                bool show_label);
 
@@ -294,6 +300,9 @@ int make_path(const char *path, mode_t mode);
 char *find_cgroup2_mount(void);
 int get_command_name(const char *pid, char *comm, size_t len);
 
+int get_rtnl_link_stats_rta(struct rtnl_link_stats64 *stats64,
+                           struct rtattr *tb[]);
+
 #ifdef NEED_STRLCPY
 size_t strlcpy(char *dst, const char *src, size_t size);
 size_t strlcat(char *dst, const char *src, size_t size);
diff --git a/ip/ip.c b/ip/ip.c
index e716fed8e8fe6f526c2665f7a5a6492a542bf317..71d5170c0cc23ee901fb104aaae5c35e640effad 100644 (file)
--- a/ip/ip.c
+++ b/ip/ip.c
@@ -53,12 +53,12 @@ static void usage(void)
 "                   netns | l2tp | fou | macsec | tcp_metrics | token | netconf | ila |\n"
 "                   vrf | sr }\n"
 "       OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
-"                    -h[uman-readable] | -iec |\n"
+"                    -h[uman-readable] | -iec | -j[son] | -p[retty] |\n"
 "                    -f[amily] { inet | inet6 | ipx | dnet | mpls | bridge | link } |\n"
 "                    -4 | -6 | -I | -D | -B | -0 |\n"
 "                    -l[oops] { maximum-addr-flush-attempts } | -br[ief] |\n"
 "                    -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |\n"
-"                    -rc[vbuf] [size] | -n[etns] name | -a[ll] | -c[olor]}\n");
+"                    -rc[vbuf] [size] | -n[etns] name | -a[ll] | -c[olor]}\n");
        exit(-1);
 }
 
@@ -268,6 +268,8 @@ int main(int argc, char **argv)
                        ++brief;
                } else if (matches(opt, "-json") == 0) {
                        ++json;
+               } else if (matches(opt, "-pretty") == 0) {
+                       ++pretty;
                } else if (matches(opt, "-rcvbuf") == 0) {
                        unsigned int size;
 
index 783e28a6e516dee8629bfd7a746c6f6b08ef79e5..999408ed801b189619df2161b27af8686b5275e9 100644 (file)
@@ -67,8 +67,9 @@ static void usage(void)
        exit(-1);
 }
 
-static void print_tunnel(struct ip6_tnl_parm2 *p)
+static void print_tunnel(const void *t)
 {
+       const struct ip6_tnl_parm2 *p = t;
        char s1[1024];
        char s2[1024];
 
@@ -295,10 +296,8 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm2 *p)
        }
        if (medium) {
                p->link = ll_name_to_index(medium);
-               if (p->link == 0) {
-                       fprintf(stderr, "Cannot find device \"%s\"\n", medium);
-                       return -1;
-               }
+               if (!p->link)
+                       return nodev(medium);
        }
        return 0;
 }
@@ -313,13 +312,24 @@ static void ip6_tnl_parm_init(struct ip6_tnl_parm2 *p, int apply_default)
        }
 }
 
-/*
- * @p1: user specified parameter
- * @p2: database entry
- */
-static int ip6_tnl_parm_match(const struct ip6_tnl_parm2 *p1,
-                             const struct ip6_tnl_parm2 *p2)
+static void ip6_tnl_parm_initialize(const struct tnl_print_nlmsg_info *info)
+{
+       const struct ifinfomsg *ifi = info->ifi;
+       const struct ip6_tnl_parm2 *p1 = info->p1;
+       struct ip6_tnl_parm2 *p2 = info->p2;
+
+       ip6_tnl_parm_init(p2, 0);
+       if (ifi->ifi_type == ARPHRD_IP6GRE)
+               p2->proto = IPPROTO_GRE;
+       p2->link = ifi->ifi_index;
+       strcpy(p2->name, p1->name);
+}
+
+static bool ip6_tnl_parm_match(const struct tnl_print_nlmsg_info *info)
 {
+       const struct ip6_tnl_parm2 *p1 = info->p1;
+       const struct ip6_tnl_parm2 *p2 = info->p2;
+
        return ((!p1->link || p1->link == p2->link) &&
                (!p1->name[0] || strcmp(p1->name, p2->name) == 0) &&
                (IN6_IS_ADDR_UNSPECIFIED(&p1->laddr) ||
@@ -336,90 +346,33 @@ static int ip6_tnl_parm_match(const struct ip6_tnl_parm2 *p1,
                (!p1->flags || (p1->flags & p2->flags)));
 }
 
-static int do_tunnels_list(struct ip6_tnl_parm2 *p)
-{
-       char buf[512];
-       int err = -1;
-       FILE *fp = fopen("/proc/net/dev", "r");
-
-       if (fp == NULL) {
-               perror("fopen");
-               return -1;
-       }
-
-       /* skip two lines at the begenning of the file */
-       if (!fgets(buf, sizeof(buf), fp) ||
-           !fgets(buf, sizeof(buf), fp)) {
-               fprintf(stderr, "/proc/net/dev read error\n");
-               goto end;
-       }
-
-       while (fgets(buf, sizeof(buf), fp) != NULL) {
-               char name[IFNAMSIZ];
-               int index, type;
-               struct ip6_tnl_parm2 p1 = {};
-               char *ptr;
-
-               buf[sizeof(buf) - 1] = '\0';
-               if ((ptr = strchr(buf, ':')) == NULL ||
-                   (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {
-                       fprintf(stderr, "Wrong format for /proc/net/dev. Giving up.\n");
-                       goto end;
-               }
-               if (p->name[0] && strcmp(p->name, name))
-                       continue;
-               index = ll_name_to_index(name);
-               if (index == 0)
-                       continue;
-               type = ll_index_to_type(index);
-               if (type == -1) {
-                       fprintf(stderr, "Failed to get type of \"%s\"\n", name);
-                       continue;
-               }
-               if (type != ARPHRD_TUNNEL6 && type != ARPHRD_IP6GRE)
-                       continue;
-               ip6_tnl_parm_init(&p1, 0);
-               if (type == ARPHRD_IP6GRE)
-                       p1.proto = IPPROTO_GRE;
-               strcpy(p1.name, name);
-               p1.link = ll_name_to_index(p1.name);
-               if (p1.link == 0)
-                       continue;
-               if (tnl_get_ioctl(p1.name, &p1))
-                       continue;
-               if (!ip6_tnl_parm_match(p, &p1))
-                       continue;
-               print_tunnel(&p1);
-               if (show_stats)
-                       tnl_print_stats(ptr);
-               printf("\n");
-       }
-       err = 0;
- end:
-       fclose(fp);
-       return err;
-}
-
 static int do_show(int argc, char **argv)
 {
-       struct ip6_tnl_parm2 p;
+       struct ip6_tnl_parm2 p, p1;
 
-       ll_init_map(&rth);
        ip6_tnl_parm_init(&p, 0);
        p.proto = 0;  /* default to any */
 
        if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0)
                return -1;
 
-       if (!p.name[0] || show_stats)
-               do_tunnels_list(&p);
-       else {
-               if (tnl_get_ioctl(p.name, &p))
-                       return -1;
-               print_tunnel(&p);
-               printf("\n");
+       if (!p.name[0] || show_stats) {
+               struct tnl_print_nlmsg_info info = {
+                       .p1    = &p,
+                       .p2    = &p1,
+                       .init  = ip6_tnl_parm_initialize,
+                       .match = ip6_tnl_parm_match,
+                       .print = print_tunnel,
+               };
+
+               return do_tunnels_list(&info);
        }
 
+       if (tnl_get_ioctl(p.name, &p))
+               return -1;
+
+       print_tunnel(&p);
+       fputc('\n', stdout);
        return 0;
 }
 
index 3203f0cd5b52af1b6233dd352084be8aef62d9e7..1b89795caa58fa26e5e48795094a40f086a51da8 100644 (file)
@@ -29,9 +29,6 @@ struct link_filter {
 int get_operstate(const char *name);
 int print_linkinfo(const struct sockaddr_nl *who,
                   struct nlmsghdr *n, void *arg);
-int print_linkinfo_brief(const struct sockaddr_nl *who,
-                        struct nlmsghdr *n, void *arg,
-                        struct link_filter *filter);
 int print_addrinfo(const struct sockaddr_nl *who,
                   struct nlmsghdr *n, void *arg);
 int print_addrlabel(const struct sockaddr_nl *who,
@@ -109,6 +106,12 @@ static inline int rtm_get_table(struct rtmsg *r, struct rtattr **tb)
 
 extern struct rtnl_handle rth;
 
+struct iplink_req {
+       struct nlmsghdr         n;
+       struct ifinfomsg        i;
+       char                    buf[1024];
+};
+
 struct link_util {
        struct link_util        *next;
        const char              *id;
@@ -129,11 +132,24 @@ struct link_util {
 
 struct link_util *get_link_kind(const char *kind);
 
+int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type);
+
+/* iplink_bridge.c */
 void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf, size_t len);
 int bridge_parse_xstats(struct link_util *lu, int argc, char **argv);
 int bridge_print_xstats(const struct sockaddr_nl *who,
                        struct nlmsghdr *n, void *arg);
 
+/* iproute_lwtunnel.c */
+int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp);
+void lwt_print_encap(FILE *fp, struct rtattr *encap_type, struct rtattr *encap);
+
+/* iplink_xdp.c */
+int xdp_parse(int *argc, char ***argv, struct iplink_req *req, __u32 ifindex,
+             bool generic, bool drv, bool offload);
+void xdp_dump(FILE *fp, struct rtattr *tb, bool link, bool details);
+
+/* iplink_vrf.c */
 __u32 ipvrf_get_table(const char *name);
 int name_is_vrf(const char *name);
 
index 955ef72e5f89a47644dbdbc873ae9f2cc5c8f579..aecc9a1d070ef859de54a61551d619168915143f 100644 (file)
@@ -34,7 +34,6 @@
 #include "utils.h"
 #include "ll_map.h"
 #include "ip_common.h"
-#include "xdp.h"
 #include "color.h"
 
 enum {
@@ -594,11 +593,18 @@ static void print_vf_stats64(FILE *fp, struct rtattr *vfstats)
        }
 }
 
-static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s,
-                              const struct rtattr *carrier_changes)
+static void __print_link_stats(FILE *fp, struct rtattr *tb[])
 {
+       const struct rtattr *carrier_changes = tb[IFLA_CARRIER_CHANGES];
+       struct rtnl_link_stats64 _s, *s = &_s;
+       int ret;
+
+       ret = get_rtnl_link_stats_rta(s, tb);
+       if (ret < 0)
+               return;
+
        if (is_json_context()) {
-               open_json_object("stats64");
+               open_json_object((ret == sizeof(*s)) ? "stats64" : "stats");
 
                /* RX stats */
                open_json_object("rx");
@@ -610,8 +616,7 @@ static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s,
                print_uint(PRINT_JSON, "multicast", NULL, s->multicast);
                if (s->rx_compressed)
                        print_uint(PRINT_JSON,
-                                  "compressed",
-                                  NULL, s->rx_compressed);
+                                  "compressed", NULL, s->rx_compressed);
 
                /* RX error stats */
                if (show_stats > 1) {
@@ -648,8 +653,7 @@ static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s,
                print_uint(PRINT_JSON, "collisions", NULL, s->collisions);
                if (s->tx_compressed)
                        print_uint(PRINT_JSON,
-                                  "compressed",
-                                  NULL, s->tx_compressed);
+                                  "compressed", NULL, s->tx_compressed);
 
                /* TX error stats */
                if (show_stats > 1) {
@@ -669,154 +673,6 @@ static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s,
                                print_uint(PRINT_JSON, "carrier_changes", NULL,
                                           rta_getattr_u32(carrier_changes));
                }
-               close_json_object();
-               close_json_object();
-
-       } else {
-               /* RX stats */
-               fprintf(fp, "    RX: bytes  packets  errors  dropped overrun mcast   %s%s",
-                       s->rx_compressed ? "compressed" : "", _SL_);
-
-               fprintf(fp, "    ");
-               print_num(fp, 10, s->rx_bytes);
-               print_num(fp, 8, s->rx_packets);
-               print_num(fp, 7, s->rx_errors);
-               print_num(fp, 7, s->rx_dropped);
-               print_num(fp, 7, s->rx_over_errors);
-               print_num(fp, 7, s->multicast);
-               if (s->rx_compressed)
-                       print_num(fp, 7, s->rx_compressed);
-
-               /* RX error stats */
-               if (show_stats > 1) {
-                       fprintf(fp, "%s", _SL_);
-                       fprintf(fp, "    RX errors: length   crc     frame   fifo    missed%s%s",
-                               s->rx_nohandler ? "   nohandler" : "", _SL_);
-
-                       fprintf(fp, "               ");
-                       print_num(fp, 8, s->rx_length_errors);
-                       print_num(fp, 7, s->rx_crc_errors);
-                       print_num(fp, 7, s->rx_frame_errors);
-                       print_num(fp, 7, s->rx_fifo_errors);
-                       print_num(fp, 7, s->rx_missed_errors);
-                       if (s->rx_nohandler)
-                               print_num(fp, 7, s->rx_nohandler);
-
-               }
-               fprintf(fp, "%s", _SL_);
-
-               /* TX stats */
-               fprintf(fp, "    TX: bytes  packets  errors  dropped carrier collsns %s%s",
-                       s->tx_compressed ? "compressed" : "", _SL_);
-
-               fprintf(fp, "    ");
-               print_num(fp, 10, s->tx_bytes);
-               print_num(fp, 8, s->tx_packets);
-               print_num(fp, 7, s->tx_errors);
-               print_num(fp, 7, s->tx_dropped);
-               print_num(fp, 7, s->tx_carrier_errors);
-               print_num(fp, 7, s->collisions);
-               if (s->tx_compressed)
-                       print_num(fp, 7, s->tx_compressed);
-
-               /* TX error stats */
-               if (show_stats > 1) {
-                       fprintf(fp, "%s", _SL_);
-                       fprintf(fp, "    TX errors: aborted  fifo   window heartbeat");
-                       if (carrier_changes)
-                               fprintf(fp, " transns");
-                       fprintf(fp, "%s", _SL_);
-
-                       fprintf(fp, "               ");
-                       print_num(fp, 8, s->tx_aborted_errors);
-                       print_num(fp, 7, s->tx_fifo_errors);
-                       print_num(fp, 7, s->tx_window_errors);
-                       print_num(fp, 7, s->tx_heartbeat_errors);
-                       if (carrier_changes)
-                               print_num(fp, 7,
-                                         rta_getattr_u32(carrier_changes));
-               }
-       }
-}
-
-static void print_link_stats32(FILE *fp, const struct rtnl_link_stats *s,
-                              const struct rtattr *carrier_changes)
-{
-       if (is_json_context()) {
-               open_json_object("stats");
-
-               /* RX stats */
-               open_json_object("rx");
-               print_uint(PRINT_JSON, "bytes", NULL, s->rx_bytes);
-               print_uint(PRINT_JSON, "packets", NULL, s->rx_packets);
-               print_uint(PRINT_JSON, "errors", NULL, s->rx_errors);
-               print_uint(PRINT_JSON, "dropped", NULL, s->rx_dropped);
-               print_uint(PRINT_JSON, "over_errors", NULL, s->rx_over_errors);
-               print_uint(PRINT_JSON, "multicast", NULL, s->multicast);
-               if (s->rx_compressed)
-                       print_int(PRINT_JSON,
-                                 "compressed",
-                                 NULL, s->rx_compressed);
-
-               /* RX error stats */
-               if (show_stats > 1) {
-                       print_uint(PRINT_JSON,
-                                  "length_errors",
-                                  NULL, s->rx_length_errors);
-                       print_uint(PRINT_JSON,
-                                  "crc_errors",
-                                  NULL, s->rx_crc_errors);
-                       print_uint(PRINT_JSON,
-                                  "frame_errors",
-                                  NULL, s->rx_frame_errors);
-                       print_uint(PRINT_JSON,
-                                  "fifo_errors",
-                                  NULL, s->rx_fifo_errors);
-                       print_uint(PRINT_JSON,
-                                  "missed_errors",
-                                  NULL, s->rx_missed_errors);
-                       if (s->rx_nohandler)
-                               print_int(PRINT_JSON,
-                                         "nohandler",
-                                         NULL, s->rx_nohandler);
-               }
-               close_json_object();
-
-               /* TX stats */
-               open_json_object("tx");
-               print_uint(PRINT_JSON, "bytes", NULL, s->tx_bytes);
-               print_uint(PRINT_JSON, "packets", NULL, s->tx_packets);
-               print_uint(PRINT_JSON, "errors", NULL, s->tx_errors);
-               print_uint(PRINT_JSON, "dropped", NULL, s->tx_dropped);
-               print_uint(PRINT_JSON,
-                          "carrier_errors",
-                          NULL, s->tx_carrier_errors);
-               print_uint(PRINT_JSON, "collisions", NULL, s->collisions);
-               if (s->tx_compressed)
-                       print_int(PRINT_JSON,
-                                 "compressed",
-                                 NULL, s->tx_compressed);
-
-               /* TX error stats */
-               if (show_stats > 1) {
-                       print_uint(PRINT_JSON,
-                                  "aborted_errors",
-                                  NULL, s->tx_aborted_errors);
-                       print_uint(PRINT_JSON,
-                                  "fifo_errors",
-                                  NULL, s->tx_fifo_errors);
-                       print_uint(PRINT_JSON,
-                                  "window_errors",
-                                  NULL, s->tx_window_errors);
-                       print_uint(PRINT_JSON,
-                                  "heartbeat_errors",
-                                  NULL, s->tx_heartbeat_errors);
-                       if (carrier_changes)
-                               print_uint(PRINT_JSON,
-                                          "carrier_changes",
-                                          NULL,
-                                          rta_getattr_u32(carrier_changes));
-               }
 
                close_json_object();
                close_json_object();
@@ -825,7 +681,6 @@ static void print_link_stats32(FILE *fp, const struct rtnl_link_stats *s,
                fprintf(fp, "    RX: bytes  packets  errors  dropped overrun mcast   %s%s",
                        s->rx_compressed ? "compressed" : "", _SL_);
 
-
                fprintf(fp, "    ");
                print_num(fp, 10, s->rx_bytes);
                print_num(fp, 8, s->rx_packets);
@@ -886,27 +741,6 @@ static void print_link_stats32(FILE *fp, const struct rtnl_link_stats *s,
        }
 }
 
-static void __print_link_stats(FILE *fp, struct rtattr **tb)
-{
-       const struct rtattr *carrier_changes = tb[IFLA_CARRIER_CHANGES];
-
-       if (tb[IFLA_STATS64]) {
-               struct rtnl_link_stats64 stats = { 0 };
-
-               memcpy(&stats, RTA_DATA(tb[IFLA_STATS64]),
-                      MIN(RTA_PAYLOAD(tb[IFLA_STATS64]), sizeof(stats)));
-
-               print_link_stats64(fp, &stats, carrier_changes);
-       } else if (tb[IFLA_STATS]) {
-               struct rtnl_link_stats stats = { 0 };
-
-               memcpy(&stats, RTA_DATA(tb[IFLA_STATS]),
-                      MIN(RTA_PAYLOAD(tb[IFLA_STATS]), sizeof(stats)));
-
-               print_link_stats32(fp, &stats, carrier_changes);
-       }
-}
-
 static void print_link_stats(FILE *fp, struct nlmsghdr *n)
 {
        struct ifinfomsg *ifi = NLMSG_DATA(n);
@@ -918,95 +752,18 @@ static void print_link_stats(FILE *fp, struct nlmsghdr *n)
        fprintf(fp, "%s", _SL_);
 }
 
-int print_linkinfo_brief(const struct sockaddr_nl *who,
-                        struct nlmsghdr *n, void *arg,
-                        struct link_filter *pfilter)
+static int print_linkinfo_brief(FILE *fp, const char *name,
+                               const struct ifinfomsg *ifi,
+                               struct rtattr *tb[])
 {
-       FILE *fp = (FILE *)arg;
-       struct ifinfomsg *ifi = NLMSG_DATA(n);
-       struct rtattr *tb[IFLA_MAX+1];
-       int len = n->nlmsg_len;
-       const char *name;
-       char buf[32] = { 0, };
        unsigned int m_flag = 0;
 
-       if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK)
-               return -1;
-
-       len -= NLMSG_LENGTH(sizeof(*ifi));
-       if (len < 0)
-               return -1;
-
-       if (!pfilter)
-               pfilter = &filter;
-
-       if (pfilter->ifindex && ifi->ifi_index != pfilter->ifindex)
-               return -1;
-       if (pfilter->up && !(ifi->ifi_flags&IFF_UP))
-               return -1;
-
-       parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
-       if (tb[IFLA_IFNAME] == NULL) {
-               fprintf(stderr, "BUG: device with ifindex %d has nil ifname\n", ifi->ifi_index);
-               name = "<nil>";
-       } else {
-               name = rta_getattr_str(tb[IFLA_IFNAME]);
-       }
-
-       if (pfilter->label &&
-           (!pfilter->family || pfilter->family == AF_PACKET) &&
-           fnmatch(pfilter->label, RTA_DATA(tb[IFLA_IFNAME]), 0))
-               return -1;
-
-       if (tb[IFLA_GROUP]) {
-               int group = rta_getattr_u32(tb[IFLA_GROUP]);
-
-               if (pfilter->group != -1 && group != pfilter->group)
-                       return -1;
-       }
-
-       if (tb[IFLA_MASTER]) {
-               int master = rta_getattr_u32(tb[IFLA_MASTER]);
-
-               if (pfilter->master > 0 && master != pfilter->master)
-                       return -1;
-       } else if (pfilter->master > 0)
-               return -1;
-
-       if (pfilter->kind && match_link_kind(tb, pfilter->kind, 0))
-               return -1;
-
-       if (pfilter->slave_kind && match_link_kind(tb, pfilter->slave_kind, 1))
-               return -1;
-
-       if (n->nlmsg_type == RTM_DELLINK)
-               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
-
-       if (tb[IFLA_LINK]) {
-               SPRINT_BUF(b1);
-               int iflink = rta_getattr_u32(tb[IFLA_LINK]);
-
-               if (iflink == 0) {
-                       snprintf(buf, sizeof(buf), "%s@NONE", name);
-                       print_null(PRINT_JSON, "link", NULL, NULL);
-               } else {
-                       const char *link = ll_idx_n2a(iflink, b1);
-
-                       print_string(PRINT_JSON, "link", NULL, link);
-                       snprintf(buf, sizeof(buf), "%s@%s", name, link);
-                       m_flag = ll_index_to_flags(iflink);
-                       m_flag = !(m_flag & IFF_UP);
-               }
-       } else
-               snprintf(buf, sizeof(buf), "%s", name);
-
-       print_string(PRINT_FP, NULL, "%-16s ", buf);
-       print_string(PRINT_JSON, "ifname", NULL, name);
+       m_flag = print_name_and_link("%-16s ", name, tb);
 
        if (tb[IFLA_OPERSTATE])
                print_operstate(fp, rta_getattr_u8(tb[IFLA_OPERSTATE]));
 
-       if (pfilter->family == AF_PACKET) {
+       if (filter.family == AF_PACKET) {
                SPRINT_BUF(b1);
 
                if (tb[IFLA_ADDRESS]) {
@@ -1020,10 +777,11 @@ int print_linkinfo_brief(const struct sockaddr_nl *who,
                }
        }
 
-       if (pfilter->family == AF_PACKET) {
+       if (filter.family == AF_PACKET) {
                print_link_flags(fp, ifi->ifi_flags, m_flag);
                print_string(PRINT_FP, NULL, "%s", "\n");
        }
+
        fflush(fp);
        return 0;
 }
@@ -1057,7 +815,9 @@ int print_linkinfo(const struct sockaddr_nl *who,
        struct ifinfomsg *ifi = NLMSG_DATA(n);
        struct rtattr *tb[IFLA_MAX+1];
        int len = n->nlmsg_len;
+       const char *name;
        unsigned int m_flag = 0;
+       SPRINT_BUF(b1);
 
        if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK)
                return 0;
@@ -1067,18 +827,20 @@ int print_linkinfo(const struct sockaddr_nl *who,
                return -1;
 
        if (filter.ifindex && ifi->ifi_index != filter.ifindex)
-               return 0;
+               return -1;
        if (filter.up && !(ifi->ifi_flags&IFF_UP))
-               return 0;
+               return -1;
 
        parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
-       if (tb[IFLA_IFNAME] == NULL)
-               fprintf(stderr, "BUG: device with ifindex %d has nil ifname\n", ifi->ifi_index);
+
+       name = get_ifname_rta(ifi->ifi_index, tb[IFLA_IFNAME]);
+       if (!name)
+               return -1;
 
        if (filter.label &&
            (!filter.family || filter.family == AF_PACKET) &&
-           fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0))
-               return 0;
+           fnmatch(filter.label, name, 0))
+               return -1;
 
        if (tb[IFLA_GROUP]) {
                int group = rta_getattr_u32(tb[IFLA_GROUP]);
@@ -1104,41 +866,12 @@ int print_linkinfo(const struct sockaddr_nl *who,
        if (n->nlmsg_type == RTM_DELLINK)
                print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 
-       print_int(PRINT_ANY, "ifindex", "%d: ", ifi->ifi_index);
-       if (tb[IFLA_IFNAME]) {
-               print_color_string(PRINT_ANY,
-                                  COLOR_IFNAME,
-                                  "ifname", "%s",
-                                  rta_getattr_str(tb[IFLA_IFNAME]));
-       } else {
-               print_null(PRINT_JSON, "ifname", NULL, NULL);
-               print_color_null(PRINT_FP, COLOR_IFNAME,
-                                "ifname", "%s", "<nil>");
-       }
-
-       if (tb[IFLA_LINK]) {
-               int iflink = rta_getattr_u32(tb[IFLA_LINK]);
+       if (brief)
+               return print_linkinfo_brief(fp, name, ifi, tb);
 
-               if (iflink == 0)
-                       print_null(PRINT_ANY, "link", "@%s: ", "NONE");
-               else {
-                       if (tb[IFLA_LINK_NETNSID])
-                               print_int(PRINT_ANY,
-                                         "link_index", "@if%d: ", iflink);
-                       else {
-                               SPRINT_BUF(b1);
+       print_int(PRINT_ANY, "ifindex", "%d: ", ifi->ifi_index);
 
-                               print_string(PRINT_ANY,
-                                            "link",
-                                            "@%s: ",
-                                            ll_idx_n2a(iflink, b1));
-                               m_flag = ll_index_to_flags(iflink);
-                               m_flag = !(m_flag & IFF_UP);
-                       }
-               }
-       } else {
-               print_string(PRINT_FP, NULL, ": ", NULL);
-       }
+       m_flag = print_name_and_link("%s: ", name, tb);
        print_link_flags(fp, ifi->ifi_flags, m_flag);
 
        if (tb[IFLA_MTU])
@@ -1153,12 +886,11 @@ int print_linkinfo(const struct sockaddr_nl *who,
                             "qdisc %s ",
                             rta_getattr_str(tb[IFLA_QDISC]));
        if (tb[IFLA_MASTER]) {
-               SPRINT_BUF(b1);
+               int master = rta_getattr_u32(tb[IFLA_MASTER]);
 
                print_string(PRINT_ANY,
-                            "master",
-                            "master %s ",
-                            ll_idx_n2a(rta_getattr_u32(tb[IFLA_MASTER]), b1));
+                            "master", "master %s ",
+                            ll_index_to_name(master));
        }
 
        if (tb[IFLA_OPERSTATE])
@@ -1168,7 +900,6 @@ int print_linkinfo(const struct sockaddr_nl *who,
                print_linkmode(fp, tb[IFLA_LINKMODE]);
 
        if (tb[IFLA_GROUP]) {
-               SPRINT_BUF(b1);
                int group = rta_getattr_u32(tb[IFLA_GROUP]);
 
                print_string(PRINT_ANY,
@@ -1184,8 +915,6 @@ int print_linkinfo(const struct sockaddr_nl *who,
                print_link_event(fp, rta_getattr_u32(tb[IFLA_EVENT]));
 
        if (!filter.family || filter.family == AF_PACKET || show_details) {
-               SPRINT_BUF(b1);
-
                print_string(PRINT_FP, NULL, "%s", _SL_);
                print_string(PRINT_ANY,
                             "link_type",
@@ -1285,7 +1014,6 @@ int print_linkinfo(const struct sockaddr_nl *who,
                                     rta_getattr_str(tb[IFLA_PHYS_PORT_NAME]));
 
                if (tb[IFLA_PHYS_PORT_ID]) {
-                       SPRINT_BUF(b1);
                        print_string(PRINT_ANY,
                                     "phys_port_id",
                                     "portid %s ",
@@ -1296,7 +1024,6 @@ int print_linkinfo(const struct sockaddr_nl *who,
                }
 
                if (tb[IFLA_PHYS_SWITCH_ID]) {
-                       SPRINT_BUF(b1);
                        print_string(PRINT_ANY,
                                     "phys_switch_id",
                                     "switchid %s ",
@@ -1335,7 +1062,7 @@ int print_linkinfo(const struct sockaddr_nl *who,
                close_json_array(PRINT_JSON, NULL);
        }
 
-       print_string(PRINT_FP, NULL, "\n", NULL);
+       print_string(PRINT_FP, NULL, "%s", "\n");
        fflush(fp);
        return 1;
 }
@@ -1474,6 +1201,21 @@ static int get_filter(const char *arg)
        return 0;
 }
 
+static int ifa_label_match_rta(int ifindex, const struct rtattr *rta)
+{
+       const char *label;
+
+       if (!filter.label)
+               return 0;
+
+       if (rta)
+               label = RTA_DATA(rta);
+       else
+               label = ll_index_to_name(ifindex);
+
+       return fnmatch(filter.label, label, 0);
+}
+
 int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
                   void *arg)
 {
@@ -1512,21 +1254,13 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
                return 0;
        if ((filter.flags ^ ifa_flags) & filter.flagmask)
                return 0;
-       if (filter.label) {
-               SPRINT_BUF(b1);
-               const char *label;
-
-               if (rta_tb[IFA_LABEL])
-                       label = RTA_DATA(rta_tb[IFA_LABEL]);
-               else
-                       label = ll_idx_n2a(ifa->ifa_index, b1);
-               if (fnmatch(filter.label, label, 0) != 0)
-                       return 0;
-       }
 
        if (filter.family && filter.family != ifa->ifa_family)
                return 0;
 
+       if (ifa_label_match_rta(ifa->ifa_index, rta_tb[IFA_LABEL]))
+               return 0;
+
        if (inet_addr_match_rta(&filter.pfx, rta_tb[IFA_LOCAL]))
                return 0;
 
@@ -1882,25 +1616,14 @@ static void ipaddr_filter(struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo)
 
                        if ((filter.flags ^ ifa_flags) & filter.flagmask)
                                continue;
-                       if (filter.pfx.family || filter.label) {
-                               struct rtattr *rta =
-                                       tb[IFA_LOCAL] ? : tb[IFA_ADDRESS];
-
-                               if (inet_addr_match_rta(&filter.pfx, rta))
-                                       continue;
-
-                               if (filter.label) {
-                                       SPRINT_BUF(b1);
-                                       const char *label;
-
-                                       if (tb[IFA_LABEL])
-                                               label = RTA_DATA(tb[IFA_LABEL]);
-                                       else
-                                               label = ll_idx_n2a(ifa->ifa_index, b1);
-                                       if (fnmatch(filter.label, label, 0) != 0)
-                                               continue;
-                               }
-                       }
+
+                       if (ifa_label_match_rta(ifa->ifa_index, tb[IFA_LABEL]))
+                               continue;
+
+                       if (!tb[IFA_LOCAL])
+                               tb[IFA_LOCAL] = tb[IFA_ADDRESS];
+                       if (inet_addr_match_rta(&filter.pfx, tb[IFA_LOCAL]))
+                               continue;
 
                        ok = 1;
                        break;
@@ -2192,25 +1915,17 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
                ipaddr_filter(&linfo, ainfo);
 
        for (l = linfo.head; l; l = l->next) {
+               struct nlmsghdr *n = &l->h;
+               struct ifinfomsg *ifi = NLMSG_DATA(n);
                int res = 0;
-               struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
 
                open_json_object(NULL);
-               if (brief) {
-                       if (print_linkinfo_brief(NULL, &l->h,
-                                                stdout, NULL) == 0)
-                               if (filter.family != AF_PACKET)
-                                       print_selected_addrinfo(ifi,
-                                                               ainfo->head,
-                                                               stdout);
-               } else if (no_link ||
-                          (res = print_linkinfo(NULL, &l->h, stdout)) >= 0) {
-                       if (filter.family != AF_PACKET)
-                               print_selected_addrinfo(ifi,
-                                                       ainfo->head, stdout);
-                       if (res > 0 && !do_link && show_stats)
-                               print_link_stats(stdout, &l->h);
-               }
+               if (brief || !no_link)
+                       res = print_linkinfo(NULL, n, stdout);
+               if (res >= 0 && filter.family != AF_PACKET)
+                       print_selected_addrinfo(ifi, ainfo->head, stdout);
+               if (res > 0 && !do_link && show_stats)
+                       print_link_stats(stdout, n);
                close_json_object();
        }
        fflush(stdout);
@@ -2496,10 +2211,9 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
        if (!scoped && cmd != RTM_DELADDR)
                req.ifa.ifa_scope = default_scope(&lcl);
 
-       if ((req.ifa.ifa_index = ll_name_to_index(d)) == 0) {
-               fprintf(stderr, "Cannot find device \"%s\"\n", d);
-               return -1;
-       }
+       req.ifa.ifa_index = ll_name_to_index(d);
+       if (!req.ifa.ifa_index)
+               return nodev(d);
 
        if (valid_lftp || preferred_lftp) {
                struct ifa_cacheinfo cinfo = {};
index 7200bf542929caa359c879e46c0fe44778166738..2f79c56dcead29e41c8bff2dbf9e977c779083cc 100644 (file)
@@ -38,6 +38,7 @@
 #include "rt_names.h"
 #include "utils.h"
 #include "ip_common.h"
+#include "json_print.h"
 
 #define IFAL_RTA(r)    ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrlblmsg))))
 #define IFAL_PAYLOAD(n)        NLMSG_PAYLOAD(n, sizeof(struct ifaddrlblmsg))
@@ -55,7 +56,6 @@ static void usage(void)
 
 int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
-       FILE *fp = (FILE *)arg;
        struct ifaddrlblmsg *ifal = NLMSG_DATA(n);
        int len = n->nlmsg_len;
        struct rtattr *tb[IFAL_MAX+1];
@@ -69,28 +69,40 @@ int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg
 
        parse_rtattr(tb, IFAL_MAX, IFAL_RTA(ifal), len);
 
+       open_json_object(NULL);
        if (n->nlmsg_type == RTM_DELADDRLABEL)
-               fprintf(fp, "Deleted ");
+               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 
        if (tb[IFAL_ADDRESS]) {
-               fprintf(fp, "prefix %s/%u ",
-                       format_host_rta(ifal->ifal_family,
-                                       tb[IFAL_ADDRESS]),
-                       ifal->ifal_prefixlen);
+               const char *host
+                       = format_host_rta(ifal->ifal_family,
+                                         tb[IFAL_ADDRESS]);
+
+               print_string(PRINT_FP, NULL, "prefix ", NULL);
+               print_color_string(PRINT_ANY,
+                                  ifa_family_color(ifal->ifal_family),
+                                  "address", "%s", host);
+
+               print_uint(PRINT_ANY, "prefixlen", "/%u ",
+                          ifal->ifal_prefixlen);
        }
 
-       if (ifal->ifal_index)
-               fprintf(fp, "dev %s ", ll_index_to_name(ifal->ifal_index));
+       if (ifal->ifal_index) {
+               print_string(PRINT_FP, NULL, "dev ", NULL);
+               print_color_string(PRINT_ANY, COLOR_IFNAME,
+                                  "ifname", "%s ",
+                                  ll_index_to_name(ifal->ifal_index));
+       }
 
        if (tb[IFAL_LABEL] && RTA_PAYLOAD(tb[IFAL_LABEL]) == sizeof(uint32_t)) {
-               uint32_t label;
+               uint32_t label = rta_getattr_u32(RTA_DATA(tb[IFAL_LABEL]));
 
-               memcpy(&label, RTA_DATA(tb[IFAL_LABEL]), sizeof(label));
-               fprintf(fp, "label %u ", label);
+               print_uint(PRINT_ANY,
+                          "label", "label %u ", label);
        }
+       print_string(PRINT_FP, NULL, "\n", "");
+       close_json_object();
 
-       fprintf(fp, "\n");
-       fflush(fp);
        return 0;
 }
 
@@ -111,10 +123,12 @@ static int ipaddrlabel_list(int argc, char **argv)
                return 1;
        }
 
+       new_json_obj(json);
        if (rtnl_dump_filter(&rth, print_addrlabel, stdout) < 0) {
                fprintf(stderr, "Dump terminated\n");
                return 1;
        }
+       delete_json_obj();
 
        return 0;
 }
index 1f392adea29d5c3894e269f0d4138a629818c5c2..0cb5e3c7a0c7c8504286320a3df312ad9c6578bb 100644 (file)
 #include "libgenl.h"
 #include "utils.h"
 #include "ip_common.h"
+#include "json_print.h"
 
 static void usage(void)
 {
-       fprintf(stderr, "Usage: ip fou add port PORT "
-               "{ ipproto PROTO  | gue } [ -6 ]\n");
-       fprintf(stderr, "       ip fou del port PORT [ -6 ]\n");
-       fprintf(stderr, "       ip fou show\n");
-       fprintf(stderr, "\n");
-       fprintf(stderr, "Where: PROTO { ipproto-name | 1..255 }\n");
-       fprintf(stderr, "       PORT { 1..65535 }\n");
+       fprintf(stderr,
+               "Usage: ip fou add port PORT { ipproto PROTO  | gue } [ -6 ]\n"
+               "       ip fou del port PORT [ -6 ]\n"
+               "       ip fou show\n"
+               "\n"
+               "Where: PROTO { ipproto-name | 1..255 }\n"
+               "       PORT { 1..65535 }\n");
 
        exit(-1);
 }
@@ -77,7 +78,8 @@ static int fou_parse_opt(int argc, char **argv, struct nlmsghdr *n,
                } else if (!matches(*argv, "-6")) {
                        family = AF_INET6;
                } else {
-                       fprintf(stderr, "fou: unknown command \"%s\"?\n", *argv);
+                       fprintf(stderr
+                               , "fou: unknown command \"%s\"?\n", *argv);
                        usage();
                        return -1;
                }
@@ -138,11 +140,9 @@ static int do_del(int argc, char **argv)
 static int print_fou_mapping(const struct sockaddr_nl *who,
                                 struct nlmsghdr *n, void *arg)
 {
-       FILE *fp = (FILE *)arg;
        struct genlmsghdr *ghdr;
        struct rtattr *tb[FOU_ATTR_MAX + 1];
        int len = n->nlmsg_len;
-       unsigned family;
 
        if (n->nlmsg_type != genl_family)
                return 0;
@@ -154,18 +154,30 @@ static int print_fou_mapping(const struct sockaddr_nl *who,
        ghdr = NLMSG_DATA(n);
        parse_rtattr(tb, FOU_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len);
 
+       open_json_object(NULL);
        if (tb[FOU_ATTR_PORT])
-               fprintf(fp, "port %u", ntohs(rta_getattr_u16(tb[FOU_ATTR_PORT])));
-       if (tb[FOU_ATTR_TYPE] && rta_getattr_u8(tb[FOU_ATTR_TYPE]) == FOU_ENCAP_GUE)
-               fprintf(fp, " gue");
+               print_uint(PRINT_ANY, "port", "port %u",
+                          ntohs(rta_getattr_u16(tb[FOU_ATTR_PORT])));
+
+       if (tb[FOU_ATTR_TYPE] &&
+           rta_getattr_u8(tb[FOU_ATTR_TYPE]) == FOU_ENCAP_GUE)
+               print_null(PRINT_ANY, "gue", " gue", NULL);
        else if (tb[FOU_ATTR_IPPROTO])
-               fprintf(fp, " ipproto %u", rta_getattr_u8(tb[FOU_ATTR_IPPROTO]));
+               print_uint(PRINT_ANY, "ipproto",
+                          " ipproto %u", rta_getattr_u8(tb[FOU_ATTR_IPPROTO]));
+
        if (tb[FOU_ATTR_AF]) {
-               family = rta_getattr_u8(tb[FOU_ATTR_AF]);
+               __u8 family = rta_getattr_u8(tb[FOU_ATTR_AF]);
+
+               print_string(PRINT_JSON, "family", NULL,
+                            family_name(family));
+
                if (family == AF_INET6)
-                       fprintf(fp, " -6");
+                       print_string(PRINT_FP, NULL,
+                                    " -6", NULL);
        }
-       fprintf(fp, "\n");
+       print_string(PRINT_FP, NULL, "\n", NULL);
+       close_json_object();
 
        return 0;
 }
@@ -175,7 +187,8 @@ static int do_show(int argc, char **argv)
        FOU_REQUEST(req, 4096, FOU_CMD_GET, NLM_F_REQUEST | NLM_F_DUMP);
 
        if (argc > 0) {
-               fprintf(stderr, "\"ip fou show\" does not take any arguments.\n");
+               fprintf(stderr,
+                       "\"ip fou show\" does not take any arguments.\n");
                return -1;
        }
 
@@ -184,10 +197,13 @@ static int do_show(int argc, char **argv)
                exit(1);
        }
 
+       new_json_obj(json);
        if (rtnl_dump_filter(&genl_rth, print_fou_mapping, stdout) < 0) {
                fprintf(stderr, "Dump terminated\n");
                return 1;
        }
+       delete_json_obj();
+       fflush(stdout);
 
        return 0;
 }
@@ -209,6 +225,8 @@ int do_ipfou(int argc, char **argv)
                return do_del(argc-1, argv+1);
        if (matches(*argv, "show") == 0)
                return do_show(argc-1, argv+1);
-       fprintf(stderr, "Command \"%s\" is unknown, try \"ip fou help\".\n", *argv);
+
+       fprintf(stderr,
+               "Command \"%s\" is unknown, try \"ip fou help\".\n", *argv);
        exit(-1);
 }
index d401311bcad9f2db4f4e867abb448c1455f1a44d..29b7062f6aa4b2a86e8106b9781069ad2c221ecc 100644 (file)
@@ -31,7 +31,6 @@
 #include "rt_names.h"
 #include "utils.h"
 #include "ip_common.h"
-#include "xdp.h"
 #include "namespace.h"
 
 #define IPLINK_IOCTL_COMPAT    1
@@ -571,10 +570,11 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
        return 0;
 }
 
-int iplink_parse(int argc, char **argv, struct iplink_req *req,
-                char **name, char **type, char **link, char **dev,
-                int *group, int *index)
+int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
 {
+       char *name = NULL;
+       char *dev = NULL;
+       char *link = NULL;
        int ret, len;
        char abuf[32];
        int qlen = -1;
@@ -585,9 +585,10 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
        int numrxqueues = -1;
        int dev_index = 0;
        int link_netnsid = -1;
+       int index = 0;
+       int group = -1;
        int addr_len = 0;
 
-       *group = -1;
        ret = argc;
 
        while (argc > 0) {
@@ -599,19 +600,25 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                        req->i.ifi_flags &= ~IFF_UP;
                } else if (strcmp(*argv, "name") == 0) {
                        NEXT_ARG();
+                       if (name)
+                               duparg("name", *argv);
                        if (check_ifname(*argv))
                                invarg("\"name\" not a valid ifname", *argv);
-                       *name = *argv;
+                       name = *argv;
+                       if (!dev) {
+                               dev = name;
+                               dev_index = ll_name_to_index(dev);
+                       }
                } else if (strcmp(*argv, "index") == 0) {
                        NEXT_ARG();
-                       if (*index)
+                       if (index)
                                duparg("index", *argv);
-                       *index = atoi(*argv);
-                       if (*index <= 0)
+                       index = atoi(*argv);
+                       if (index <= 0)
                                invarg("Invalid \"index\" value", *argv);
                } else if (matches(*argv, "link") == 0) {
                        NEXT_ARG();
-                       *link = *argv;
+                       link = *argv;
                } else if (matches(*argv, "address") == 0) {
                        NEXT_ARG();
                        addr_len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
@@ -656,6 +663,9 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                        if (xdp_parse(&argc, &argv, req, dev_index,
                                      generic, drv, offload))
                                exit(-1);
+
+                       if (offload && name == dev)
+                               dev = NULL;
                } else if (strcmp(*argv, "netns") == 0) {
                        NEXT_ARG();
                        if (netns != -1)
@@ -747,6 +757,9 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                        if (len < 0)
                                return -1;
                        addattr_nest_end(&req->n, vflist);
+
+                       if (name == dev)
+                               dev = NULL;
                } else if (matches(*argv, "master") == 0) {
                        int ifindex;
 
@@ -796,10 +809,11 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                                  *argv, len);
                } else if (strcmp(*argv, "group") == 0) {
                        NEXT_ARG();
-                       if (*group != -1)
+                       if (group != -1)
                                duparg("group", *argv);
-                       if (rtnl_group_a2n(group, *argv))
+                       if (rtnl_group_a2n(&group, *argv))
                                invarg("Invalid \"group\" value\n", *argv);
+                       addattr32(&req->n, sizeof(*req), IFLA_GROUP, group);
                } else if (strcmp(*argv, "mode") == 0) {
                        int mode;
 
@@ -897,16 +911,26 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
 
                        if (strcmp(*argv, "dev") == 0)
                                NEXT_ARG();
-                       if (*dev)
+                       if (dev != name)
                                duparg2("dev", *argv);
                        if (check_ifname(*argv))
                                invarg("\"dev\" not a valid ifname", *argv);
-                       *dev = *argv;
-                       dev_index = ll_name_to_index(*dev);
+                       dev = *argv;
+                       dev_index = ll_name_to_index(dev);
                }
                argc--; argv++;
        }
 
+       ret -= argc;
+
+       /* Allow "ip link add dev" and "ip link add name" */
+       if (!name)
+               name = dev;
+       else if (!dev)
+               dev = name;
+       else if (!strcmp(name, dev))
+               name = dev;
+
        if (dev_index && addr_len) {
                int halen = nl_get_ll_addr_len(dev_index);
 
@@ -918,101 +942,89 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                }
        }
 
-       return ret - argc;
-}
-
-static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
-{
-       char *dev = NULL;
-       char *name = NULL;
-       char *link = NULL;
-       char *type = NULL;
-       int index = 0;
-       int group;
-       struct link_util *lu = NULL;
-       struct iplink_req req = {
-               .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
-               .n.nlmsg_flags = NLM_F_REQUEST | flags,
-               .n.nlmsg_type = cmd,
-               .i.ifi_family = preferred_family,
-       };
-       int ret;
-
-       ret = iplink_parse(argc, argv,
-                          &req, &name, &type, &link, &dev, &group, &index);
-       if (ret < 0)
-               return ret;
-
-       argc -= ret;
-       argv += ret;
+       if (!(req->n.nlmsg_flags & NLM_F_CREATE) && index) {
+               fprintf(stderr,
+                       "index can be used only when creating devices.\n");
+               exit(-1);
+       }
 
        if (group != -1) {
-               if (dev)
-                       addattr_l(&req.n, sizeof(req), IFLA_GROUP,
-                                       &group, sizeof(group));
-               else {
+               if (!dev) {
                        if (argc) {
                                fprintf(stderr,
                                        "Garbage instead of arguments \"%s ...\". Try \"ip link help\".\n",
                                        *argv);
-                               return -1;
+                               exit(-1);
                        }
-                       if (flags & NLM_F_CREATE) {
+                       if (req->n.nlmsg_flags & NLM_F_CREATE) {
                                fprintf(stderr,
                                        "group cannot be used when creating devices.\n");
-                               return -1;
+                               exit(-1);
                        }
 
-                       addattr32(&req.n, sizeof(req), IFLA_GROUP, group);
-                       if (rtnl_talk(&rth, &req.n, NULL) < 0)
-                               return -2;
-                       return 0;
+                       *type = NULL;
+                       return ret;
                }
        }
 
-       if (!(flags & NLM_F_CREATE)) {
+       if (!(req->n.nlmsg_flags & NLM_F_CREATE)) {
                if (!dev) {
                        fprintf(stderr,
                                "Not enough information: \"dev\" argument is required.\n");
                        exit(-1);
                }
-               if (cmd == RTM_NEWLINK && index) {
+
+               req->i.ifi_index = ll_name_to_index(dev);
+               if (!req->i.ifi_index)
+                       return nodev(dev);
+
+               /* Not renaming to the same name */
+               if (name == dev)
+                       name = NULL;
+       } else {
+               if (name != dev) {
                        fprintf(stderr,
-                               "index can be used only when creating devices.\n");
+                               "both \"name\" and \"dev\" cannot be used when creating devices.\n");
                        exit(-1);
                }
 
-               req.i.ifi_index = ll_name_to_index(dev);
-               if (req.i.ifi_index == 0) {
-                       fprintf(stderr, "Cannot find device \"%s\"\n", dev);
-                       return -1;
-               }
-       } else {
-               /* Allow "ip link add dev" and "ip link add name" */
-               if (!name)
-                       name = dev;
-
                if (link) {
                        int ifindex;
 
                        ifindex = ll_name_to_index(link);
-                       if (ifindex == 0) {
-                               fprintf(stderr, "Cannot find device \"%s\"\n",
-                                       link);
-                               return -1;
-                       }
-                       addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
+                       if (!ifindex)
+                               return nodev(link);
+                       addattr32(&req->n, sizeof(*req), IFLA_LINK, ifindex);
                }
 
-               req.i.ifi_index = index;
+               req->i.ifi_index = index;
        }
 
        if (name) {
-               addattr_l(&req.n, sizeof(req),
+               addattr_l(&req->n, sizeof(*req),
                          IFLA_IFNAME, name, strlen(name) + 1);
        }
 
+       return ret;
+}
+
+static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
+{
+       char *type = NULL;
+       struct iplink_req req = {
+               .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+               .n.nlmsg_flags = NLM_F_REQUEST | flags,
+               .n.nlmsg_type = cmd,
+               .i.ifi_family = preferred_family,
+       };
+       int ret;
+
+       ret = iplink_parse(argc, argv, &req, &type);
+       if (ret < 0)
+               return ret;
+
        if (type) {
+               struct link_util *lu;
                struct rtattr *linkinfo;
                char *ulinep = strchr(type, '_');
                int iflatype;
@@ -1026,10 +1038,14 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
                        iflatype = IFLA_INFO_SLAVE_DATA;
                else
                        iflatype = IFLA_INFO_DATA;
+
+               argc -= ret;
+               argv += ret;
+
                if (lu && argc) {
-                       struct rtattr *data
-                               = addattr_nest(&req.n,
-                                              sizeof(req), iflatype);
+                       struct rtattr *data;
+
+                       data = addattr_nest(&req.n, sizeof(req), iflatype);
 
                        if (lu->parse_opt &&
                            lu->parse_opt(lu, argc, argv, &req.n))
@@ -1077,10 +1093,7 @@ int iplink_get(unsigned int flags, char *name, __u32 filt_mask)
                return -2;
 
        open_json_object(NULL);
-       if (brief)
-               print_linkinfo_brief(NULL, answer, stdout, NULL);
-       else
-               print_linkinfo(NULL, answer, stdout);
+       print_linkinfo(NULL, answer, stdout);
        close_json_object();
 
        free(answer);
index 8e8723a99fff5206c53ff35d6b843e76ff1ae24e..f906e7f1b323239f63162748dbc34b77ef44fbfd 100644 (file)
@@ -179,7 +179,7 @@ static int bond_parse_opt(struct link_util *lu, int argc, char **argv,
                        NEXT_ARG();
                        ifindex = ll_name_to_index(*argv);
                        if (!ifindex)
-                               return -1;
+                               return nodev(*argv);
                        addattr32(n, 1024, IFLA_BOND_ACTIVE_SLAVE, ifindex);
                } else if (matches(*argv, "clear_active_slave") == 0) {
                        addattr32(n, 1024, IFLA_BOND_ACTIVE_SLAVE, 0);
@@ -242,7 +242,7 @@ static int bond_parse_opt(struct link_util *lu, int argc, char **argv,
                        NEXT_ARG();
                        ifindex = ll_name_to_index(*argv);
                        if (!ifindex)
-                               return -1;
+                               return nodev(*argv);
                        addattr32(n, 1024, IFLA_BOND_PRIMARY, ifindex);
                } else if (matches(*argv, "primary_reselect") == 0) {
                        NEXT_ARG();
index 06ec092f1ae456fd7e8458821ed7a84fb3721cce..3008e44b7d72537913e4970fc8e9cbca3faf16c8 100644 (file)
@@ -793,11 +793,8 @@ int bridge_parse_xstats(struct link_util *lu, int argc, char **argv)
                } else if (strcmp(*argv, "dev") == 0) {
                        NEXT_ARG();
                        filter_index = ll_name_to_index(*argv);
-                       if (filter_index == 0) {
-                               fprintf(stderr, "Cannot find device \"%s\"\n",
-                                       *argv);
-                               return -1;
-                       }
+                       if (!filter_index)
+                               return nodev(*argv);
                } else if (strcmp(*argv, "help") == 0) {
                        bridge_print_xstats_help(lu, stdout);
                        exit(0);
index be0fb4fa34b701f255a307ea88e0aa4bbd5f338d..3fbfb878cdc4f40ed952d573acc7d41d3e79242d 100644 (file)
@@ -81,21 +81,6 @@ static void _print_onoff(FILE *f, char *json_flag, char *flag, __u8 val)
                fprintf(f, "%s %s ", flag, val ? "on" : "off");
 }
 
-static void _print_hex(FILE *f,
-                      const char *json_attr,
-                      const char *attr,
-                      __u16 val)
-{
-       if (is_json_context()) {
-               SPRINT_BUF(b1);
-
-               snprintf(b1, sizeof(b1), "0x%x", val);
-               print_string(PRINT_JSON, json_attr, NULL, b1);
-       } else {
-               fprintf(f, "%s 0x%x ", attr, val);
-       }
-}
-
 static void _print_timer(FILE *f, const char *attr, struct rtattr *timer)
 {
        struct timeval tv;
@@ -181,11 +166,11 @@ static void bridge_slave_print_opt(struct link_util *lu, FILE *f,
                             rta_getattr_u8(tb[IFLA_BRPORT_UNICAST_FLOOD]));
 
        if (tb[IFLA_BRPORT_ID])
-               _print_hex(f, "id", "port_id",
-                          rta_getattr_u16(tb[IFLA_BRPORT_ID]));
+               print_0xhex(PRINT_ANY, "id", "port_id 0x%x ",
+                           rta_getattr_u16(tb[IFLA_BRPORT_ID]));
 
        if (tb[IFLA_BRPORT_NO])
-               _print_hex(f, "no", "port_no",
+               print_0xhex(PRINT_ANY, "no", "port_no 0x%x ",
                           rta_getattr_u16(tb[IFLA_BRPORT_NO]));
 
        if (tb[IFLA_BRPORT_DESIGNATED_PORT])
@@ -279,7 +264,8 @@ static void bridge_slave_print_opt(struct link_util *lu, FILE *f,
                __u16 fwd_mask;
 
                fwd_mask = rta_getattr_u16(tb[IFLA_BRPORT_GROUP_FWD_MASK]);
-               _print_hex(f, "group_fwd_mask", "group_fwd_mask", fwd_mask);
+               print_0xhex(PRINT_ANY, "group_fwd_mask",
+                           "group_fwd_mask 0x%x ", fwd_mask);
                _bitmask2str(fwd_mask, convbuf, sizeof(convbuf), fwd_mask_tbl);
                print_string(PRINT_ANY, "group_fwd_mask_str",
                             "group_fwd_mask_str %s ", convbuf);
index c66607267f7d1c618d3e2dd184c64792f9e40a2e..1fcdd83acca92e9df8b4859f04977da2d9a918ed 100644 (file)
@@ -71,7 +71,7 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv,
        bool set_op = (n->nlmsg_type == RTM_NEWLINK &&
                       !(n->nlmsg_flags & NLM_F_CREATE));
 
-       daddr.flags = 0;
+       inet_prefix_reset(&daddr);
 
        while (argc > 0) {
                if (!matches(*argv, "id") ||
index 4d78cf9e4b3a9fe4ed6b27b5e1621f241c9db877..74f4614a2193129fb46a46e7cb3349e99c4d14bb 100644 (file)
@@ -56,8 +56,7 @@ static int vlan_parse_qos_map(int *argcp, char ***argvp, struct nlmsghdr *n,
        struct ifla_vlan_qos_mapping m;
        struct rtattr *tail;
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, attrtype, NULL, 0);
+       tail = addattr_nest(n, 1024, attrtype);
 
        while (argc > 0) {
                char *colon = strchr(*argv, ':');
@@ -75,7 +74,7 @@ static int vlan_parse_qos_map(int *argcp, char ***argvp, struct nlmsghdr *n,
                addattr_l(n, 1024, IFLA_VLAN_QOS_MAPPING, &m, sizeof(m));
        }
 
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *)tail;
+       addattr_nest_end(n, tail);
 
        *argcp = argc;
        *argvp = argv;
index ed0ad8b98ce87d1b0f8635c0909db02662634b67..8b08c9a70c65169734c3037efd6c3ca5ae3bb5f9 100644 (file)
@@ -31,59 +31,47 @@ static void usage(void)
 }
 
 static int vxcan_parse_opt(struct link_util *lu, int argc, char **argv,
-                         struct nlmsghdr *hdr)
+                         struct nlmsghdr *n)
 {
-       char *dev = NULL;
-       char *name = NULL;
-       char *link = NULL;
        char *type = NULL;
-       int index = 0;
        int err;
        struct rtattr *data;
-       int group;
        struct ifinfomsg *ifm, *peer_ifm;
-       unsigned int ifi_flags, ifi_change;
+       unsigned int ifi_flags, ifi_change, ifi_index;
 
        if (strcmp(argv[0], "peer") != 0) {
                usage();
                return -1;
        }
 
-       ifm = NLMSG_DATA(hdr);
+       ifm = NLMSG_DATA(n);
        ifi_flags = ifm->ifi_flags;
        ifi_change = ifm->ifi_change;
+       ifi_index = ifm->ifi_index;
        ifm->ifi_flags = 0;
        ifm->ifi_change = 0;
+       ifm->ifi_index = 0;
 
-       data = NLMSG_TAIL(hdr);
-       addattr_l(hdr, 1024, VXCAN_INFO_PEER, NULL, 0);
+       data = addattr_nest(n, 1024, VXCAN_INFO_PEER);
 
-       hdr->nlmsg_len += sizeof(struct ifinfomsg);
+       n->nlmsg_len += sizeof(struct ifinfomsg);
 
-       err = iplink_parse(argc - 1, argv + 1, (struct iplink_req *)hdr,
-                          &name, &type, &link, &dev, &group, &index);
+       err = iplink_parse(argc - 1, argv + 1, (struct iplink_req *)n, &type);
        if (err < 0)
                return err;
 
        if (type)
                duparg("type", argv[err]);
 
-       if (name) {
-               addattr_l(hdr, 1024,
-                         IFLA_IFNAME, name, strlen(name) + 1);
-       }
-
        peer_ifm = RTA_DATA(data);
-       peer_ifm->ifi_index = index;
+       peer_ifm->ifi_index = ifm->ifi_index;
        peer_ifm->ifi_flags = ifm->ifi_flags;
        peer_ifm->ifi_change = ifm->ifi_change;
        ifm->ifi_flags = ifi_flags;
        ifm->ifi_change = ifi_change;
+       ifm->ifi_index = ifi_index;
 
-       if (group != -1)
-               addattr32(hdr, 1024, IFLA_GROUP, group);
-
-       data->rta_len = (void *)NLMSG_TAIL(hdr) - (void *)data;
+       addattr_nest_end(n, data);
        return argc - 1 - err;
 }
 
index 00875ba73cb4066e45af60f915c384714eeeba71..be9f35e4d9c6bc1721c5d9654a8cf56956eba175 100644 (file)
@@ -74,8 +74,7 @@ static void check_duparg(__u64 *attrs, int type, const char *key,
 static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
                          struct nlmsghdr *n)
 {
-       inet_prefix saddr;
-       inet_prefix daddr;
+       inet_prefix saddr, daddr;
        __u32 vni = 0;
        __u8 learning = 1;
        __u16 dstport = 0;
@@ -85,7 +84,9 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
                       !(n->nlmsg_flags & NLM_F_CREATE));
 
        saddr.family = daddr.family = AF_UNSPEC;
-       saddr.flags = daddr.flags = 0;
+
+       inet_prefix_reset(&saddr);
+       inet_prefix_reset(&daddr);
 
        while (argc > 0) {
                if (!matches(*argv, "id") ||
@@ -132,11 +133,8 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
                        NEXT_ARG();
                        check_duparg(&attrs, IFLA_VXLAN_LINK, "dev", *argv);
                        link = ll_name_to_index(*argv);
-                       if (link == 0) {
-                               fprintf(stderr, "Cannot find device \"%s\"\n",
-                                       *argv);
-                               exit(-1);
-                       }
+                       if (!link)
+                               exit(nodev(*argv));
                        addattr32(n, 1024, IFLA_VXLAN_LINK, link);
                } else if (!matches(*argv, "ttl") ||
                           !matches(*argv, "hoplimit")) {
index 6eeb820af0c34fed6267bfb2c6e33b9c59b28d2e..83826358aa227a5563ecf859d2bd61f5d79ea12b 100644 (file)
@@ -14,9 +14,9 @@
 
 #include <linux/bpf.h>
 
-#include "json_print.h"
-#include "xdp.h"
 #include "bpf_util.h"
+#include "utils.h"
+#include "ip_common.h"
 
 extern int force;
 
index 345a7073c76b69e6721cc429a8725fe7100e2112..38ec7136e55599e679c893f6d43e05f83623d821 100644 (file)
@@ -23,9 +23,9 @@
 #include "ll_map.h"
 #include "libgenl.h"
 
-static const char *values_on_off[] = { "off", "on" };
+static const char * const values_on_off[] = { "off", "on" };
 
-static const char *VALIDATE_STR[] = {
+static const char * const validate_str[] = {
        [MACSEC_VALIDATE_DISABLED] = "disabled",
        [MACSEC_VALIDATE_CHECK] = "check",
        [MACSEC_VALIDATE_STRICT] = "strict",
@@ -81,26 +81,27 @@ static int genl_family = -1;
 
 static void ipmacsec_usage(void)
 {
-       fprintf(stderr, "Usage: ip macsec add DEV tx sa { 0..3 } [ OPTS ] key ID KEY\n");
-       fprintf(stderr, "       ip macsec set DEV tx sa { 0..3 } [ OPTS ]\n");
-       fprintf(stderr, "       ip macsec del DEV tx sa { 0..3 }\n");
-       fprintf(stderr, "       ip macsec add DEV rx SCI [ on | off ]\n");
-       fprintf(stderr, "       ip macsec set DEV rx SCI [ on | off ]\n");
-       fprintf(stderr, "       ip macsec del DEV rx SCI\n");
-       fprintf(stderr, "       ip macsec add DEV rx SCI sa { 0..3 } [ OPTS ] key ID KEY\n");
-       fprintf(stderr, "       ip macsec set DEV rx SCI sa { 0..3 } [ OPTS ]\n");
-       fprintf(stderr, "       ip macsec del DEV rx SCI sa { 0..3 }\n");
-       fprintf(stderr, "       ip macsec show\n");
-       fprintf(stderr, "       ip macsec show DEV\n");
-       fprintf(stderr, "where  OPTS := [ pn <u32> ] [ on | off ]\n");
-       fprintf(stderr, "       ID   := 128-bit hex string\n");
-       fprintf(stderr, "       KEY  := 128-bit hex string\n");
-       fprintf(stderr, "       SCI  := { sci <u64> | port { 1..2^16-1 } address <lladdr> }\n");
+       fprintf(stderr,
+               "Usage: ip macsec add DEV tx sa { 0..3 } [ OPTS ] key ID KEY\n"
+               "       ip macsec set DEV tx sa { 0..3 } [ OPTS ]\n"
+               "       ip macsec del DEV tx sa { 0..3 }\n"
+               "       ip macsec add DEV rx SCI [ on | off ]\n"
+               "       ip macsec set DEV rx SCI [ on | off ]\n"
+               "       ip macsec del DEV rx SCI\n"
+               "       ip macsec add DEV rx SCI sa { 0..3 } [ OPTS ] key ID KEY\n"
+               "       ip macsec set DEV rx SCI sa { 0..3 } [ OPTS ]\n"
+               "       ip macsec del DEV rx SCI sa { 0..3 }\n"
+               "       ip macsec show\n"
+               "       ip macsec show DEV\n"
+               "where  OPTS := [ pn <u32> ] [ on | off ]\n"
+               "       ID   := 128-bit hex string\n"
+               "       KEY  := 128-bit hex string\n"
+               "       SCI  := { sci <u64> | port { 1..2^16-1 } address <lladdr> }\n");
 
        exit(-1);
 }
 
-static int one_of(const char *msg, const char *realval, const char **list,
+static int one_of(const char *msg, const char *realval, const char * const *list,
                  size_t len, int *index)
 {
        int i;
@@ -558,19 +559,33 @@ static int validate_secy_dump(struct rtattr **attrs)
               attrs[MACSEC_SECY_ATTR_SCB];
 }
 
-static void print_flag(FILE *f, struct rtattr *attrs[], const char *desc,
+static void print_flag(struct rtattr *attrs[], const char *desc,
                       int field)
 {
-       if (attrs[field]) {
-               const char *v = values_on_off[!!rta_getattr_u8(attrs[field])];
+       __u8 flag;
 
-               if (is_json_context())
-                       print_string(PRINT_JSON, desc, NULL, v);
-               else
-                       fprintf(f, "%s %s ", desc, v);
+       if (!attrs[field])
+               return;
+
+       flag = rta_getattr_u8(attrs[field]);
+       if (is_json_context())
+               print_bool(PRINT_JSON, desc, NULL, flag);
+       else {
+               print_string(PRINT_FP, NULL, "%s ", desc);
+               print_string(PRINT_FP, NULL, "%s ",
+                            flag ? "on" : "off");
        }
 }
 
+static void print_key(struct rtattr *key)
+{
+       SPRINT_BUF(keyid);
+
+       print_string(PRINT_ANY, "key", " key %s\n",
+                    hexstring_n2a(RTA_DATA(key), RTA_PAYLOAD(key),
+                                  keyid, sizeof(keyid)));
+}
+
 #define DEFAULT_CIPHER_NAME "GCM-AES-128"
 
 static const char *cs_id_to_name(__u64 cid)
@@ -584,58 +599,118 @@ static const char *cs_id_to_name(__u64 cid)
        }
 }
 
-static void print_cipher_suite(const char *prefix, __u64 cid, __u8 icv_len)
-{
-       printf("%scipher suite: %s, using ICV length %d\n", prefix,
-              cs_id_to_name(cid), icv_len);
-}
-
-static void print_attrs(const char *prefix, struct rtattr *attrs[])
+static void print_attrs(struct rtattr *attrs[])
 {
-       print_flag(stdout, attrs, "protect", MACSEC_SECY_ATTR_PROTECT);
+       print_flag(attrs, "protect", MACSEC_SECY_ATTR_PROTECT);
 
        if (attrs[MACSEC_SECY_ATTR_VALIDATE]) {
                __u8 val = rta_getattr_u8(attrs[MACSEC_SECY_ATTR_VALIDATE]);
 
-               printf("validate %s ", VALIDATE_STR[val]);
+               print_string(PRINT_ANY, "validate",
+                            "validate %s ", validate_str[val]);
        }
 
-       print_flag(stdout, attrs, "sc", MACSEC_RXSC_ATTR_ACTIVE);
-       print_flag(stdout, attrs, "sa", MACSEC_SA_ATTR_ACTIVE);
-       print_flag(stdout, attrs, "encrypt", MACSEC_SECY_ATTR_ENCRYPT);
-       print_flag(stdout, attrs, "send_sci", MACSEC_SECY_ATTR_INC_SCI);
-       print_flag(stdout, attrs, "end_station", MACSEC_SECY_ATTR_ES);
-       print_flag(stdout, attrs, "scb", MACSEC_SECY_ATTR_SCB);
+       print_flag(attrs, "sc", MACSEC_RXSC_ATTR_ACTIVE);
+       print_flag(attrs, "sa", MACSEC_SA_ATTR_ACTIVE);
+       print_flag(attrs, "encrypt", MACSEC_SECY_ATTR_ENCRYPT);
+       print_flag(attrs, "send_sci", MACSEC_SECY_ATTR_INC_SCI);
+       print_flag(attrs, "end_station", MACSEC_SECY_ATTR_ES);
+       print_flag(attrs, "scb", MACSEC_SECY_ATTR_SCB);
+       print_flag(attrs, "replay", MACSEC_SECY_ATTR_REPLAY);
 
-       print_flag(stdout, attrs, "replay", MACSEC_SECY_ATTR_REPLAY);
        if (attrs[MACSEC_SECY_ATTR_WINDOW]) {
-               printf("window %d ",
-                      rta_getattr_u32(attrs[MACSEC_SECY_ATTR_WINDOW]));
+               __u32 win = rta_getattr_u32(attrs[MACSEC_SECY_ATTR_WINDOW]);
+
+               print_uint(PRINT_ANY, "window", "window %u ", win);
        }
 
-       if (attrs[MACSEC_SECY_ATTR_CIPHER_SUITE] &&
-           attrs[MACSEC_SECY_ATTR_ICV_LEN]) {
-               printf("\n");
-               print_cipher_suite(prefix,
-                       rta_getattr_u64(attrs[MACSEC_SECY_ATTR_CIPHER_SUITE]),
-                       rta_getattr_u8(attrs[MACSEC_SECY_ATTR_ICV_LEN]));
+       if (attrs[MACSEC_SECY_ATTR_CIPHER_SUITE]) {
+               __u64 cid = rta_getattr_u64(attrs[MACSEC_SECY_ATTR_CIPHER_SUITE]);
+
+               print_string(PRINT_FP, NULL, "%s", _SL_);
+               print_string(PRINT_ANY, "cipher_suite",
+                            "    cipher suite: %s,", cs_id_to_name(cid));
        }
 
+       if (attrs[MACSEC_SECY_ATTR_ICV_LEN]) {
+               __u8 icv_len = rta_getattr_u8(attrs[MACSEC_SECY_ATTR_ICV_LEN]);
+
+               print_uint(PRINT_ANY, "icv_length",
+                    " using ICV length %u\n", icv_len);
+       }
 }
 
-static void print_one_stat(const char **names, struct rtattr **attr, int idx,
-                          bool long_stat)
+static __u64 getattr_uint(struct rtattr *stat)
 {
-       int pad = strlen(names[idx]) + 1;
+       switch (RTA_PAYLOAD(stat)) {
+       case sizeof(__u64):
+               return rta_getattr_u64(stat);
+       case sizeof(__u32):
+               return rta_getattr_u32(stat);
+       case sizeof(__u16):
+               return rta_getattr_u16(stat);
+       case sizeof(__u8):
+               return rta_getattr_u8(stat);
+       default:
+               fprintf(stderr, "invalid attribute length %lu\n",
+                       RTA_PAYLOAD(stat));
+               exit(-1);
+       }
+}
+
+static void print_fp_stats(const char *prefix,
+                          const char *names[], unsigned int num,
+                          struct rtattr *stats[])
+{
+       unsigned int i;
+       int pad;
+
+       printf("%sstats:", prefix);
+
+       for (i = 1; i < num; i++) {
+               if (!names[i])
+                       continue;
+               printf(" %s", names[i]);
+       }
 
-       if (attr[idx]) {
-               if (long_stat)
-                       printf("%*llu", pad, rta_getattr_u64(attr[idx]));
+       printf("\n%s      ", prefix);
+
+       for (i = 1; i < num; i++) {
+               if (!names[i])
+                       continue;
+
+               pad = strlen(names[i]) + 1;
+               if (stats[i])
+                       printf("%*llu", pad, getattr_uint(stats[i]));
                else
-                       printf("%*u", pad, rta_getattr_u32(attr[idx]));
-       } else {
-               printf("%*c", pad, '-');
+                       printf("%*c", pad, '-');
        }
+       printf("\n");
+}
+
+static void print_json_stats(const char *names[], unsigned int num,
+                            struct rtattr *stats[])
+{
+       unsigned int i;
+
+       for (i = 1; i < num; i++) {
+               if (!names[i] || !stats[i])
+                       continue;
+
+               print_uint(PRINT_JSON, names[i],
+                          NULL, getattr_uint(stats[i]));
+       }
+}
+
+static void print_stats(const char *prefix,
+                       const char *names[], unsigned int num,
+                       struct rtattr *stats[])
+{
+
+       if (is_json_context())
+               print_json_stats(names, num, stats);
+       else
+               print_fp_stats(prefix, names, num, stats);
 }
 
 static const char *txsc_stats_names[NUM_MACSEC_TXSC_STATS_ATTR] = {
@@ -648,29 +723,14 @@ static const char *txsc_stats_names[NUM_MACSEC_TXSC_STATS_ATTR] = {
 static void print_txsc_stats(const char *prefix, struct rtattr *attr)
 {
        struct rtattr *stats[MACSEC_TXSC_STATS_ATTR_MAX + 1];
-       int i;
 
        if (!attr || show_stats == 0)
                return;
 
        parse_rtattr_nested(stats, MACSEC_TXSC_STATS_ATTR_MAX + 1, attr);
-       printf("%sstats:", prefix);
-
-       for (i = 1; i < NUM_MACSEC_TXSC_STATS_ATTR; i++) {
-               if (!txsc_stats_names[i])
-                       continue;
-               printf(" %s", txsc_stats_names[i]);
-       }
 
-       printf("\n%s      ", prefix);
-
-       for (i = 1; i < NUM_MACSEC_TXSC_STATS_ATTR; i++) {
-               if (!txsc_stats_names[i])
-                       continue;
-               print_one_stat(txsc_stats_names, stats, i, true);
-       }
-
-       printf("\n");
+       print_stats(prefix, txsc_stats_names, NUM_MACSEC_TXSC_STATS_ATTR,
+                   stats);
 }
 
 static const char *secy_stats_names[NUM_MACSEC_SECY_STATS_ATTR] = {
@@ -687,29 +747,14 @@ static const char *secy_stats_names[NUM_MACSEC_SECY_STATS_ATTR] = {
 static void print_secy_stats(const char *prefix, struct rtattr *attr)
 {
        struct rtattr *stats[MACSEC_SECY_STATS_ATTR_MAX + 1];
-       int i;
 
        if (!attr || show_stats == 0)
                return;
 
        parse_rtattr_nested(stats, MACSEC_SECY_STATS_ATTR_MAX + 1, attr);
-       printf("%sstats:", prefix);
 
-       for (i = 1; i < NUM_MACSEC_SECY_STATS_ATTR; i++) {
-               if (!secy_stats_names[i])
-                       continue;
-               printf(" %s", secy_stats_names[i]);
-       }
-
-       printf("\n%s      ", prefix);
-
-       for (i = 1; i < NUM_MACSEC_SECY_STATS_ATTR; i++) {
-               if (!secy_stats_names[i])
-                       continue;
-               print_one_stat(secy_stats_names, stats, i, true);
-       }
-
-       printf("\n");
+       print_stats(prefix, secy_stats_names,
+                   NUM_MACSEC_SECY_STATS_ATTR, stats);
 }
 
 static const char *rxsa_stats_names[NUM_MACSEC_SA_STATS_ATTR] = {
@@ -723,29 +768,13 @@ static const char *rxsa_stats_names[NUM_MACSEC_SA_STATS_ATTR] = {
 static void print_rxsa_stats(const char *prefix, struct rtattr *attr)
 {
        struct rtattr *stats[MACSEC_SA_STATS_ATTR_MAX + 1];
-       int i;
 
        if (!attr || show_stats == 0)
                return;
 
        parse_rtattr_nested(stats, MACSEC_SA_STATS_ATTR_MAX + 1, attr);
-       printf("%s%s  ", prefix, prefix);
-
-       for (i = 1; i < NUM_MACSEC_SA_STATS_ATTR; i++) {
-               if (!rxsa_stats_names[i])
-                       continue;
-               printf(" %s", rxsa_stats_names[i]);
-       }
 
-       printf("\n%s%s  ", prefix, prefix);
-
-       for (i = 1; i < NUM_MACSEC_SA_STATS_ATTR; i++) {
-               if (!rxsa_stats_names[i])
-                       continue;
-               print_one_stat(rxsa_stats_names, stats, i, false);
-       }
-
-       printf("\n");
+       print_stats(prefix, rxsa_stats_names, NUM_MACSEC_SA_STATS_ATTR, stats);
 }
 
 static const char *txsa_stats_names[NUM_MACSEC_SA_STATS_ATTR] = {
@@ -761,16 +790,8 @@ static void print_txsa_stats(const char *prefix, struct rtattr *attr)
                return;
 
        parse_rtattr_nested(stats, MACSEC_SA_STATS_ATTR_MAX + 1, attr);
-       printf("%s%s   %s %s\n", prefix, prefix,
-              txsa_stats_names[MACSEC_SA_STATS_ATTR_OUT_PKTS_PROTECTED],
-              txsa_stats_names[MACSEC_SA_STATS_ATTR_OUT_PKTS_ENCRYPTED]);
-       printf("%s%s  ", prefix, prefix);
-
-       print_one_stat(txsa_stats_names, stats,
-                      MACSEC_SA_STATS_ATTR_OUT_PKTS_PROTECTED, false);
-       print_one_stat(txsa_stats_names, stats,
-                      MACSEC_SA_STATS_ATTR_OUT_PKTS_ENCRYPTED, false);
-       printf("\n");
+
+       print_stats(prefix, txsa_stats_names, NUM_MACSEC_SA_STATS_ATTR, stats);
 }
 
 static void print_tx_sc(const char *prefix, __u64 sci, __u8 encoding_sa,
@@ -781,26 +802,40 @@ static void print_tx_sc(const char *prefix, __u64 sci, __u8 encoding_sa,
        struct rtattr *a;
        int rem;
 
-       printf("%sTXSC: %016llx on SA %d\n", prefix, ntohll(sci), encoding_sa);
+       print_string(PRINT_FP, NULL, "%s", prefix);
+       print_0xhex(PRINT_ANY, "sci",
+                   "TXSC: %016llx", ntohll(sci));
+       print_uint(PRINT_ANY, "encoding_sa",
+                  " on SA %d\n", encoding_sa);
+
        print_secy_stats(prefix, secy_stats);
        print_txsc_stats(prefix, txsc_stats);
 
+       open_json_array(PRINT_JSON, "sa_list");
        rem = RTA_PAYLOAD(sa);
        for (a = RTA_DATA(sa); RTA_OK(a, rem); a = RTA_NEXT(a, rem)) {
-               SPRINT_BUF(keyid);
                bool state;
 
+               open_json_object(NULL);
                parse_rtattr_nested(sa_attr, MACSEC_SA_ATTR_MAX + 1, a);
                state = rta_getattr_u8(sa_attr[MACSEC_SA_ATTR_ACTIVE]);
-               printf("%s%s%d: PN %u, state %s, key %s\n", prefix, prefix,
-                      rta_getattr_u8(sa_attr[MACSEC_SA_ATTR_AN]),
-                      rta_getattr_u32(sa_attr[MACSEC_SA_ATTR_PN]),
-                      values_on_off[state],
-                      hexstring_n2a(RTA_DATA(sa_attr[MACSEC_SA_ATTR_KEYID]),
-                                    RTA_PAYLOAD(sa_attr[MACSEC_SA_ATTR_KEYID]),
-                                    keyid, sizeof(keyid)));
+
+               print_string(PRINT_FP, NULL, "%s", prefix);
+               print_string(PRINT_FP, NULL, "%s", prefix);
+               print_uint(PRINT_ANY, "an", "%d:",
+                          rta_getattr_u8(sa_attr[MACSEC_SA_ATTR_AN]));
+               print_uint(PRINT_ANY, "pn", " PN %u,",
+                          rta_getattr_u32(sa_attr[MACSEC_SA_ATTR_PN]));
+
+               print_bool(PRINT_JSON, "active", NULL, state);
+               print_string(PRINT_FP, NULL,
+                            " state %s,", state ? "on" : "off");
+               print_key(sa_attr[MACSEC_SA_ATTR_KEYID]);
+
                print_txsa_stats(prefix, sa_attr[MACSEC_SA_ATTR_STATS]);
+               close_json_object();
        }
+       close_json_array(PRINT_JSON, NULL);
 }
 
 static const char *rxsc_stats_names[NUM_MACSEC_RXSC_STATS_ATTR] = {
@@ -819,70 +854,91 @@ static const char *rxsc_stats_names[NUM_MACSEC_RXSC_STATS_ATTR] = {
 static void print_rxsc_stats(const char *prefix, struct rtattr *attr)
 {
        struct rtattr *stats[MACSEC_RXSC_STATS_ATTR_MAX + 1];
-       int i;
 
        if (!attr || show_stats == 0)
                return;
 
        parse_rtattr_nested(stats, MACSEC_RXSC_STATS_ATTR_MAX + 1, attr);
-       printf("%sstats:", prefix);
-       for (i = 1; i < NUM_MACSEC_RXSC_STATS_ATTR; i++) {
-               if (!rxsc_stats_names[i])
-                       continue;
-               printf(" %s", rxsc_stats_names[i]);
-       }
-
-       printf("\n%s      ", prefix);
 
-       for (i = 1; i < NUM_MACSEC_RXSC_STATS_ATTR; i++) {
-               if (!rxsc_stats_names[i])
-                       continue;
-               print_one_stat(rxsc_stats_names, stats, i, true);
-       }
-
-       printf("\n");
+       print_stats(prefix, rxsc_stats_names,
+                   NUM_MACSEC_RXSC_STATS_ATTR, stats);
 }
 
-static void print_rx_sc(const char *prefix, __u64 sci, __u8 active,
+static void print_rx_sc(const char *prefix, __be64 sci, __u8 active,
                        struct rtattr *rxsc_stats, struct rtattr *sa)
 {
        struct rtattr *sa_attr[MACSEC_SA_ATTR_MAX + 1];
        struct rtattr *a;
        int rem;
 
-       printf("%sRXSC: %016llx, state %s\n", prefix, ntohll(sci),
-              values_on_off[!!active]);
+       print_string(PRINT_FP, NULL, "%s", prefix);
+       print_0xhex(PRINT_ANY, "sci",
+                   "RXSC: %016llx,", ntohll(sci));
+       print_bool(PRINT_JSON, "active", NULL, active);
+       print_string(PRINT_FP, NULL,
+                    " state %s\n", active ? "on" : "off");
        print_rxsc_stats(prefix, rxsc_stats);
 
+       open_json_array(PRINT_JSON, "sa_list");
        rem = RTA_PAYLOAD(sa);
        for (a = RTA_DATA(sa); RTA_OK(a, rem); a = RTA_NEXT(a, rem)) {
-               SPRINT_BUF(keyid);
                bool state;
 
+               open_json_object(NULL);
                parse_rtattr_nested(sa_attr, MACSEC_SA_ATTR_MAX + 1, a);
                state = rta_getattr_u8(sa_attr[MACSEC_SA_ATTR_ACTIVE]);
-               printf("%s%s%d: PN %u, state %s, key %s\n", prefix, prefix,
-                      rta_getattr_u8(sa_attr[MACSEC_SA_ATTR_AN]),
-                      rta_getattr_u32(sa_attr[MACSEC_SA_ATTR_PN]),
-                      values_on_off[state],
-                      hexstring_n2a(RTA_DATA(sa_attr[MACSEC_SA_ATTR_KEYID]),
-                                    RTA_PAYLOAD(sa_attr[MACSEC_SA_ATTR_KEYID]),
-                                    keyid, sizeof(keyid)));
+
+               print_string(PRINT_FP, NULL, "%s", prefix);
+               print_string(PRINT_FP, NULL, "%s", prefix);
+               print_uint(PRINT_ANY, "an", "%u:",
+                          rta_getattr_u8(sa_attr[MACSEC_SA_ATTR_AN]));
+               print_uint(PRINT_ANY, "pn", " PN %u,",
+                          rta_getattr_u32(sa_attr[MACSEC_SA_ATTR_PN]));
+
+               print_bool(PRINT_JSON, "active", NULL, state);
+               print_string(PRINT_FP, NULL, " state %s,",
+                            state ? "on" : "off");
+
+               print_key(sa_attr[MACSEC_SA_ATTR_KEYID]);
+
                print_rxsa_stats(prefix, sa_attr[MACSEC_SA_ATTR_STATS]);
+               close_json_object();
+       }
+       close_json_array(PRINT_JSON, NULL);
+}
+
+static void print_rxsc_list(struct rtattr *sc)
+{
+       int rem = RTA_PAYLOAD(sc);
+       struct rtattr *c;
+
+       open_json_array(PRINT_JSON, "rx_sc");
+       for (c = RTA_DATA(sc); RTA_OK(c, rem); c = RTA_NEXT(c, rem)) {
+               struct rtattr *sc_attr[MACSEC_RXSC_ATTR_MAX + 1];
+
+               open_json_object(NULL);
+
+               parse_rtattr_nested(sc_attr, MACSEC_RXSC_ATTR_MAX + 1, c);
+               print_rx_sc("    ",
+                           rta_getattr_u64(sc_attr[MACSEC_RXSC_ATTR_SCI]),
+                           rta_getattr_u32(sc_attr[MACSEC_RXSC_ATTR_ACTIVE]),
+                           sc_attr[MACSEC_RXSC_ATTR_STATS],
+                           sc_attr[MACSEC_RXSC_ATTR_SA_LIST]);
+               close_json_object();
        }
+       close_json_array(PRINT_JSON, NULL);
 }
 
 static int process(const struct sockaddr_nl *who, struct nlmsghdr *n,
                   void *arg)
 {
        struct genlmsghdr *ghdr;
-       struct rtattr *attrs[MACSEC_ATTR_MAX + 1], *sc, *c;
+       struct rtattr *attrs[MACSEC_ATTR_MAX + 1];
        struct rtattr *attrs_secy[MACSEC_SECY_ATTR_MAX + 1];
        int len = n->nlmsg_len;
        int ifindex;
        __u64 sci;
        __u8 encoding_sa;
-       int rem;
 
        if (n->nlmsg_type != genl_family)
                return -1;
@@ -897,7 +953,7 @@ static int process(const struct sockaddr_nl *who, struct nlmsghdr *n,
 
        parse_rtattr(attrs, MACSEC_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len);
        if (!validate_dump(attrs)) {
-               printf("incomplete dump message\n");
+               fprintf(stderr, "incomplete dump message\n");
                return -1;
        }
 
@@ -906,7 +962,7 @@ static int process(const struct sockaddr_nl *who, struct nlmsghdr *n,
                            attrs[MACSEC_ATTR_SECY]);
 
        if (!validate_secy_dump(attrs_secy)) {
-               printf("incomplete dump message\n");
+               fprintf(stderr, "incomplete dump message\n");
                return -1;
        }
 
@@ -919,29 +975,22 @@ static int process(const struct sockaddr_nl *who, struct nlmsghdr *n,
        if (filter.sci && sci != filter.sci)
                return 0;
 
-       printf("%d: %s: ", ifindex, ll_index_to_name(ifindex));
-       print_attrs("    ", attrs_secy);
+       open_json_object(NULL);
+       print_uint(PRINT_ANY, "ifindex", "%u: ", ifindex);
+       print_color_string(PRINT_ANY, COLOR_IFNAME, "ifname",
+                          "%s: ", ll_index_to_name(ifindex));
+
+       print_attrs(attrs_secy);
 
        print_tx_sc("    ", sci, encoding_sa,
                    attrs[MACSEC_ATTR_TXSC_STATS],
                    attrs[MACSEC_ATTR_SECY_STATS],
                    attrs[MACSEC_ATTR_TXSA_LIST]);
 
-       if (!attrs[MACSEC_ATTR_RXSC_LIST])
-               return 0;
+       if (attrs[MACSEC_ATTR_RXSC_LIST])
+               print_rxsc_list(attrs[MACSEC_ATTR_RXSC_LIST]);
 
-       sc = attrs[MACSEC_ATTR_RXSC_LIST];
-       rem = RTA_PAYLOAD(sc);
-       for (c = RTA_DATA(sc); RTA_OK(c, rem); c = RTA_NEXT(c, rem)) {
-               struct rtattr *sc_attr[MACSEC_RXSC_ATTR_MAX + 1];
-
-               parse_rtattr_nested(sc_attr, MACSEC_RXSC_ATTR_MAX + 1, c);
-               print_rx_sc("    ",
-                           rta_getattr_u64(sc_attr[MACSEC_RXSC_ATTR_SCI]),
-                           rta_getattr_u32(sc_attr[MACSEC_RXSC_ATTR_ACTIVE]),
-                           sc_attr[MACSEC_RXSC_ATTR_STATS],
-                           sc_attr[MACSEC_RXSC_ATTR_SA_LIST]);
-       }
+       close_json_object();
 
        return 0;
 }
@@ -960,10 +1009,13 @@ static int do_dump(int ifindex)
                exit(1);
        }
 
+       new_json_obj(json);
        if (rtnl_dump_filter(&genl_rth, process, stdout) < 0) {
+               delete_json_obj();
                fprintf(stderr, "Dump terminated\n");
                exit(1);
        }
+       delete_json_obj();
 
        return 0;
 }
@@ -1034,10 +1086,11 @@ static void macsec_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                }
        }
 
-       print_flag(f, tb, "protect", IFLA_MACSEC_PROTECT);
+       print_flag(tb, "protect", IFLA_MACSEC_PROTECT);
 
        if (tb[IFLA_MACSEC_CIPHER_SUITE]) {
-               __u64 csid = rta_getattr_u64(tb[IFLA_MACSEC_CIPHER_SUITE]);
+               __u64 csid
+                       = rta_getattr_u64(tb[IFLA_MACSEC_CIPHER_SUITE]);
 
                print_string(PRINT_ANY,
                             "cipher_suite",
@@ -1077,7 +1130,7 @@ static void macsec_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                print_string(PRINT_ANY,
                             "validation",
                             "validate %s ",
-                            VALIDATE_STR[val]);
+                            validate_str[val]);
        }
 
        const char *inc_sci, *es, *replay;
@@ -1092,11 +1145,11 @@ static void macsec_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                replay = "replay";
        }
 
-       print_flag(f, tb, "encrypt", IFLA_MACSEC_ENCRYPT);
-       print_flag(f, tb, inc_sci, IFLA_MACSEC_INC_SCI);
-       print_flag(f, tb, es, IFLA_MACSEC_ES);
-       print_flag(f, tb, "scb", IFLA_MACSEC_SCB);
-       print_flag(f, tb, replay, IFLA_MACSEC_REPLAY_PROTECT);
+       print_flag(tb, "encrypt", IFLA_MACSEC_ENCRYPT);
+       print_flag(tb, inc_sci, IFLA_MACSEC_INC_SCI);
+       print_flag(tb, es, IFLA_MACSEC_ES);
+       print_flag(tb, "scb", IFLA_MACSEC_SCB);
+       print_flag(tb, replay, IFLA_MACSEC_REPLAY_PROTECT);
 
        if (tb[IFLA_MACSEC_WINDOW])
                print_int(PRINT_ANY,
@@ -1132,7 +1185,7 @@ static void usage(FILE *f)
 }
 
 static int macsec_parse_opt(struct link_util *lu, int argc, char **argv,
-                           struct nlmsghdr *hdr)
+                           struct nlmsghdr *n)
 {
        int ret;
        __u8 encoding_sa = 0xff;
@@ -1151,10 +1204,10 @@ static int macsec_parse_opt(struct link_util *lu, int argc, char **argv,
 
        if (ret > 0) {
                if (sci.sci)
-                       addattr_l(hdr, MACSEC_BUFLEN, IFLA_MACSEC_SCI,
+                       addattr_l(n, MACSEC_BUFLEN, IFLA_MACSEC_SCI,
                                  &sci.sci, sizeof(sci.sci));
                else
-                       addattr_l(hdr, MACSEC_BUFLEN, IFLA_MACSEC_PORT,
+                       addattr_l(n, MACSEC_BUFLEN, IFLA_MACSEC_PORT,
                                  &sci.port, sizeof(sci.port));
        }
 
@@ -1183,7 +1236,7 @@ static int macsec_parse_opt(struct link_util *lu, int argc, char **argv,
                                     ARRAY_SIZE(values_on_off), &i);
                        if (ret != 0)
                                return ret;
-                       addattr8(hdr, MACSEC_BUFLEN, IFLA_MACSEC_ENCRYPT, i);
+                       addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_ENCRYPT, i);
                } else if (strcmp(*argv, "send_sci") == 0) {
                        NEXT_ARG();
                        int i;
@@ -1193,7 +1246,7 @@ static int macsec_parse_opt(struct link_util *lu, int argc, char **argv,
                        if (ret != 0)
                                return ret;
                        send_sci = i;
-                       addattr8(hdr, MACSEC_BUFLEN,
+                       addattr8(n, MACSEC_BUFLEN,
                                 IFLA_MACSEC_INC_SCI, send_sci);
                } else if (strcmp(*argv, "end_station") == 0) {
                        NEXT_ARG();
@@ -1204,7 +1257,7 @@ static int macsec_parse_opt(struct link_util *lu, int argc, char **argv,
                        if (ret != 0)
                                return ret;
                        es = i;
-                       addattr8(hdr, MACSEC_BUFLEN, IFLA_MACSEC_ES, es);
+                       addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_ES, es);
                } else if (strcmp(*argv, "scb") == 0) {
                        NEXT_ARG();
                        int i;
@@ -1214,7 +1267,7 @@ static int macsec_parse_opt(struct link_util *lu, int argc, char **argv,
                        if (ret != 0)
                                return ret;
                        scb = i;
-                       addattr8(hdr, MACSEC_BUFLEN, IFLA_MACSEC_SCB, scb);
+                       addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_SCB, scb);
                } else if (strcmp(*argv, "protect") == 0) {
                        NEXT_ARG();
                        int i;
@@ -1223,7 +1276,7 @@ static int macsec_parse_opt(struct link_util *lu, int argc, char **argv,
                                     ARRAY_SIZE(values_on_off), &i);
                        if (ret != 0)
                                return ret;
-                       addattr8(hdr, MACSEC_BUFLEN, IFLA_MACSEC_PROTECT, i);
+                       addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_PROTECT, i);
                } else if (strcmp(*argv, "replay") == 0) {
                        NEXT_ARG();
                        int i;
@@ -1241,11 +1294,11 @@ static int macsec_parse_opt(struct link_util *lu, int argc, char **argv,
                } else if (strcmp(*argv, "validate") == 0) {
                        NEXT_ARG();
                        ret = one_of("validate", *argv,
-                                    VALIDATE_STR, ARRAY_SIZE(VALIDATE_STR),
+                                    validate_str, ARRAY_SIZE(validate_str),
                                     (int *)&validate);
                        if (ret != 0)
                                return ret;
-                       addattr8(hdr, MACSEC_BUFLEN,
+                       addattr8(n, MACSEC_BUFLEN,
                                 IFLA_MACSEC_VALIDATION, validate);
                } else if (strcmp(*argv, "encodingsa") == 0) {
                        if (encoding_sa != 0xff)
@@ -1265,7 +1318,8 @@ static int macsec_parse_opt(struct link_util *lu, int argc, char **argv,
        }
 
        if (!check_txsc_flags(es, scb, send_sci)) {
-               fprintf(stderr, "invalid combination of send_sci/end_station/scb\n");
+               fprintf(stderr,
+                       "invalid combination of send_sci/end_station/scb\n");
                return -1;
        }
 
@@ -1281,20 +1335,20 @@ static int macsec_parse_opt(struct link_util *lu, int argc, char **argv,
        }
 
        if (cipher.id)
-               addattr_l(hdr, MACSEC_BUFLEN, IFLA_MACSEC_CIPHER_SUITE,
+               addattr_l(n, MACSEC_BUFLEN, IFLA_MACSEC_CIPHER_SUITE,
                          &cipher.id, sizeof(cipher.id));
        if (cipher.icv_len)
-               addattr_l(hdr, MACSEC_BUFLEN, IFLA_MACSEC_ICV_LEN,
+               addattr_l(n, MACSEC_BUFLEN, IFLA_MACSEC_ICV_LEN,
                          &cipher.icv_len, sizeof(cipher.icv_len));
 
        if (replay_protect != -1) {
-               addattr32(hdr, MACSEC_BUFLEN, IFLA_MACSEC_WINDOW, window);
-               addattr8(hdr, MACSEC_BUFLEN, IFLA_MACSEC_REPLAY_PROTECT,
+               addattr32(n, MACSEC_BUFLEN, IFLA_MACSEC_WINDOW, window);
+               addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_REPLAY_PROTECT,
                         replay_protect);
        }
 
        if (encoding_sa != 0xff) {
-               addattr_l(hdr, MACSEC_BUFLEN, IFLA_MACSEC_ENCODING_SA,
+               addattr_l(n, MACSEC_BUFLEN, IFLA_MACSEC_ENCODING_SA,
                          &encoding_sa, sizeof(encoding_sa));
        }
 
index d7bf1f99f67e5f80b8dedf9ed155a9f9be89cea3..a48499029e17d1f92611fb0a64964a5efa4ea0f6 100644 (file)
@@ -28,6 +28,7 @@
 #include "rt_names.h"
 #include "utils.h"
 #include "ip_common.h"
+#include "json_print.h"
 
 static struct {
        char *dev;
@@ -193,50 +194,66 @@ static void read_igmp6(struct ma_info **result_p)
 
 static void print_maddr(FILE *fp, struct ma_info *list)
 {
-       fprintf(fp, "\t");
+       print_string(PRINT_FP, NULL, "\t", NULL);
 
+       open_json_object(NULL);
        if (list->addr.family == AF_PACKET) {
                SPRINT_BUF(b1);
-               fprintf(fp, "link  %s", ll_addr_n2a((unsigned char *)list->addr.data,
-                                                   list->addr.bytelen, 0,
-                                                   b1, sizeof(b1)));
+
+               print_string(PRINT_FP, NULL, "link  ", NULL);
+               print_color_string(PRINT_ANY, COLOR_MAC, "link", "%s",
+                                  ll_addr_n2a((void *)list->addr.data, list->addr.bytelen,
+                                              0, b1, sizeof(b1)));
        } else {
-               switch (list->addr.family) {
-               case AF_INET:
-                       fprintf(fp, "inet  ");
-                       break;
-               case AF_INET6:
-                       fprintf(fp, "inet6 ");
-                       break;
-               default:
-                       fprintf(fp, "family %d ", list->addr.family);
-                       break;
-               }
-               fprintf(fp, "%s",
-                       format_host(list->addr.family,
-                                   -1, list->addr.data));
+               print_string(PRINT_ANY, "family", "%-5s ",
+                            family_name(list->addr.family));
+               print_color_string(PRINT_ANY, ifa_family_color(list->addr.family),
+                                  "address", "%s",
+                                  format_host(list->addr.family,
+                                              -1, list->addr.data));
        }
+
        if (list->users != 1)
-               fprintf(fp, " users %d", list->users);
+               print_uint(PRINT_ANY, "users", " users %u", list->users);
+
        if (list->features)
-               fprintf(fp, " %s", list->features);
-       fprintf(fp, "\n");
+               print_string(PRINT_ANY, "features", " %s", list->features);
+
+       print_string(PRINT_FP, NULL, "\n", NULL);
+       close_json_object();
 }
 
 static void print_mlist(FILE *fp, struct ma_info *list)
 {
        int cur_index = 0;
 
+       new_json_obj(json);
        for (; list; list = list->next) {
-               if (oneline) {
-                       cur_index = list->index;
-                       fprintf(fp, "%d:\t%s%s", cur_index, list->name, _SL_);
-               } else if (cur_index != list->index) {
+
+               if (list->index != cur_index || oneline) {
+                       if (cur_index) {
+                               close_json_array(PRINT_JSON, NULL);
+                               close_json_object();
+                       }
+                       open_json_object(NULL);
+
+                       print_uint(PRINT_ANY, "ifindex", "%d:", list->index);
+                       print_color_string(PRINT_ANY, COLOR_IFNAME,
+                                          "ifname", "\t%s", list->name);
+                       print_string(PRINT_FP, NULL, "%s", _SL_);
                        cur_index = list->index;
-                       fprintf(fp, "%d:\t%s\n", cur_index, list->name);
+
+                       open_json_array(PRINT_JSON, "maddr");
                }
+
                print_maddr(fp, list);
        }
+       if (cur_index) {
+               close_json_array(PRINT_JSON, NULL);
+               close_json_object();
+       }
+
+       delete_json_obj();
 }
 
 static int multiaddr_list(int argc, char **argv)
index aa5029b44f411de3960feb1cd6db94c5a5719be1..59c5b7718e1823a0c00116b3e2993e6cdc74bc2b 100644 (file)
@@ -29,6 +29,7 @@
 #include <rt_names.h>
 #include "utils.h"
 #include "ip_common.h"
+#include "json_print.h"
 
 static void usage(void) __attribute__((noreturn));
 
@@ -53,13 +54,12 @@ struct rtfilter {
 
 int print_mroute(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
-       FILE *fp = (FILE *)arg;
        struct rtmsg *r = NLMSG_DATA(n);
        int len = n->nlmsg_len;
        struct rtattr *tb[RTA_MAX+1];
-       char obuf[256];
-
+       const char *src, *dst;
        SPRINT_BUF(b1);
+       SPRINT_BUF(b2);
        __u32 table;
        int iif = 0;
        int family;
@@ -75,10 +75,11 @@ int print_mroute(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
                return -1;
        }
+
        if (r->rtm_type != RTN_MULTICAST) {
-               fprintf(stderr, "Not a multicast route (type: %s)\n",
-                       rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
-               return 0;
+               fprintf(stderr,
+                       "Non multicast route received, kernel does support IP multicast?\n");
+               return -1;
        }
 
        parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
@@ -103,30 +104,44 @@ int print_mroute(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 
        family = get_real_family(r->rtm_type, r->rtm_family);
 
+       open_json_object(NULL);
        if (n->nlmsg_type == RTM_DELROUTE)
-               fprintf(fp, "Deleted ");
+               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 
        if (tb[RTA_SRC])
-               len = snprintf(obuf, sizeof(obuf),
-                              "(%s, ", rt_addr_n2a_rta(family, tb[RTA_SRC]));
+               src = rt_addr_n2a_r(family, RTA_PAYLOAD(tb[RTA_SRC]),
+                                   RTA_DATA(tb[RTA_SRC]), b1, sizeof(b1));
        else
-               len = sprintf(obuf, "(unknown, ");
+               src = "unknown";
+
        if (tb[RTA_DST])
-               snprintf(obuf + len, sizeof(obuf) - len,
-                        "%s)", rt_addr_n2a_rta(family, tb[RTA_DST]));
+               dst = rt_addr_n2a_r(family, RTA_PAYLOAD(tb[RTA_DST]),
+                                   RTA_DATA(tb[RTA_DST]), b2, sizeof(b2));
        else
-               snprintf(obuf + len, sizeof(obuf) - len, "unknown) ");
+               dst = "unknown";
+
+       if (is_json_context()) {
+               print_string(PRINT_JSON, "src", NULL, src);
+               print_string(PRINT_JSON, "dst", NULL, dst);
+       } else {
+               char obuf[256];
+
+               snprintf(obuf, sizeof(obuf), "(%s,%s)", src, dst);
+               print_string(PRINT_FP, NULL,
+                            "%-32s Iif: ", obuf);
+       }
 
-       fprintf(fp, "%-32s Iif: ", obuf);
        if (iif)
-               fprintf(fp, "%-10s ", ll_index_to_name(iif));
+               print_color_string(PRINT_ANY, COLOR_IFNAME,
+                                  "iif", "%-10s ", ll_index_to_name(iif));
        else
-               fprintf(fp, "unresolved ");
+               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 (;;) {
@@ -135,47 +150,65 @@ int print_mroute(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                        if (nh->rtnh_len > len)
                                break;
 
+                       open_json_object(NULL);
                        if (first) {
-                               fprintf(fp, "Oifs: ");
+                               print_string(PRINT_FP, NULL, "Oifs: ", NULL);
                                first = 0;
                        }
-                       fprintf(fp, "%s", ll_index_to_name(nh->rtnh_ifindex));
+
+                       print_color_string(PRINT_ANY, COLOR_IFNAME,
+                                          "oif", "%s", ll_index_to_name(nh->rtnh_ifindex));
+
                        if (nh->rtnh_hops > 1)
-                               fprintf(fp, "(ttl %d) ", nh->rtnh_hops);
+                               print_uint(PRINT_ANY,
+                                          "ttl", "(ttl %u) ", nh->rtnh_hops);
                        else
-                               fprintf(fp, " ");
+                               print_string(PRINT_FP, NULL, " ", NULL);
+
+                       close_json_object();
                        len -= NLMSG_ALIGN(nh->rtnh_len);
                        nh = RTNH_NEXT(nh);
                }
+               close_json_array(PRINT_JSON, NULL);
        }
-       fprintf(fp, " State: %s",
-               r->rtm_flags & RTNH_F_UNRESOLVED ? "unresolved" : "resolved");
+
+       print_string(PRINT_ANY, "state", " State: %s",
+                    (r->rtm_flags & RTNH_F_UNRESOLVED) ? "unresolved" : "resolved");
+
        if (r->rtm_flags & RTNH_F_OFFLOAD)
-               fprintf(fp, " offload");
+               print_null(PRINT_ANY, "offload", " offload", NULL);
+
        if (show_stats && tb[RTA_MFC_STATS]) {
                struct rta_mfc_stats *mfcs = RTA_DATA(tb[RTA_MFC_STATS]);
 
-               fprintf(fp, "%s  %"PRIu64" packets, %"PRIu64" bytes", _SL_,
-                       (uint64_t)mfcs->mfcs_packets,
-                       (uint64_t)mfcs->mfcs_bytes);
+               print_string(PRINT_FP, NULL, "%s", _SL_);
+               print_uint(PRINT_ANY, "packets", "  %"PRIu64" packets,",
+                          mfcs->mfcs_packets);
+               print_uint(PRINT_ANY, "bytes", " %"PRIu64" bytes", mfcs->mfcs_bytes);
+
                if (mfcs->mfcs_wrong_if)
-                       fprintf(fp, ", %"PRIu64" arrived on wrong iif.",
-                               (uint64_t)mfcs->mfcs_wrong_if);
+                       print_uint(PRINT_ANY, "wrong_if",
+                                  ", %"PRIu64" arrived on wrong iif.",
+                                  mfcs->mfcs_wrong_if);
        }
+
        if (show_stats && tb[RTA_EXPIRES]) {
                struct timeval tv;
+               double age;
 
                __jiffies_to_tv(&tv, rta_getattr_u64(tb[RTA_EXPIRES]));
-               fprintf(fp, ", Age %4i.%.2i", (int)tv.tv_sec,
-                       (int)tv.tv_usec/10000);
+               age = tv.tv_sec;
+               age += tv.tv_usec / 1000000.;
+               print_float(PRINT_ANY, "expires",
+                           ", Age %.2f", age);
        }
 
        if (table && (table != RT_TABLE_MAIN || show_details > 0) && !filter.tb)
-               fprintf(fp, " Table: %s",
-                       rtnl_rttable_n2a(table, b1, sizeof(b1)));
+               print_string(PRINT_ANY, "table", " Table: %s",
+                            rtnl_rttable_n2a(table, b1, sizeof(b1)));
 
-       fprintf(fp, "\n");
-       fflush(fp);
+       print_string(PRINT_FP, NULL, "\n", NULL);
+       close_json_object();
        return 0;
 }
 
@@ -244,10 +277,9 @@ static int mroute_list(int argc, char **argv)
        if (id)  {
                int idx;
 
-               if ((idx = ll_name_to_index(id)) == 0) {
-                       fprintf(stderr, "Cannot find device \"%s\"\n", id);
-                       return -1;
-               }
+               idx = ll_name_to_index(id);
+               if (!idx)
+                       return nodev(id);
                filter.iif = idx;
        }
 
@@ -256,12 +288,15 @@ static int mroute_list(int argc, char **argv)
                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();
 
-       exit(0);
+       return 0;
 }
 
 int do_multiroute(int argc, char **argv)
index 0735424900f622d27d07f6ed5e4480e5d464bbce..4748381701e451eec9233050a36a1e6430ebabaa 100644 (file)
@@ -23,6 +23,7 @@
 #include "rt_names.h"
 #include "utils.h"
 #include "ip_common.h"
+#include "json_print.h"
 
 #define NUD_VALID      (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY)
 #define MAX_ROUNDS     10
@@ -178,9 +179,10 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv)
 
        ll_init_map(&rth);
 
-       if (dev && (req.ndm.ndm_ifindex = ll_name_to_index(dev)) == 0) {
-               fprintf(stderr, "Cannot find device \"%s\"\n", dev);
-               return -1;
+       if (dev) {
+               req.ndm.ndm_ifindex = ll_name_to_index(dev);
+               if (!req.ndm.ndm_ifindex)
+                       return nodev(dev);
        }
 
        if (rtnl_talk(&rth, &req.n, NULL) < 0)
@@ -189,6 +191,46 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv)
        return 0;
 }
 
+static void print_cacheinfo(const struct nda_cacheinfo *ci)
+{
+       static int hz;
+
+       if (!hz)
+               hz = get_user_hz();
+
+       if (ci->ndm_refcnt)
+               print_uint(PRINT_ANY, "refcnt",
+                               " ref %u", ci->ndm_refcnt);
+
+       print_uint(PRINT_ANY, "used", " used %u", ci->ndm_used / hz);
+       print_uint(PRINT_ANY, "confirmed", "/%u", ci->ndm_confirmed / hz);
+       print_uint(PRINT_ANY, "updated", "/u", ci->ndm_updated / hz);
+}
+
+static void print_neigh_state(unsigned int nud)
+{
+
+       open_json_array(PRINT_JSON,
+                       is_json_context() ?  "state" : "");
+
+#define PRINT_FLAG(f)                                          \
+       if (nud & NUD_##f) {                                    \
+               nud &= ~NUD_##f;                                \
+               print_string(PRINT_ANY, NULL, " %s", #f);       \
+       }
+
+       PRINT_FLAG(INCOMPLETE);
+       PRINT_FLAG(REACHABLE);
+       PRINT_FLAG(STALE);
+       PRINT_FLAG(DELAY);
+       PRINT_FLAG(PROBE);
+       PRINT_FLAG(FAILED);
+       PRINT_FLAG(NOARP);
+       PRINT_FLAG(PERMANENT);
+#undef PRINT_FLAG
+
+       close_json_array(PRINT_JSON, NULL);
+}
 
 int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
@@ -221,7 +263,7 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
        if (!(filter.state&r->ndm_state) &&
            !(r->ndm_flags & NTF_PROXY) &&
            (r->ndm_state || !(filter.state&0x100)) &&
-            (r->ndm_family != AF_DECnet))
+           (r->ndm_family != AF_DECnet))
                return 0;
 
        if (filter.master && !(n->nlmsg_flags & NLM_F_DUMP_FILTERED)) {
@@ -262,65 +304,68 @@ int print_neigh(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                        return 0;
        }
 
+       open_json_object(NULL);
        if (n->nlmsg_type == RTM_DELNEIGH)
-               fprintf(fp, "Deleted ");
+               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
        else if (n->nlmsg_type == RTM_GETNEIGH)
-               fprintf(fp, "miss ");
+               print_null(PRINT_ANY, "miss", "%s ", "miss");
+
        if (tb[NDA_DST]) {
-               fprintf(fp, "%s ",
-                       format_host_rta(r->ndm_family, tb[NDA_DST]));
+               const char *dst;
+
+               dst = format_host_rta(r->ndm_family, tb[NDA_DST]);
+               print_color_string(PRINT_ANY,
+                                  ifa_family_color(r->ndm_family),
+                                  "dst", "%s ", dst);
        }
-       if (!filter.index && r->ndm_ifindex)
-               fprintf(fp, "dev %s ", ll_index_to_name(r->ndm_ifindex));
+
+       if (!filter.index && r->ndm_ifindex) {
+               if (!is_json_context())
+                       fprintf(fp, "dev ");
+
+               print_color_string(PRINT_ANY, COLOR_IFNAME,
+                                  "dev", "%s ",
+                                  ll_index_to_name(r->ndm_ifindex));
+       }
+
        if (tb[NDA_LLADDR]) {
+               const char *lladdr;
                SPRINT_BUF(b1);
-               fprintf(fp, "lladdr %s", ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
-                                             RTA_PAYLOAD(tb[NDA_LLADDR]),
-                                             ll_index_to_type(r->ndm_ifindex),
-                                             b1, sizeof(b1)));
-       }
-       if (r->ndm_flags & NTF_ROUTER) {
-               fprintf(fp, " router");
-       }
-       if (r->ndm_flags & NTF_PROXY) {
-               fprintf(fp, " proxy");
-       }
-       if (tb[NDA_CACHEINFO] && show_stats) {
-               struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
-               int hz = get_user_hz();
 
-               if (ci->ndm_refcnt)
-                       printf(" ref %d", ci->ndm_refcnt);
-               fprintf(fp, " used %d/%d/%d", ci->ndm_used/hz,
-                      ci->ndm_confirmed/hz, ci->ndm_updated/hz);
-       }
+               lladdr = ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
+                                    RTA_PAYLOAD(tb[NDA_LLADDR]),
+                                    ll_index_to_type(r->ndm_ifindex),
+                                    b1, sizeof(b1));
 
-       if (tb[NDA_PROBES] && show_stats) {
-               __u32 p = rta_getattr_u32(tb[NDA_PROBES]);
+               if (!is_json_context())
+                       fprintf(fp, "lladdr ");
 
-               fprintf(fp, " probes %u", p);
+               print_color_string(PRINT_ANY, COLOR_MAC,
+                                  "lladdr", "%s", lladdr);
        }
 
-       if (r->ndm_state) {
-               int nud = r->ndm_state;
-
-               fprintf(fp, " ");
-
-#define PRINT_FLAG(f) if (nud & NUD_##f) { \
-       nud &= ~NUD_##f; fprintf(fp, #f "%s", nud ? "," : ""); }
-               PRINT_FLAG(INCOMPLETE);
-               PRINT_FLAG(REACHABLE);
-               PRINT_FLAG(STALE);
-               PRINT_FLAG(DELAY);
-               PRINT_FLAG(PROBE);
-               PRINT_FLAG(FAILED);
-               PRINT_FLAG(NOARP);
-               PRINT_FLAG(PERMANENT);
-#undef PRINT_FLAG
+       if (r->ndm_flags & NTF_ROUTER)
+               print_null(PRINT_ANY, "router", " %s", "router");
+
+       if (r->ndm_flags & NTF_PROXY)
+               print_null(PRINT_ANY, "proxy", " %s", "proxy");
+
+       if (show_stats) {
+               if (tb[NDA_CACHEINFO])
+                       print_cacheinfo(RTA_DATA(tb[NDA_CACHEINFO]));
+
+               if (tb[NDA_PROBES])
+                       print_uint(PRINT_ANY, "probes", " probes %u",
+                                  rta_getattr_u32(tb[NDA_PROBES]));
        }
-       fprintf(fp, "\n");
 
-       fflush(fp);
+       if (r->ndm_state)
+               print_neigh_state(r->ndm_state);
+
+       print_string(PRINT_FP, NULL, "\n", "");
+       close_json_object();
+       fflush(stdout);
+
        return 0;
 }
 
@@ -423,10 +468,9 @@ static int do_show_or_flush(int argc, char **argv, int flush)
        ll_init_map(&rth);
 
        if (filter_dev) {
-               if ((filter.index = ll_name_to_index(filter_dev)) == 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);
                addattr32(&req.n, sizeof(req), NDA_IFINDEX, filter.index);
        }
 
@@ -479,10 +523,12 @@ static int do_show_or_flush(int argc, char **argv, int flush)
                exit(1);
        }
 
+       new_json_obj(json);
        if (rtnl_dump_filter(&rth, print_neigh, stdout) < 0) {
                fprintf(stderr, "Dump terminated\n");
                exit(1);
        }
+       delete_json_obj();
 
        return 0;
 }
index 76e639a813e41cee29e6e145f53fa3465faf83de..03f98ace91450fb1c5260a9fcac73169321a76a3 100644 (file)
@@ -29,6 +29,10 @@ static struct {
        int ifindex;
 } filter;
 
+static const char * const rp_filter_names[] = {
+       "off", "strict", "loose"
+};
+
 static void usage(void) __attribute__((noreturn));
 
 static void usage(void)
@@ -37,9 +41,12 @@ static void usage(void)
        exit(-1);
 }
 
-static void print_onoff(FILE *f, const char *flag, __u32 val)
+static void print_onoff(FILE *fp, const char *flag, __u32 val)
 {
-       fprintf(f, "%s %s ", flag, val ? "on" : "off");
+       if (is_json_context())
+               print_bool(PRINT_JSON, flag, NULL, val);
+       else
+               fprintf(fp, "%s %s ", flag, val ? "on" : "off");
 }
 
 static struct rtattr *netconf_rta(struct netconfmsg *ncm)
@@ -83,50 +90,44 @@ int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl,
        if (filter.ifindex && filter.ifindex != ifindex)
                return 0;
 
-       switch (ncm->ncm_family) {
-       case AF_INET:
-               fprintf(fp, "ipv4 ");
-               break;
-       case AF_INET6:
-               fprintf(fp, "ipv6 ");
-               break;
-       case AF_MPLS:
-               fprintf(fp, "mpls ");
-               break;
-       default:
-               fprintf(fp, "unknown ");
-               break;
-       }
+       open_json_object(NULL);
+       print_string(PRINT_ANY, "family",
+                    "%s ", family_name(ncm->ncm_family));
 
        if (tb[NETCONFA_IFINDEX]) {
+               const char *dev;
+
                switch (ifindex) {
                case NETCONFA_IFINDEX_ALL:
-                       fprintf(fp, "all ");
+                       dev = "all";
                        break;
                case NETCONFA_IFINDEX_DEFAULT:
-                       fprintf(fp, "default ");
+                       dev = "default";
                        break;
                default:
-                       fprintf(fp, "dev %s ", ll_index_to_name(ifindex));
+                       dev = ll_index_to_name(ifindex);
                        break;
                }
+               print_color_string(PRINT_ANY, COLOR_IFNAME,
+                                  "interface", "%s ", dev);
        }
 
        if (tb[NETCONFA_FORWARDING])
                print_onoff(fp, "forwarding",
                                rta_getattr_u32(tb[NETCONFA_FORWARDING]));
+
        if (tb[NETCONFA_RP_FILTER]) {
                __u32 rp_filter = rta_getattr_u32(tb[NETCONFA_RP_FILTER]);
 
-               if (rp_filter == 0)
-                       fprintf(fp, "rp_filter off ");
-               else if (rp_filter == 1)
-                       fprintf(fp, "rp_filter strict ");
-               else if (rp_filter == 2)
-                       fprintf(fp, "rp_filter loose ");
+               if (rp_filter < ARRAY_SIZE(rp_filter_names))
+                       print_string(PRINT_ANY, "rp_filter",
+                                    "rp_filter %s ",
+                                    rp_filter_names[rp_filter]);
                else
-                       fprintf(fp, "rp_filter unknown mode ");
+                       print_uint(PRINT_ANY, "rp_filter",
+                                  "rp_filter %u ", rp_filter);
        }
+
        if (tb[NETCONFA_MC_FORWARDING])
                print_onoff(fp, "mc_forwarding",
                                rta_getattr_u32(tb[NETCONFA_MC_FORWARDING]));
@@ -142,7 +143,8 @@ int print_netconf(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl,
        if (tb[NETCONFA_INPUT])
                print_onoff(fp, "input", rta_getattr_u32(tb[NETCONFA_INPUT]));
 
-       fprintf(fp, "\n");
+       close_json_object();
+       print_string(PRINT_FP, NULL, "\n", NULL);
        fflush(fp);
        return 0;
 }
@@ -179,7 +181,8 @@ static int do_show(int argc, char **argv)
                        NEXT_ARG();
                        filter.ifindex = ll_name_to_index(*argv);
                        if (filter.ifindex <= 0) {
-                               fprintf(stderr, "Device \"%s\" does not exist.\n",
+                               fprintf(stderr,
+                                       "Device \"%s\" does not exist.\n",
                                        *argv);
                                return -1;
                        }
@@ -202,10 +205,13 @@ static int do_show(int argc, char **argv)
        } else {
                rth.flags = RTNL_HANDLE_F_SUPPRESS_NLERR;
 dump:
-               if (rtnl_wilddump_request(&rth, filter.family, RTM_GETNETCONF) < 0) {
+               if (rtnl_wilddump_request(&rth, filter.family,
+                                         RTM_GETNETCONF) < 0) {
                        perror("Cannot send dump request");
                        exit(1);
                }
+
+               new_json_obj(json);
                if (rtnl_dump_filter(&rth, print_netconf2, stdout) < 0) {
                        /* kernel does not support netconf dump on AF_UNSPEC;
                         * fall back to requesting by family
@@ -219,6 +225,7 @@ dump:
                        fprintf(stderr, "Dump terminated\n");
                        exit(1);
                }
+               delete_json_obj();
                if (preferred_family == AF_UNSPEC && filter.family == AF_INET) {
                        preferred_family = AF_INET6;
                        filter.family = AF_INET6;
@@ -240,6 +247,8 @@ int do_ipnetconf(int argc, char **argv)
        } else
                return do_show(0, NULL);
 
-       fprintf(stderr, "Command \"%s\" is unknown, try \"ip netconf help\".\n", *argv);
+       fprintf(stderr,
+               "Command \"%s\" is unknown, try \"ip netconf help\".\n",
+               *argv);
        exit(-1);
 }
index 631794b8a3412a4b3de76d244a1e3908ff975c34..e06100f4ad2d2896705c76ff43167965d8c09975 100644 (file)
@@ -22,6 +22,7 @@
 #include "list.h"
 #include "ip_common.h"
 #include "namespace.h"
+#include "json_print.h"
 
 static int usage(void)
 {
@@ -293,26 +294,30 @@ int print_nsid(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                return -1;
        }
 
+       open_json_object(NULL);
        if (n->nlmsg_type == RTM_DELNSID)
-               fprintf(fp, "Deleted ");
+               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 
        nsid = rta_getattr_u32(tb[NETNSA_NSID]);
-       fprintf(fp, "nsid %u ", nsid);
+       print_uint(PRINT_ANY, "nsid", "nsid %u ", nsid);
 
        c = netns_map_get_by_nsid(nsid);
        if (c != NULL) {
-               fprintf(fp, "(iproute2 netns name: %s)", c->name);
+               print_string(PRINT_ANY, "name",
+                            "(iproute2 netns name: %s)", c->name);
                netns_map_del(c);
        }
 
        /* During 'ip monitor nsid', no chance to have new nsid in cache. */
        if (c == NULL && n->nlmsg_type == RTM_NEWNSID)
                if (netns_get_name(nsid, name) == 0) {
-                       fprintf(fp, "(iproute2 netns name: %s)", name);
+                       print_string(PRINT_ANY, "name",
+                                    "(iproute2 netns name: %s)", name);
                        netns_map_add(nsid, name);
                }
 
-       fprintf(fp, "\n");
+       print_string(PRINT_FP, NULL, "\n", NULL);
+       close_json_object();
        fflush(fp);
        return 0;
 }
@@ -329,10 +334,14 @@ static int netns_list_id(int argc, char **argv)
                perror("Cannot send dump request");
                exit(1);
        }
+
+       new_json_obj(json);
        if (rtnl_dump_filter(&rth, print_nsid, stdout) < 0) {
+               delete_json_obj();
                fprintf(stderr, "Dump terminated\n");
                exit(1);
        }
+       delete_json_obj();
        return 0;
 }
 
@@ -346,20 +355,27 @@ static int netns_list(int argc, char **argv)
        if (!dir)
                return 0;
 
+       new_json_obj(json);
        while ((entry = readdir(dir)) != NULL) {
                if (strcmp(entry->d_name, ".") == 0)
                        continue;
                if (strcmp(entry->d_name, "..") == 0)
                        continue;
-               printf("%s", entry->d_name);
+
+               open_json_object(NULL);
+               print_string(PRINT_ANY, "name",
+                            "%s", entry->d_name);
                if (ipnetns_have_nsid()) {
                        id = get_netnsid_from_name(entry->d_name);
                        if (id >= 0)
-                               printf(" (id: %d)", id);
+                               print_uint(PRINT_ANY, "id",
+                                          " (id: %d)", id);
                }
-               printf("\n");
+               print_string(PRINT_FP, NULL, "\n", NULL);
+               close_json_object();
        }
        closedir(dir);
+       delete_json_obj();
        return 0;
 }
 
index 2f72c989f35dfcecc176dafead8a2872e6a10505..82f40f87ae1528093befaebdedb91f329a91453d 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "utils.h"
 #include "ip_common.h"
+#include "json_print.h"
 
 static struct
 {
@@ -139,10 +140,8 @@ static int ipntable_modify(int cmd, int flags, int argc, char **argv)
 
                        NEXT_ARG();
                        ifindex = ll_name_to_index(*argv);
-                       if (ifindex == 0) {
-                               fprintf(stderr, "Cannot find device \"%s\"\n", *argv);
-                               return -1;
-                       }
+                       if (!ifindex)
+                               return nodev(*argv);
 
                        rta_addattr32(parms_rta, sizeof(parms_buf),
                                      NDTPA_IFINDEX, ifindex);
@@ -338,274 +337,295 @@ static const char *ntable_strtime_delta(__u32 msec)
        return str;
 }
 
-static int print_ntable(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+static void print_ndtconfig(const struct ndt_config *ndtc)
 {
-       FILE *fp = (FILE *)arg;
-       struct ndtmsg *ndtm = NLMSG_DATA(n);
-       int len = n->nlmsg_len;
-       struct rtattr *tb[NDTA_MAX+1];
-       struct rtattr *tpb[NDTPA_MAX+1];
-       int ret;
 
-       if (n->nlmsg_type != RTM_NEWNEIGHTBL) {
-               fprintf(stderr, "Not NEIGHTBL: %08x %08x %08x\n",
-                       n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
-               return 0;
-       }
-       len -= NLMSG_LENGTH(sizeof(*ndtm));
-       if (len < 0) {
-               fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
-               return -1;
-       }
+       print_uint(PRINT_ANY, "key_length",
+                  "    config key_len %u ", ndtc->ndtc_key_len);
+       print_uint(PRINT_ANY, "entry_size",
+                  "entry_size %u ", ndtc->ndtc_entry_size);
+       print_uint(PRINT_ANY, "entries", "entries %u ", ndtc->ndtc_entries);
 
-       if (preferred_family && preferred_family != ndtm->ndtm_family)
-               return 0;
+       print_string(PRINT_FP, NULL, "%s", _SL_);
 
-       parse_rtattr(tb, NDTA_MAX, NDTA_RTA(ndtm),
-                    n->nlmsg_len - NLMSG_LENGTH(sizeof(*ndtm)));
+       print_string(PRINT_ANY, "last_flush",
+                    "        last_flush %s ",
+                    ntable_strtime_delta(ndtc->ndtc_last_flush));
+       print_string(PRINT_ANY, "last_rand",
+                    "last_rand %s ",
+                    ntable_strtime_delta(ndtc->ndtc_last_rand));
 
-       if (tb[NDTA_NAME]) {
-               const char *name = rta_getattr_str(tb[NDTA_NAME]);
+       print_string(PRINT_FP, NULL, "%s", _SL_);
 
-               if (filter.name && strcmp(filter.name, name))
-                       return 0;
-       }
-       if (tb[NDTA_PARMS]) {
-               parse_rtattr(tpb, NDTPA_MAX, RTA_DATA(tb[NDTA_PARMS]),
-                            RTA_PAYLOAD(tb[NDTA_PARMS]));
+       print_uint(PRINT_ANY, "hash_rnd",
+                  "        hash_rnd %u ", ndtc->ndtc_hash_rnd);
+       print_0xhex(PRINT_ANY, "hash_mask",
+                   "hash_mask %08x ", ndtc->ndtc_hash_mask);
 
-               if (tpb[NDTPA_IFINDEX]) {
-                       __u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]);
+       print_uint(PRINT_ANY, "hash_chain_gc",
+                  "hash_chain_gc %u ", ndtc->ndtc_hash_chain_gc);
+       print_uint(PRINT_ANY, "proxy_qlen",
+                  "proxy_qlen %u ", ndtc->ndtc_proxy_qlen);
 
-                       if (filter.index && filter.index != ifindex)
-                               return 0;
-               } else {
-                       if (filter.index && filter.index != NONE_DEV)
-                               return 0;
-               }
+       print_string(PRINT_FP, NULL, "%s", _SL_);
+}
+
+static void print_ndtparams(struct rtattr *tpb[])
+{
+
+       if (tpb[NDTPA_IFINDEX]) {
+               __u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]);
+
+               print_string(PRINT_FP, NULL, "    dev ", NULL);
+               print_color_string(PRINT_ANY, COLOR_IFNAME,
+                                  "dev", "%s ", ll_index_to_name(ifindex));
+               print_string(PRINT_FP, NULL, "%s", _SL_);
        }
 
-       if (ndtm->ndtm_family == AF_INET)
-               fprintf(fp, "inet ");
-       else if (ndtm->ndtm_family == AF_INET6)
-               fprintf(fp, "inet6 ");
-       else if (ndtm->ndtm_family == AF_DECnet)
-               fprintf(fp, "dnet ");
-       else
-               fprintf(fp, "(%d) ", ndtm->ndtm_family);
+       print_string(PRINT_FP, NULL, "    ", NULL);
+       if (tpb[NDTPA_REFCNT]) {
+               __u32 refcnt = rta_getattr_u32(tpb[NDTPA_REFCNT]);
 
-       if (tb[NDTA_NAME]) {
-               const char *name = rta_getattr_str(tb[NDTA_NAME]);
+               print_uint(PRINT_ANY, "refcnt", "refcnt %u ", refcnt);
+       }
 
-               fprintf(fp, "%s ", name);
+       if (tpb[NDTPA_REACHABLE_TIME]) {
+               __u64 reachable = rta_getattr_u64(tpb[NDTPA_REACHABLE_TIME]);
+
+               print_uint(PRINT_ANY, "reachable",
+                          "reachable %llu ", reachable);
        }
 
-       fprintf(fp, "%s", _SL_);
+       if (tpb[NDTPA_BASE_REACHABLE_TIME]) {
+               __u64 breachable
+                       = rta_getattr_u64(tpb[NDTPA_BASE_REACHABLE_TIME]);
 
-       ret = (tb[NDTA_THRESH1] || tb[NDTA_THRESH2] || tb[NDTA_THRESH3] ||
-              tb[NDTA_GC_INTERVAL]);
-       if (ret)
-               fprintf(fp, "    ");
+               print_uint(PRINT_ANY, "base_reachable",
+                          "base_reachable %llu ", breachable);
+       }
 
-       if (tb[NDTA_THRESH1]) {
-               __u32 thresh1 = rta_getattr_u32(tb[NDTA_THRESH1]);
+       if (tpb[NDTPA_RETRANS_TIME]) {
+               __u64 retrans = rta_getattr_u64(tpb[NDTPA_RETRANS_TIME]);
 
-               fprintf(fp, "thresh1 %u ", thresh1);
+               print_uint(PRINT_ANY, "retrans", "retrans %llu ", retrans);
        }
-       if (tb[NDTA_THRESH2]) {
-               __u32 thresh2 = rta_getattr_u32(tb[NDTA_THRESH2]);
 
-               fprintf(fp, "thresh2 %u ", thresh2);
+       print_string(PRINT_FP, NULL, "%s    ", _SL_);
+
+       if (tpb[NDTPA_GC_STALETIME]) {
+               __u64 gc_stale = rta_getattr_u64(tpb[NDTPA_GC_STALETIME]);
+
+               print_uint(PRINT_ANY, "gc_stale", "gc_stale %llu ", gc_stale);
        }
-       if (tb[NDTA_THRESH3]) {
-               __u32 thresh3 = rta_getattr_u32(tb[NDTA_THRESH3]);
 
-               fprintf(fp, "thresh3 %u ", thresh3);
+       if (tpb[NDTPA_DELAY_PROBE_TIME]) {
+               __u64 delay_probe
+                       = rta_getattr_u64(tpb[NDTPA_DELAY_PROBE_TIME]);
+
+               print_uint(PRINT_ANY, "delay_probe",
+                          "delay_probe %llu ", delay_probe);
        }
-       if (tb[NDTA_GC_INTERVAL]) {
-               unsigned long long gc_int = rta_getattr_u64(tb[NDTA_GC_INTERVAL]);
 
-               fprintf(fp, "gc_int %llu ", gc_int);
+       if (tpb[NDTPA_QUEUE_LEN]) {
+               __u32 queue = rta_getattr_u32(tpb[NDTPA_QUEUE_LEN]);
+
+               print_uint(PRINT_ANY, "queue", "queue %u ", queue);
        }
 
-       if (ret)
-               fprintf(fp, "%s", _SL_);
+       print_string(PRINT_FP, NULL, "%s    ", _SL_);
 
-       if (tb[NDTA_CONFIG] && show_stats) {
-               struct ndt_config *ndtc = RTA_DATA(tb[NDTA_CONFIG]);
+       if (tpb[NDTPA_APP_PROBES]) {
+               __u32 aprobe = rta_getattr_u32(tpb[NDTPA_APP_PROBES]);
 
-               fprintf(fp, "    ");
-               fprintf(fp, "config ");
+               print_uint(PRINT_ANY, "app_probes", "app_probes %u ", aprobe);
+       }
 
-               fprintf(fp, "key_len %u ", ndtc->ndtc_key_len);
-               fprintf(fp, "entry_size %u ", ndtc->ndtc_entry_size);
-               fprintf(fp, "entries %u ", ndtc->ndtc_entries);
+       if (tpb[NDTPA_UCAST_PROBES]) {
+               __u32 uprobe = rta_getattr_u32(tpb[NDTPA_UCAST_PROBES]);
 
-               fprintf(fp, "%s", _SL_);
-               fprintf(fp, "        ");
+               print_uint(PRINT_ANY, "ucast_probes",
+                          "ucast_probes %u ", uprobe);
+       }
 
-               fprintf(fp, "last_flush %s ",
-                       ntable_strtime_delta(ndtc->ndtc_last_flush));
-               fprintf(fp, "last_rand %s ",
-                       ntable_strtime_delta(ndtc->ndtc_last_rand));
+       if (tpb[NDTPA_MCAST_PROBES]) {
+               __u32 mprobe = rta_getattr_u32(tpb[NDTPA_MCAST_PROBES]);
 
-               fprintf(fp, "%s", _SL_);
-               fprintf(fp, "        ");
+               print_uint(PRINT_ANY, "mcast_probes",
+                          "mcast_probes %u ", mprobe);
+       }
 
-               fprintf(fp, "hash_rnd %u ", ndtc->ndtc_hash_rnd);
-               fprintf(fp, "hash_mask %08x ", ndtc->ndtc_hash_mask);
+       print_string(PRINT_FP, NULL, "%s    ", _SL_);
 
-               fprintf(fp, "hash_chain_gc %u ", ndtc->ndtc_hash_chain_gc);
-               fprintf(fp, "proxy_qlen %u ", ndtc->ndtc_proxy_qlen);
+       if (tpb[NDTPA_ANYCAST_DELAY]) {
+               __u64 anycast_delay = rta_getattr_u64(tpb[NDTPA_ANYCAST_DELAY]);
 
-               fprintf(fp, "%s", _SL_);
+               print_uint(PRINT_ANY, "anycast_delay",
+                          "anycast_delay %llu ", anycast_delay);
        }
 
-       if (tb[NDTA_PARMS]) {
-               if (tpb[NDTPA_IFINDEX]) {
-                       __u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]);
+       if (tpb[NDTPA_PROXY_DELAY]) {
+               __u64 proxy_delay = rta_getattr_u64(tpb[NDTPA_PROXY_DELAY]);
 
-                       fprintf(fp, "    ");
-                       fprintf(fp, "dev %s ", ll_index_to_name(ifindex));
-                       fprintf(fp, "%s", _SL_);
-               }
+               print_uint(PRINT_ANY, "proxy_delay",
+                          "proxy_delay %llu ", proxy_delay);
+       }
 
-               fprintf(fp, "    ");
+       if (tpb[NDTPA_PROXY_QLEN]) {
+               __u32 pqueue = rta_getattr_u32(tpb[NDTPA_PROXY_QLEN]);
 
-               if (tpb[NDTPA_REFCNT]) {
-                       __u32 refcnt = rta_getattr_u32(tpb[NDTPA_REFCNT]);
+               print_uint(PRINT_ANY, "proxy_queue", "proxy_queue %u ", pqueue);
+       }
 
-                       fprintf(fp, "refcnt %u ", refcnt);
-               }
-               if (tpb[NDTPA_REACHABLE_TIME]) {
-                       unsigned long long reachable = rta_getattr_u64(tpb[NDTPA_REACHABLE_TIME]);
+       if (tpb[NDTPA_LOCKTIME]) {
+               __u64 locktime = rta_getattr_u64(tpb[NDTPA_LOCKTIME]);
 
-                       fprintf(fp, "reachable %llu ", reachable);
-               }
-               if (tpb[NDTPA_BASE_REACHABLE_TIME]) {
-                       unsigned long long breachable = rta_getattr_u64(tpb[NDTPA_BASE_REACHABLE_TIME]);
+               print_uint(PRINT_ANY, "locktime", "locktime %llu ", locktime);
+       }
 
-                       fprintf(fp, "base_reachable %llu ", breachable);
-               }
-               if (tpb[NDTPA_RETRANS_TIME]) {
-                       unsigned long long retrans = rta_getattr_u64(tpb[NDTPA_RETRANS_TIME]);
+       print_string(PRINT_FP, NULL, "%s", _SL_);
+}
 
-                       fprintf(fp, "retrans %llu ", retrans);
-               }
+static void print_ndtstats(const struct ndt_stats *ndts)
+{
 
-               fprintf(fp, "%s", _SL_);
+       print_string(PRINT_FP, NULL, "    stats ", NULL);
 
-               fprintf(fp, "    ");
+       print_uint(PRINT_ANY, "allocs", "allocs %llu ", ndts->ndts_allocs);
+       print_uint(PRINT_ANY, "destroys", "destroys %llu ",
+                  ndts->ndts_destroys);
+       print_uint(PRINT_ANY, "hash_grows", "hash_grows %llu ",
+                  ndts->ndts_hash_grows);
 
-               if (tpb[NDTPA_GC_STALETIME]) {
-                       unsigned long long gc_stale = rta_getattr_u64(tpb[NDTPA_GC_STALETIME]);
+       print_string(PRINT_FP, NULL, "%s    ", _SL_);
 
-                       fprintf(fp, "gc_stale %llu ", gc_stale);
-               }
-               if (tpb[NDTPA_DELAY_PROBE_TIME]) {
-                       unsigned long long delay_probe = rta_getattr_u64(tpb[NDTPA_DELAY_PROBE_TIME]);
+       print_uint(PRINT_ANY, "res_failed", "res_failed %llu ",
+                  ndts->ndts_res_failed);
+       print_uint(PRINT_ANY, "lookups", "lookups %llu ", ndts->ndts_lookups);
+       print_uint(PRINT_ANY, "hits", "hits %llu ", ndts->ndts_hits);
 
-                       fprintf(fp, "delay_probe %llu ", delay_probe);
-               }
-               if (tpb[NDTPA_QUEUE_LEN]) {
-                       __u32 queue = rta_getattr_u32(tpb[NDTPA_QUEUE_LEN]);
+       print_string(PRINT_FP, NULL, "%s    ", _SL_);
 
-                       fprintf(fp, "queue %u ", queue);
-               }
+       print_uint(PRINT_ANY, "rcv_probes_mcast", "rcv_probes_mcast %llu ",
+                  ndts->ndts_rcv_probes_mcast);
+       print_uint(PRINT_ANY, "rcv_probes_ucast", "rcv_probes_ucast %llu ",
+                  ndts->ndts_rcv_probes_ucast);
 
-               fprintf(fp, "%s", _SL_);
+       print_string(PRINT_FP, NULL, "%s    ", _SL_);
 
-               fprintf(fp, "    ");
+       print_uint(PRINT_ANY, "periodic_gc_runs", "periodic_gc_runs %llu ",
+                  ndts->ndts_periodic_gc_runs);
+       print_uint(PRINT_ANY, "forced_gc_runs", "forced_gc_runs %llu ",
+                  ndts->ndts_forced_gc_runs);
 
-               if (tpb[NDTPA_APP_PROBES]) {
-                       __u32 aprobe = rta_getattr_u32(tpb[NDTPA_APP_PROBES]);
+       print_string(PRINT_FP, NULL, "%s", _SL_);
+}
 
-                       fprintf(fp, "app_probes %u ", aprobe);
-               }
-               if (tpb[NDTPA_UCAST_PROBES]) {
-                       __u32 uprobe = rta_getattr_u32(tpb[NDTPA_UCAST_PROBES]);
+static int print_ntable(const struct sockaddr_nl *who,
+                       struct nlmsghdr *n, void *arg)
+{
+       FILE *fp = (FILE *)arg;
+       struct ndtmsg *ndtm = NLMSG_DATA(n);
+       int len = n->nlmsg_len;
+       struct rtattr *tb[NDTA_MAX+1];
+       struct rtattr *tpb[NDTPA_MAX+1];
+       int ret;
 
-                       fprintf(fp, "ucast_probes %u ", uprobe);
-               }
-               if (tpb[NDTPA_MCAST_PROBES]) {
-                       __u32 mprobe = rta_getattr_u32(tpb[NDTPA_MCAST_PROBES]);
+       if (n->nlmsg_type != RTM_NEWNEIGHTBL) {
+               fprintf(stderr, "Not NEIGHTBL: %08x %08x %08x\n",
+                       n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
+               return 0;
+       }
+       len -= NLMSG_LENGTH(sizeof(*ndtm));
+       if (len < 0) {
+               fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+               return -1;
+       }
 
-                       fprintf(fp, "mcast_probes %u ", mprobe);
-               }
+       if (preferred_family && preferred_family != ndtm->ndtm_family)
+               return 0;
 
-               fprintf(fp, "%s", _SL_);
+       parse_rtattr(tb, NDTA_MAX, NDTA_RTA(ndtm),
+                    n->nlmsg_len - NLMSG_LENGTH(sizeof(*ndtm)));
 
-               fprintf(fp, "    ");
+       if (tb[NDTA_NAME]) {
+               const char *name = rta_getattr_str(tb[NDTA_NAME]);
+
+               if (filter.name && strcmp(filter.name, name))
+                       return 0;
+       }
 
-               if (tpb[NDTPA_ANYCAST_DELAY]) {
-                       unsigned long long anycast_delay = rta_getattr_u64(tpb[NDTPA_ANYCAST_DELAY]);
+       if (tb[NDTA_PARMS]) {
+               parse_rtattr(tpb, NDTPA_MAX, RTA_DATA(tb[NDTA_PARMS]),
+                            RTA_PAYLOAD(tb[NDTA_PARMS]));
 
-                       fprintf(fp, "anycast_delay %llu ", anycast_delay);
-               }
-               if (tpb[NDTPA_PROXY_DELAY]) {
-                       unsigned long long proxy_delay = rta_getattr_u64(tpb[NDTPA_PROXY_DELAY]);
+               if (tpb[NDTPA_IFINDEX]) {
+                       __u32 ifindex = rta_getattr_u32(tpb[NDTPA_IFINDEX]);
 
-                       fprintf(fp, "proxy_delay %llu ", proxy_delay);
+                       if (filter.index && filter.index != ifindex)
+                               return 0;
+               } else {
+                       if (filter.index && filter.index != NONE_DEV)
+                               return 0;
                }
-               if (tpb[NDTPA_PROXY_QLEN]) {
-                       __u32 pqueue = rta_getattr_u32(tpb[NDTPA_PROXY_QLEN]);
+       }
 
-                       fprintf(fp, "proxy_queue %u ", pqueue);
-               }
-               if (tpb[NDTPA_LOCKTIME]) {
-                       unsigned long long locktime = rta_getattr_u64(tpb[NDTPA_LOCKTIME]);
+       open_json_object(NULL);
+       print_string(PRINT_ANY, "family",
+                    "%s ", family_name(ndtm->ndtm_family));
 
-                       fprintf(fp, "locktime %llu ", locktime);
-               }
+       if (tb[NDTA_NAME]) {
+               const char *name = rta_getattr_str(tb[NDTA_NAME]);
 
-               fprintf(fp, "%s", _SL_);
+               print_string(PRINT_ANY, "name", "%s ", name);
        }
 
-       if (tb[NDTA_STATS] && show_stats) {
-               struct ndt_stats *ndts = RTA_DATA(tb[NDTA_STATS]);
+       print_string(PRINT_FP, NULL, "%s", _SL_);
 
-               fprintf(fp, "    ");
-               fprintf(fp, "stats ");
+       ret = (tb[NDTA_THRESH1] || tb[NDTA_THRESH2] || tb[NDTA_THRESH3] ||
+              tb[NDTA_GC_INTERVAL]);
+       if (ret)
+               print_string(PRINT_FP, NULL, "    ", NULL);
 
-               fprintf(fp, "allocs %llu ",
-                       (unsigned long long) ndts->ndts_allocs);
-               fprintf(fp, "destroys %llu ",
-                       (unsigned long long) ndts->ndts_destroys);
-               fprintf(fp, "hash_grows %llu ",
-                       (unsigned long long) ndts->ndts_hash_grows);
+       if (tb[NDTA_THRESH1]) {
+               __u32 thresh1 = rta_getattr_u32(tb[NDTA_THRESH1]);
 
-               fprintf(fp, "%s", _SL_);
-               fprintf(fp, "        ");
+               print_uint(PRINT_ANY, "thresh1", "thresh1 %u ", thresh1);
+       }
 
-               fprintf(fp, "res_failed %llu ",
-                       (unsigned long long) ndts->ndts_res_failed);
-               fprintf(fp, "lookups %llu ",
-                       (unsigned long long) ndts->ndts_lookups);
-               fprintf(fp, "hits %llu ",
-                       (unsigned long long) ndts->ndts_hits);
+       if (tb[NDTA_THRESH2]) {
+               __u32 thresh2 = rta_getattr_u32(tb[NDTA_THRESH2]);
 
-               fprintf(fp, "%s", _SL_);
-               fprintf(fp, "        ");
+               print_uint(PRINT_ANY, "thresh2", "thresh2 %u ", thresh2);
+       }
 
-               fprintf(fp, "rcv_probes_mcast %llu ",
-                       (unsigned long long) ndts->ndts_rcv_probes_mcast);
-               fprintf(fp, "rcv_probes_ucast %llu ",
-                       (unsigned long long) ndts->ndts_rcv_probes_ucast);
+       if (tb[NDTA_THRESH3]) {
+               __u32 thresh3 = rta_getattr_u32(tb[NDTA_THRESH3]);
 
-               fprintf(fp, "%s", _SL_);
-               fprintf(fp, "        ");
+               print_uint(PRINT_ANY, "thresh3", "thresh3 %u ", thresh3);
+       }
 
-               fprintf(fp, "periodic_gc_runs %llu ",
-                       (unsigned long long) ndts->ndts_periodic_gc_runs);
-               fprintf(fp, "forced_gc_runs %llu ",
-                       (unsigned long long) ndts->ndts_forced_gc_runs);
+       if (tb[NDTA_GC_INTERVAL]) {
+               __u64 gc_int = rta_getattr_u64(tb[NDTA_GC_INTERVAL]);
 
-               fprintf(fp, "%s", _SL_);
+               print_uint(PRINT_ANY, "gc_interval", "gc_int %llu ", gc_int);
        }
 
-       fprintf(fp, "\n");
+       if (ret)
+               print_string(PRINT_FP, NULL, "%s", _SL_);
 
+       if (tb[NDTA_CONFIG] && show_stats)
+               print_ndtconfig(RTA_DATA(tb[NDTA_CONFIG]));
+
+       if (tb[NDTA_PARMS])
+               print_ndtparams(tpb);
+
+       if (tb[NDTA_STATS] && show_stats)
+               print_ndtstats(RTA_DATA(tb[NDTA_STATS]));
+
+       print_string(PRINT_FP, NULL, "\n", "");
+       close_json_object();
        fflush(fp);
+
        return 0;
 }
 
@@ -643,10 +663,12 @@ static int ipntable_show(int argc, char **argv)
                exit(1);
        }
 
+       new_json_obj(json);
        if (rtnl_dump_filter(&rth, print_ntable, stdout) < 0) {
                fprintf(stderr, "Dump terminated\n");
                exit(1);
        }
+       delete_json_obj();
 
        return 0;
 }
index 32c93ed5abd9c1878fc9cde0ea23124682fedf7e..e8d1f89806bb0883146fbf61fd7ab9fee2f0a9d3 100644 (file)
@@ -28,7 +28,6 @@
 #include "rt_names.h"
 #include "utils.h"
 #include "ip_common.h"
-#include "iproute_lwtunnel.h"
 
 #ifndef RTAX_RTTVAR
 #define RTAX_RTTVAR RTAX_HOPS
@@ -163,7 +162,7 @@ static int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
        if (r->rtm_family == AF_INET6 && table != RT_TABLE_MAIN)
                ip6_multiple_tables = 1;
 
-       if (filter.cloned == !(r->rtm_flags&RTM_F_CLONED))
+       if (filter.cloned == !(r->rtm_flags & RTM_F_CLONED))
                return 0;
 
        if (r->rtm_family == AF_INET6 && !ip6_multiple_tables) {
@@ -313,12 +312,372 @@ static void print_rtax_features(FILE *fp, unsigned int features)
        unsigned int of = features;
 
        if (features & RTAX_FEATURE_ECN) {
-               fprintf(fp, "ecn ");
+               print_null(PRINT_ANY, "ecn", "ecn ", NULL);
                features &= ~RTAX_FEATURE_ECN;
        }
 
        if (features)
-               fprintf(fp, "0x%x ", of);
+               print_0xhex(PRINT_ANY,
+                           "features", "0x%x ", of);
+}
+
+static void print_rt_flags(FILE *fp, unsigned int flags)
+{
+       open_json_array(PRINT_JSON,
+                       is_json_context() ?  "flags" : "");
+
+       if (flags & RTNH_F_DEAD)
+               print_string(PRINT_ANY, NULL, "%s ", "dead");
+       if (flags & RTNH_F_ONLINK)
+               print_string(PRINT_ANY, NULL, "%s ", "onlink");
+       if (flags & RTNH_F_PERVASIVE)
+               print_string(PRINT_ANY, NULL, "%s ", "pervasive");
+       if (flags & RTNH_F_OFFLOAD)
+               print_string(PRINT_ANY, NULL, "%s ", "offload");
+       if (flags & RTM_F_NOTIFY)
+               print_string(PRINT_ANY, NULL, "%s ", "notify");
+       if (flags & RTNH_F_LINKDOWN)
+               print_string(PRINT_ANY, NULL, "%s ", "linkdown");
+       if (flags & RTNH_F_UNRESOLVED)
+               print_string(PRINT_ANY, NULL, "%s ", "unresolved");
+
+       close_json_array(PRINT_JSON, NULL);
+}
+
+static void print_rt_pref(FILE *fp, unsigned int pref)
+{
+
+       switch (pref) {
+       case ICMPV6_ROUTER_PREF_LOW:
+               print_string(PRINT_ANY,
+                            "pref", "pref %s", "low");
+               break;
+       case ICMPV6_ROUTER_PREF_MEDIUM:
+               print_string(PRINT_ANY,
+                            "pref", "pref %s", "medium");
+               break;
+       case ICMPV6_ROUTER_PREF_HIGH:
+               print_string(PRINT_ANY,
+                            "pref", "pref %s", "high");
+               break;
+       default:
+               print_uint(PRINT_ANY,
+                          "pref", "%u", pref);
+       }
+}
+
+static void print_rta_if(FILE *fp, const struct rtattr *rta,
+                       const char *prefix)
+{
+       const char *ifname = ll_index_to_name(rta_getattr_u32(rta));
+
+       if (is_json_context())
+               print_string(PRINT_JSON, prefix, NULL, ifname);
+       else {
+               fprintf(fp, "%s ", prefix);
+               color_fprintf(fp, COLOR_IFNAME, "%s ", ifname);
+       }
+}
+
+static void print_cache_flags(FILE *fp, __u32 flags)
+{
+       json_writer_t *jw = get_json_writer();
+       flags &= ~0xFFFF;
+
+       if (jw) {
+               jsonw_name(jw, "cache");
+               jsonw_start_array(jw);
+       } else {
+               fprintf(fp, "%s    cache ", _SL_);
+               if (flags == 0)
+                       return;
+               putc('<', fp);
+       }
+
+#define PRTFL(fl, flname)                                              \
+       if (flags & RTCF_##fl) {                                        \
+               flags &= ~RTCF_##fl;                                    \
+               if (jw)                                                 \
+                       jsonw_string(jw, flname);                       \
+               else                                                    \
+                       fprintf(fp, "%s%s", flname, flags ? "," : "> "); \
+       }
+
+       PRTFL(LOCAL, "local");
+       PRTFL(REJECT, "reject");
+       PRTFL(MULTICAST, "mc");
+       PRTFL(BROADCAST, "brd");
+       PRTFL(DNAT, "dst-nat");
+       PRTFL(SNAT, "src-nat");
+       PRTFL(MASQ, "masq");
+       PRTFL(DIRECTDST, "dst-direct");
+       PRTFL(DIRECTSRC, "src-direct");
+       PRTFL(REDIRECTED, "redirected");
+       PRTFL(DOREDIRECT, "redirect");
+       PRTFL(FAST, "fastroute");
+       PRTFL(NOTIFY, "notify");
+       PRTFL(TPROXY, "proxy");
+#undef PRTFL
+
+       if (flags)
+               print_hex(PRINT_ANY, "flags", "%x>", flags);
+
+       if (jw) {
+               jsonw_end_array(jw);
+               jsonw_destroy(&jw);
+       }
+}
+
+static void print_rta_cacheinfo(FILE *fp, const struct rta_cacheinfo *ci)
+{
+       static int hz;
+
+       if (!hz)
+               hz = get_user_hz();
+
+       if (ci->rta_expires != 0)
+               print_uint(PRINT_ANY, "expires",
+                          "expires %usec ", ci->rta_expires/hz);
+       if (ci->rta_error != 0)
+               print_uint(PRINT_ANY, "error",
+                          "error %u ", ci->rta_error);
+
+       if (show_stats) {
+               if (ci->rta_clntref)
+                       print_uint(PRINT_ANY, "users",
+                                  "users %u ", ci->rta_clntref);
+               if (ci->rta_used != 0)
+                       print_uint(PRINT_ANY, "used",
+                                  "used %u ", ci->rta_used);
+               if (ci->rta_lastuse != 0)
+                       print_uint(PRINT_ANY, "age",
+                                  "age %usec ", ci->rta_lastuse/hz);
+       }
+       if (ci->rta_id)
+               print_0xhex(PRINT_ANY, "ipid",
+                           "ipid 0x%04x ", ci->rta_id);
+       if (ci->rta_ts || ci->rta_tsage) {
+               print_0xhex(PRINT_ANY, "ts",
+                           "ts 0x%x", ci->rta_ts);
+               print_uint(PRINT_ANY, "tsage",
+                          "tsage %usec ", ci->rta_tsage);
+       }
+}
+
+static void print_rta_flow(FILE *fp, const struct rtattr *rta)
+{
+       __u32 to = rta_getattr_u32(rta);
+       __u32 from = to >> 16;
+       SPRINT_BUF(b1);
+
+       to &= 0xFFFF;
+       if (is_json_context()) {
+               open_json_object("flow");
+
+               if (from)
+                       print_string(PRINT_JSON, "from", NULL,
+                                    rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
+               print_string(PRINT_JSON, "to", NULL,
+                            rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
+               close_json_object();
+       } else {
+               fprintf(fp, "realm%s ", from ? "s" : "");
+
+               if (from)
+                       print_string(PRINT_FP, NULL, "%s/",
+                                    rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
+               print_string(PRINT_FP, NULL, "%s ",
+                            rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
+       }
+}
+
+static void print_rta_newdst(FILE *fp, const struct rtmsg *r,
+                            const struct rtattr *rta)
+{
+       const char *newdst = format_host_rta(r->rtm_family, rta);
+
+       if (is_json_context())
+               print_string(PRINT_JSON, "to", NULL, newdst);
+       else {
+               fprintf(fp, "as to ");
+               print_color_string(PRINT_FP,
+                                  ifa_family_color(r->rtm_family),
+                                  NULL, "%s ", newdst);
+       }
+}
+
+static void print_rta_gateway(FILE *fp, const struct rtmsg *r,
+                             const struct rtattr *rta)
+{
+       const char *gateway = format_host_rta(r->rtm_family, rta);
+
+       if (is_json_context())
+               print_string(PRINT_JSON, "gateway", NULL, gateway);
+       else {
+               fprintf(fp, "via ");
+               print_color_string(PRINT_FP,
+                                  ifa_family_color(r->rtm_family),
+                                  NULL, "%s ", gateway);
+       }
+}
+
+static void print_rta_via(FILE *fp, const struct rtattr *rta)
+{
+       size_t len = RTA_PAYLOAD(rta) - 2;
+       const struct rtvia *via = RTA_DATA(rta);
+
+       if (is_json_context()) {
+               open_json_object("via");
+               print_string(PRINT_JSON, "family", NULL,
+                            family_name(via->rtvia_family));
+               print_string(PRINT_JSON, "host", NULL,
+                            format_host(via->rtvia_family, len,
+                                        via->rtvia_addr));
+               close_json_object();
+       } else {
+               print_string(PRINT_FP, NULL, "via %s ",
+                            family_name(via->rtvia_family));
+               print_color_string(PRINT_FP,
+                                  ifa_family_color(via->rtvia_family),
+                                  NULL, "%s ",
+                                  format_host(via->rtvia_family,
+                                              len, via->rtvia_addr));
+       }
+}
+
+static void print_rta_metrics(FILE *fp, const struct rtattr *rta)
+{
+       struct rtattr *mxrta[RTAX_MAX+1];
+       unsigned int mxlock = 0;
+       int i;
+
+       open_json_array(PRINT_JSON, "metrics");
+
+       parse_rtattr(mxrta, RTAX_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta));
+
+       if (mxrta[RTAX_LOCK])
+               mxlock = rta_getattr_u32(mxrta[RTAX_LOCK]);
+
+       for (i = 2; i <= RTAX_MAX; i++) {
+               __u32 val = 0U;
+
+               if (mxrta[i] == NULL && !(mxlock & (1 << i)))
+                       continue;
+
+               if (mxrta[i] != NULL && i != RTAX_CC_ALGO)
+                       val = rta_getattr_u32(mxrta[i]);
+
+               if (i == RTAX_HOPLIMIT && (int)val == -1)
+                       continue;
+
+               if (!is_json_context()) {
+                       if (i < sizeof(mx_names)/sizeof(char *) && mx_names[i])
+                               fprintf(fp, "%s ", mx_names[i]);
+                       else
+                               fprintf(fp, "metric %d ", i);
+
+                       if (mxlock & (1<<i))
+                               fprintf(fp, "lock ");
+               }
+
+               switch (i) {
+               case RTAX_FEATURES:
+                       print_rtax_features(fp, val);
+                       break;
+               default:
+                       fprintf(fp, "%u ", val);
+                       break;
+
+               case RTAX_RTT:
+               case RTAX_RTTVAR:
+               case RTAX_RTO_MIN:
+                       if (i == RTAX_RTT)
+                               val /= 8;
+                       else if (i == RTAX_RTTVAR)
+                               val /= 4;
+
+                       if (is_json_context())
+                               print_uint(PRINT_JSON, mx_names[i],
+                                          NULL, val);
+                       else {
+                               if (val >= 1000)
+                                       fprintf(fp, "%gs ", val/1e3);
+                               else
+                                       fprintf(fp, "%ums ", val);
+                       }
+                       break;
+               case RTAX_CC_ALGO:
+                       print_string(PRINT_ANY, "congestion",
+                                    "%s ", rta_getattr_str(mxrta[i]));
+                       break;
+               }
+       }
+
+       close_json_array(PRINT_JSON, NULL);
+}
+
+static void print_rta_multipath(FILE *fp, const struct rtmsg *r,
+                               struct rtattr *rta)
+{
+       const struct rtnexthop *nh = RTA_DATA(rta);
+       int len = RTA_PAYLOAD(rta);
+       int first = 1;
+
+       while (len > sizeof(*nh)) {
+               struct rtattr *tb[RTA_MAX + 1];
+
+               if (nh->rtnh_len > len)
+                       break;
+
+               if (!is_json_context()) {
+                       if ((r->rtm_flags & RTM_F_CLONED) &&
+                           r->rtm_type == RTN_MULTICAST) {
+                               if (first) {
+                                       fprintf(fp, "Oifs: ");
+                                       first = 0;
+                               } else {
+                                       fprintf(fp, " ");
+                               }
+                       } else
+                               fprintf(fp, "%s\tnexthop ", _SL_);
+               }
+
+               if (nh->rtnh_len > sizeof(*nh)) {
+                       parse_rtattr(tb, RTA_MAX, RTNH_DATA(nh),
+                                    nh->rtnh_len - sizeof(*nh));
+
+                       if (tb[RTA_ENCAP])
+                               lwt_print_encap(fp,
+                                               tb[RTA_ENCAP_TYPE],
+                                               tb[RTA_ENCAP]);
+                       if (tb[RTA_NEWDST])
+                               print_rta_newdst(fp, r, tb[RTA_NEWDST]);
+                       if (tb[RTA_GATEWAY])
+                               print_rta_gateway(fp, r, tb[RTA_GATEWAY]);
+                       if (tb[RTA_VIA])
+                               print_rta_via(fp, tb[RTA_VIA]);
+                       if (tb[RTA_FLOW])
+                               print_rta_flow(fp, tb[RTA_FLOW]);
+               }
+
+               if ((r->rtm_flags & RTM_F_CLONED) &&
+                   r->rtm_type == RTN_MULTICAST) {
+                       fprintf(fp, "%s", ll_index_to_name(nh->rtnh_ifindex));
+                       if (nh->rtnh_hops != 1)
+                               fprintf(fp, "(ttl>%d)", nh->rtnh_hops);
+                       fprintf(fp, " ");
+               } else {
+                       fprintf(fp, "dev %s ", ll_index_to_name(nh->rtnh_ifindex));
+                       if (r->rtm_family != AF_MPLS)
+                               fprintf(fp, "weight %d ",
+                                       nh->rtnh_hops+1);
+               }
+
+               print_rt_flags(fp, nh->rtnh_flags);
+
+               len -= NLMSG_ALIGN(nh->rtnh_len);
+               nh = RTNH_NEXT(nh);
+       }
 }
 
 int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
@@ -327,12 +686,11 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
        struct rtmsg *r = NLMSG_DATA(n);
        int len = n->nlmsg_len;
        struct rtattr *tb[RTA_MAX+1];
-       int host_len, family;
+       int family, color, host_len;
        __u32 table;
        int ret;
 
        SPRINT_BUF(b1);
-       static int hz;
 
        if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
                fprintf(stderr, "Not a route: %08x %08x %08x\n",
@@ -359,7 +717,8 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                struct nlmsghdr *fn;
 
                if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
-                       if ((ret = flush_update()) < 0)
+                       ret = flush_update();
+                       if (ret < 0)
                                return ret;
                }
                fn = (struct nlmsghdr *)(filter.flushb + NLMSG_ALIGN(filter.flushp));
@@ -373,376 +732,185 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                        return 0;
        }
 
+       open_json_object(NULL);
        if (n->nlmsg_type == RTM_DELROUTE)
-               fprintf(fp, "Deleted ");
+               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
+
        if ((r->rtm_type != RTN_UNICAST || show_details > 0) &&
            (!filter.typemask || (filter.typemask & (1 << r->rtm_type))))
-               fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
+               print_string(PRINT_ANY, NULL, "%s ",
+                            rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
 
+       color = COLOR_NONE;
        if (tb[RTA_DST]) {
                family = get_real_family(r->rtm_type, r->rtm_family);
+               color = ifa_family_color(family);
+
                if (r->rtm_dst_len != host_len) {
-                       fprintf(fp, "%s/%u ",
-                               rt_addr_n2a_rta(family, tb[RTA_DST]),
-                               r->rtm_dst_len);
+                       snprintf(b1, sizeof(b1),
+                                "%s/%u", rt_addr_n2a_rta(family, tb[RTA_DST]),
+                                r->rtm_dst_len);
                } else {
-                       fprintf(fp, "%s ",
-                               format_host_rta(family, tb[RTA_DST]));
+                       format_host_rta_r(family, tb[RTA_DST],
+                                         b1, sizeof(b1));
+
                }
        } else if (r->rtm_dst_len) {
-               fprintf(fp, "0/%d ", r->rtm_dst_len);
+               snprintf(b1, sizeof(b1), "0/%d ", r->rtm_dst_len);
        } else {
-               fprintf(fp, "default ");
+               strncpy(b1, "default", sizeof(b1));
        }
+       print_color_string(PRINT_ANY, color,
+                          "dst", "%s ", b1);
+
        if (tb[RTA_SRC]) {
                family = get_real_family(r->rtm_type, r->rtm_family);
+               color = ifa_family_color(family);
+
                if (r->rtm_src_len != host_len) {
-                       fprintf(fp, "from %s/%u ",
-                               rt_addr_n2a_rta(family, tb[RTA_SRC]),
-                               r->rtm_src_len);
+                       snprintf(b1, sizeof(b1),
+                                "%s/%u",
+                                rt_addr_n2a_rta(family, tb[RTA_SRC]),
+                                r->rtm_src_len);
                } else {
-                       fprintf(fp, "from %s ",
-                               format_host_rta(family, tb[RTA_SRC]));
+                       format_host_rta_r(family, tb[RTA_SRC],
+                                         b1, sizeof(b1));
                }
+               print_color_string(PRINT_ANY, color,
+                                  "from", "from %s ", b1);
        } else if (r->rtm_src_len) {
-               fprintf(fp, "from 0/%u ", r->rtm_src_len);
-       }
-       if (tb[RTA_NEWDST]) {
-               fprintf(fp, "as to %s ",
-                       format_host_rta(r->rtm_family, tb[RTA_NEWDST]));
+               snprintf(b1, sizeof(b1), "0/%u", r->rtm_src_len);
+
+               print_string(PRINT_ANY, "src", "from %s ", b1);
        }
 
+       if (tb[RTA_NEWDST])
+               print_rta_newdst(fp, r, tb[RTA_NEWDST]);
+
        if (tb[RTA_ENCAP])
                lwt_print_encap(fp, tb[RTA_ENCAP_TYPE], tb[RTA_ENCAP]);
 
        if (r->rtm_tos && filter.tosmask != -1) {
-               SPRINT_BUF(b1);
-               fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
+               print_string(PRINT_ANY, "tos", "tos %s ",
+                            rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
        }
 
-       if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
-               fprintf(fp, "via %s ",
-                       format_host_rta(r->rtm_family, tb[RTA_GATEWAY]));
-       }
-       if (tb[RTA_VIA]) {
-               size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2;
-               struct rtvia *via = RTA_DATA(tb[RTA_VIA]);
+       if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len)
+               print_rta_gateway(fp, r, tb[RTA_GATEWAY]);
+
+       if (tb[RTA_VIA])
+               print_rta_via(fp, tb[RTA_VIA]);
 
-               fprintf(fp, "via %s %s ",
-                       family_name(via->rtvia_family),
-                       format_host(via->rtvia_family, len, via->rtvia_addr));
-       }
        if (tb[RTA_OIF] && filter.oifmask != -1)
-               fprintf(fp, "dev %s ", ll_index_to_name(rta_getattr_u32(tb[RTA_OIF])));
+               print_rta_if(fp, tb[RTA_OIF], "dev");
 
        if (table && (table != RT_TABLE_MAIN || show_details > 0) && !filter.tb)
-               fprintf(fp, "table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1)));
-       if (!(r->rtm_flags&RTM_F_CLONED)) {
-               if ((r->rtm_protocol != RTPROT_BOOT || show_details > 0) && filter.protocolmask != -1)
-                       fprintf(fp, "proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1)));
-               if ((r->rtm_scope != RT_SCOPE_UNIVERSE || show_details > 0) && filter.scopemask != -1)
-                       fprintf(fp, "scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1)));
+               print_string(PRINT_ANY,
+                            "table", "table %s ",
+                            rtnl_rttable_n2a(table, b1, sizeof(b1)));
+
+       if (!(r->rtm_flags & RTM_F_CLONED)) {
+               if ((r->rtm_protocol != RTPROT_BOOT || show_details > 0) &&
+                   filter.protocolmask != -1)
+                       print_string(PRINT_ANY,
+                                    "protocol", "proto %s ",
+                                    rtnl_rtprot_n2a(r->rtm_protocol,
+                                                    b1, sizeof(b1)));
+
+               if ((r->rtm_scope != RT_SCOPE_UNIVERSE || show_details > 0) &&
+                   filter.scopemask != -1)
+                       print_string(PRINT_ANY,
+                                    "scope", "scope %s ",
+                                    rtnl_rtscope_n2a(r->rtm_scope,
+                                                     b1, sizeof(b1)));
        }
+
        if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) {
+               const char *psrc
+                       = rt_addr_n2a_rta(r->rtm_family, tb[RTA_PREFSRC]);
+
                /* Do not use format_host(). It is our local addr
                   and symbolic name will not be useful.
-                */
-               fprintf(fp, "src %s ",
-                       rt_addr_n2a_rta(r->rtm_family, tb[RTA_PREFSRC]));
+               */
+               if (is_json_context())
+                       print_string(PRINT_JSON, "prefsrc", NULL, psrc);
+               else {
+                       fprintf(fp, "src ");
+                       print_color_string(PRINT_FP,
+                                          ifa_family_color(r->rtm_family),
+                                          NULL, "%s ", psrc);
+               }
+
        }
+
        if (tb[RTA_PRIORITY] && filter.metricmask != -1)
-               fprintf(fp, "metric %u ", rta_getattr_u32(tb[RTA_PRIORITY]));
-       if (r->rtm_flags & RTNH_F_DEAD)
-               fprintf(fp, "dead ");
-       if (r->rtm_flags & RTNH_F_ONLINK)
-               fprintf(fp, "onlink ");
-       if (r->rtm_flags & RTNH_F_PERVASIVE)
-               fprintf(fp, "pervasive ");
-       if (r->rtm_flags & RTNH_F_OFFLOAD)
-               fprintf(fp, "offload ");
-       if (r->rtm_flags & RTM_F_NOTIFY)
-               fprintf(fp, "notify ");
-       if (r->rtm_flags & RTNH_F_LINKDOWN)
-               fprintf(fp, "linkdown ");
-       if (r->rtm_flags & RTNH_F_UNRESOLVED)
-               fprintf(fp, "unresolved ");
+               print_uint(PRINT_ANY, "metric", "metric %u ",
+                          rta_getattr_u32(tb[RTA_PRIORITY]));
+
+       print_rt_flags(fp, r->rtm_flags);
+
        if (tb[RTA_MARK]) {
                unsigned int mark = rta_getattr_u32(tb[RTA_MARK]);
 
                if (mark) {
-                       if (mark >= 16)
-                               fprintf(fp, "mark 0x%x ", mark);
+                       if (is_json_context())
+                               print_uint(PRINT_JSON, "mark", NULL, mark);
+                       else if (mark >= 16)
+                               print_0xhex(PRINT_FP, NULL,
+                                           "mark 0x%x ", mark);
                        else
-                               fprintf(fp, "mark %u ", mark);
+                               print_uint(PRINT_FP, NULL,
+                                          "mark %u ", mark);
                }
        }
 
-       if (tb[RTA_FLOW] && filter.realmmask != ~0U) {
-               __u32 to = rta_getattr_u32(tb[RTA_FLOW]);
-               __u32 from = to>>16;
-
-               to &= 0xFFFF;
-               fprintf(fp, "realm%s ", from ? "s" : "");
-               if (from) {
-                       fprintf(fp, "%s/",
-                               rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
-               }
-               fprintf(fp, "%s ",
-                       rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
-       }
+       if (tb[RTA_FLOW] && filter.realmmask != ~0U)
+               print_rta_flow(fp, tb[RTA_FLOW]);
 
        if (tb[RTA_UID])
-               fprintf(fp, "uid %u ", rta_getattr_u32(tb[RTA_UID]));
+               print_uint(PRINT_ANY, "uid", "uid %u ",
+                          rta_getattr_u32(tb[RTA_UID]));
 
-       if ((r->rtm_flags&RTM_F_CLONED) && r->rtm_family == AF_INET) {
-               __u32 flags = r->rtm_flags&~0xFFFF;
-               int first = 1;
+       if (r->rtm_family == AF_INET) {
+               if (r->rtm_flags & RTM_F_CLONED) {
+                       print_cache_flags(fp, r->rtm_flags);
 
-               fprintf(fp, "%s    cache ", _SL_);
-
-#define PRTFL(fl, flname) if (flags&RTCF_##fl) { \
-  flags &= ~RTCF_##fl; \
-  fprintf(fp, "%s" flname "%s", first ? "<" : "", flags ? "," : "> "); \
-  first = 0; }
-               PRTFL(LOCAL, "local");
-               PRTFL(REJECT, "reject");
-               PRTFL(MULTICAST, "mc");
-               PRTFL(BROADCAST, "brd");
-               PRTFL(DNAT, "dst-nat");
-               PRTFL(SNAT, "src-nat");
-               PRTFL(MASQ, "masq");
-               PRTFL(DIRECTDST, "dst-direct");
-               PRTFL(DIRECTSRC, "src-direct");
-               PRTFL(REDIRECTED, "redirected");
-               PRTFL(DOREDIRECT, "redirect");
-               PRTFL(FAST, "fastroute");
-               PRTFL(NOTIFY, "notify");
-               PRTFL(TPROXY, "proxy");
-
-               if (flags)
-                       fprintf(fp, "%s%x> ", first ? "<" : "", flags);
-               if (tb[RTA_CACHEINFO]) {
-                       struct rta_cacheinfo *ci = RTA_DATA(tb[RTA_CACHEINFO]);
-
-                       if (!hz)
-                               hz = get_user_hz();
-                       if (ci->rta_expires != 0)
-                               fprintf(fp, "expires %dsec ", ci->rta_expires/hz);
-                       if (ci->rta_error != 0)
-                               fprintf(fp, "error %d ", ci->rta_error);
-                       if (show_stats) {
-                               if (ci->rta_clntref)
-                                       fprintf(fp, "users %d ", ci->rta_clntref);
-                               if (ci->rta_used != 0)
-                                       fprintf(fp, "used %d ", ci->rta_used);
-                               if (ci->rta_lastuse != 0)
-                                       fprintf(fp, "age %dsec ", ci->rta_lastuse/hz);
-                       }
-                       if (ci->rta_id)
-                               fprintf(fp, "ipid 0x%04x ", ci->rta_id);
-                       if (ci->rta_ts || ci->rta_tsage)
-                               fprintf(fp, "ts 0x%x tsage %dsec ",
-                                       ci->rta_ts, ci->rta_tsage);
+                       if (tb[RTA_CACHEINFO])
+                               print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
                }
        } else if (r->rtm_family == AF_INET6) {
-               struct rta_cacheinfo *ci = NULL;
-
-               if (tb[RTA_CACHEINFO])
-                       ci = RTA_DATA(tb[RTA_CACHEINFO]);
-               if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
-                       if (!hz)
-                               hz = get_user_hz();
-                       if (r->rtm_flags & RTM_F_CLONED)
-                               fprintf(fp, "%s    cache ", _SL_);
-                       if (ci->rta_expires)
-                               fprintf(fp, "expires %dsec ", ci->rta_expires/hz);
-                       if (ci->rta_error != 0)
-                               fprintf(fp, "error %d ", ci->rta_error);
-                       if (show_stats) {
-                               if (ci->rta_clntref)
-                                       fprintf(fp, "users %d ", ci->rta_clntref);
-                               if (ci->rta_used != 0)
-                                       fprintf(fp, "used %d ", ci->rta_used);
-                               if (ci->rta_lastuse != 0)
-                                       fprintf(fp, "age %dsec ", ci->rta_lastuse/hz);
-                       }
-               } else if (ci) {
-                       if (ci->rta_error != 0)
-                               fprintf(fp, "error %d ", ci->rta_error);
+               if (r->rtm_flags & RTM_F_CLONED) {
+                       if (tb[RTA_CACHEINFO])
+                               print_rta_cacheinfo(fp, RTA_DATA(tb[RTA_CACHEINFO]));
                }
        }
-       if (tb[RTA_METRICS]) {
-               int i;
-               unsigned int mxlock = 0;
-               struct rtattr *mxrta[RTAX_MAX+1];
-
-               parse_rtattr(mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
-                           RTA_PAYLOAD(tb[RTA_METRICS]));
-               if (mxrta[RTAX_LOCK])
-                       mxlock = rta_getattr_u32(mxrta[RTAX_LOCK]);
 
-               for (i = 2; i <= RTAX_MAX; i++) {
-                       __u32 val = 0U;
+       if (tb[RTA_METRICS])
+               print_rta_metrics(fp, tb[RTA_METRICS]);
 
-                       if (mxrta[i] == NULL && !(mxlock & (1 << i)))
-                               continue;
+       if (tb[RTA_IIF] && filter.iifmask != -1)
+               print_rta_if(fp, tb[RTA_IIF], "iif");
 
-                       if (mxrta[i] != NULL && i != RTAX_CC_ALGO)
-                               val = rta_getattr_u32(mxrta[i]);
+       if (tb[RTA_MULTIPATH])
+               print_rta_multipath(fp, r, tb[RTA_MULTIPATH]);
 
-                       if (i == RTAX_HOPLIMIT && (int)val == -1)
-                               continue;
+       if (tb[RTA_PREF])
+               print_rt_pref(fp, rta_getattr_u8(tb[RTA_PREF]));
 
-                       if (i < sizeof(mx_names)/sizeof(char *) && mx_names[i])
-                               fprintf(fp, "%s ", mx_names[i]);
-                       else
-                               fprintf(fp, "metric %d ", i);
-
-                       if (mxlock & (1<<i))
-                               fprintf(fp, "lock ");
-
-                       switch (i) {
-                       case RTAX_FEATURES:
-                               print_rtax_features(fp, val);
-                               break;
-                       default:
-                               fprintf(fp, "%u ", val);
-                               break;
-
-                       case RTAX_RTT:
-                       case RTAX_RTTVAR:
-                       case RTAX_RTO_MIN:
-                               if (i == RTAX_RTT)
-                                       val /= 8;
-                               else if (i == RTAX_RTTVAR)
-                                       val /= 4;
-
-                               if (val >= 1000)
-                                       fprintf(fp, "%gs ", val/1e3);
-                               else
-                                       fprintf(fp, "%ums ", val);
-                               break;
-                       case RTAX_CC_ALGO:
-                               fprintf(fp, "%s ", rta_getattr_str(mxrta[i]));
-                               break;
-                       }
-               }
-       }
-       if (tb[RTA_IIF] && filter.iifmask != -1) {
-               fprintf(fp, "iif %s ",
-                       ll_index_to_name(rta_getattr_u32(tb[RTA_IIF])));
-       }
-       if (tb[RTA_MULTIPATH]) {
-               struct rtnexthop *nh = RTA_DATA(tb[RTA_MULTIPATH]);
-               int first = 1;
-
-               len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
-
-               for (;;) {
-                       if (len < sizeof(*nh))
-                               break;
-                       if (nh->rtnh_len > len)
-                               break;
-                       if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) {
-                               if (first) {
-                                       fprintf(fp, "Oifs: ");
-                                       first = 0;
-                               } else {
-                                       fprintf(fp, " ");
-                               }
-                       } else
-                               fprintf(fp, "%s\tnexthop ", _SL_);
-                       if (nh->rtnh_len > sizeof(*nh)) {
-                               parse_rtattr(tb, RTA_MAX, RTNH_DATA(nh), nh->rtnh_len - sizeof(*nh));
-
-                               if (tb[RTA_ENCAP])
-                                       lwt_print_encap(fp,
-                                                       tb[RTA_ENCAP_TYPE],
-                                                       tb[RTA_ENCAP]);
-                               if (tb[RTA_NEWDST]) {
-                                       fprintf(fp, "as to %s ",
-                                               format_host_rta(r->rtm_family,
-                                                               tb[RTA_NEWDST]));
-                               }
-                               if (tb[RTA_GATEWAY]) {
-                                       fprintf(fp, "via %s ",
-                                               format_host_rta(r->rtm_family,
-                                                               tb[RTA_GATEWAY]));
-                               }
-                               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));
-                               }
-                               if (tb[RTA_FLOW]) {
-                                       __u32 to = rta_getattr_u32(tb[RTA_FLOW]);
-                                       __u32 from = to>>16;
-
-                                       to &= 0xFFFF;
-                                       fprintf(fp, "realm%s ", from ? "s" : "");
-                                       if (from) {
-                                               fprintf(fp, "%s/",
-                                                       rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
-                                       }
-                                       fprintf(fp, "%s ",
-                                               rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
-                               }
-                       }
-                       if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) {
-                               fprintf(fp, "%s", ll_index_to_name(nh->rtnh_ifindex));
-                               if (nh->rtnh_hops != 1)
-                                       fprintf(fp, "(ttl>%d)", nh->rtnh_hops);
-                               fprintf(fp, " ");
-                       } else {
-                               fprintf(fp, "dev %s ", ll_index_to_name(nh->rtnh_ifindex));
-                               if (r->rtm_family != AF_MPLS)
-                                       fprintf(fp, "weight %d ",
-                                               nh->rtnh_hops+1);
-                       }
-                       if (nh->rtnh_flags & RTNH_F_DEAD)
-                               fprintf(fp, "dead ");
-                       if (nh->rtnh_flags & RTNH_F_ONLINK)
-                               fprintf(fp, "onlink ");
-                       if (nh->rtnh_flags & RTNH_F_PERVASIVE)
-                               fprintf(fp, "pervasive ");
-                       if (nh->rtnh_flags & RTNH_F_OFFLOAD)
-                               fprintf(fp, "offload ");
-                       if (nh->rtnh_flags & RTNH_F_LINKDOWN)
-                               fprintf(fp, "linkdown ");
-                       len -= NLMSG_ALIGN(nh->rtnh_len);
-                       nh = RTNH_NEXT(nh);
-               }
-       }
-       if (tb[RTA_PREF]) {
-               unsigned int pref = rta_getattr_u8(tb[RTA_PREF]);
-
-               fprintf(fp, "pref ");
-
-               switch (pref) {
-               case ICMPV6_ROUTER_PREF_LOW:
-                       fprintf(fp, "low");
-                       break;
-               case ICMPV6_ROUTER_PREF_MEDIUM:
-                       fprintf(fp, "medium");
-                       break;
-               case ICMPV6_ROUTER_PREF_HIGH:
-                       fprintf(fp, "high");
-                       break;
-               default:
-                       fprintf(fp, "%u", pref);
-               }
-       }
        if (tb[RTA_TTL_PROPAGATE]) {
-               fprintf(fp, "ttl-propagate ");
-               if (rta_getattr_u8(tb[RTA_TTL_PROPAGATE]))
-                       fprintf(fp, "enabled");
+               bool propogate = rta_getattr_u8(tb[RTA_TTL_PROPAGATE]);
+
+               if (is_json_context())
+                       print_bool(PRINT_JSON, "ttl-propogate", NULL,
+                                  propogate);
                else
-                       fprintf(fp, "disabled");
+                       print_string(PRINT_FP, NULL,
+                                    "ttl-propogate %s",
+                                    propogate ? "enabled" : "disabled");
        }
-       fprintf(fp, "\n");
+
+       print_string(PRINT_FP, NULL, "\n", NULL);
+       close_json_object();
        fflush(fp);
        return 0;
 }
@@ -777,10 +945,9 @@ static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r,
                        }
                } else if (strcmp(*argv, "dev") == 0) {
                        NEXT_ARG();
-                       if ((rtnh->rtnh_ifindex = ll_name_to_index(*argv)) == 0) {
-                               fprintf(stderr, "Cannot find device \"%s\"\n", *argv);
-                               return -1;
-                       }
+                       rtnh->rtnh_ifindex = ll_name_to_index(*argv);
+                       if (!rtnh->rtnh_ifindex)
+                               return nodev(*argv);
                } else if (strcmp(*argv, "weight") == 0) {
                        unsigned int w;
 
@@ -1276,12 +1443,10 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv)
                usage();
 
        if (d) {
-               int idx;
+               int idx = ll_name_to_index(d);
 
-               if ((idx = ll_name_to_index(d)) == 0) {
-                       fprintf(stderr, "Cannot find device \"%s\"\n", d);
-                       return -1;
-               }
+               if (!idx)
+                       return nodev(d);
                addattr32(&req.n, sizeof(req), RTA_OIF, idx);
        }
 
@@ -1421,6 +1586,68 @@ static int save_route_prep(void)
        return 0;
 }
 
+static int iproute_flush(int do_ipv6, rtnl_filter_t filter_fn)
+{
+       time_t start = time(0);
+       char flushb[4096-512];
+       int round = 0;
+       int ret;
+
+       if (filter.cloned) {
+               if (do_ipv6 != AF_INET6) {
+                       iproute_flush_cache();
+                       if (show_stats)
+                               printf("*** IPv4 routing cache is flushed.\n");
+               }
+               if (do_ipv6 == AF_INET)
+                       return 0;
+       }
+
+       filter.flushb = flushb;
+       filter.flushp = 0;
+       filter.flushe = sizeof(flushb);
+
+       for (;;) {
+               if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
+                       perror("Cannot send dump request");
+                       return -2;
+               }
+               filter.flushed = 0;
+               if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
+                       fprintf(stderr, "Flush terminated\n");
+                       return -2;
+               }
+               if (filter.flushed == 0) {
+                       if (show_stats) {
+                               if (round == 0 &&
+                                   (!filter.cloned || do_ipv6 == AF_INET6))
+                                       printf("Nothing to flush.\n");
+                               else
+                                       printf("*** Flush is complete after %d round%s ***\n",
+                                              round, round > 1 ? "s" : "");
+                       }
+                       fflush(stdout);
+                       return 0;
+               }
+               round++;
+               ret = flush_update();
+               if (ret < 0)
+                       return ret;
+
+               if (time(0) - start > 30) {
+                       printf("\n*** Flush not completed after %ld seconds, %d entries remain ***\n",
+                              (long)(time(0) - start), filter.flushed);
+                       return -1;
+               }
+
+               if (show_stats) {
+                       printf("\n*** Round %d, deleting %d entries ***\n",
+                              round, filter.flushed);
+                       fflush(stdout);
+               }
+       }
+}
+
 static int iproute_list_flush_or_save(int argc, char **argv, int action)
 {
        int do_ipv6 = preferred_family;
@@ -1428,7 +1655,6 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
        char *od = NULL;
        unsigned int mark = 0;
        rtnl_filter_t filter_fn;
-       int ret;
 
        if (action == IPROUTE_SAVE) {
                if (save_route_prep())
@@ -1528,8 +1754,8 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
                                invarg("invalid mark value", *argv);
                        filter.markmask = -1;
                } else if (matches(*argv, "metric") == 0 ||
-                          matches(*argv, "priority") == 0 ||
-                          strcmp(*argv, "preference") == 0) {
+                          matches(*argv, "priority") == 0 ||
+                          strcmp(*argv, "preference") == 0) {
                        __u32 metric;
 
                        NEXT_ARG();
@@ -1608,79 +1834,24 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
                int idx;
 
                if (id) {
-                       if ((idx = ll_name_to_index(id)) == 0) {
-                               fprintf(stderr, "Cannot find device \"%s\"\n", id);
-                               return -1;
-                       }
+                       idx = ll_name_to_index(id);
+                       if (!idx)
+                               return nodev(id);
                        filter.iif = idx;
                        filter.iifmask = -1;
                }
                if (od) {
-                       if ((idx = ll_name_to_index(od)) == 0) {
-                               fprintf(stderr, "Cannot find device \"%s\"\n", od);
-                               return -1;
-                       }
+                       idx = ll_name_to_index(od);
+                       if (!idx)
+                               return nodev(od);
                        filter.oif = idx;
                        filter.oifmask = -1;
                }
        }
        filter.mark = mark;
 
-       if (action == IPROUTE_FLUSH) {
-               int round = 0;
-               char flushb[4096-512];
-               time_t start = time(0);
-
-               if (filter.cloned) {
-                       if (do_ipv6 != AF_INET6) {
-                               iproute_flush_cache();
-                               if (show_stats)
-                                       printf("*** IPv4 routing cache is flushed.\n");
-                       }
-                       if (do_ipv6 == AF_INET)
-                               return 0;
-               }
-
-               filter.flushb = flushb;
-               filter.flushp = 0;
-               filter.flushe = sizeof(flushb);
-
-               for (;;) {
-                       if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
-                               perror("Cannot send dump request");
-                               return -2;
-                       }
-                       filter.flushed = 0;
-                       if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
-                               fprintf(stderr, "Flush terminated\n");
-                               return -2;
-                       }
-                       if (filter.flushed == 0) {
-                               if (show_stats) {
-                                       if (round == 0 && (!filter.cloned || do_ipv6 == AF_INET6))
-                                               printf("Nothing to flush.\n");
-                                       else
-                                               printf("*** Flush is complete after %d round%s ***\n", round, round > 1?"s":"");
-                               }
-                               fflush(stdout);
-                               return 0;
-                       }
-                       round++;
-                       if ((ret = flush_update()) < 0)
-                               return ret;
-
-                       if (time(0) - start > 30) {
-                               printf("\n*** Flush not completed after %ld seconds, %d entries remain ***\n",
-                                      (long)(time(0) - start), filter.flushed);
-                               return -1;
-                       }
-
-                       if (show_stats) {
-                               printf("\n*** Round %d, deleting %d entries ***\n", round, filter.flushed);
-                               fflush(stdout);
-                       }
-               }
-       }
+       if (action == IPROUTE_FLUSH)
+               return iproute_flush(do_ipv6, filter_fn);
 
        if (!filter.cloned) {
                if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
@@ -1694,11 +1865,15 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
                }
        }
 
+       new_json_obj(json);
+
        if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
                fprintf(stderr, "Dump terminated\n");
                return -2;
        }
 
+       delete_json_obj();
+       fflush(stdout);
        return 0;
 }
 
@@ -1817,17 +1992,15 @@ static int iproute_get(int argc, char **argv)
                int idx;
 
                if (idev) {
-                       if ((idx = ll_name_to_index(idev)) == 0) {
-                               fprintf(stderr, "Cannot find device \"%s\"\n", idev);
-                               return -1;
-                       }
+                       idx = ll_name_to_index(idev);
+                       if (!idx)
+                               return nodev(idev);
                        addattr32(&req.n, sizeof(req), RTA_IIF, idx);
                }
                if (odev) {
-                       if ((idx = ll_name_to_index(odev)) == 0) {
-                               fprintf(stderr, "Cannot find device \"%s\"\n", odev);
-                               return -1;
-                       }
+                       idx = ll_name_to_index(odev);
+                       if (!idx)
+                               return nodev(odev);
                        addattr32(&req.n, sizeof(req), RTA_OIF, idx);
                }
        }
@@ -2068,6 +2241,8 @@ int do_iproute(int argc, char **argv)
                return iproute_showdump();
        if (matches(*argv, "help") == 0)
                usage();
-       fprintf(stderr, "Command \"%s\" is unknown, try \"ip route help\".\n", *argv);
+
+       fprintf(stderr,
+               "Command \"%s\" is unknown, try \"ip route help\".\n", *argv);
        exit(-1);
 }
index ffa897a3f3dd1c76ef399cffddabee12aafcc0d4..cde9b3d298ecbb96137826e6c172f3398f8f19ba 100644 (file)
@@ -22,9 +22,9 @@
 #include <errno.h>
 
 #include "rt_names.h"
-#include "utils.h"
-#include "iproute_lwtunnel.h"
 #include "bpf_util.h"
+#include "utils.h"
+#include "ip_common.h"
 #include "ila_common.h"
 
 #include <linux/seg6.h>
@@ -94,20 +94,28 @@ static void print_srh(FILE *fp, struct ipv6_sr_hdr *srh)
 {
        int i;
 
-       fprintf(fp, "segs %d [ ", srh->first_segment + 1);
+       if (is_json_context())
+               open_json_array(PRINT_JSON, "segs");
+       else
+               fprintf(fp, "segs %d [ ", srh->first_segment + 1);
 
        for (i = srh->first_segment; i >= 0; i--)
-               fprintf(fp, "%s ",
-                       rt_addr_n2a(AF_INET6, 16, &srh->segments[i]));
+               print_color_string(PRINT_ANY, COLOR_INET6,
+                                  NULL, "%s ",
+                                  rt_addr_n2a(AF_INET6, 16, &srh->segments[i]));
 
-       fprintf(fp, "] ");
+       if (is_json_context())
+               close_json_array(PRINT_JSON, NULL);
+       else
+               fprintf(fp, "] ");
 
        if (sr_has_hmac(srh)) {
                unsigned int offset = ((srh->hdrlen + 1) << 3) - 40;
                struct sr6_tlv_hmac *tlv;
 
                tlv = (struct sr6_tlv_hmac *)((char *)srh + offset);
-               fprintf(fp, "hmac 0x%X ", ntohl(tlv->hmackeyid));
+               print_0xhex(PRINT_ANY, "hmac",
+                           "hmac 0x%X ", ntohl(tlv->hmackeyid));
        }
 }
 
@@ -148,7 +156,8 @@ static void print_encap_seg6(FILE *fp, struct rtattr *encap)
                return;
 
        tuninfo = RTA_DATA(tb[SEG6_IPTUNNEL_SRH]);
-       fprintf(fp, "mode %s ", format_seg6mode_type(tuninfo->mode));
+       print_string(PRINT_ANY, "mode",
+                    "mode %s ", format_seg6mode_type(tuninfo->mode));
 
        print_srh(fp, tuninfo->srh);
 }
@@ -205,36 +214,41 @@ static void print_encap_seg6local(FILE *fp, struct rtattr *encap)
 
        action = rta_getattr_u32(tb[SEG6_LOCAL_ACTION]);
 
-       fprintf(fp, "action %s ", format_action_type(action));
+       print_string(PRINT_ANY, "action",
+                    "action %s ", format_action_type(action));
 
        if (tb[SEG6_LOCAL_SRH]) {
-               fprintf(fp, "srh ");
+               open_json_object("srh");
                print_srh(fp, RTA_DATA(tb[SEG6_LOCAL_SRH]));
+               close_json_object();
        }
 
        if (tb[SEG6_LOCAL_TABLE])
-               fprintf(fp, "table %u ", rta_getattr_u32(tb[SEG6_LOCAL_TABLE]));
+               print_uint(PRINT_ANY, "table",
+                          "table %u ", rta_getattr_u32(tb[SEG6_LOCAL_TABLE]));
 
        if (tb[SEG6_LOCAL_NH4]) {
-               fprintf(fp, "nh4 %s ",
-                       rt_addr_n2a_rta(AF_INET, tb[SEG6_LOCAL_NH4]));
+               print_string(PRINT_ANY, "nh4",
+                            "nh4 %s ", rt_addr_n2a_rta(AF_INET, tb[SEG6_LOCAL_NH4]));
        }
 
        if (tb[SEG6_LOCAL_NH6]) {
-               fprintf(fp, "nh6 %s ",
-                       rt_addr_n2a_rta(AF_INET6, tb[SEG6_LOCAL_NH6]));
+               print_string(PRINT_ANY, "nh6",
+                            "nh6 %s ", rt_addr_n2a_rta(AF_INET6, tb[SEG6_LOCAL_NH6]));
        }
 
        if (tb[SEG6_LOCAL_IIF]) {
                int iif = rta_getattr_u32(tb[SEG6_LOCAL_IIF]);
 
-               fprintf(fp, "iif %s ", ll_index_to_name(iif));
+               print_string(PRINT_ANY, "iif",
+                            "iif %s ", ll_index_to_name(iif));
        }
 
        if (tb[SEG6_LOCAL_OIF]) {
                int oif = rta_getattr_u32(tb[SEG6_LOCAL_OIF]);
 
-               fprintf(fp, "oif %s ", ll_index_to_name(oif));
+               print_string(PRINT_ANY, "oif",
+                            "oif %s ", ll_index_to_name(oif));
        }
 }
 
@@ -245,10 +259,10 @@ static void print_encap_mpls(FILE *fp, struct rtattr *encap)
        parse_rtattr_nested(tb, MPLS_IPTUNNEL_MAX, encap);
 
        if (tb[MPLS_IPTUNNEL_DST])
-               fprintf(fp, " %s ",
+               print_string(PRINT_ANY, "dst", " %s ",
                        format_host_rta(AF_MPLS, tb[MPLS_IPTUNNEL_DST]));
        if (tb[MPLS_IPTUNNEL_TTL])
-               fprintf(fp, "ttl %u ",
+               print_uint(PRINT_ANY, "ttl", "ttl %u ",
                        rta_getattr_u8(tb[MPLS_IPTUNNEL_TTL]));
 }
 
@@ -259,22 +273,26 @@ static void print_encap_ip(FILE *fp, struct rtattr *encap)
        parse_rtattr_nested(tb, LWTUNNEL_IP_MAX, encap);
 
        if (tb[LWTUNNEL_IP_ID])
-               fprintf(fp, "id %llu ",
-                       ntohll(rta_getattr_u64(tb[LWTUNNEL_IP_ID])));
+               print_uint(PRINT_ANY, "id", "id %llu ",
+                          ntohll(rta_getattr_u64(tb[LWTUNNEL_IP_ID])));
 
        if (tb[LWTUNNEL_IP_SRC])
-               fprintf(fp, "src %s ",
-                       rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_SRC]));
+               print_color_string(PRINT_ANY, COLOR_INET,
+                                  "src", "src %s ",
+                                  rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_SRC]));
 
        if (tb[LWTUNNEL_IP_DST])
-               fprintf(fp, "dst %s ",
-                       rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_DST]));
+               print_color_string(PRINT_ANY, COLOR_INET,
+                                  "dst", "dst %s ",
+                                  rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_DST]));
 
        if (tb[LWTUNNEL_IP_TTL])
-               fprintf(fp, "ttl %u ", rta_getattr_u8(tb[LWTUNNEL_IP_TTL]));
+               print_uint(PRINT_ANY, "ttl",
+                          "ttl %u ", rta_getattr_u8(tb[LWTUNNEL_IP_TTL]));
 
        if (tb[LWTUNNEL_IP_TOS])
-               fprintf(fp, "tos %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TOS]));
+               print_uint(PRINT_ANY, "tos",
+                          "tos %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TOS]));
 }
 
 static void print_encap_ila(FILE *fp, struct rtattr *encap)
@@ -288,23 +306,24 @@ static void print_encap_ila(FILE *fp, struct rtattr *encap)
 
                addr64_n2a(rta_getattr_u64(tb[ILA_ATTR_LOCATOR]),
                           abuf, sizeof(abuf));
-               fprintf(fp, " %s ", abuf);
+               print_string(PRINT_ANY, "locator",
+                            " %s ", abuf);
        }
 
        if (tb[ILA_ATTR_CSUM_MODE])
-               fprintf(fp, " csum-mode %s ",
-                       ila_csum_mode2name(rta_getattr_u8(
-                                               tb[ILA_ATTR_CSUM_MODE])));
+               print_string(PRINT_ANY, "csum_mode",
+                            " csum-mode %s ",
+                            ila_csum_mode2name(rta_getattr_u8(tb[ILA_ATTR_CSUM_MODE])));
 
        if (tb[ILA_ATTR_IDENT_TYPE])
-               fprintf(fp, " ident-type %s ",
-                       ila_ident_type2name(rta_getattr_u8(
-                                               tb[ILA_ATTR_IDENT_TYPE])));
+               print_string(PRINT_ANY, "ident_type",
+                            " ident-type %s ",
+                            ila_ident_type2name(rta_getattr_u8(tb[ILA_ATTR_IDENT_TYPE])));
 
        if (tb[ILA_ATTR_HOOK_TYPE])
-               fprintf(fp, " hook-type %s ",
-                       ila_hook_type2name(rta_getattr_u8(
-                                               tb[ILA_ATTR_HOOK_TYPE])));
+               print_string(PRINT_ANY, "hook_type",
+                            " hook-type %s ",
+                            ila_hook_type2name(rta_getattr_u8(tb[ILA_ATTR_HOOK_TYPE])));
 }
 
 static void print_encap_ip6(FILE *fp, struct rtattr *encap)
@@ -314,35 +333,48 @@ static void print_encap_ip6(FILE *fp, struct rtattr *encap)
        parse_rtattr_nested(tb, LWTUNNEL_IP6_MAX, encap);
 
        if (tb[LWTUNNEL_IP6_ID])
-               fprintf(fp, "id %llu ",
-                       ntohll(rta_getattr_u64(tb[LWTUNNEL_IP6_ID])));
+               print_uint(PRINT_ANY, "id", "id %llu ",
+                           ntohll(rta_getattr_u64(tb[LWTUNNEL_IP6_ID])));
 
        if (tb[LWTUNNEL_IP6_SRC])
-               fprintf(fp, "src %s ",
-                       rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_SRC]));
+               print_color_string(PRINT_ANY, COLOR_INET6,
+                                  "src", "src %s ",
+                                  rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_SRC]));
 
        if (tb[LWTUNNEL_IP6_DST])
-               fprintf(fp, "dst %s ",
-                       rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_DST]));
+               print_color_string(PRINT_ANY, COLOR_INET6,
+                                  "dst", "dst %s ",
+                                  rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_DST]));
 
        if (tb[LWTUNNEL_IP6_HOPLIMIT])
-               fprintf(fp, "hoplimit %u ",
-                       rta_getattr_u8(tb[LWTUNNEL_IP6_HOPLIMIT]));
+               print_uint(PRINT_ANY, "hoplimit",
+                          "hoplimit %u ",
+                          rta_getattr_u8(tb[LWTUNNEL_IP6_HOPLIMIT]));
 
        if (tb[LWTUNNEL_IP6_TC])
-               fprintf(fp, "tc %d ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC]));
+               print_uint(PRINT_ANY, "tc",
+                          "tc %u ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC]));
 }
 
 static void print_encap_bpf_prog(FILE *fp, struct rtattr *encap,
                                 const char *str)
 {
        struct rtattr *tb[LWT_BPF_PROG_MAX+1];
+       const char *progname = NULL;
 
        parse_rtattr_nested(tb, LWT_BPF_PROG_MAX, encap);
-       fprintf(fp, "%s ", str);
 
        if (tb[LWT_BPF_PROG_NAME])
-               fprintf(fp, "%s ", rta_getattr_str(tb[LWT_BPF_PROG_NAME]));
+               progname = rta_getattr_str(tb[LWT_BPF_PROG_NAME]);
+
+       if (is_json_context())
+               print_string(PRINT_JSON, str, NULL,
+                            progname ? : "<unknown>");
+       else {
+               fprintf(fp, "%s ", str);
+               if (progname)
+                       fprintf(fp, "%s ", progname);
+       }
 }
 
 static void print_encap_bpf(FILE *fp, struct rtattr *encap)
@@ -358,7 +390,8 @@ static void print_encap_bpf(FILE *fp, struct rtattr *encap)
        if (tb[LWT_BPF_XMIT])
                print_encap_bpf_prog(fp, tb[LWT_BPF_XMIT], "xmit");
        if (tb[LWT_BPF_XMIT_HEADROOM])
-               fprintf(fp, "%d ", rta_getattr_u32(tb[LWT_BPF_XMIT_HEADROOM]));
+               print_uint(PRINT_ANY, "headroom",
+                          " %u ", rta_getattr_u32(tb[LWT_BPF_XMIT_HEADROOM]));
 }
 
 void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
@@ -371,7 +404,7 @@ void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
 
        et = rta_getattr_u16(encap_type);
 
-       fprintf(fp, " encap %s ", format_encap_type(et));
+       print_string(PRINT_ANY, "encap", " encap %s ", format_encap_type(et));
 
        switch (et) {
        case LWTUNNEL_ENCAP_MPLS:
@@ -561,7 +594,7 @@ static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
                                duparg2("iif", *argv);
                        iif = ll_name_to_index(*argv);
                        if (!iif)
-                               invarg("\"iif\" interface not found\n", *argv);
+                               exit(nodev(*argv));
                        rta_addattr32(rta, len, SEG6_LOCAL_IIF, iif);
                } else if (strcmp(*argv, "oif") == 0) {
                        NEXT_ARG();
@@ -569,7 +602,7 @@ static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
                                duparg2("oif", *argv);
                        oif = ll_name_to_index(*argv);
                        if (!oif)
-                               invarg("\"oif\" interface not found\n", *argv);
+                               exit(nodev(*argv));
                        rta_addattr32(rta, len, SEG6_LOCAL_OIF, oif);
                } else if (strcmp(*argv, "srh") == 0) {
                        NEXT_ARG();
diff --git a/ip/iproute_lwtunnel.h b/ip/iproute_lwtunnel.h
deleted file mode 100644 (file)
index be003ce..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __LWTUNNEL_H__
-#define __LETUNNEL_H__ 1
-
-int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp);
-void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
-                    struct rtattr *encap);
-
-#endif
index a3abf2f646731d6217b04544e683152d98b6f9b0..8b9421431c26adc77d8bd32dd3e6970095f4f76d 100644 (file)
@@ -26,6 +26,7 @@
 #include "rt_names.h"
 #include "utils.h"
 #include "ip_common.h"
+#include "json_print.h"
 
 enum list_action {
        IPRULE_LIST,
@@ -46,7 +47,11 @@ static void usage(void)
                "SELECTOR := [ not ] [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK[/MASK] ]\n"
                "            [ iif STRING ] [ oif STRING ] [ pref NUMBER ] [ l3mdev ]\n"
                "            [ uidrange NUMBER-NUMBER ]\n"
+               "            [ ipproto PROTOCOL ]\n"
+               "            [ sport [ NUMBER | NUMBER-NUMBER ]\n"
+               "            [ dport [ NUMBER | NUMBER-NUMBER ] ]\n"
                "ACTION := [ table TABLE_ID ]\n"
+               "          [ protocol PROTO ]\n"
                "          [ nat ADDRESS ]\n"
                "          [ realms [SRCREALM/]DSTREALM ]\n"
                "          [ goto NUMBER ]\n"
@@ -71,27 +76,37 @@ static struct
        struct fib_rule_uid_range range;
        inet_prefix src;
        inet_prefix dst;
+       int protocol;
+       int protocolmask;
 } filter;
 
+static inline int frh_get_table(struct fib_rule_hdr *frh, struct rtattr **tb)
+{
+       __u32 table = frh->table;
+       if (tb[RTA_TABLE])
+               table = rta_getattr_u32(tb[RTA_TABLE]);
+       return table;
+}
+
 static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
 {
-       struct rtmsg *r = NLMSG_DATA(n);
+       struct fib_rule_hdr *frh = NLMSG_DATA(n);
        __u32 table;
 
-       if (preferred_family != AF_UNSPEC && r->rtm_family != preferred_family)
+       if (preferred_family != AF_UNSPEC && frh->family != preferred_family)
                return false;
 
        if (filter.prefmask &&
            filter.pref ^ (tb[FRA_PRIORITY] ? rta_getattr_u32(tb[FRA_PRIORITY]) : 0))
                return false;
-       if (filter.not && !(r->rtm_flags & FIB_RULE_INVERT))
+       if (filter.not && !(frh->flags & FIB_RULE_INVERT))
                return false;
 
        if (filter.src.family) {
                inet_prefix *f_src = &filter.src;
 
-               if (f_src->family != r->rtm_family ||
-                   f_src->bitlen > r->rtm_src_len)
+               if (f_src->family != frh->family ||
+                   f_src->bitlen > frh->src_len)
                        return false;
 
                if (inet_addr_match_rta(f_src, tb[FRA_SRC]))
@@ -101,15 +116,15 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
        if (filter.dst.family) {
                inet_prefix *f_dst = &filter.dst;
 
-               if (f_dst->family != r->rtm_family ||
-                   f_dst->bitlen > r->rtm_dst_len)
+               if (f_dst->family != frh->family ||
+                   f_dst->bitlen > frh->dst_len)
                        return false;
 
                if (inet_addr_match_rta(f_dst, tb[FRA_DST]))
                        return false;
        }
 
-       if (filter.tosmask && filter.tos ^ r->rtm_tos)
+       if (filter.tosmask && filter.tos ^ frh->tos)
                return false;
 
        if (filter.fwmark) {
@@ -159,7 +174,7 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
                        return false;
        }
 
-       table = rtm_get_table(r, tb);
+       table = frh_get_table(frh, tb);
        if (filter.tb > 0 && filter.tb ^ table)
                return false;
 
@@ -168,73 +183,76 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
 
 int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
-       FILE *fp = (FILE *)arg;
-       struct rtmsg *r = NLMSG_DATA(n);
+       FILE *fp = arg;
+       struct fib_rule_hdr *frh = NLMSG_DATA(n);
        int len = n->nlmsg_len;
        int host_len = -1;
-       __u32 table;
+       __u32 table, prio = 0;
        struct rtattr *tb[FRA_MAX+1];
-
        SPRINT_BUF(b1);
 
        if (n->nlmsg_type != RTM_NEWRULE && n->nlmsg_type != RTM_DELRULE)
                return 0;
 
-       len -= NLMSG_LENGTH(sizeof(*r));
+       len -= NLMSG_LENGTH(sizeof(*frh));
        if (len < 0)
                return -1;
 
-       parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len);
+       parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
 
-       host_len = af_bit_len(r->rtm_family);
+       host_len = af_bit_len(frh->family);
 
        if (!filter_nlmsg(n, tb, host_len))
                return 0;
 
+       open_json_object(NULL);
        if (n->nlmsg_type == RTM_DELRULE)
-               fprintf(fp, "Deleted ");
+               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 
        if (tb[FRA_PRIORITY])
-               fprintf(fp, "%u:\t",
-                       rta_getattr_u32(tb[FRA_PRIORITY]));
-       else
-               fprintf(fp, "0:\t");
+               prio = rta_getattr_u32(tb[FRA_PRIORITY]);
+
+       print_uint(PRINT_ANY, "priority", "%u:\t", prio);
 
-       if (r->rtm_flags & FIB_RULE_INVERT)
-               fprintf(fp, "not ");
+       if (frh->flags & FIB_RULE_INVERT)
+               print_null(PRINT_ANY, "not", "not ", NULL);
 
        if (tb[FRA_SRC]) {
-               if (r->rtm_src_len != host_len) {
-                       fprintf(fp, "from %s/%u ",
-                               rt_addr_n2a_rta(r->rtm_family, tb[FRA_SRC]),
-                               r->rtm_src_len);
-               } else {
-                       fprintf(fp, "from %s ",
-                               format_host_rta(r->rtm_family, tb[FRA_SRC]));
-               }
-       } else if (r->rtm_src_len) {
-               fprintf(fp, "from 0/%d ", r->rtm_src_len);
+               const char *src = rt_addr_n2a_rta(frh->family, tb[FRA_SRC]);
+
+               print_string(PRINT_FP, NULL, "from ", NULL);
+               print_color_string(PRINT_ANY, ifa_family_color(frh->family),
+                                  "src", "%s", src);
+               if (frh->src_len != host_len)
+                       print_uint(PRINT_ANY, "srclen", "/%u ", frh->src_len);
+               else
+                       print_string(PRINT_FP, NULL, " ", NULL);
+       } else if (frh->src_len) {
+               print_string(PRINT_ANY, "src", "from %s", "0");
+               print_uint(PRINT_ANY, "srclen", "/%u ", frh->src_len);
        } else {
-               fprintf(fp, "from all ");
+               print_string(PRINT_ANY, "src", "from %s ", "all");
        }
 
        if (tb[FRA_DST]) {
-               if (r->rtm_dst_len != host_len) {
-                       fprintf(fp, "to %s/%u ",
-                               rt_addr_n2a_rta(r->rtm_family, tb[FRA_DST]),
-                               r->rtm_dst_len);
-               } else {
-                       fprintf(fp, "to %s ",
-                               format_host_rta(r->rtm_family, tb[FRA_DST]));
-               }
-       } else if (r->rtm_dst_len) {
-               fprintf(fp, "to 0/%d ", r->rtm_dst_len);
+               const char *dst = rt_addr_n2a_rta(frh->family, tb[FRA_DST]);
+
+               print_string(PRINT_FP, NULL, "to ", NULL);
+               print_color_string(PRINT_ANY, ifa_family_color(frh->family),
+                                  "dst", "%s ", dst);
+               if (frh->dst_len != host_len)
+                       print_uint(PRINT_ANY, "dstlen", "/%u ", frh->dst_len);
+               else
+                       print_string(PRINT_FP, NULL, " ", NULL);
+       } else if (frh->dst_len) {
+               print_string(PRINT_ANY, "dst", "to %s", "0");
+               print_uint(PRINT_ANY, "dstlen", "/%u ", frh->dst_len);
        }
 
-       if (r->rtm_tos) {
-               SPRINT_BUF(b1);
-               fprintf(fp, "tos %s ",
-                       rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
+       if (frh->tos) {
+               print_string(PRINT_ANY, "tos",
+                            "tos %s ",
+                            rtnl_dsfield_n2a(frh->tos, b1, sizeof(b1)));
        }
 
        if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) {
@@ -244,53 +262,107 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                        mark = rta_getattr_u32(tb[FRA_FWMARK]);
 
                if (tb[FRA_FWMASK] &&
-                   (mask = rta_getattr_u32(tb[FRA_FWMASK])) != 0xFFFFFFFF)
-                       fprintf(fp, "fwmark 0x%x/0x%x ", mark, mask);
-               else
-                       fprintf(fp, "fwmark 0x%x ", mark);
+                   (mask = rta_getattr_u32(tb[FRA_FWMASK])) != 0xFFFFFFFF) {
+                       print_0xhex(PRINT_ANY, "fwmark", "fwmark 0x%x", mark);
+                       print_0xhex(PRINT_ANY, "fwmask", "/0x%x ", mask);
+               } else {
+                       print_0xhex(PRINT_ANY, "fwmark", "fwmark 0x%x ", mark);
+               }
        }
 
        if (tb[FRA_IFNAME]) {
-               fprintf(fp, "iif %s ", rta_getattr_str(tb[FRA_IFNAME]));
-               if (r->rtm_flags & FIB_RULE_IIF_DETACHED)
-                       fprintf(fp, "[detached] ");
+               if (!is_json_context())
+                       fprintf(fp, "iif ");
+               print_color_string(PRINT_ANY, COLOR_IFNAME,
+                                  "iif", "%s ",
+                                  rta_getattr_str(tb[FRA_IFNAME]));
+
+               if (frh->flags & FIB_RULE_IIF_DETACHED)
+                       print_null(PRINT_ANY, "iif_detached", "[detached] ",
+                                  NULL);
        }
 
        if (tb[FRA_OIFNAME]) {
-               fprintf(fp, "oif %s ", rta_getattr_str(tb[FRA_OIFNAME]));
-               if (r->rtm_flags & FIB_RULE_OIF_DETACHED)
-                       fprintf(fp, "[detached] ");
+               if (!is_json_context())
+                       fprintf(fp, "oif ");
+
+               print_color_string(PRINT_ANY, COLOR_IFNAME, "oif", "%s ",
+                                  rta_getattr_str(tb[FRA_OIFNAME]));
+
+               if (frh->flags & FIB_RULE_OIF_DETACHED)
+                       print_null(PRINT_ANY, "oif_detached", "[detached] ",
+                                  NULL);
        }
 
        if (tb[FRA_L3MDEV]) {
-               if (rta_getattr_u8(tb[FRA_L3MDEV]))
-                       fprintf(fp, "lookup [l3mdev-table] ");
+               __u8 mdev = rta_getattr_u8(tb[FRA_L3MDEV]);
+
+               if (mdev)
+                       print_null(PRINT_ANY, "l3mdev",
+                                  "lookup [l3mdev-table] ", NULL);
        }
 
        if (tb[FRA_UID_RANGE]) {
                struct fib_rule_uid_range *r = RTA_DATA(tb[FRA_UID_RANGE]);
 
-               fprintf(fp, "uidrange %u-%u ", r->start, r->end);
+               print_uint(PRINT_ANY, "uid_start", "uidrange %u", r->start);
+               print_uint(PRINT_ANY, "uid_end", "-%u ", r->end);
+       }
+
+       if (tb[FRA_IP_PROTO]) {
+               SPRINT_BUF(pbuf);
+               print_string(PRINT_ANY, "ipproto", "ipproto %s ",
+                            inet_proto_n2a(rta_getattr_u8(tb[FRA_IP_PROTO]),
+                                           pbuf, sizeof(pbuf)));
+       }
+
+       if (tb[FRA_SPORT_RANGE]) {
+               struct fib_rule_port_range *r = RTA_DATA(tb[FRA_SPORT_RANGE]);
+
+               if (r->start == r->end) {
+                       print_uint(PRINT_ANY, "sport", "sport %u ", r->start);
+               } else {
+                       print_uint(PRINT_ANY, "sport_start", "sport %u",
+                                  r->start);
+                       print_uint(PRINT_ANY, "sport_end", "-%u ", r->end);
+               }
+       }
+
+       if (tb[FRA_DPORT_RANGE]) {
+               struct fib_rule_port_range *r = RTA_DATA(tb[FRA_DPORT_RANGE]);
+
+               if (r->start == r->end) {
+                       print_uint(PRINT_ANY, "dport", "dport %u ", r->start);
+               } else {
+                       print_uint(PRINT_ANY, "dport_start", "dport %u",
+                                  r->start);
+                       print_uint(PRINT_ANY, "dport_end", "-%u ", r->end);
+               }
        }
 
-       table = rtm_get_table(r, tb);
+       table = frh_get_table(frh, tb);
        if (table) {
-               fprintf(fp, "lookup %s ",
-                       rtnl_rttable_n2a(table, b1, sizeof(b1)));
+               print_string(PRINT_ANY, "table",
+                            "lookup %s ",
+                            rtnl_rttable_n2a(table, b1, sizeof(b1)));
 
                if (tb[FRA_SUPPRESS_PREFIXLEN]) {
                        int pl = rta_getattr_u32(tb[FRA_SUPPRESS_PREFIXLEN]);
 
                        if (pl != -1)
-                               fprintf(fp, "suppress_prefixlength %d ", pl);
+                               print_int(PRINT_ANY, "suppress_prefixlen",
+                                         "suppress_prefixlength %d ", pl);
                }
+
                if (tb[FRA_SUPPRESS_IFGROUP]) {
                        int group = rta_getattr_u32(tb[FRA_SUPPRESS_IFGROUP]);
 
                        if (group != -1) {
-                               SPRINT_BUF(b1);
-                               fprintf(fp, "suppress_ifgroup %s ",
-                                       rtnl_group_n2a(group, b1, sizeof(b1)));
+                               const char *grname
+                                       = rtnl_group_n2a(group, b1, sizeof(b1));
+
+                               print_string(PRINT_ANY, "suppress_ifgroup",
+                                            "suppress_ifgroup %s ", grname);
                        }
                }
        }
@@ -300,37 +372,52 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                __u32 from = to>>16;
 
                to &= 0xFFFF;
-               if (from) {
-                       fprintf(fp, "realms %s/",
-                               rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
-               }
-               fprintf(fp, "%s ",
-                       rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
+               if (from)
+                       print_string(PRINT_ANY,
+                                    "flow_from", "realms %s/",
+                                    rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
+
+               print_string(PRINT_ANY, "flow_to", "%s ",
+                            rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
        }
 
-       if (r->rtm_type == RTN_NAT) {
+       if (frh->action == RTN_NAT) {
                if (tb[RTA_GATEWAY]) {
-                       fprintf(fp, "map-to %s ",
-                               format_host_rta(r->rtm_family,
-                                               tb[RTA_GATEWAY]));
-               } else
-                       fprintf(fp, "masquerade");
-       } else if (r->rtm_type == FR_ACT_GOTO) {
-               fprintf(fp, "goto ");
+                       const char *gateway;
+
+                       gateway = format_host_rta(frh->family, tb[RTA_GATEWAY]);
+
+                       print_string(PRINT_ANY, "nat_gateway",
+                                    "map-to %s ", gateway);
+               } else {
+                       print_null(PRINT_ANY, "masquerade", "masquerade", NULL);
+               }
+       } else if (frh->action == FR_ACT_GOTO) {
                if (tb[FRA_GOTO])
-                       fprintf(fp, "%u", rta_getattr_u32(tb[FRA_GOTO]));
+                       print_uint(PRINT_ANY, "goto", "goto %u",
+                                  rta_getattr_u32(tb[FRA_GOTO]));
                else
-                       fprintf(fp, "none");
-               if (r->rtm_flags & FIB_RULE_UNRESOLVED)
-                       fprintf(fp, " [unresolved]");
-       } else if (r->rtm_type == FR_ACT_NOP)
-               fprintf(fp, "nop");
-       else if (r->rtm_type != RTN_UNICAST)
-               fprintf(fp, "%s",
-                       rtnl_rtntype_n2a(r->rtm_type,
-                                        b1, sizeof(b1)));
-
-       fprintf(fp, "\n");
+                       print_string(PRINT_ANY, "goto", "goto %s", "none");
+
+               if (frh->flags & FIB_RULE_UNRESOLVED)
+                       print_null(PRINT_ANY, "unresolved", "unresolved", NULL);
+       } else if (frh->action == FR_ACT_NOP) {
+               print_null(PRINT_ANY, "nop", "nop", NULL);
+       } else if (frh->action != FR_ACT_TO_TBL) {
+               print_string(PRINT_ANY, "to_tbl", "%s",
+                            rtnl_rtntype_n2a(frh->action, b1, sizeof(b1)));
+       }
+
+       if (tb[FRA_PROTOCOL]) {
+               __u8 protocol = rta_getattr_u8(tb[FRA_PROTOCOL]);
+
+               if ((protocol && protocol != RTPROT_KERNEL) || show_details > 0) {
+                       print_string(PRINT_ANY, "protocol", " proto %s ",
+                                    rtnl_rtprot_n2a(protocol, b1, sizeof(b1)));
+               }
+       }
+       print_string(PRINT_FP, NULL, "\n", "");
+       close_json_object();
        fflush(fp);
        return 0;
 }
@@ -373,15 +460,22 @@ static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n,
                      void *arg)
 {
        struct rtnl_handle rth2;
-       struct rtmsg *r = NLMSG_DATA(n);
+       struct fib_rule_hdr *frh = NLMSG_DATA(n);
        int len = n->nlmsg_len;
        struct rtattr *tb[FRA_MAX+1];
 
-       len -= NLMSG_LENGTH(sizeof(*r));
+       len -= NLMSG_LENGTH(sizeof(*frh));
        if (len < 0)
                return -1;
 
-       parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len);
+       parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
+
+       if (tb[FRA_PROTOCOL]) {
+               __u8 protocol = rta_getattr_u8(tb[FRA_PROTOCOL]);
+
+               if ((filter.protocol ^ protocol) & filter.protocolmask)
+                       return 0;
+       }
 
        if (tb[FRA_PRIORITY]) {
                n->nlmsg_type = RTM_DELRULE;
@@ -407,9 +501,8 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
        if (af == AF_UNSPEC)
                af = AF_INET;
 
-       if (action != IPRULE_LIST && argc > 0) {
-               fprintf(stderr, "\"ip rule %s\" does not take any arguments.\n",
-                               action == IPRULE_SAVE ? "save" : "flush");
+       if (action == IPRULE_SAVE && argc > 0) {
+               fprintf(stderr, "\"ip rule save\" does not take any arguments.\n");
                return -1;
        }
 
@@ -500,7 +593,18 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
                        NEXT_ARG();
                        if (get_prefix(&filter.src, *argv, af))
                                invarg("from value is invalid\n", *argv);
-               } else {
+               } else if (matches(*argv, "protocol") == 0) {
+                       __u32 prot;
+                       NEXT_ARG();
+                       filter.protocolmask = -1;
+                       if (rtnl_rtprot_a2n(&prot, *argv)) {
+                               if (strcmp(*argv, "all") != 0)
+                                       invarg("invalid \"protocol\"\n", *argv);
+                               prot = 0;
+                               filter.protocolmask = 0;
+                       }
+                       filter.protocol = prot;
+               } else{
                        if (matches(*argv, "dst") == 0 ||
                            matches(*argv, "to") == 0) {
                                NEXT_ARG();
@@ -516,10 +620,12 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
                return 1;
        }
 
+       new_json_obj(json);
        if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
                fprintf(stderr, "Dump terminated\n");
                return 1;
        }
+       delete_json_obj();
 
        return 0;
 }
@@ -577,21 +683,19 @@ static int iprule_modify(int cmd, int argc, char **argv)
        __u32 tid = 0;
        struct {
                struct nlmsghdr n;
-               struct rtmsg            r;
+               struct fib_rule_hdr     frh;
                char                    buf[1024];
        } req = {
                .n.nlmsg_type = cmd,
-               .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
+               .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)),
                .n.nlmsg_flags = NLM_F_REQUEST,
-               .r.rtm_family = preferred_family,
-               .r.rtm_protocol = RTPROT_BOOT,
-               .r.rtm_scope = RT_SCOPE_UNIVERSE,
-               .r.rtm_type = RTN_UNSPEC,
+               .frh.family = preferred_family,
+               .frh.action = FR_ACT_UNSPEC,
        };
 
        if (cmd == RTM_NEWRULE) {
                req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
-               req.r.rtm_type = RTN_UNICAST;
+               req.frh.action = FR_ACT_TO_TBL;
        }
 
        if (cmd == RTM_DELRULE && argc == 0) {
@@ -601,21 +705,21 @@ static int iprule_modify(int cmd, int argc, char **argv)
 
        while (argc > 0) {
                if (strcmp(*argv, "not") == 0) {
-                       req.r.rtm_flags |= FIB_RULE_INVERT;
+                       req.frh.flags |= FIB_RULE_INVERT;
                } else if (strcmp(*argv, "from") == 0) {
                        inet_prefix dst;
 
                        NEXT_ARG();
-                       get_prefix(&dst, *argv, req.r.rtm_family);
-                       req.r.rtm_src_len = dst.bitlen;
+                       get_prefix(&dst, *argv, req.frh.family);
+                       req.frh.src_len = dst.bitlen;
                        addattr_l(&req.n, sizeof(req), FRA_SRC,
                                  &dst.data, dst.bytelen);
                } else if (strcmp(*argv, "to") == 0) {
                        inet_prefix dst;
 
                        NEXT_ARG();
-                       get_prefix(&dst, *argv, req.r.rtm_family);
-                       req.r.rtm_dst_len = dst.bitlen;
+                       get_prefix(&dst, *argv, req.frh.family);
+                       req.frh.dst_len = dst.bitlen;
                        addattr_l(&req.n, sizeof(req), FRA_DST,
                                  &dst.data, dst.bytelen);
                } else if (matches(*argv, "preference") == 0 ||
@@ -634,7 +738,7 @@ static int iprule_modify(int cmd, int argc, char **argv)
                        NEXT_ARG();
                        if (rtnl_dsfield_a2n(&tos, *argv))
                                invarg("TOS value is invalid\n", *argv);
-                       req.r.rtm_tos = tos;
+                       req.frh.tos = tos;
                } else if (strcmp(*argv, "fwmark") == 0) {
                        char *slash;
                        __u32 fwmark, fwmask;
@@ -661,15 +765,22 @@ static int iprule_modify(int cmd, int argc, char **argv)
                        if (get_rt_realms_or_raw(&realm, *argv))
                                invarg("invalid realms\n", *argv);
                        addattr32(&req.n, sizeof(req), FRA_FLOW, realm);
+               } else if (matches(*argv, "protocol") == 0) {
+                       __u32 proto;
+
+                       NEXT_ARG();
+                       if (rtnl_rtprot_a2n(&proto, *argv))
+                               invarg("\"protocol\" value is invalid\n", *argv);
+                       addattr8(&req.n, sizeof(req), FRA_PROTOCOL, proto);
                } else if (matches(*argv, "table") == 0 ||
                           strcmp(*argv, "lookup") == 0) {
                        NEXT_ARG();
                        if (rtnl_rttable_a2n(&tid, *argv))
                                invarg("invalid table ID\n", *argv);
                        if (tid < 256)
-                               req.r.rtm_table = tid;
+                               req.frh.table = tid;
                        else {
-                               req.r.rtm_table = RT_TABLE_UNSPEC;
+                               req.frh.table = RT_TABLE_UNSPEC;
                                addattr32(&req.n, sizeof(req), FRA_TABLE, tid);
                        }
                        table_ok = 1;
@@ -724,7 +835,40 @@ static int iprule_modify(int cmd, int argc, char **argv)
                        fprintf(stderr, "Warning: route NAT is deprecated\n");
                        addattr32(&req.n, sizeof(req), RTA_GATEWAY,
                                  get_addr32(*argv));
-                       req.r.rtm_type = RTN_NAT;
+                       req.frh.action = RTN_NAT;
+               } else if (strcmp(*argv, "ipproto") == 0) {
+                       int ipproto;
+
+                       NEXT_ARG();
+                       ipproto = inet_proto_a2n(*argv);
+                       if (ipproto < 0)
+                               invarg("Invalid \"ipproto\" value\n",
+                                      *argv);
+                       addattr8(&req.n, sizeof(req), FRA_IP_PROTO, ipproto);
+               } else if (strcmp(*argv, "sport") == 0) {
+                       struct fib_rule_port_range r;
+                       int ret = 0;
+
+                       NEXT_ARG();
+                       ret = sscanf(*argv, "%hu-%hu", &r.start, &r.end);
+                       if (ret == 1)
+                               r.end = r.start;
+                       else if (ret != 2)
+                               invarg("invalid port range\n", *argv);
+                       addattr_l(&req.n, sizeof(req), FRA_SPORT_RANGE, &r,
+                                 sizeof(r));
+               } else if (strcmp(*argv, "dport") == 0) {
+                       struct fib_rule_port_range r;
+                       int ret = 0;
+
+                       NEXT_ARG();
+                       ret = sscanf(*argv, "%hu-%hu", &r.start, &r.end);
+                       if (ret == 1)
+                               r.end = r.start;
+                       else if (ret != 2)
+                               invarg("invalid dport range\n", *argv);
+                       addattr_l(&req.n, sizeof(req), FRA_DPORT_RANGE, &r,
+                                 sizeof(r));
                } else {
                        int type;
 
@@ -746,7 +890,7 @@ static int iprule_modify(int cmd, int argc, char **argv)
                                type = FR_ACT_NOP;
                        else if (rtnl_rtntype_a2n(&type, *argv))
                                invarg("Failed to parse rule type", *argv);
-                       req.r.rtm_type = type;
+                       req.frh.action = type;
                        table_ok = 1;
                }
                argc--;
@@ -759,11 +903,11 @@ static int iprule_modify(int cmd, int argc, char **argv)
                return -EINVAL;
        }
 
-       if (req.r.rtm_family == AF_UNSPEC)
-               req.r.rtm_family = AF_INET;
+       if (req.frh.family == AF_UNSPEC)
+               req.frh.family = AF_INET;
 
        if (!table_ok && cmd == RTM_NEWRULE)
-               req.r.rtm_table = RT_TABLE_MAIN;
+               req.frh.table = RT_TABLE_MAIN;
 
        if (rtnl_talk(&rth, &req.n, NULL) < 0)
                return -2;
index e3ab31a516b83e55f284acbc63c6d37a1c75dd08..6f5ae4d239f74f097534a47c3bea61ee1e346496 100644 (file)
@@ -26,6 +26,7 @@
 #include "utils.h"
 #include "ip_common.h"
 #include "libgenl.h"
+#include "json_print.h"
 
 #define HMAC_KEY_PROMPT "Enter secret for HMAC key ID (blank to delete): "
 
@@ -55,12 +56,54 @@ static struct {
        __u8 alg_id;
 } opts;
 
+static void print_dumphmac(struct rtattr *attrs[])
+{
+       char secret[64];
+       char *algstr;
+       __u8 slen = rta_getattr_u8(attrs[SEG6_ATTR_SECRETLEN]);
+       __u8 alg_id = rta_getattr_u8(attrs[SEG6_ATTR_ALGID]);
+
+       memset(secret, 0, 64);
+
+       if (slen > 63) {
+               fprintf(stderr, "HMAC secret length %d > 63, truncated\n", slen);
+               slen = 63;
+       }
+
+       memcpy(secret, RTA_DATA(attrs[SEG6_ATTR_SECRET]), slen);
+
+       switch (alg_id) {
+       case SEG6_HMAC_ALGO_SHA1:
+               algstr = "sha1";
+               break;
+       case SEG6_HMAC_ALGO_SHA256:
+               algstr = "sha256";
+               break;
+       default:
+               algstr = "<unknown>";
+       }
+
+       print_uint(PRINT_ANY, "hmac", "hmac %u ",
+                  rta_getattr_u32(attrs[SEG6_ATTR_HMACKEYID]));
+       print_string(PRINT_ANY, "algo", "algo %s ", algstr);
+       print_string(PRINT_ANY, "secret", "secret \"%s\"\n", secret);
+}
+
+static void print_tunsrc(struct rtattr *attrs[])
+{
+       const char *dst
+               = rt_addr_n2a(AF_INET6, 16,
+                             RTA_DATA(attrs[SEG6_ATTR_DST]));
+
+       print_string(PRINT_ANY, "tunsrc",
+                    "tunsrc addr %s\n", dst);
+}
+
 static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
                       void *arg)
 {
        struct rtattr *attrs[SEG6_ATTR_MAX + 1];
        struct genlmsghdr *ghdr;
-       FILE *fp = (FILE *)arg;
        int len = n->nlmsg_len;
 
        if (n->nlmsg_type != genl_family)
@@ -74,50 +117,17 @@ static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
 
        parse_rtattr(attrs, SEG6_ATTR_MAX, (void *)ghdr + GENL_HDRLEN, len);
 
+       open_json_object(NULL);
        switch (ghdr->cmd) {
        case SEG6_CMD_DUMPHMAC:
-       {
-               char secret[64];
-               char *algstr;
-               __u8 slen = rta_getattr_u8(attrs[SEG6_ATTR_SECRETLEN]);
-               __u8 alg_id = rta_getattr_u8(attrs[SEG6_ATTR_ALGID]);
-
-               memset(secret, 0, 64);
-
-               if (slen > 63) {
-                       fprintf(stderr, "HMAC secret length %d > 63, "
-                                       "truncated\n", slen);
-                       slen = 63;
-               }
-               memcpy(secret, RTA_DATA(attrs[SEG6_ATTR_SECRET]), slen);
-
-               switch (alg_id) {
-               case SEG6_HMAC_ALGO_SHA1:
-                       algstr = "sha1";
-                       break;
-               case SEG6_HMAC_ALGO_SHA256:
-                       algstr = "sha256";
-                       break;
-               default:
-                       algstr = "<unknown>";
-               }
-
-               fprintf(fp, "hmac %u ",
-                       rta_getattr_u32(attrs[SEG6_ATTR_HMACKEYID]));
-               fprintf(fp, "algo %s ", algstr);
-               fprintf(fp, "secret \"%s\" ", secret);
-
-               fprintf(fp, "\n");
+               print_dumphmac(attrs);
                break;
-       }
+
        case SEG6_CMD_GET_TUNSRC:
-       {
-               fprintf(fp, "tunsrc addr %s\n",
-                       rt_addr_n2a(AF_INET6, 16,
-                                   RTA_DATA(attrs[SEG6_ATTR_DST])));
+               print_tunsrc(attrs);
                break;
        }
-       }
+       close_json_object();
 
        return 0;
 }
@@ -169,10 +179,12 @@ static int seg6_do_cmd(void)
        } else if (repl) {
                if (rtnl_talk(&grth, &req.n, &answer) < 0)
                        return -2;
+               new_json_obj(json);
                if (process_msg(NULL, answer, stdout) < 0) {
                        fprintf(stderr, "Error parsing reply\n");
                        exit(1);
                }
+               delete_json_obj();
                free(answer);
        } else {
                req.n.nlmsg_flags |= NLM_F_DUMP;
@@ -182,10 +194,13 @@ static int seg6_do_cmd(void)
                        exit(1);
                }
 
+               new_json_obj(json);
                if (rtnl_dump_filter(&grth, process_msg, stdout) < 0) {
                        fprintf(stderr, "Dump terminated\n");
                        exit(1);
                }
+               delete_json_obj();
+               fflush(stdout);
        }
 
        return 0;
index 48cc14b502c6c1a175899ddfaa430be24c7bd806..fb64da4ec26224fad8a1f73630b100062d4b075c 100644 (file)
@@ -25,6 +25,7 @@
 #include "rt_names.h"
 #include "utils.h"
 #include "ip_common.h"
+#include "json_print.h"
 
 extern struct rtnl_handle rth;
 
@@ -77,9 +78,17 @@ static int print_token(const struct sockaddr_nl *who, struct nlmsghdr *n, void *
                return -1;
        }
 
-       fprintf(fp, "token %s dev %s\n",
-               format_host_rta(ifi->ifi_family, ltb[IFLA_INET6_TOKEN]),
-               ll_index_to_name(ifi->ifi_index));
+       open_json_object(NULL);
+       print_string(PRINT_FP, NULL, "token ", NULL);
+       print_color_string(PRINT_ANY,
+                          ifa_family_color(ifi->ifi_family),
+                          "token", "%s",
+                          format_host_rta(ifi->ifi_family, ltb[IFLA_INET6_TOKEN]));
+       print_string(PRINT_FP, NULL, " dev ", NULL);
+       print_color_string(PRINT_ANY, COLOR_IFNAME,
+                          "ifname", "%s\n",
+                          ll_index_to_name(ifi->ifi_index));
+       close_json_object();
        fflush(fp);
 
        return 0;
@@ -105,10 +114,13 @@ static int iptoken_list(int argc, char **argv)
                return -1;
        }
 
+       new_json_obj(json);
        if (rtnl_dump_filter(&rth, print_token, &da) < 0) {
+               delete_json_obj();
                fprintf(stderr, "Dump terminated\n");
                return -1;
        }
+       delete_json_obj();
 
        return 0;
 }
index 0aa3b332e6cff73d806c66578b750d64f1af17b2..d597908fa209e63bb7928ab87fac2640fdd6e199 100644 (file)
@@ -213,10 +213,8 @@ static int parse_args(int argc, char **argv, int cmd, struct ip_tunnel_parm *p)
 
        if (medium) {
                p->link = ll_name_to_index(medium);
-               if (p->link == 0) {
-                       fprintf(stderr, "Cannot find device \"%s\"\n", medium);
-                       return -1;
-               }
+               if (!p->link)
+                       return nodev(medium);
        }
 
        if (p->i_key == 0 && IN_MULTICAST(ntohl(p->iph.daddr))) {
@@ -286,8 +284,9 @@ static int do_del(int argc, char **argv)
        return tnl_del_ioctl(tnl_defname(&p) ? : p.name, p.name, &p);
 }
 
-static void print_tunnel(struct ip_tunnel_parm *p)
+static void print_tunnel(const void *t)
 {
+       const struct ip_tunnel_parm *p = t;
        struct ip_tunnel_6rd ip6rd = {};
        char s1[1024];
        char s2[1024];
@@ -373,86 +372,52 @@ static void print_tunnel(struct ip_tunnel_parm *p)
                printf("%s  Checksum output packets.", _SL_);
 }
 
-static int do_tunnels_list(struct ip_tunnel_parm *p)
-{
-       char buf[512];
-       int err = -1;
-       FILE *fp = fopen("/proc/net/dev", "r");
 
-       if (fp == NULL) {
-               perror("fopen");
-               return -1;
-       }
+static void ip_tunnel_parm_initialize(const struct tnl_print_nlmsg_info *info)
+{
+       struct ip_tunnel_parm *p2 = info->p2;
 
-       /* skip header lines */
-       if (!fgets(buf, sizeof(buf), fp) ||
-           !fgets(buf, sizeof(buf), fp)) {
-               fprintf(stderr, "/proc/net/dev read error\n");
-               goto end;
-       }
+       memset(p2, 0, sizeof(*p2));
+}
 
-       while (fgets(buf, sizeof(buf), fp) != NULL) {
-               char name[IFNAMSIZ];
-               int index, type;
-               struct ip_tunnel_parm p1 = {};
-               char *ptr;
-
-               buf[sizeof(buf) - 1] = 0;
-               ptr = strchr(buf, ':');
-               if (ptr == NULL ||
-                   (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {
-                       fprintf(stderr, "Wrong format for /proc/net/dev. Giving up.\n");
-                       goto end;
-               }
-               if (p->name[0] && strcmp(p->name, name))
-                       continue;
-               index = ll_name_to_index(name);
-               if (index == 0)
-                       continue;
-               type = ll_index_to_type(index);
-               if (type == -1) {
-                       fprintf(stderr, "Failed to get type of \"%s\"\n", name);
-                       continue;
-               }
-               if (type != ARPHRD_TUNNEL && type != ARPHRD_IPGRE && type != ARPHRD_SIT)
-                       continue;
-               if (tnl_get_ioctl(name, &p1))
-                       continue;
-               if ((p->link && p1.link != p->link) ||
-                   (p->name[0] && strcmp(p1.name, p->name)) ||
-                   (p->iph.daddr && p1.iph.daddr != p->iph.daddr) ||
-                   (p->iph.saddr && p1.iph.saddr != p->iph.saddr) ||
-                   (p->i_key && p1.i_key != p->i_key))
-                       continue;
-               print_tunnel(&p1);
-               if (show_stats)
-                       tnl_print_stats(ptr);
-               printf("\n");
-       }
-       err = 0;
- end:
-       fclose(fp);
-       return err;
+static bool ip_tunnel_parm_match(const struct tnl_print_nlmsg_info *info)
+{
+       const struct ip_tunnel_parm *p1 = info->p1;
+       const struct ip_tunnel_parm *p2 = info->p2;
+
+       return ((!p1->link || p1->link == p2->link) &&
+               (!p1->name[0] || strcmp(p1->name, p2->name) == 0) &&
+               (!p1->iph.daddr || p1->iph.daddr == p2->iph.daddr) &&
+               (!p1->iph.saddr || p1->iph.saddr == p2->iph.saddr) &&
+               (!p1->i_key || p1->i_key == p2->i_key));
 }
 
 static int do_show(int argc, char **argv)
 {
-       struct ip_tunnel_parm p;
+       struct ip_tunnel_parm p, p1;
        const char *basedev;
 
-       ll_init_map(&rth);
        if (parse_args(argc, argv, SIOCGETTUNNEL, &p) < 0)
                return -1;
 
        basedev = tnl_defname(&p);
-       if (!basedev)
-               return do_tunnels_list(&p);
+       if (!basedev) {
+               struct tnl_print_nlmsg_info info = {
+                       .p1    = &p,
+                       .p2    = &p1,
+                       .init  = ip_tunnel_parm_initialize,
+                       .match = ip_tunnel_parm_match,
+                       .print = print_tunnel,
+               };
+
+               return do_tunnels_list(&info);
+       }
 
        if (tnl_get_ioctl(p.name[0] ? p.name : basedev, &p))
                return -1;
 
        print_tunnel(&p);
-       printf("\n");
+       fputc('\n', stdout);
        return 0;
 }
 
index 09f2be2426b05b6bf5a38fad186e05ea8b4df081..6c5a7259d15573bd7763686163afd5d50d28af22 100644 (file)
@@ -20,6 +20,7 @@
 #include <sys/ioctl.h>
 #include <linux/if.h>
 #include <linux/if_tun.h>
+#include <linux/if_arp.h>
 #include <pwd.h>
 #include <grp.h>
 #include <fcntl.h>
@@ -31,6 +32,8 @@
 #include "utils.h"
 #include "ip_common.h"
 
+static const char drv_name[] = "tun";
+
 #define TUNDEV "/dev/net/tun"
 
 static void usage(void) __attribute__((noreturn));
@@ -225,24 +228,35 @@ static int do_del(int argc, char **argv)
 
 static void print_flags(long flags)
 {
+       open_json_array(PRINT_JSON, "flags");
+
        if (flags & IFF_TUN)
-               printf(" tun");
+               print_string(PRINT_ANY, NULL, " %s", "tun");
 
        if (flags & IFF_TAP)
-               printf(" tap");
+               print_string(PRINT_ANY, NULL, " %s", "tap");
 
        if (!(flags & IFF_NO_PI))
-               printf(" pi");
+               print_string(PRINT_ANY, NULL, " %s", "pi");
 
        if (flags & IFF_ONE_QUEUE)
-               printf(" one_queue");
+               print_string(PRINT_ANY, NULL, " %s", "one_queue");
 
        if (flags & IFF_VNET_HDR)
-               printf(" vnet_hdr");
+               print_string(PRINT_ANY, NULL, " %s", "vnet_hdr");
+
+       if (flags & IFF_PERSIST)
+               print_string(PRINT_ANY, NULL, " %s", "persist");
 
-       flags &= ~(IFF_TUN|IFF_TAP|IFF_NO_PI|IFF_ONE_QUEUE|IFF_VNET_HDR);
+       if (!(flags & IFF_NOFILTER))
+               print_string(PRINT_ANY, NULL, " %s", "filter");
+
+       flags &= ~(IFF_TUN | IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE |
+                  IFF_VNET_HDR | IFF_PERSIST | IFF_NOFILTER);
        if (flags)
-               printf(" UNKNOWN_FLAGS:%lx", flags);
+               print_0xhex(PRINT_ANY, NULL, "%#x", flags);
+
+       close_json_array(PRINT_JSON, NULL);
 }
 
 static char *pid_name(pid_t pid)
@@ -285,6 +299,8 @@ static void show_processes(const char *name)
        if (err)
                return;
 
+       open_json_array(PRINT_JSON, "processes");
+
        fd_path = globbuf.gl_pathv;
        while (*fd_path) {
                const char *dev_net_tun = "/dev/net/tun";
@@ -331,7 +347,11 @@ static void show_processes(const char *name)
                                   !strcmp(name, value)) {
                                char *pname = pid_name(pid);
 
-                               printf(" %s(%d)", pname ? : "<NULL>", pid);
+                               print_string(PRINT_ANY, "name",
+                                            "%s", pname ? : "<NULL>");
+
+                               print_uint(PRINT_ANY, "pid",
+                                          "(%d)", pid);
                                free(pname);
                        }
 
@@ -344,47 +364,117 @@ static void show_processes(const char *name)
 next:
                ++fd_path;
        }
+       close_json_array(PRINT_JSON, NULL);
 
        globfree(&globbuf);
 }
 
+static int tuntap_filter_req(struct nlmsghdr *nlh, int reqlen)
+{
+       struct rtattr *linkinfo;
+       int err;
 
-static int do_show(int argc, char **argv)
+       linkinfo = addattr_nest(nlh, reqlen, IFLA_LINKINFO);
+
+       err = addattr_l(nlh, reqlen, IFLA_INFO_KIND,
+                       drv_name, sizeof(drv_name) - 1);
+       if (err)
+               return err;
+
+       addattr_nest_end(nlh, linkinfo);
+
+       return 0;
+}
+
+static int print_tuntap(const struct sockaddr_nl *who,
+                       struct nlmsghdr *n, void *arg)
 {
-       DIR *dir;
-       struct dirent *d;
+       struct ifinfomsg *ifi = NLMSG_DATA(n);
+       struct rtattr *tb[IFLA_MAX+1];
+       struct rtattr *linkinfo[IFLA_INFO_MAX+1];
+       const char *name, *kind;
        long flags, owner = -1, group = -1;
 
-       dir = opendir("/sys/class/net");
-       if (!dir) {
-               perror("opendir");
+       if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK)
+               return 0;
+
+       if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*ifi)))
                return -1;
+
+       switch (ifi->ifi_type) {
+       case ARPHRD_NONE:
+       case ARPHRD_ETHER:
+               break;
+       default:
+               return 0;
        }
-       while ((d = readdir(dir))) {
-               if (d->d_name[0] == '.' &&
-                   (d->d_name[1] == 0 || d->d_name[1] == '.'))
-                       continue;
-
-               if (read_prop(d->d_name, "tun_flags", &flags))
-                       continue;
-
-               read_prop(d->d_name, "owner", &owner);
-               read_prop(d->d_name, "group", &group);
-
-               printf("%s:", d->d_name);
-               print_flags(flags);
-               if (owner != -1)
-                       printf(" user %ld", owner);
-               if (group != -1)
-                       printf(" group %ld", group);
-               printf("\n");
-               if (show_details) {
-                       printf("\tAttached to processes:");
-                       show_processes(d->d_name);
-                       printf("\n");
-               }
+
+       parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
+
+       if (!tb[IFLA_IFNAME])
+               return 0;
+
+       if (!tb[IFLA_LINKINFO])
+               return 0;
+
+       parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
+
+       if (!linkinfo[IFLA_INFO_KIND])
+               return 0;
+
+       kind = rta_getattr_str(linkinfo[IFLA_INFO_KIND]);
+       if (strcmp(kind, drv_name))
+               return 0;
+
+       name = rta_getattr_str(tb[IFLA_IFNAME]);
+
+       if (read_prop(name, "tun_flags", &flags))
+               return 0;
+       if (read_prop(name, "owner", &owner))
+               return 0;
+       if (read_prop(name, "group", &group))
+               return 0;
+
+       open_json_object(NULL);
+       print_color_string(PRINT_ANY, COLOR_IFNAME,
+                          "ifname", "%s:", name);
+       print_flags(flags);
+       if (owner != -1)
+               print_uint(PRINT_ANY, "user",
+                          " user %ld", owner);
+       if (group != -1)
+               print_uint(PRINT_ANY, "group",
+                          " group %ld", group);
+
+       if (show_details) {
+               print_string(PRINT_FP, NULL,
+                            "%s\tAttached to processes:", _SL_);
+               show_processes(name);
        }
-       closedir(dir);
+       close_json_object();
+       print_string(PRINT_FP, NULL, "%s", "\n");
+
+       return 0;
+}
+
+static int do_show(int argc, char **argv)
+{
+       if (rtnl_wilddump_req_filter_fn(&rth, AF_UNSPEC, RTM_GETLINK,
+                                       tuntap_filter_req) < 0) {
+               perror("Cannot send dump request\n");
+               return -1;
+       }
+
+       new_json_obj(json);
+
+       if (rtnl_dump_filter(&rth, print_tuntap, NULL) < 0) {
+               fprintf(stderr, "Dump terminated\n");
+               return -1;
+       }
+
+       delete_json_obj();
+       fflush(stdout);
+
        return 0;
 }
 
@@ -408,3 +498,102 @@ int do_iptuntap(int argc, char **argv)
                *argv);
        exit(-1);
 }
+
+static void print_owner(FILE *f, uid_t uid)
+{
+       struct passwd *pw = getpwuid(uid);
+
+       if (pw)
+               print_string(PRINT_ANY, "user", "user %s ", pw->pw_name);
+       else
+               print_uint(PRINT_ANY, "user", "user %u ", uid);
+}
+
+static void print_group(FILE *f, gid_t gid)
+{
+       struct group *group = getgrgid(gid);
+
+       if (group)
+               print_string(PRINT_ANY, "group", "group %s ", group->gr_name);
+       else
+               print_uint(PRINT_ANY, "group", "group %u ", gid);
+}
+
+static void print_mq(FILE *f, struct rtattr *tb[])
+{
+       if (!tb[IFLA_TUN_MULTI_QUEUE] ||
+           !rta_getattr_u8(tb[IFLA_TUN_MULTI_QUEUE])) {
+               if (is_json_context())
+                       print_bool(PRINT_JSON, "multi_queue", NULL, false);
+               return;
+       }
+
+       print_bool(PRINT_ANY, "multi_queue", "multi_queue ", true);
+
+       if (tb[IFLA_TUN_NUM_QUEUES]) {
+               print_uint(PRINT_ANY, "numqueues", "numqueues %u ",
+                          rta_getattr_u32(tb[IFLA_TUN_NUM_QUEUES]));
+       }
+
+       if (tb[IFLA_TUN_NUM_DISABLED_QUEUES]) {
+               print_uint(PRINT_ANY, "numdisabled", "numdisabled %u ",
+                          rta_getattr_u32(tb[IFLA_TUN_NUM_DISABLED_QUEUES]));
+       }
+}
+
+static void print_onoff(FILE *f, const char *flag, __u8 val)
+{
+       if (is_json_context())
+               print_bool(PRINT_JSON, flag, NULL, !!val);
+       else
+               fprintf(f, "%s %s ", flag, val ? "on" : "off");
+}
+
+static void print_type(FILE *f, __u8 type)
+{
+       SPRINT_BUF(buf);
+       const char *str = buf;
+
+       if (type == IFF_TUN)
+               str = "tun";
+       else if (type == IFF_TAP)
+               str = "tap";
+       else
+               snprintf(buf, sizeof(buf), "UNKNOWN:%hhu", type);
+
+       print_string(PRINT_ANY, "type", "type %s ", str);
+}
+
+static void tun_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+{
+       if (!tb)
+               return;
+
+       if (tb[IFLA_TUN_TYPE])
+               print_type(f, rta_getattr_u8(tb[IFLA_TUN_TYPE]));
+
+       if (tb[IFLA_TUN_PI])
+               print_onoff(f, "pi", rta_getattr_u8(tb[IFLA_TUN_PI]));
+
+       if (tb[IFLA_TUN_VNET_HDR]) {
+               print_onoff(f, "vnet_hdr",
+                           rta_getattr_u8(tb[IFLA_TUN_VNET_HDR]));
+       }
+
+       print_mq(f, tb);
+
+       if (tb[IFLA_TUN_PERSIST])
+               print_onoff(f, "persist", rta_getattr_u8(tb[IFLA_TUN_PERSIST]));
+
+       if (tb[IFLA_TUN_OWNER])
+               print_owner(f, rta_getattr_u32(tb[IFLA_TUN_OWNER]));
+
+       if (tb[IFLA_TUN_GROUP])
+               print_group(f, rta_getattr_u32(tb[IFLA_TUN_GROUP]));
+}
+
+struct link_util tun_link_util = {
+       .id = "tun",
+       .maxattr = IFLA_TUN_MAX,
+       .print_opt = tun_print_opt,
+};
index 8fb8fe5d679294de290d05f1418496f9044d85fc..bc1cee8fbca2ab0c811c99c431fbc753bec7d52d 100644 (file)
 #include "ip_common.h"
 #include "tunnel.h"
 
-static void print_usage(FILE *f)
+static void gre_print_help(struct link_util *lu, int argc, char **argv, FILE *f)
 {
        fprintf(f,
-               "Usage: ... { gre | gretap | erspan } [ remote ADDR ]\n"
-               "                            [ local ADDR ]\n"
-               "                            [ [i|o]seq ]\n"
-               "                            [ [i|o]key KEY ]\n"
-               "                            [ [i|o]csum ]\n"
-               "                            [ ttl TTL ]\n"
-               "                            [ tos TOS ]\n"
-               "                            [ [no]pmtudisc ]\n"
-               "                            [ [no]ignore-df ]\n"
-               "                            [ dev PHYS_DEV ]\n"
-               "                            [ noencap ]\n"
-               "                            [ encap { fou | gue | none } ]\n"
-               "                            [ encap-sport PORT ]\n"
-               "                            [ encap-dport PORT ]\n"
-               "                            [ [no]encap-csum ]\n"
-               "                            [ [no]encap-csum6 ]\n"
-               "                            [ [no]encap-remcsum ]\n"
-               "                            [ external ]\n"
-               "                            [ fwmark MARK ]\n"
-               "                            [ erspan_ver version ]\n"
-               "                            [ erspan IDX ]\n"
-               "                            [ erspan_dir { ingress | egress } ]\n"
-               "                            [ erspan_hwid hwid ]\n"
-               "                            [ external ]\n"
+               "Usage: ... %-9s [ remote ADDR ]\n",
+               lu->id
+       );
+       fprintf(f,
+               "                     [ local ADDR ]\n"
+               "                     [ [i|o]seq ]\n"
+               "                     [ [i|o]key KEY ]\n"
+               "                     [ [i|o]csum ]\n"
+               "                     [ ttl TTL ]\n"
+               "                     [ tos TOS ]\n"
+               "                     [ [no]pmtudisc ]\n"
+               "                     [ [no]ignore-df ]\n"
+               "                     [ dev PHYS_DEV ]\n"
+               "                     [ fwmark MARK ]\n"
+               "                     [ external ]\n"
+               "                     [ noencap ]\n"
+               "                     [ encap { fou | gue | none } ]\n"
+               "                     [ encap-sport PORT ]\n"
+               "                     [ encap-dport PORT ]\n"
+               "                     [ [no]encap-csum ]\n"
+               "                     [ [no]encap-csum6 ]\n"
+               "                     [ [no]encap-remcsum ]\n"
+               "                     [ erspan_ver version ]\n"
+               "                     [ erspan IDX ]\n"
+               "                     [ erspan_dir { ingress | egress } ]\n"
+               "                     [ erspan_hwid hwid ]\n"
                "\n"
+       );
+       fprintf(f,
                "Where: ADDR := { IP_ADDRESS | any }\n"
                "       TOS  := { NUMBER | inherit }\n"
                "       TTL  := { 1..255 | inherit }\n"
@@ -59,17 +63,10 @@ static void print_usage(FILE *f)
        );
 }
 
-static void usage(void) __attribute__((noreturn));
-static void usage(void)
-{
-       print_usage(stderr);
-       exit(-1);
-}
-
 static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
                         struct nlmsghdr *n)
 {
-       struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
+       struct ifinfomsg *ifi = NLMSG_DATA(n);
        struct {
                struct nlmsghdr n;
                struct ifinfomsg i;
@@ -84,30 +81,34 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
        struct rtattr *tb[IFLA_MAX + 1];
        struct rtattr *linkinfo[IFLA_INFO_MAX+1];
        struct rtattr *greinfo[IFLA_GRE_MAX + 1];
+       int len;
        __u16 iflags = 0;
        __u16 oflags = 0;
        __be32 ikey = 0;
        __be32 okey = 0;
-       unsigned int saddr = 0;
-       unsigned int daddr = 0;
-       unsigned int link = 0;
+       inet_prefix saddr, daddr;
        __u8 pmtudisc = 1;
-       __u8 ttl = 0;
+       __u8 ignore_df = 0;
        __u8 tos = 0;
-       int len;
+       __u8 ttl = 0;
+       __u32 link = 0;
        __u16 encaptype = 0;
        __u16 encapflags = 0;
        __u16 encapsport = 0;
        __u16 encapdport = 0;
        __u8 metadata = 0;
-       __u8 ignore_df = 0;
        __u32 fwmark = 0;
        __u32 erspan_idx = 0;
        __u8 erspan_ver = 0;
        __u8 erspan_dir = 0;
        __u16 erspan_hwid = 0;
 
+       inet_prefix_reset(&saddr);
+       inet_prefix_reset(&daddr);
+
        if (!(n->nlmsg_flags & NLM_F_CREATE)) {
+               const struct rtattr *rta;
+
                if (rtnl_talk(&rth, &req.n, &answer) < 0) {
 get_failed:
                        fprintf(stderr,
@@ -133,6 +134,14 @@ get_failed:
                parse_rtattr_nested(greinfo, IFLA_GRE_MAX,
                                    linkinfo[IFLA_INFO_DATA]);
 
+               rta = greinfo[IFLA_GRE_LOCAL];
+               if (rta && get_addr_rta(&saddr, rta, AF_INET))
+                       goto get_failed;
+
+               rta = greinfo[IFLA_GRE_REMOTE];
+               if (rta && get_addr_rta(&daddr, rta, AF_INET))
+                       goto get_failed;
+
                if (greinfo[IFLA_GRE_IKEY])
                        ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]);
 
@@ -145,41 +154,38 @@ get_failed:
                if (greinfo[IFLA_GRE_OFLAGS])
                        oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]);
 
-               if (greinfo[IFLA_GRE_LOCAL])
-                       saddr = rta_getattr_u32(greinfo[IFLA_GRE_LOCAL]);
-
-               if (greinfo[IFLA_GRE_REMOTE])
-                       daddr = rta_getattr_u32(greinfo[IFLA_GRE_REMOTE]);
-
                if (greinfo[IFLA_GRE_PMTUDISC])
                        pmtudisc = rta_getattr_u8(
                                greinfo[IFLA_GRE_PMTUDISC]);
 
-               if (greinfo[IFLA_GRE_TTL])
-                       ttl = rta_getattr_u8(greinfo[IFLA_GRE_TTL]);
+               if (greinfo[IFLA_GRE_IGNORE_DF])
+                       ignore_df =
+                               !!rta_getattr_u8(greinfo[IFLA_GRE_IGNORE_DF]);
 
                if (greinfo[IFLA_GRE_TOS])
                        tos = rta_getattr_u8(greinfo[IFLA_GRE_TOS]);
 
+               if (greinfo[IFLA_GRE_TTL])
+                       ttl = rta_getattr_u8(greinfo[IFLA_GRE_TTL]);
+
                if (greinfo[IFLA_GRE_LINK])
                        link = rta_getattr_u32(greinfo[IFLA_GRE_LINK]);
 
                if (greinfo[IFLA_GRE_ENCAP_TYPE])
                        encaptype = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_TYPE]);
+
                if (greinfo[IFLA_GRE_ENCAP_FLAGS])
                        encapflags = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_FLAGS]);
+
                if (greinfo[IFLA_GRE_ENCAP_SPORT])
                        encapsport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_SPORT]);
+
                if (greinfo[IFLA_GRE_ENCAP_DPORT])
                        encapdport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_DPORT]);
 
                if (greinfo[IFLA_GRE_COLLECT_METADATA])
                        metadata = 1;
 
-               if (greinfo[IFLA_GRE_IGNORE_DF])
-                       ignore_df =
-                               !!rta_getattr_u8(greinfo[IFLA_GRE_IGNORE_DF]);
-
                if (greinfo[IFLA_GRE_FWMARK])
                        fwmark = rta_getattr_u32(greinfo[IFLA_GRE_FWMARK]);
 
@@ -232,18 +238,15 @@ get_failed:
                        pmtudisc = 1;
                } else if (!matches(*argv, "remote")) {
                        NEXT_ARG();
-                       daddr = get_addr32(*argv);
+                       get_addr(&daddr, *argv, AF_INET);
                } else if (!matches(*argv, "local")) {
                        NEXT_ARG();
-                       saddr = get_addr32(*argv);
+                       get_addr(&saddr, *argv, AF_INET);
                } else if (!matches(*argv, "dev")) {
                        NEXT_ARG();
                        link = ll_name_to_index(*argv);
-                       if (link == 0) {
-                               fprintf(stderr, "Cannot find device \"%s\"\n",
-                                       *argv);
-                               exit(-1);
-                       }
+                       if (!link)
+                               exit(nodev(*argv));
                } else if (!matches(*argv, "ttl") ||
                           !matches(*argv, "hoplimit") ||
                           !matches(*argv, "hlim")) {
@@ -336,58 +339,63 @@ get_failed:
                        NEXT_ARG();
                        if (get_u16(&erspan_hwid, *argv, 0))
                                invarg("invalid erspan hwid\n", *argv);
-               } else
-                       usage();
+               } else {
+                       gre_print_help(lu, argc, argv, stderr);
+                       return -1;
+               }
                argc--; argv++;
        }
 
-       if (!ikey && IN_MULTICAST(ntohl(daddr))) {
-               ikey = daddr;
-               iflags |= GRE_KEY;
-       }
-       if (!okey && IN_MULTICAST(ntohl(daddr))) {
-               okey = daddr;
-               oflags |= GRE_KEY;
+       if (is_addrtype_inet_multi(&daddr)) {
+               if (!ikey) {
+                       ikey = daddr.data[0];
+                       iflags |= GRE_KEY;
+               }
+               if (!okey) {
+                       okey = daddr.data[0];
+                       oflags |= GRE_KEY;
+               }
+               if (!is_addrtype_inet_not_unspec(&saddr)) {
+                       fprintf(stderr,
+                               "A broadcast tunnel requires a source address.\n");
+                       return -1;
+               }
        }
-       if (IN_MULTICAST(ntohl(daddr)) && !saddr) {
-               fprintf(stderr, "A broadcast tunnel requires a source address.\n");
-               return -1;
+
+       if (metadata) {
+               addattr_l(n, 1024, IFLA_GRE_COLLECT_METADATA, NULL, 0);
+               return 0;
        }
 
-       if (!metadata) {
-               addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
-               addattr32(n, 1024, IFLA_GRE_OKEY, okey);
-               addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
-               addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
-               addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4);
-               addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4);
-               addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1);
-               if (ignore_df)
-                       addattr8(n, 1024, IFLA_GRE_IGNORE_DF, ignore_df & 1);
-               if (link)
-                       addattr32(n, 1024, IFLA_GRE_LINK, link);
-               addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
-               addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
-               addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark);
-               if (erspan_ver) {
-                       addattr8(n, 1024, IFLA_GRE_ERSPAN_VER, erspan_ver);
-                       if (erspan_ver == 1 && erspan_idx != 0) {
-                               addattr32(n, 1024,
-                                         IFLA_GRE_ERSPAN_INDEX, erspan_idx);
-                       } else if (erspan_ver == 2) {
-                               addattr8(n, 1024,
-                                        IFLA_GRE_ERSPAN_DIR, erspan_dir);
-                               addattr16(n, 1024,
-                                         IFLA_GRE_ERSPAN_HWID, erspan_hwid);
-                       }
+       addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
+       addattr32(n, 1024, IFLA_GRE_OKEY, okey);
+       addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
+       addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
+       if (is_addrtype_inet(&saddr))
+               addattr_l(n, 1024, IFLA_GRE_LOCAL, saddr.data, saddr.bytelen);
+       if (is_addrtype_inet(&daddr))
+               addattr_l(n, 1024, IFLA_GRE_REMOTE, daddr.data, daddr.bytelen);
+       addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1);
+       if (ignore_df)
+               addattr8(n, 1024, IFLA_GRE_IGNORE_DF, ignore_df & 1);
+       addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
+       if (link)
+               addattr32(n, 1024, IFLA_GRE_LINK, link);
+       addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
+       addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark);
+       if (erspan_ver) {
+               addattr8(n, 1024, IFLA_GRE_ERSPAN_VER, erspan_ver);
+               if (erspan_ver == 1 && erspan_idx != 0) {
+                       addattr32(n, 1024, IFLA_GRE_ERSPAN_INDEX, erspan_idx);
+               } else if (erspan_ver == 2) {
+                       addattr8(n, 1024, IFLA_GRE_ERSPAN_DIR, erspan_dir);
+                       addattr16(n, 1024, IFLA_GRE_ERSPAN_HWID, erspan_hwid);
                }
-               addattr16(n, 1024, IFLA_GRE_ENCAP_TYPE, encaptype);
-               addattr16(n, 1024, IFLA_GRE_ENCAP_FLAGS, encapflags);
-               addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport));
-               addattr16(n, 1024, IFLA_GRE_ENCAP_DPORT, htons(encapdport));
-       } else {
-               addattr_l(n, 1024, IFLA_GRE_COLLECT_METADATA, NULL, 0);
        }
+       addattr16(n, 1024, IFLA_GRE_ENCAP_TYPE, encaptype);
+       addattr16(n, 1024, IFLA_GRE_ENCAP_FLAGS, encapflags);
+       addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport));
+       addattr16(n, 1024, IFLA_GRE_ENCAP_DPORT, htons(encapdport));
 
        return 0;
 }
@@ -395,8 +403,8 @@ get_failed:
 static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
 {
        char s2[64];
-       unsigned int iflags = 0;
-       unsigned int oflags = 0;
+       __u16 iflags = 0;
+       __u16 oflags = 0;
        __u8 ttl = 0;
        __u8 tos = 0;
 
@@ -412,7 +420,7 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
        tnl_print_endpoint("local", tb[IFLA_GRE_LOCAL], AF_INET);
 
        if (tb[IFLA_GRE_LINK]) {
-               unsigned int link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
+               __u32 link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
 
                if (link) {
                        print_string(PRINT_ANY, "link", "dev %s ",
@@ -490,7 +498,8 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
        if (tb[IFLA_GRE_ERSPAN_VER]) {
                __u8 erspan_ver = rta_getattr_u8(tb[IFLA_GRE_ERSPAN_VER]);
 
-               print_uint(PRINT_ANY, "erspan_ver", "erspan_ver %u ", erspan_ver);
+               print_uint(PRINT_ANY,
+                          "erspan_ver", "erspan_ver %u ", erspan_ver);
        }
 
        if (tb[IFLA_GRE_ERSPAN_DIR]) {
@@ -507,7 +516,8 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
        if (tb[IFLA_GRE_ERSPAN_HWID]) {
                __u16 erspan_hwid = rta_getattr_u16(tb[IFLA_GRE_ERSPAN_HWID]);
 
-               print_hex(PRINT_ANY, "erspan_hwid", "erspan_hwid 0x%x ", erspan_hwid);
+               print_0xhex(PRINT_ANY,
+                           "erspan_hwid", "erspan_hwid 0x%x ", erspan_hwid);
        }
 
        tnl_print_encap(tb,
@@ -517,12 +527,6 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                        IFLA_GRE_ENCAP_DPORT);
 }
 
-static void gre_print_help(struct link_util *lu, int argc, char **argv,
-                          FILE *f)
-{
-       print_usage(f);
-}
-
 struct link_util gre_link_util = {
        .id = "gre",
        .maxattr = IFLA_GRE_MAX,
index 4045f656157233f2d214959ace2fdfe2f9d75878..a6fe0b73d2354b5deadf34684dc288b2a0b9120c 100644 (file)
 
 #define DEFAULT_TNL_HOP_LIMIT  (64)
 
-static void print_usage(FILE *f)
+static void gre_print_help(struct link_util *lu, int argc, char **argv, FILE *f)
 {
        fprintf(f,
-               "Usage: ... { ip6gre | ip6gretap | ip6erspan} [ remote ADDR ]\n"
-               "                                  [ local ADDR ]\n"
-               "                                  [ [i|o]seq ]\n"
-               "                                  [ [i|o]key KEY ]\n"
-               "                                  [ [i|o]csum ]\n"
-               "                                  [ hoplimit TTL ]\n"
-               "                                  [ encaplimit ELIM ]\n"
-               "                                  [ tclass TCLASS ]\n"
-               "                                  [ flowlabel FLOWLABEL ]\n"
-               "                                  [ dscp inherit ]\n"
-               "                                  [ fwmark MARK ]\n"
-               "                                  [ dev PHYS_DEV ]\n"
-               "                                  [ noencap ]\n"
-               "                                  [ encap { fou | gue | none } ]\n"
-               "                                  [ encap-sport PORT ]\n"
-               "                                  [ encap-dport PORT ]\n"
-               "                                  [ [no]encap-csum ]\n"
-               "                                  [ [no]encap-csum6 ]\n"
-               "                                  [ [no]encap-remcsum ]\n"
-               "                                  [ erspan_ver version ]\n"
-               "                                  [ erspan IDX ]\n"
-               "                                  [ erspan_dir { ingress | egress } ]\n"
-               "                                  [ erspan_hwid hwid ]\n"
-               "                                  [ external ]\n"
+               "Usage: ... %-9s [ remote ADDR ]\n",
+               lu->id
+       );
+       fprintf(f,
+               "                     [ local ADDR ]\n"
+               "                     [ [i|o]seq ]\n"
+               "                     [ [i|o]key KEY ]\n"
+               "                     [ [i|o]csum ]\n"
+               "                     [ hoplimit TTL ]\n"
+               "                     [ encaplimit ELIM ]\n"
+               "                     [ tclass TCLASS ]\n"
+               "                     [ flowlabel FLOWLABEL ]\n"
+               "                     [ dscp inherit ]\n"
+               "                     [ dev PHYS_DEV ]\n"
+               "                     [ fwmark MARK ]\n"
+               "                     [ [no]allow-localremote ]\n"
+               "                     [ external ]\n"
+               "                     [ noencap ]\n"
+               "                     [ encap { fou | gue | none } ]\n"
+               "                     [ encap-sport PORT ]\n"
+               "                     [ encap-dport PORT ]\n"
+               "                     [ [no]encap-csum ]\n"
+               "                     [ [no]encap-csum6 ]\n"
+               "                     [ [no]encap-remcsum ]\n"
+               "                     [ erspan_ver version ]\n"
+               "                     [ erspan IDX ]\n"
+               "                     [ erspan_dir { ingress | egress } ]\n"
+               "                     [ erspan_hwid hwid ]\n"
                "\n"
+       );
+       fprintf(f,
                "Where: ADDR      := IPV6_ADDRESS\n"
                "       TTL       := { 0..255 } (default=%d)\n"
                "       KEY       := { DOTTED_QUAD | NUMBER }\n"
@@ -69,17 +75,10 @@ static void print_usage(FILE *f)
        );
 }
 
-static void usage(void) __attribute__((noreturn));
-static void usage(void)
-{
-       print_usage(stderr);
-       exit(-1);
-}
-
 static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
                         struct nlmsghdr *n)
 {
-       struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
+       struct ifinfomsg *ifi = NLMSG_DATA(n);
        struct {
                struct nlmsghdr n;
                struct ifinfomsg i;
@@ -94,30 +93,34 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
        struct rtattr *tb[IFLA_MAX + 1];
        struct rtattr *linkinfo[IFLA_INFO_MAX+1];
        struct rtattr *greinfo[IFLA_GRE_MAX + 1];
+       int len;
        __u16 iflags = 0;
        __u16 oflags = 0;
        __be32 ikey = 0;
        __be32 okey = 0;
-       struct in6_addr raddr = IN6ADDR_ANY_INIT;
-       struct in6_addr laddr = IN6ADDR_ANY_INIT;
-       unsigned int link = 0;
-       unsigned int flowinfo = 0;
-       unsigned int flags = 0;
+       inet_prefix saddr, daddr;
        __u8 hop_limit = DEFAULT_TNL_HOP_LIMIT;
        __u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
+       __u32 flowinfo = 0;
+       __u32 flags = 0;
+       __u32 link = 0;
        __u16 encaptype = 0;
        __u16 encapflags = TUNNEL_ENCAP_FLAG_CSUM6;
        __u16 encapsport = 0;
        __u16 encapdport = 0;
        __u8 metadata = 0;
-       int len;
        __u32 fwmark = 0;
        __u32 erspan_idx = 0;
        __u8 erspan_ver = 0;
        __u8 erspan_dir = 0;
        __u16 erspan_hwid = 0;
 
+       inet_prefix_reset(&saddr);
+       inet_prefix_reset(&daddr);
+
        if (!(n->nlmsg_flags & NLM_F_CREATE)) {
+               const struct rtattr *rta;
+
                if (rtnl_talk(&rth, &req.n, &answer) < 0) {
 get_failed:
                        fprintf(stderr,
@@ -143,6 +146,14 @@ get_failed:
                parse_rtattr_nested(greinfo, IFLA_GRE_MAX,
                                    linkinfo[IFLA_INFO_DATA]);
 
+               rta = greinfo[IFLA_GRE_LOCAL];
+               if (rta && get_addr_rta(&saddr, rta, AF_INET6))
+                       goto get_failed;
+
+               rta = greinfo[IFLA_GRE_REMOTE];
+               if (rta && get_addr_rta(&daddr, rta, AF_INET6))
+                       goto get_failed;
+
                if (greinfo[IFLA_GRE_IKEY])
                        ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]);
 
@@ -155,12 +166,6 @@ get_failed:
                if (greinfo[IFLA_GRE_OFLAGS])
                        oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]);
 
-               if (greinfo[IFLA_GRE_LOCAL])
-                       memcpy(&laddr, RTA_DATA(greinfo[IFLA_GRE_LOCAL]), sizeof(laddr));
-
-               if (greinfo[IFLA_GRE_REMOTE])
-                       memcpy(&raddr, RTA_DATA(greinfo[IFLA_GRE_REMOTE]), sizeof(raddr));
-
                if (greinfo[IFLA_GRE_TTL])
                        hop_limit = rta_getattr_u8(greinfo[IFLA_GRE_TTL]);
 
@@ -185,12 +190,12 @@ get_failed:
                if (greinfo[IFLA_GRE_ENCAP_SPORT])
                        encapsport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_SPORT]);
 
-               if (greinfo[IFLA_GRE_COLLECT_METADATA])
-                       metadata = 1;
-
                if (greinfo[IFLA_GRE_ENCAP_DPORT])
                        encapdport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_DPORT]);
 
+               if (greinfo[IFLA_GRE_COLLECT_METADATA])
+                       metadata = 1;
+
                if (greinfo[IFLA_GRE_FWMARK])
                        fwmark = rta_getattr_u32(greinfo[IFLA_GRE_FWMARK]);
 
@@ -238,25 +243,16 @@ get_failed:
                } else if (!matches(*argv, "ocsum")) {
                        oflags |= GRE_CSUM;
                } else if (!matches(*argv, "remote")) {
-                       inet_prefix addr;
-
                        NEXT_ARG();
-                       get_addr(&addr, *argv, AF_INET6);
-                       memcpy(&raddr, &addr.data, sizeof(raddr));
+                       get_addr(&daddr, *argv, AF_INET6);
                } else if (!matches(*argv, "local")) {
-                       inet_prefix addr;
-
                        NEXT_ARG();
-                       get_addr(&addr, *argv, AF_INET6);
-                       memcpy(&laddr, &addr.data, sizeof(laddr));
+                       get_addr(&saddr, *argv, AF_INET6);
                } else if (!matches(*argv, "dev")) {
                        NEXT_ARG();
                        link = ll_name_to_index(*argv);
-                       if (link == 0) {
-                               fprintf(stderr, "Cannot find device \"%s\"\n",
-                                       *argv);
-                               exit(-1);
-                       }
+                       if (!link)
+                               exit(nodev(*argv));
                } else if (!matches(*argv, "ttl") ||
                           !matches(*argv, "hoplimit") ||
                           !matches(*argv, "hlim")) {
@@ -348,6 +344,10 @@ get_failed:
                                        invarg("invalid fwmark\n", *argv);
                                flags &= ~IP6_TNL_F_USE_ORIG_FWMARK;
                        }
+               } else if (strcmp(*argv, "allow-localremote") == 0) {
+                       flags |= IP6_TNL_F_ALLOW_LOCAL_REMOTE;
+               } else if (strcmp(*argv, "noallow-localremote") == 0) {
+                       flags &= ~IP6_TNL_F_ALLOW_LOCAL_REMOTE;
                } else if (strcmp(*argv, "encaplimit") == 0) {
                        NEXT_ARG();
                        if (strcmp(*argv, "none") == 0) {
@@ -384,44 +384,46 @@ get_failed:
                        NEXT_ARG();
                        if (get_u16(&erspan_hwid, *argv, 0))
                                invarg("invalid erspan hwid\n", *argv);
-               } else
-                       usage();
+               } else {
+                       gre_print_help(lu, argc, argv, stderr);
+                       return -1;
+               }
                argc--; argv++;
        }
 
-       if (!metadata) {
-               addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
-               addattr32(n, 1024, IFLA_GRE_OKEY, okey);
-               addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
-               addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
-               addattr_l(n, 1024, IFLA_GRE_LOCAL, &laddr, sizeof(laddr));
-               addattr_l(n, 1024, IFLA_GRE_REMOTE, &raddr, sizeof(raddr));
-               if (link)
-                       addattr32(n, 1024, IFLA_GRE_LINK, link);
-               addattr_l(n, 1024, IFLA_GRE_TTL, &hop_limit, 1);
-               addattr_l(n, 1024, IFLA_GRE_ENCAP_LIMIT, &encap_limit, 1);
-               addattr_l(n, 1024, IFLA_GRE_FLOWINFO, &flowinfo, 4);
-               addattr32(n, 1024, IFLA_GRE_FLAGS, flags);
-               addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark);
-               if (erspan_ver) {
-                       addattr8(n, 1024, IFLA_GRE_ERSPAN_VER, erspan_ver);
-                       if (erspan_ver == 1 && erspan_idx != 0) {
-                               addattr32(n, 1024,
-                                         IFLA_GRE_ERSPAN_INDEX, erspan_idx);
-                       } else if (erspan_ver == 2) {
-                               addattr8(n, 1024,
-                                        IFLA_GRE_ERSPAN_DIR, erspan_dir);
-                               addattr16(n, 1024,
-                                         IFLA_GRE_ERSPAN_HWID, erspan_hwid);
-                       }
-               }
-               addattr16(n, 1024, IFLA_GRE_ENCAP_TYPE, encaptype);
-               addattr16(n, 1024, IFLA_GRE_ENCAP_FLAGS, encapflags);
-               addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport));
-               addattr16(n, 1024, IFLA_GRE_ENCAP_DPORT, htons(encapdport));
-       } else {
+       if (metadata) {
                addattr_l(n, 1024, IFLA_GRE_COLLECT_METADATA, NULL, 0);
+               return 0;
+       }
+
+       addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
+       addattr32(n, 1024, IFLA_GRE_OKEY, okey);
+       addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
+       addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
+       if (is_addrtype_inet(&saddr))
+               addattr_l(n, 1024, IFLA_GRE_LOCAL, saddr.data, saddr.bytelen);
+       if (is_addrtype_inet(&daddr))
+               addattr_l(n, 1024, IFLA_GRE_REMOTE, daddr.data, daddr.bytelen);
+       if (link)
+               addattr32(n, 1024, IFLA_GRE_LINK, link);
+       addattr_l(n, 1024, IFLA_GRE_TTL, &hop_limit, 1);
+       addattr_l(n, 1024, IFLA_GRE_ENCAP_LIMIT, &encap_limit, 1);
+       addattr_l(n, 1024, IFLA_GRE_FLOWINFO, &flowinfo, 4);
+       addattr32(n, 1024, IFLA_GRE_FLAGS, flags);
+       addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark);
+       if (erspan_ver) {
+               addattr8(n, 1024, IFLA_GRE_ERSPAN_VER, erspan_ver);
+               if (erspan_ver == 1 && erspan_idx != 0) {
+                       addattr32(n, 1024, IFLA_GRE_ERSPAN_INDEX, erspan_idx);
+               } else if (erspan_ver == 2) {
+                       addattr8(n, 1024, IFLA_GRE_ERSPAN_DIR, erspan_dir);
+                       addattr16(n, 1024, IFLA_GRE_ERSPAN_HWID, erspan_hwid);
+               }
        }
+       addattr16(n, 1024, IFLA_GRE_ENCAP_TYPE, encaptype);
+       addattr16(n, 1024, IFLA_GRE_ENCAP_FLAGS, encapflags);
+       addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport));
+       addattr16(n, 1024, IFLA_GRE_ENCAP_DPORT, htons(encapdport));
 
        return 0;
 }
@@ -429,9 +431,9 @@ get_failed:
 static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
 {
        char s2[64];
-       unsigned int iflags = 0;
-       unsigned int oflags = 0;
-       unsigned int flags = 0;
+       __u16 iflags = 0;
+       __u16 oflags = 0;
+       __u32 flags = 0;
        __u32 flowinfo = 0;
        __u8 ttl = 0;
 
@@ -453,7 +455,7 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
        tnl_print_endpoint("local", tb[IFLA_GRE_LOCAL], AF_INET6);
 
        if (tb[IFLA_GRE_LINK]) {
-               unsigned int link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
+               __u32 link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
 
                if (link) {
                        print_string(PRINT_ANY, "link", "dev %s ",
@@ -534,6 +536,12 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
        if (oflags & GRE_CSUM)
                print_bool(PRINT_ANY, "ocsum", "ocsum ", true);
 
+       if (flags & IP6_TNL_F_ALLOW_LOCAL_REMOTE)
+               print_bool(PRINT_ANY,
+                          "ip6_tnl_f_allow_local_remote",
+                          "allow-localremote ",
+                          true);
+
        if (flags & IP6_TNL_F_USE_ORIG_FWMARK) {
                print_bool(PRINT_ANY,
                           "ip6_tnl_f_use_orig_fwmark",
@@ -550,6 +558,7 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
 
        if (tb[IFLA_GRE_ERSPAN_INDEX]) {
                __u32 erspan_idx = rta_getattr_u32(tb[IFLA_GRE_ERSPAN_INDEX]);
+
                print_uint(PRINT_ANY,
                           "erspan_index", "erspan_index %u ", erspan_idx);
        }
@@ -557,7 +566,8 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
        if (tb[IFLA_GRE_ERSPAN_VER]) {
                __u8 erspan_ver = rta_getattr_u8(tb[IFLA_GRE_ERSPAN_VER]);
 
-               print_uint(PRINT_ANY, "erspan_ver", "erspan_ver %u ", erspan_ver);
+               print_uint(PRINT_ANY,
+                          "erspan_ver", "erspan_ver %u ", erspan_ver);
        }
 
        if (tb[IFLA_GRE_ERSPAN_DIR]) {
@@ -574,7 +584,8 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
        if (tb[IFLA_GRE_ERSPAN_HWID]) {
                __u16 erspan_hwid = rta_getattr_u16(tb[IFLA_GRE_ERSPAN_HWID]);
 
-               print_hex(PRINT_ANY, "erspan_hwid", "erspan_hwid 0x%x ", erspan_hwid);
+               print_0xhex(PRINT_ANY,
+                           "erspan_hwid", "erspan_hwid 0x%x ", erspan_hwid);
        }
 
        tnl_print_encap(tb,
@@ -584,12 +595,6 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                        IFLA_GRE_ENCAP_DPORT);
 }
 
-static void gre_print_help(struct link_util *lu, int argc, char **argv,
-                          FILE *f)
-{
-       print_usage(f);
-}
-
 struct link_util ip6gre_link_util = {
        .id = "ip6gre",
        .maxattr = IFLA_GRE_MAX,
index ccc79ff91d6c49ac5ac2efca9212c4e4009055b9..c7fef2e0366010e18fd09032cd8c43c138d7f51d 100644 (file)
 
 #define DEFAULT_TNL_HOP_LIMIT  (64)
 
-static void print_usage(FILE *f)
+static void ip6tunnel_print_help(struct link_util *lu, int argc, char **argv,
+                                FILE *f)
 {
+       const char *mode;
+
+       fprintf(f,
+               "Usage: ... %-6s [ remote ADDR ]\n",
+               lu->id
+       );
        fprintf(f,
-               "Usage: ... ip6tnl [ mode { ip6ip6 | ipip6 | any } ]\n"
-               "                  [ remote ADDR ]\n"
                "                  [ local ADDR ]\n"
-               "                  [ dev PHYS_DEV ]\n"
                "                  [ encaplimit ELIM ]\n"
                "                  [ hoplimit HLIM ]\n"
                "                  [ tclass TCLASS ]\n"
                "                  [ flowlabel FLOWLABEL ]\n"
                "                  [ dscp inherit ]\n"
-               "                  [ fwmark MARK ]\n"
                "                  [ [no]allow-localremote ]\n"
+               "                  [ dev PHYS_DEV ]\n"
+               "                  [ fwmark MARK ]\n"
+               "                  [ external ]\n"
                "                  [ noencap ]\n"
                "                  [ encap { fou | gue | none } ]\n"
                "                  [ encap-sport PORT ]\n"
@@ -50,8 +56,14 @@ static void print_usage(FILE *f)
                "                  [ [no]encap-csum ]\n"
                "                  [ [no]encap-csum6 ]\n"
                "                  [ [no]encap-remcsum ]\n"
-               "                  [ external ]\n"
-               "\n"
+       );
+       mode = "{ ip6ip6 | ipip6 | any }";
+       fprintf(f,
+               "                  [ mode %s ]\n"
+               "\n",
+               mode
+       );
+       fprintf(f,
                "Where: ADDR      := IPV6_ADDRESS\n"
                "       ELIM      := { none | 0..255 }(default=%d)\n"
                "       HLIM      := 0..255 (default=%d)\n"
@@ -62,17 +74,10 @@ static void print_usage(FILE *f)
        );
 }
 
-static void usage(void) __attribute__((noreturn));
-static void usage(void)
-{
-       print_usage(stderr);
-       exit(-1);
-}
-
 static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv,
                               struct nlmsghdr *n)
 {
-       struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
+       struct ifinfomsg *ifi = NLMSG_DATA(n);
        struct {
                struct nlmsghdr n;
                struct ifinfomsg i;
@@ -88,14 +93,13 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv,
        struct rtattr *linkinfo[IFLA_INFO_MAX+1];
        struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1];
        int len;
-       struct in6_addr laddr = IN6ADDR_ANY_INIT;
-       struct in6_addr raddr = IN6ADDR_ANY_INIT;
+       inet_prefix saddr, daddr;
        __u8 hop_limit = DEFAULT_TNL_HOP_LIMIT;
        __u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
        __u32 flowinfo = 0;
        __u32 flags = 0;
-       __u32 link = 0;
        __u8 proto = 0;
+       __u32 link = 0;
        __u16 encaptype = 0;
        __u16 encapflags = TUNNEL_ENCAP_FLAG_CSUM6;
        __u16 encapsport = 0;
@@ -103,7 +107,12 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv,
        __u8 metadata = 0;
        __u32 fwmark = 0;
 
+       inet_prefix_reset(&saddr);
+       inet_prefix_reset(&daddr);
+
        if (!(n->nlmsg_flags & NLM_F_CREATE)) {
+               const struct rtattr *rta;
+
                if (rtnl_talk(&rth, &req.n, &answer) < 0) {
 get_failed:
                        fprintf(stderr,
@@ -129,13 +138,13 @@ get_failed:
                parse_rtattr_nested(iptuninfo, IFLA_IPTUN_MAX,
                                    linkinfo[IFLA_INFO_DATA]);
 
-               if (iptuninfo[IFLA_IPTUN_LOCAL])
-                       memcpy(&laddr, RTA_DATA(iptuninfo[IFLA_IPTUN_LOCAL]),
-                              sizeof(laddr));
+               rta = iptuninfo[IFLA_IPTUN_LOCAL];
+               if (rta && get_addr_rta(&saddr, rta, AF_INET6))
+                       goto get_failed;
 
-               if (iptuninfo[IFLA_IPTUN_REMOTE])
-                       memcpy(&raddr, RTA_DATA(iptuninfo[IFLA_IPTUN_REMOTE]),
-                              sizeof(raddr));
+               rta = iptuninfo[IFLA_IPTUN_REMOTE];
+               if (rta && get_addr_rta(&daddr, rta, AF_INET6))
+                       goto get_failed;
 
                if (iptuninfo[IFLA_IPTUN_TTL])
                        hop_limit = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TTL]);
@@ -164,7 +173,7 @@ get_failed:
        }
 
        while (argc > 0) {
-               if (matches(*argv, "mode") == 0) {
+               if (strcmp(*argv, "mode") == 0) {
                        NEXT_ARG();
                        if (strcmp(*argv, "ipv6/ipv6") == 0 ||
                            strcmp(*argv, "ip6ip6") == 0)
@@ -180,22 +189,16 @@ get_failed:
                        else
                                invarg("Cannot guess tunnel mode.", *argv);
                } else if (strcmp(*argv, "remote") == 0) {
-                       inet_prefix addr;
-
                        NEXT_ARG();
-                       get_addr(&addr, *argv, AF_INET6);
-                       memcpy(&raddr, addr.data, sizeof(raddr));
+                       get_addr(&daddr, *argv, AF_INET6);
                } else if (strcmp(*argv, "local") == 0) {
-                       inet_prefix addr;
-
                        NEXT_ARG();
-                       get_addr(&addr, *argv, AF_INET6);
-                       memcpy(&laddr, addr.data, sizeof(laddr));
+                       get_addr(&saddr, *argv, AF_INET6);
                } else if (matches(*argv, "dev") == 0) {
                        NEXT_ARG();
                        link = ll_name_to_index(*argv);
-                       if (link == 0)
-                               invarg("\"dev\" is invalid", *argv);
+                       if (!link)
+                               exit(nodev(*argv));
                } else if (strcmp(*argv, "ttl") == 0 ||
                           strcmp(*argv, "hoplimit") == 0 ||
                           strcmp(*argv, "hlim") == 0) {
@@ -217,9 +220,9 @@ get_failed:
                                encap_limit = uval;
                                flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT;
                        }
-               } else if (strcmp(*argv, "tclass") == 0 ||
+               } else if (strcmp(*argv, "tos") == 0 ||
+                          strcmp(*argv, "tclass") == 0 ||
                           strcmp(*argv, "tc") == 0 ||
-                          strcmp(*argv, "tos") == 0 ||
                           matches(*argv, "dsfield") == 0) {
                        __u8 uval;
 
@@ -304,8 +307,10 @@ get_failed:
                        encapflags &= ~TUNNEL_ENCAP_FLAG_REMCSUM;
                } else if (strcmp(*argv, "external") == 0) {
                        metadata = 1;
-               } else
-                       usage();
+               } else {
+                       ip6tunnel_print_help(lu, argc, argv, stderr);
+                       return -1;
+               }
                argc--, argv++;
        }
 
@@ -314,8 +319,15 @@ get_failed:
                addattr_l(n, 1024, IFLA_IPTUN_COLLECT_METADATA, NULL, 0);
                return 0;
        }
-       addattr_l(n, 1024, IFLA_IPTUN_LOCAL, &laddr, sizeof(laddr));
-       addattr_l(n, 1024, IFLA_IPTUN_REMOTE, &raddr, sizeof(raddr));
+
+       if (is_addrtype_inet(&saddr)) {
+               addattr_l(n, 1024, IFLA_IPTUN_LOCAL,
+                         saddr.data, saddr.bytelen);
+       }
+       if (is_addrtype_inet(&daddr)) {
+               addattr_l(n, 1024, IFLA_IPTUN_REMOTE,
+                         daddr.data, daddr.bytelen);
+       }
        addattr8(n, 1024, IFLA_IPTUN_TTL, hop_limit);
        addattr8(n, 1024, IFLA_IPTUN_ENCAP_LIMIT, encap_limit);
        addattr32(n, 1024, IFLA_IPTUN_FLOWINFO, flowinfo);
@@ -334,7 +346,7 @@ get_failed:
 static void ip6tunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
 {
        char s2[64];
-       int flags = 0;
+       __u32 flags = 0;
        __u32 flowinfo = 0;
        __u8 ttl = 0;
 
@@ -370,7 +382,7 @@ static void ip6tunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb
        tnl_print_endpoint("local", tb[IFLA_IPTUN_LOCAL], AF_INET6);
 
        if (tb[IFLA_IPTUN_LINK]) {
-               unsigned int link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]);
+               __u32 link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]);
 
                if (link) {
                        print_string(PRINT_ANY, "link", "dev %s ",
@@ -456,12 +468,6 @@ static void ip6tunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb
                        IFLA_IPTUN_ENCAP_DPORT);
 }
 
-static void ip6tunnel_print_help(struct link_util *lu, int argc, char **argv,
-                                FILE *f)
-{
-       print_usage(f);
-}
-
 struct link_util ip6tnl_link_util = {
        .id = "ip6tnl",
        .maxattr = IFLA_IPTUN_MAX,
index 622c6f143632f58756c23a00cd1327e9f32ba77f..57f4d0c7a8731b073551ccffd633441e6be4c464 100644 (file)
 #include "ip_common.h"
 #include "tunnel.h"
 
-static void print_usage(FILE *f, int sit)
+static void iptunnel_print_help(struct link_util *lu, int argc, char **argv,
+                               FILE *f)
 {
-       const char *type = sit ? "sit " : "ipip";
+       const char *mode;
 
        fprintf(f,
-               "Usage: ... %s [ remote ADDR ]\n"
-               "                [ local ADDR ]\n"
-               "                [ ttl TTL ]\n"
-               "                [ tos TOS ]\n"
-               "                [ [no]pmtudisc ]\n"
-               "                [ dev PHYS_DEV ]\n"
-               "                [ 6rd-prefix ADDR ]\n"
-               "                [ 6rd-relay_prefix ADDR ]\n"
-               "                [ 6rd-reset ]\n"
-               "                [ noencap ]\n"
-               "                [ encap { fou | gue | none } ]\n"
-               "                [ encap-sport PORT ]\n"
-               "                [ encap-dport PORT ]\n"
-               "                [ [no]encap-csum ]\n"
-               "                [ [no]encap-csum6 ]\n"
-               "                [ [no]encap-remcsum ]\n",
-               type
+               "Usage: ... %-6s [ remote ADDR ]\n",
+               lu->id
+       );
+       fprintf(f,
+               "                  [ local ADDR ]\n"
+               "                  [ ttl TTL ]\n"
+               "                  [ tos TOS ]\n"
+               "                  [ [no]pmtudisc ]\n"
+               "                  [ 6rd-prefix ADDR ]\n"
+               "                  [ 6rd-relay_prefix ADDR ]\n"
+               "                  [ 6rd-reset ]\n"
+               "                  [ dev PHYS_DEV ]\n"
+               "                  [ fwmark MARK ]\n"
+               "                  [ external ]\n"
+               "                  [ noencap ]\n"
+               "                  [ encap { fou | gue | none } ]\n"
+               "                  [ encap-sport PORT ]\n"
+               "                  [ encap-dport PORT ]\n"
+               "                  [ [no]encap-csum ]\n"
+               "                  [ [no]encap-csum6 ]\n"
+               "                  [ [no]encap-remcsum ]\n"
        );
-       if (sit) {
-               fprintf(f, "          [ mode { ip6ip | ipip | mplsip | any } ]\n");
-               fprintf(f, "          [ isatap ]\n");
+       if (strcmp(lu->id, "sit") == 0) {
+               mode = "{ ip6ip | ipip | mplsip | any } ]\n"
+               "                  [ isatap";
        } else {
-               fprintf(f, "          [ mode { ipip | mplsip | any } ]\n");
+               mode = "{ ipip | mplsip | any }";
        }
-       fprintf(f, "                [ external ]\n");
-       fprintf(f, "                [ fwmark MARK ]\n");
-       fprintf(f, "\n");
-       fprintf(f, "Where: ADDR := { IP_ADDRESS | any }\n");
-       fprintf(f, "       TOS  := { NUMBER | inherit }\n");
-       fprintf(f, "       TTL  := { 1..255 | inherit }\n");
-       fprintf(f, "       MARK := { 0x0..0xffffffff }\n");
-}
-
-static void usage(int sit) __attribute__((noreturn));
-static void usage(int sit)
-{
-       print_usage(stderr, sit);
-       exit(-1);
+       fprintf(f,
+               "                  [ mode %s ]\n"
+               "\n",
+               mode
+       );
+       fprintf(f,
+               "Where: ADDR := { IP_ADDRESS | any }\n"
+               "       TOS  := { NUMBER | inherit }\n"
+               "       TTL  := { 1..255 | inherit }\n"
+               "       MARK := { 0x0..0xffffffff }\n"
+       );
 }
 
 static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv,
                              struct nlmsghdr *n)
 {
-       struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
+       struct ifinfomsg *ifi = NLMSG_DATA(n);
        struct {
                struct nlmsghdr n;
                struct ifinfomsg i;
@@ -88,18 +90,13 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv,
        struct rtattr *linkinfo[IFLA_INFO_MAX+1];
        struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1];
        int len;
-       __u32 link = 0;
-       __u32 laddr = 0;
-       __u32 raddr = 0;
-       __u8 ttl = 0;
-       __u8 tos = 0;
+       inet_prefix saddr, daddr, ip6rdprefix, ip6rdrelayprefix;
        __u8 pmtudisc = 1;
+       __u8 tos = 0;
        __u16 iflags = 0;
+       __u8 ttl = 0;
        __u8 proto = 0;
-       struct in6_addr ip6rdprefix = {};
-       __u16 ip6rdprefixlen = 0;
-       __u32 ip6rdrelayprefix = 0;
-       __u16 ip6rdrelayprefixlen = 0;
+       __u32 link = 0;
        __u16 encaptype = 0;
        __u16 encapflags = 0;
        __u16 encapsport = 0;
@@ -107,7 +104,15 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv,
        __u8 metadata = 0;
        __u32 fwmark = 0;
 
+       inet_prefix_reset(&saddr);
+       inet_prefix_reset(&daddr);
+
+       inet_prefix_reset(&ip6rdprefix);
+       inet_prefix_reset(&ip6rdrelayprefix);
+
        if (!(n->nlmsg_flags & NLM_F_CREATE)) {
+               const struct rtattr *rta;
+
                if (rtnl_talk(&rth, &req.n, &answer) < 0) {
 get_failed:
                        fprintf(stderr,
@@ -133,22 +138,38 @@ get_failed:
                parse_rtattr_nested(iptuninfo, IFLA_IPTUN_MAX,
                                    linkinfo[IFLA_INFO_DATA]);
 
-               if (iptuninfo[IFLA_IPTUN_LOCAL])
-                       laddr = rta_getattr_u32(iptuninfo[IFLA_IPTUN_LOCAL]);
+               rta = iptuninfo[IFLA_IPTUN_LOCAL];
+               if (rta && get_addr_rta(&saddr, rta, AF_INET))
+                       goto get_failed;
+
+               rta = iptuninfo[IFLA_IPTUN_REMOTE];
+               if (rta && get_addr_rta(&daddr, rta, AF_INET))
+                       goto get_failed;
+
+               rta = iptuninfo[IFLA_IPTUN_6RD_PREFIX];
+               if (rta && get_addr_rta(&ip6rdprefix, rta, AF_INET6))
+                       goto get_failed;
+
+               rta = iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX];
+               if (rta && get_addr_rta(&ip6rdrelayprefix, rta, AF_INET))
+                       goto get_failed;
+
+               rta = iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN];
+               ip6rdprefix.bitlen = rta ? rta_getattr_u16(rta) : 0;
 
-               if (iptuninfo[IFLA_IPTUN_REMOTE])
-                       raddr = rta_getattr_u32(iptuninfo[IFLA_IPTUN_REMOTE]);
+               rta = iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN];
+               ip6rdrelayprefix.bitlen = rta ? rta_getattr_u16(rta) : 0;
 
                if (iptuninfo[IFLA_IPTUN_TTL])
                        ttl = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TTL]);
 
-               if (iptuninfo[IFLA_IPTUN_TOS])
-                       tos = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TOS]);
-
                if (iptuninfo[IFLA_IPTUN_PMTUDISC])
                        pmtudisc =
                                rta_getattr_u8(iptuninfo[IFLA_IPTUN_PMTUDISC]);
 
+               if (iptuninfo[IFLA_IPTUN_TOS])
+                       tos = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TOS]);
+
                if (iptuninfo[IFLA_IPTUN_FLAGS])
                        iflags = rta_getattr_u16(iptuninfo[IFLA_IPTUN_FLAGS]);
 
@@ -166,22 +187,7 @@ get_failed:
                        encapsport = rta_getattr_u16(iptuninfo[IFLA_IPTUN_ENCAP_SPORT]);
                if (iptuninfo[IFLA_IPTUN_ENCAP_DPORT])
                        encapdport = rta_getattr_u16(iptuninfo[IFLA_IPTUN_ENCAP_DPORT]);
-               if (iptuninfo[IFLA_IPTUN_6RD_PREFIX])
-                       memcpy(&ip6rdprefix,
-                              RTA_DATA(iptuninfo[IFLA_IPTUN_6RD_PREFIX]),
-                              sizeof(laddr));
-
-               if (iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN])
-                       ip6rdprefixlen =
-                               rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN]);
-
-               if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX])
-                       ip6rdrelayprefix =
-                               rta_getattr_u32(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX]);
-
-               if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN])
-                       ip6rdrelayprefixlen =
-                               rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]);
+
                if (iptuninfo[IFLA_IPTUN_COLLECT_METADATA])
                        metadata = 1;
 
@@ -192,17 +198,35 @@ get_failed:
        }
 
        while (argc > 0) {
-               if (strcmp(*argv, "remote") == 0) {
+               if (strcmp(*argv, "mode") == 0) {
+                       NEXT_ARG();
+                       if (strcmp(lu->id, "sit") == 0 &&
+                           (strcmp(*argv, "ipv6/ipv4") == 0 ||
+                            strcmp(*argv, "ip6ip") == 0))
+                               proto = IPPROTO_IPV6;
+                       else if (strcmp(*argv, "ipv4/ipv4") == 0 ||
+                                strcmp(*argv, "ipip") == 0 ||
+                                strcmp(*argv, "ip4ip4") == 0)
+                               proto = IPPROTO_IPIP;
+                       else if (strcmp(*argv, "mpls/ipv4") == 0 ||
+                                  strcmp(*argv, "mplsip") == 0)
+                               proto = IPPROTO_MPLS;
+                       else if (strcmp(*argv, "any/ipv4") == 0 ||
+                                strcmp(*argv, "any") == 0)
+                               proto = 0;
+                       else
+                               invarg("Cannot guess tunnel mode.", *argv);
+               } else if (strcmp(*argv, "remote") == 0) {
                        NEXT_ARG();
-                       raddr = get_addr32(*argv);
+                       get_addr(&daddr, *argv, AF_INET);
                } else if (strcmp(*argv, "local") == 0) {
                        NEXT_ARG();
-                       laddr = get_addr32(*argv);
+                       get_addr(&saddr, *argv, AF_INET);
                } else if (matches(*argv, "dev") == 0) {
                        NEXT_ARG();
                        link = ll_name_to_index(*argv);
-                       if (link == 0)
-                               invarg("\"dev\" is invalid", *argv);
+                       if (!link)
+                               exit(nodev(*argv));
                } else if (strcmp(*argv, "ttl") == 0 ||
                           strcmp(*argv, "hoplimit") == 0 ||
                           strcmp(*argv, "hlim") == 0) {
@@ -214,6 +238,7 @@ get_failed:
                                ttl = 0;
                } else if (strcmp(*argv, "tos") == 0 ||
                           strcmp(*argv, "tclass") == 0 ||
+                          strcmp(*argv, "tc") == 0 ||
                           matches(*argv, "dsfield") == 0) {
                        __u32 uval;
 
@@ -231,24 +256,6 @@ get_failed:
                } else if (strcmp(lu->id, "sit") == 0 &&
                           strcmp(*argv, "isatap") == 0) {
                        iflags |= SIT_ISATAP;
-               } else if (strcmp(*argv, "mode") == 0) {
-                       NEXT_ARG();
-                       if (strcmp(lu->id, "sit") == 0 &&
-                           (strcmp(*argv, "ipv6/ipv4") == 0 ||
-                            strcmp(*argv, "ip6ip") == 0))
-                               proto = IPPROTO_IPV6;
-                       else if (strcmp(*argv, "ipv4/ipv4") == 0 ||
-                                strcmp(*argv, "ipip") == 0 ||
-                                strcmp(*argv, "ip4ip4") == 0)
-                               proto = IPPROTO_IPIP;
-                       else if (strcmp(*argv, "mpls/ipv4") == 0 ||
-                                  strcmp(*argv, "mplsip") == 0)
-                               proto = IPPROTO_MPLS;
-                       else if (strcmp(*argv, "any/ipv4") == 0 ||
-                                strcmp(*argv, "any") == 0)
-                               proto = 0;
-                       else
-                               invarg("Cannot guess tunnel mode.", *argv);
                } else if (strcmp(*argv, "noencap") == 0) {
                        encaptype = TUNNEL_ENCAP_NONE;
                } else if (strcmp(*argv, "encap") == 0) {
@@ -286,35 +293,24 @@ get_failed:
                } else if (strcmp(*argv, "external") == 0) {
                        metadata = 1;
                } else if (strcmp(*argv, "6rd-prefix") == 0) {
-                       inet_prefix prefix;
-
                        NEXT_ARG();
-                       if (get_prefix(&prefix, *argv, AF_INET6))
+                       if (get_prefix(&ip6rdprefix, *argv, AF_INET6))
                                invarg("invalid 6rd_prefix\n", *argv);
-                       memcpy(&ip6rdprefix, prefix.data, 16);
-                       ip6rdprefixlen = prefix.bitlen;
                } else if (strcmp(*argv, "6rd-relay_prefix") == 0) {
-                       inet_prefix prefix;
-
                        NEXT_ARG();
-                       if (get_prefix(&prefix, *argv, AF_INET))
+                       if (get_prefix(&ip6rdrelayprefix, *argv, AF_INET))
                                invarg("invalid 6rd-relay_prefix\n", *argv);
-                       memcpy(&ip6rdrelayprefix, prefix.data, 4);
-                       ip6rdrelayprefixlen = prefix.bitlen;
                } else if (strcmp(*argv, "6rd-reset") == 0) {
-                       inet_prefix prefix;
-
-                       get_prefix(&prefix, "2002::", AF_INET6);
-                       memcpy(&ip6rdprefix, prefix.data, 16);
-                       ip6rdprefixlen = 16;
-                       ip6rdrelayprefix = 0;
-                       ip6rdrelayprefixlen = 0;
+                       get_prefix(&ip6rdprefix, "2002::/16", AF_INET6);
+                       inet_prefix_reset(&ip6rdrelayprefix);
                } else if (strcmp(*argv, "fwmark") == 0) {
                        NEXT_ARG();
                        if (get_u32(&fwmark, *argv, 0))
                                invarg("invalid fwmark\n", *argv);
-               } else
-                       usage(strcmp(lu->id, "sit") == 0);
+               } else {
+                       iptunnel_print_help(lu, argc, argv, stderr);
+                       return -1;
+               }
                argc--, argv++;
        }
 
@@ -329,12 +325,18 @@ get_failed:
                return 0;
        }
 
-       addattr32(n, 1024, IFLA_IPTUN_LINK, link);
-       addattr32(n, 1024, IFLA_IPTUN_LOCAL, laddr);
-       addattr32(n, 1024, IFLA_IPTUN_REMOTE, raddr);
-       addattr8(n, 1024, IFLA_IPTUN_TTL, ttl);
-       addattr8(n, 1024, IFLA_IPTUN_TOS, tos);
+       if (is_addrtype_inet(&saddr)) {
+               addattr_l(n, 1024, IFLA_IPTUN_LOCAL,
+                         saddr.data, saddr.bytelen);
+       }
+       if (is_addrtype_inet(&daddr)) {
+               addattr_l(n, 1024, IFLA_IPTUN_REMOTE,
+                         daddr.data, daddr.bytelen);
+       }
        addattr8(n, 1024, IFLA_IPTUN_PMTUDISC, pmtudisc);
+       addattr8(n, 1024, IFLA_IPTUN_TOS, tos);
+       addattr8(n, 1024, IFLA_IPTUN_TTL, ttl);
+       addattr32(n, 1024, IFLA_IPTUN_LINK, link);
        addattr32(n, 1024, IFLA_IPTUN_FWMARK, fwmark);
 
        addattr16(n, 1024, IFLA_IPTUN_ENCAP_TYPE, encaptype);
@@ -344,15 +346,17 @@ get_failed:
 
        if (strcmp(lu->id, "sit") == 0) {
                addattr16(n, 1024, IFLA_IPTUN_FLAGS, iflags);
-               if (ip6rdprefixlen) {
+               if (is_addrtype_inet(&ip6rdprefix)) {
                        addattr_l(n, 1024, IFLA_IPTUN_6RD_PREFIX,
-                                 &ip6rdprefix, sizeof(ip6rdprefix));
+                                 ip6rdprefix.data, ip6rdprefix.bytelen);
                        addattr16(n, 1024, IFLA_IPTUN_6RD_PREFIXLEN,
-                                 ip6rdprefixlen);
+                                 ip6rdprefix.bitlen);
+               }
+               if (is_addrtype_inet(&ip6rdrelayprefix)) {
                        addattr32(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIX,
-                                 ip6rdrelayprefix);
+                                 ip6rdrelayprefix.data[0]);
                        addattr16(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIXLEN,
-                                 ip6rdrelayprefixlen);
+                                 ip6rdrelayprefix.bitlen);
                }
        }
 
@@ -395,7 +399,7 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[
        tnl_print_endpoint("local", tb[IFLA_IPTUN_LOCAL], AF_INET);
 
        if (tb[IFLA_IPTUN_LINK]) {
-               unsigned int link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]);
+               __u32 link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]);
 
                if (link) {
                        print_string(PRINT_ANY, "link", "dev %s ",
@@ -483,12 +487,6 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[
                        IFLA_IPTUN_ENCAP_DPORT);
 }
 
-static void iptunnel_print_help(struct link_util *lu, int argc, char **argv,
-       FILE *f)
-{
-       print_usage(f, strcmp(lu->id, "sit") == 0);
-}
-
 struct link_util ipip_link_util = {
        .id = "ipip",
        .maxattr = IFLA_IPTUN_MAX,
index fddb7ac3c6a5cbd62a462cb6ab57247a62dec7c4..33e8f2b102e7f8178afe04694ebe8d62160317fb 100644 (file)
@@ -29,59 +29,47 @@ static void usage(void)
 }
 
 static int veth_parse_opt(struct link_util *lu, int argc, char **argv,
-                         struct nlmsghdr *hdr)
+                         struct nlmsghdr *n)
 {
-       char *dev = NULL;
-       char *name = NULL;
-       char *link = NULL;
        char *type = NULL;
-       int index = 0;
        int err;
        struct rtattr *data;
-       int group;
        struct ifinfomsg *ifm, *peer_ifm;
-       unsigned int ifi_flags, ifi_change;
+       unsigned int ifi_flags, ifi_change, ifi_index;
 
        if (strcmp(argv[0], "peer") != 0) {
                usage();
                return -1;
        }
 
-       ifm = NLMSG_DATA(hdr);
+       ifm = NLMSG_DATA(n);
        ifi_flags = ifm->ifi_flags;
        ifi_change = ifm->ifi_change;
+       ifi_index = ifm->ifi_index;
        ifm->ifi_flags = 0;
        ifm->ifi_change = 0;
+       ifm->ifi_index = 0;
 
-       data = NLMSG_TAIL(hdr);
-       addattr_l(hdr, 1024, VETH_INFO_PEER, NULL, 0);
+       data = addattr_nest(n, 1024, VETH_INFO_PEER);
 
-       hdr->nlmsg_len += sizeof(struct ifinfomsg);
+       n->nlmsg_len += sizeof(struct ifinfomsg);
 
-       err = iplink_parse(argc - 1, argv + 1, (struct iplink_req *)hdr,
-                          &name, &type, &link, &dev, &group, &index);
+       err = iplink_parse(argc - 1, argv + 1, (struct iplink_req *)n, &type);
        if (err < 0)
                return err;
 
        if (type)
                duparg("type", argv[err]);
 
-       if (name) {
-               addattr_l(hdr, 1024,
-                         IFLA_IFNAME, name, strlen(name) + 1);
-       }
-
        peer_ifm = RTA_DATA(data);
-       peer_ifm->ifi_index = index;
+       peer_ifm->ifi_index = ifm->ifi_index;
        peer_ifm->ifi_flags = ifm->ifi_flags;
        peer_ifm->ifi_change = ifm->ifi_change;
        ifm->ifi_flags = ifi_flags;
        ifm->ifi_change = ifi_change;
+       ifm->ifi_index = ifi_index;
 
-       if (group != -1)
-               addattr32(hdr, 1024, IFLA_GROUP, group);
-
-       data->rta_len = (void *)NLMSG_TAIL(hdr) - (void *)data;
+       addattr_nest_end(n, data);
        return argc - 1 - err;
 }
 
index a5b84a0759d127e13256d9db04a1fb1846a64325..6196a1c9e2f37a1da34d2ae5408d53ad929884b2 100644 (file)
 #include "ip_common.h"
 #include "tunnel.h"
 
-
-static void print_usage(FILE *f)
+static void vti_print_help(struct link_util *lu, int argc, char **argv, FILE *f)
 {
        fprintf(f,
-               "Usage: ... vti [ remote ADDR ]\n"
-               "               [ local ADDR ]\n"
-               "               [ [i|o]key KEY ]\n"
-               "               [ dev PHYS_DEV ]\n"
-               "               [ fwmark MARK ]\n"
+               "Usage: ... %-4s [ remote ADDR ]\n",
+               lu->id
+       );
+       fprintf(f,
+               "                [ local ADDR ]\n"
+               "                [ [i|o]key KEY ]\n"
+               "                [ dev PHYS_DEV ]\n"
+               "                [ fwmark MARK ]\n"
                "\n"
-               "Where: ADDR := { IP_ADDRESS }\n"
+       );
+       fprintf(f,
+               "Where: ADDR := { IP%s_ADDRESS }\n"
                "       KEY  := { DOTTED_QUAD | NUMBER }\n"
-               "       MARK := { 0x0..0xffffffff }\n"
+               "       MARK := { 0x0..0xffffffff }\n",
+               ""
        );
 }
 
-static void usage(void) __attribute__((noreturn));
-static void usage(void)
-{
-       print_usage(stderr);
-       exit(-1);
-}
-
 static int vti_parse_opt(struct link_util *lu, int argc, char **argv,
                         struct nlmsghdr *n)
 {
-       struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
+       struct ifinfomsg *ifi = NLMSG_DATA(n);
        struct {
                struct nlmsghdr n;
                struct ifinfomsg i;
@@ -66,13 +64,17 @@ static int vti_parse_opt(struct link_util *lu, int argc, char **argv,
        struct rtattr *vtiinfo[IFLA_VTI_MAX + 1];
        __be32 ikey = 0;
        __be32 okey = 0;
-       unsigned int saddr = 0;
-       unsigned int daddr = 0;
+       inet_prefix saddr, daddr;
        unsigned int link = 0;
        __u32 fwmark = 0;
        int len;
 
+       inet_prefix_reset(&saddr);
+       inet_prefix_reset(&daddr);
+
        if (!(n->nlmsg_flags & NLM_F_CREATE)) {
+               const struct rtattr *rta;
+
                if (rtnl_talk(&rth, &req.n, &answer) < 0) {
 get_failed:
                        fprintf(stderr,
@@ -98,18 +100,20 @@ get_failed:
                parse_rtattr_nested(vtiinfo, IFLA_VTI_MAX,
                                    linkinfo[IFLA_INFO_DATA]);
 
+               rta = vtiinfo[IFLA_VTI_LOCAL];
+               if (rta && get_addr_rta(&saddr, rta, AF_INET))
+                       goto get_failed;
+
+               rta = vtiinfo[IFLA_VTI_REMOTE];
+               if (rta && get_addr_rta(&daddr, rta, AF_INET))
+                       goto get_failed;
+
                if (vtiinfo[IFLA_VTI_IKEY])
                        ikey = rta_getattr_u32(vtiinfo[IFLA_VTI_IKEY]);
 
                if (vtiinfo[IFLA_VTI_OKEY])
                        okey = rta_getattr_u32(vtiinfo[IFLA_VTI_OKEY]);
 
-               if (vtiinfo[IFLA_VTI_LOCAL])
-                       saddr = rta_getattr_u32(vtiinfo[IFLA_VTI_LOCAL]);
-
-               if (vtiinfo[IFLA_VTI_REMOTE])
-                       daddr = rta_getattr_u32(vtiinfo[IFLA_VTI_REMOTE]);
-
                if (vtiinfo[IFLA_VTI_LINK])
                        link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]);
 
@@ -131,31 +135,32 @@ get_failed:
                        okey = tnl_parse_key("okey", *argv);
                } else if (!matches(*argv, "remote")) {
                        NEXT_ARG();
-                       daddr = get_addr32(*argv);
+                       get_addr(&daddr, *argv, AF_INET);
                } else if (!matches(*argv, "local")) {
                        NEXT_ARG();
-                       saddr = get_addr32(*argv);
+                       get_addr(&saddr, *argv, AF_INET);
                } else if (!matches(*argv, "dev")) {
                        NEXT_ARG();
                        link = ll_name_to_index(*argv);
-                       if (link == 0) {
-                               fprintf(stderr, "Cannot find device \"%s\"\n",
-                                       *argv);
-                               exit(-1);
-                       }
+                       if (!link)
+                               exit(nodev(*argv));
                } else if (strcmp(*argv, "fwmark") == 0) {
                        NEXT_ARG();
                        if (get_u32(&fwmark, *argv, 0))
                                invarg("invalid fwmark\n", *argv);
-               } else
-                       usage();
+               } else {
+                       vti_print_help(lu, argc, argv, stderr);
+                       return -1;
+               }
                argc--; argv++;
        }
 
        addattr32(n, 1024, IFLA_VTI_IKEY, ikey);
        addattr32(n, 1024, IFLA_VTI_OKEY, okey);
-       addattr_l(n, 1024, IFLA_VTI_LOCAL, &saddr, 4);
-       addattr_l(n, 1024, IFLA_VTI_REMOTE, &daddr, 4);
+       if (is_addrtype_inet(&saddr))
+               addattr_l(n, 1024, IFLA_VTI_LOCAL, saddr.data, saddr.bytelen);
+       if (is_addrtype_inet(&daddr))
+               addattr_l(n, 1024, IFLA_VTI_REMOTE, daddr.data, daddr.bytelen);
        addattr32(n, 1024, IFLA_VTI_FWMARK, fwmark);
        if (link)
                addattr32(n, 1024, IFLA_VTI_LINK, link);
@@ -174,7 +179,7 @@ static void vti_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
        tnl_print_endpoint("local", tb[IFLA_VTI_LOCAL], AF_INET);
 
        if (tb[IFLA_VTI_LINK]) {
-               unsigned int link = rta_getattr_u32(tb[IFLA_VTI_LINK]);
+               __u32 link = rta_getattr_u32(tb[IFLA_VTI_LINK]);
 
                if (link) {
                        print_string(PRINT_ANY, "link", "dev %s ",
@@ -208,12 +213,6 @@ static void vti_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
        }
 }
 
-static void vti_print_help(struct link_util *lu, int argc, char **argv,
-       FILE *f)
-{
-       print_usage(f);
-}
-
 struct link_util vti_link_util = {
        .id = "vti",
        .maxattr = IFLA_VTI_MAX,
index 39d12e63a4cb97b9c7887376df25791354eeab2c..4263615b2aecfaf3a3370441deeb0e6a6a93e8e1 100644 (file)
 #include "ip_common.h"
 #include "tunnel.h"
 
-static void print_usage(FILE *f)
+static void vti6_print_help(struct link_util *lu, int argc, char **argv,
+                           FILE *f)
 {
        fprintf(f,
-               "Usage: ... vti6 [ remote ADDR ]\n"
+               "Usage: ... %-4s [ remote ADDR ]\n",
+               lu->id
+       );
+       fprintf(f,
                "                [ local ADDR ]\n"
                "                [ [i|o]key KEY ]\n"
                "                [ dev PHYS_DEV ]\n"
                "                [ fwmark MARK ]\n"
                "\n"
-               "Where: ADDR := { IPV6_ADDRESS }\n"
+       );
+       fprintf(f,
+               "Where: ADDR := { IP%s_ADDRESS }\n"
                "       KEY  := { DOTTED_QUAD | NUMBER }\n"
-               "       MARK := { 0x0..0xffffffff }\n"
+               "       MARK := { 0x0..0xffffffff }\n",
+               "V6"
        );
 }
 
-static void usage(void) __attribute__((noreturn));
-static void usage(void)
-{
-       print_usage(stderr);
-       exit(-1);
-}
-
 static int vti6_parse_opt(struct link_util *lu, int argc, char **argv,
                          struct nlmsghdr *n)
 {
-       struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
+       struct ifinfomsg *ifi = NLMSG_DATA(n);
        struct {
                struct nlmsghdr n;
                struct ifinfomsg i;
@@ -64,15 +64,19 @@ static int vti6_parse_opt(struct link_util *lu, int argc, char **argv,
        struct rtattr *tb[IFLA_MAX + 1];
        struct rtattr *linkinfo[IFLA_INFO_MAX+1];
        struct rtattr *vtiinfo[IFLA_VTI_MAX + 1];
-       struct in6_addr saddr = IN6ADDR_ANY_INIT;
-       struct in6_addr daddr = IN6ADDR_ANY_INIT;
        __be32 ikey = 0;
        __be32 okey = 0;
+       inet_prefix saddr, daddr;
        unsigned int link = 0;
        __u32 fwmark = 0;
        int len;
 
+       inet_prefix_reset(&saddr);
+       inet_prefix_reset(&daddr);
+
        if (!(n->nlmsg_flags & NLM_F_CREATE)) {
+               const struct rtattr *rta;
+
                if (rtnl_talk(&rth, &req.n, &answer) < 0) {
 get_failed:
                        fprintf(stderr,
@@ -98,18 +102,20 @@ get_failed:
                parse_rtattr_nested(vtiinfo, IFLA_VTI_MAX,
                                    linkinfo[IFLA_INFO_DATA]);
 
+               rta = vtiinfo[IFLA_VTI_LOCAL];
+               if (rta && get_addr_rta(&saddr, rta, AF_INET6))
+                       goto get_failed;
+
+               rta = vtiinfo[IFLA_VTI_REMOTE];
+               if (rta && get_addr_rta(&daddr, rta, AF_INET6))
+                       goto get_failed;
+
                if (vtiinfo[IFLA_VTI_IKEY])
                        ikey = rta_getattr_u32(vtiinfo[IFLA_VTI_IKEY]);
 
                if (vtiinfo[IFLA_VTI_OKEY])
                        okey = rta_getattr_u32(vtiinfo[IFLA_VTI_OKEY]);
 
-               if (vtiinfo[IFLA_VTI_LOCAL])
-                       memcpy(&saddr, RTA_DATA(vtiinfo[IFLA_VTI_LOCAL]), sizeof(saddr));
-
-               if (vtiinfo[IFLA_VTI_REMOTE])
-                       memcpy(&daddr, RTA_DATA(vtiinfo[IFLA_VTI_REMOTE]), sizeof(daddr));
-
                if (vtiinfo[IFLA_VTI_LINK])
                        link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]);
 
@@ -130,38 +136,33 @@ get_failed:
                        NEXT_ARG();
                        okey = tnl_parse_key("okey", *argv);
                } else if (!matches(*argv, "remote")) {
-                       inet_prefix addr;
-
                        NEXT_ARG();
-                       get_addr(&addr, *argv, AF_INET6);
-                       memcpy(&daddr, addr.data, sizeof(daddr));
+                       get_addr(&daddr, *argv, AF_INET6);
                } else if (!matches(*argv, "local")) {
-                       inet_prefix addr;
-
                        NEXT_ARG();
-                       get_addr(&addr, *argv, AF_INET6);
-                       memcpy(&saddr, addr.data, sizeof(saddr));
+                       get_addr(&saddr, *argv, AF_INET6);
                } else if (!matches(*argv, "dev")) {
                        NEXT_ARG();
                        link = ll_name_to_index(*argv);
-                       if (link == 0) {
-                               fprintf(stderr, "Cannot find device \"%s\"\n",
-                                       *argv);
-                               exit(-1);
-                       }
+                       if (!link)
+                               exit(nodev(*argv));
                } else if (strcmp(*argv, "fwmark") == 0) {
                        NEXT_ARG();
                        if (get_u32(&fwmark, *argv, 0))
                                invarg("invalid fwmark\n", *argv);
-               } else
-                       usage();
+               } else {
+                       vti6_print_help(lu, argc, argv, stderr);
+                       return -1;
+               }
                argc--; argv++;
        }
 
        addattr32(n, 1024, IFLA_VTI_IKEY, ikey);
        addattr32(n, 1024, IFLA_VTI_OKEY, okey);
-       addattr_l(n, 1024, IFLA_VTI_LOCAL, &saddr, sizeof(saddr));
-       addattr_l(n, 1024, IFLA_VTI_REMOTE, &daddr, sizeof(daddr));
+       if (is_addrtype_inet(&saddr))
+               addattr_l(n, 1024, IFLA_VTI_LOCAL, saddr.data, saddr.bytelen);
+       if (is_addrtype_inet(&daddr))
+               addattr_l(n, 1024, IFLA_VTI_REMOTE, daddr.data, daddr.bytelen);
        addattr32(n, 1024, IFLA_VTI_FWMARK, fwmark);
        if (link)
                addattr32(n, 1024, IFLA_VTI_LINK, link);
@@ -180,7 +181,7 @@ static void vti6_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
        tnl_print_endpoint("local", tb[IFLA_VTI_LOCAL], AF_INET6);
 
        if (tb[IFLA_VTI_LINK]) {
-               unsigned int link = rta_getattr_u32(tb[IFLA_VTI_LINK]);
+               __u32 link = rta_getattr_u32(tb[IFLA_VTI_LINK]);
 
                if (link) {
                        print_string(PRINT_ANY, "link", "dev %s ",
@@ -214,12 +215,6 @@ static void vti6_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
        }
 }
 
-static void vti6_print_help(struct link_util *lu, int argc, char **argv,
-       FILE *f)
-{
-       print_usage(f);
-}
-
 struct link_util vti6_link_util = {
        .id = "vti6",
        .maxattr = IFLA_VTI_MAX,
index 7e2d9eb34b799389cf329c8886c72a73fa105c43..72dc980c92a64c6a6453ee5eae32565ca1c8ba4e 100644 (file)
@@ -38,6 +38,7 @@ static void usage(void)
 /* netlink socket */
 static struct rtnl_handle grth = { .fd = -1 };
 static int genl_family = -1;
+static const double usec_per_sec = 1000000.;
 
 #define TCPM_REQUEST(_req, _bufsiz, _cmd, _flags) \
        GENL_REQUEST(_req, _bufsiz, genl_family, 0, \
@@ -47,8 +48,8 @@ static int genl_family = -1;
 #define CMD_DEL                0x0002  /* delete, remove               */
 #define CMD_FLUSH      0x0004  /* flush                        */
 
-static struct {
-       char    *name;
+static const struct {
+       const char *name;
        int     code;
 } cmds[] = {
        {       "list",         CMD_LIST        },
@@ -59,7 +60,7 @@ static struct {
        {       "flush",        CMD_FLUSH       },
 };
 
-static char *metric_name[TCP_METRIC_MAX + 1] = {
+static const char *metric_name[TCP_METRIC_MAX + 1] = {
        [TCP_METRIC_RTT]                = "rtt",
        [TCP_METRIC_RTTVAR]             = "rttvar",
        [TCP_METRIC_SSTHRESH]           = "ssthresh",
@@ -67,8 +68,7 @@ static char *metric_name[TCP_METRIC_MAX + 1] = {
        [TCP_METRIC_REORDERING]         = "reordering",
 };
 
-static struct
-{
+static struct {
        int flushed;
        char *flushb;
        int flushp;
@@ -88,15 +88,84 @@ static int flush_update(void)
        return 0;
 }
 
+static void print_tcp_metrics(struct rtattr *a)
+{
+       struct rtattr *m[TCP_METRIC_MAX + 1 + 1];
+       unsigned long rtt = 0, rttvar = 0;
+       int i;
+
+       parse_rtattr_nested(m, TCP_METRIC_MAX + 1, a);
+
+       for (i = 0; i < TCP_METRIC_MAX + 1; i++) {
+               const char *name;
+               __u32 val;
+               SPRINT_BUF(b1);
+
+               a = m[i + 1];
+               if (!a)
+                       continue;
+
+               val = rta_getattr_u32(a);
+
+               switch (i) {
+               case TCP_METRIC_RTT:
+                       if (!rtt)
+                               rtt = (val * 1000UL) >> 3;
+                       continue;
+               case TCP_METRIC_RTTVAR:
+                       if (!rttvar)
+                               rttvar = (val * 1000UL) >> 2;
+                       continue;
+               case TCP_METRIC_RTT_US:
+                       rtt = val >> 3;
+                       continue;
+
+               case TCP_METRIC_RTTVAR_US:
+                       rttvar = val >> 2;
+                       continue;
+
+               case TCP_METRIC_SSTHRESH:
+               case TCP_METRIC_CWND:
+               case TCP_METRIC_REORDERING:
+                       name = metric_name[i];
+                       break;
+
+               default:
+                       snprintf(b1, sizeof(b1),
+                                " metric_%d ", i);
+                       name = b1;
+               }
+
+
+               print_uint(PRINT_JSON, name, NULL, val);
+               print_string(PRINT_FP, NULL, " %s ", name);
+               print_uint(PRINT_FP, NULL, "%lu", val);
+       }
+
+       if (rtt) {
+               print_float(PRINT_JSON, "rtt", NULL,
+                           (double)rtt / usec_per_sec);
+               print_uint(PRINT_FP, NULL,
+                          " rtt %luus", rtt);
+       }
+       if (rttvar) {
+               print_float(PRINT_JSON, "rttvar", NULL,
+                           (double) rttvar / usec_per_sec);
+               print_uint(PRINT_FP, NULL,
+                          " rttvar %luus", rttvar);
+       }
+}
+
 static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
                       void *arg)
 {
        FILE *fp = (FILE *) arg;
        struct genlmsghdr *ghdr;
        struct rtattr *attrs[TCP_METRICS_ATTR_MAX + 1], *a;
+       const char *h;
        int len = n->nlmsg_len;
        inet_prefix daddr, saddr;
-       int i, atype, stype;
+       int atype, stype;
 
        if (n->nlmsg_type != genl_family)
                return -1;
@@ -186,96 +255,60 @@ static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
                        return 0;
        }
 
+       open_json_object(NULL);
        if (f.cmd & (CMD_DEL | CMD_FLUSH))
-               fprintf(fp, "Deleted ");
+               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 
-       fprintf(fp, "%s",
-               format_host(daddr.family, daddr.bytelen, daddr.data));
+       h = format_host(daddr.family, daddr.bytelen, daddr.data);
+       print_color_string(PRINT_ANY,
+                          ifa_family_color(daddr.family),
+                          "dst", "%s", h);
 
        a = attrs[TCP_METRICS_ATTR_AGE];
        if (a) {
-               unsigned long long val = rta_getattr_u64(a);
+               __u64 val = rta_getattr_u64(a);
+               double age = val / 1000.;
 
-               fprintf(fp, " age %llu.%03llusec",
-                       val / 1000, val % 1000);
+               print_float(PRINT_ANY, "age",
+                            " age %.03fsec", age);
        }
 
        a = attrs[TCP_METRICS_ATTR_TW_TS_STAMP];
        if (a) {
                __s32 val = (__s32) rta_getattr_u32(a);
                __u32 tsval;
+               char tw_ts[64];
 
                a = attrs[TCP_METRICS_ATTR_TW_TSVAL];
                tsval = a ? rta_getattr_u32(a) : 0;
-               fprintf(fp, " tw_ts %u/%dsec ago", tsval, val);
+               snprintf(tw_ts, sizeof(tw_ts),
+                        "%u/%d", tsval, val);
+               print_string(PRINT_ANY, "tw_ts_stamp",
+                    " tw_ts %s ago", tw_ts);
        }
 
-       a = attrs[TCP_METRICS_ATTR_VALS];
-       if (a) {
-               struct rtattr *m[TCP_METRIC_MAX + 1 + 1];
-               unsigned long rtt = 0, rttvar = 0;
-
-               parse_rtattr_nested(m, TCP_METRIC_MAX + 1, a);
-
-               for (i = 0; i < TCP_METRIC_MAX + 1; i++) {
-                       unsigned long val;
-
-                       a = m[i + 1];
-                       if (!a)
-                               continue;
-                       if (i != TCP_METRIC_RTT &&
-                           i != TCP_METRIC_RTT_US &&
-                           i != TCP_METRIC_RTTVAR &&
-                           i != TCP_METRIC_RTTVAR_US) {
-                               if (metric_name[i])
-                                       fprintf(fp, " %s ", metric_name[i]);
-                               else
-                                       fprintf(fp, " metric_%d ", i);
-                       }
-                       val = rta_getattr_u32(a);
-                       switch (i) {
-                       case TCP_METRIC_RTT:
-                               if (!rtt)
-                                       rtt = (val * 1000UL) >> 3;
-                               break;
-                       case TCP_METRIC_RTTVAR:
-                               if (!rttvar)
-                                       rttvar = (val * 1000UL) >> 2;
-                               break;
-                       case TCP_METRIC_RTT_US:
-                               rtt = val >> 3;
-                               break;
-                       case TCP_METRIC_RTTVAR_US:
-                               rttvar = val >> 2;
-                               break;
-                       case TCP_METRIC_SSTHRESH:
-                       case TCP_METRIC_CWND:
-                       case TCP_METRIC_REORDERING:
-                       default:
-                               fprintf(fp, "%lu", val);
-                               break;
-                       }
-               }
-               if (rtt)
-                       fprintf(fp, " rtt %luus", rtt);
-               if (rttvar)
-                       fprintf(fp, " rttvar %luus", rttvar);
-       }
+       if (attrs[TCP_METRICS_ATTR_VALS])
+               print_tcp_metrics(attrs[TCP_METRICS_ATTR_VALS]);
 
        a = attrs[TCP_METRICS_ATTR_FOPEN_MSS];
-       if (a)
-               fprintf(fp, " fo_mss %u", rta_getattr_u16(a));
+       if (a) {
+               print_uint(PRINT_ANY, "fopen_miss", " fo_mss %u",
+                          rta_getattr_u16(a));
+       }
 
        a = attrs[TCP_METRICS_ATTR_FOPEN_SYN_DROPS];
        if (a) {
                __u16 syn_loss = rta_getattr_u16(a);
-               unsigned long long ts;
+               double ts;
 
                a = attrs[TCP_METRICS_ATTR_FOPEN_SYN_DROP_TS];
                ts = a ? rta_getattr_u64(a) : 0;
 
-               fprintf(fp, " fo_syn_drops %u/%llu.%03llusec ago",
-                       syn_loss, ts / 1000, ts % 1000);
+               print_uint(PRINT_ANY, "fopen_syn_drops",
+                          " fo_syn_drops %u", syn_loss);
+               print_float(PRINT_ANY, "fopen_syn_drop_ts",
+                            "/%.03fusec ago",
+                            ts / 1000000.);
        }
 
        a = attrs[TCP_METRICS_ATTR_FOPEN_COOKIE];
@@ -289,16 +322,21 @@ static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
                cookie[0] = 0;
                for (i = 0; i < max; i++)
                        sprintf(cookie + i + i, "%02x", ptr[i]);
-               fprintf(fp, " fo_cookie %s", cookie);
+
+               print_string(PRINT_ANY, "fo_cookie",
+                            " fo_cookie %s", cookie);
        }
 
        if (saddr.family) {
-               fprintf(fp, " source %s",
-                       format_host(saddr.family, saddr.bytelen, saddr.data));
-       }
+               const char *src;
 
-       fprintf(fp, "\n");
+               src = format_host(saddr.family, saddr.bytelen, saddr.data);
+               print_string(PRINT_ANY, "source",
+                            " source %s", src);
+       }
 
+       print_string(PRINT_FP, NULL, "\n", "");
+       close_json_object();
        fflush(fp);
        return 0;
 }
@@ -475,10 +513,12 @@ static int tcpm_do_cmd(int cmd, int argc, char **argv)
                        exit(1);
                }
 
+               new_json_obj(json);
                if (rtnl_dump_filter(&grth, process_msg, stdout) < 0) {
                        fprintf(stderr, "Dump terminated\n");
                        exit(1);
                }
+               delete_json_obj();
        }
        return 0;
 }
index 948d5f7c90f6de48d2fe76f8a03a2f2d953e4155..7030995cd61ab0245bebb7440d488e985803adc8 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/if.h>
 #include <linux/ip.h>
 #include <linux/if_tunnel.h>
+#include <linux/if_arp.h>
 
 #include "utils.h"
 #include "tunnel.h"
@@ -307,30 +308,99 @@ void tnl_print_endpoint(const char *name, const struct rtattr *rta, int family)
        }
 }
 
-/* tnl_print_stats - print tunnel statistics
- *
- * @buf - tunnel interface's line in /proc/net/dev,
- *        starting past the interface name and following colon
- */
-void tnl_print_stats(const char *buf)
+static void tnl_print_stats(const struct rtnl_link_stats64 *s)
 {
-       unsigned long rx_bytes, rx_packets, rx_errs, rx_drops,
-                     rx_fifo, rx_frame,
-                     tx_bytes, tx_packets, tx_errs, tx_drops,
-                     tx_fifo, tx_colls, tx_carrier, rx_multi;
-
-       if (sscanf(buf, "%lu%lu%lu%lu%lu%lu%lu%*d%lu%lu%lu%lu%lu%lu%lu",
-                  &rx_bytes, &rx_packets, &rx_errs, &rx_drops,
-                  &rx_fifo, &rx_frame, &rx_multi,
-                  &tx_bytes, &tx_packets, &tx_errs, &tx_drops,
-                  &tx_fifo, &tx_colls, &tx_carrier) != 14)
-               return;
-
        printf("%s", _SL_);
        printf("RX: Packets    Bytes        Errors CsumErrs OutOfSeq Mcasts%s", _SL_);
-       printf("    %-10ld %-12ld %-6ld %-8ld %-8ld %-8ld%s",
-              rx_packets, rx_bytes, rx_errs, rx_frame, rx_fifo, rx_multi, _SL_);
+       printf("    %-10lld %-12lld %-6lld %-8lld %-8lld %-8lld%s",
+              s->rx_packets, s->rx_bytes, s->rx_errors, s->rx_frame_errors,
+              s->rx_fifo_errors, s->multicast, _SL_);
        printf("TX: Packets    Bytes        Errors DeadLoop NoRoute  NoBufs%s", _SL_);
-       printf("    %-10ld %-12ld %-6ld %-8ld %-8ld %-6ld",
-              tx_packets, tx_bytes, tx_errs, tx_colls, tx_carrier, tx_drops);
+       printf("    %-10lld %-12lld %-6lld %-8lld %-8lld %-6lld",
+              s->tx_packets, s->tx_bytes, s->tx_errors, s->collisions,
+              s->tx_carrier_errors, s->tx_dropped);
+}
+
+static int print_nlmsg_tunnel(const struct sockaddr_nl *who,
+                             struct nlmsghdr *n, void *arg)
+{
+       struct tnl_print_nlmsg_info *info = arg;
+       struct ifinfomsg *ifi = NLMSG_DATA(n);
+       struct rtattr *tb[IFLA_MAX+1];
+       const char *name, *n1;
+
+       if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK)
+               return 0;
+
+       if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*ifi)))
+               return -1;
+
+       if (preferred_family == AF_INET) {
+               switch (ifi->ifi_type) {
+               case ARPHRD_TUNNEL:
+               case ARPHRD_IPGRE:
+               case ARPHRD_SIT:
+                       break;
+               default:
+                       return 0;
+               }
+       } else {
+               switch (ifi->ifi_type) {
+               case ARPHRD_TUNNEL6:
+               case ARPHRD_IP6GRE:
+                       break;
+               default:
+                       return 0;
+               }
+       }
+
+       parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
+
+       if (!tb[IFLA_IFNAME])
+               return 0;
+
+       name = rta_getattr_str(tb[IFLA_IFNAME]);
+
+       /* Assume p1->name[IFNAMSIZ] is first field of structure */
+       n1 = info->p1;
+       if (n1[0] && strcmp(n1, name))
+               return 0;
+
+       info->ifi = ifi;
+       info->init(info);
+
+       /* TODO: parse netlink attributes */
+       if (tnl_get_ioctl(name, info->p2))
+               return 0;
+
+       if (!info->match(info))
+               return 0;
+
+       info->print(info->p2);
+       if (show_stats) {
+               struct rtnl_link_stats64 s;
+
+               if (get_rtnl_link_stats_rta(&s, tb) <= 0)
+                       return -1;
+
+               tnl_print_stats(&s);
+       }
+       fputc('\n', stdout);
+
+       return 0;
+}
+
+int do_tunnels_list(struct tnl_print_nlmsg_info *info)
+{
+       if (rtnl_wilddump_request(&rth, preferred_family, RTM_GETLINK) < 0) {
+               perror("Cannot send dump request\n");
+               return -1;
+       }
+
+       if (rtnl_dump_filter(&rth, print_nlmsg_tunnel, info) < 0) {
+               fprintf(stderr, "Dump terminated\n");
+               return -1;
+       }
+
+       return 0;
 }
index 5bd27c324e6efc083d4ddd8026656251803a6116..e530d07cbf6a2f4a7acfef1727f3b441c95f7d85 100644 (file)
 #ifndef __TUNNEL_H__
 #define __TUNNEL_H__ 1
 
+#include <stdbool.h>
 #include <linux/types.h>
 
 struct rtattr;
+struct ifinfomsg;
+
+extern struct rtnl_handle rth;
+
+struct tnl_print_nlmsg_info {
+       const struct ifinfomsg *ifi;
+       const void *p1;
+       void *p2;
+
+       void (*init)(const struct tnl_print_nlmsg_info *info);
+       bool (*match)(const struct tnl_print_nlmsg_info *info);
+       void (*print)(const void *t);
+};
+
+int do_tunnels_list(struct tnl_print_nlmsg_info *info);
 
 const char *tnl_strproto(__u8 proto);
 
@@ -39,6 +55,5 @@ void tnl_print_encap(struct rtattr *tb[],
                     int encap_sport, int encap_dport);
 void tnl_print_endpoint(const char *name,
                        const struct rtattr *rta, int family);
-void tnl_print_stats(const char *buf);
 
 #endif
diff --git a/ip/xdp.h b/ip/xdp.h
deleted file mode 100644 (file)
index 7e10696..0000000
--- a/ip/xdp.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __XDP__
-#define __XDP__
-
-#include "utils.h"
-
-int xdp_parse(int *argc, char ***argv, struct iplink_req *req, __u32 ifindex,
-             bool generic, bool drv, bool offload);
-void xdp_dump(FILE *fp, struct rtattr *tb, bool link, bool details);
-
-#endif /* __XDP__ */
index 7b34ed5f8a48ed68398cf85e73a35c1d3f0752ae..bab8cbf510074bf9c68a8e4e74e35536fa2b9107 100644 (file)
@@ -3,11 +3,11 @@ include ../config.mk
 
 CFLAGS += -fPIC
 
-UTILOBJ = utils.o rt_names.o ll_types.o ll_proto.o ll_addr.o \
+UTILOBJ = utils.o rt_names.o ll_map.o ll_types.o ll_proto.o ll_addr.o \
        inet_proto.o namespace.o json_writer.o json_print.o \
        names.o color.o bpf.o exec.o fs.o
 
-NLOBJ=libgenl.o ll_map.o libnetlink.o
+NLOBJ=libgenl.o libnetlink.o
 
 all: libnetlink.a libutil.a
 
index 6518ba98f5bf8cc0875fa089dcfa2fa7e185f121..bda7293350c33907c64ce3ad8fcbbf4d0f73e5ee 100644 (file)
@@ -28,7 +28,8 @@ void new_json_obj(int json)
                        perror("json object");
                        exit(1);
                }
-               jsonw_pretty(_jw, true);
+               if (pretty)
+                       jsonw_pretty(_jw, true);
                jsonw_start_array(_jw);
        }
 }
@@ -88,9 +89,7 @@ void open_json_array(enum output_type type, const char *str)
 void close_json_array(enum output_type type, const char *str)
 {
        if (_IS_JSON_CONTEXT(type)) {
-               jsonw_pretty(_jw, false);
                jsonw_end_array(_jw);
-               jsonw_pretty(_jw, true);
        } else if (_IS_FP_CONTEXT(type)) {
                printf("%s", str);
        }
index cddd4dcae7da01d4c6cb88617d7cb540e534d40e..68401ae3f2ac68bd94f3dd325963935e883437d5 100644 (file)
@@ -176,10 +176,15 @@ void jsonw_end_object(json_writer_t *self)
 void jsonw_start_array(json_writer_t *self)
 {
        jsonw_begin(self, '[');
+       if (self->pretty)
+               putc(' ', self->out);
 }
 
 void jsonw_end_array(json_writer_t *self)
 {
+       if (self->pretty && self->sep)
+               putc(' ', self->out);
+       self->sep = '\0';
        jsonw_end(self, ']');
 }
 
index f65614fa46fc2f95ee1ee4f355d62079c7357726..0afe68979283b8d485f443e344ed8a1457a9c93b 100644 (file)
@@ -136,8 +136,26 @@ int ll_remember_index(const struct sockaddr_nl *who,
        return 0;
 }
 
-const char *ll_idx_n2a(unsigned idx, char *buf)
+const char *ll_idx_n2a(unsigned int idx)
 {
+       static char buf[IFNAMSIZ];
+
+       snprintf(buf, sizeof(buf), "if%u", idx);
+       return buf;
+}
+
+unsigned int ll_idx_a2n(const char *name)
+{
+       unsigned int idx;
+
+       if (sscanf(name, "if%u", &idx) != 1)
+               return 0;
+       return idx;
+}
+
+const char *ll_index_to_name(unsigned int idx)
+{
+       static char buf[IFNAMSIZ];
        const struct ll_cache *im;
 
        if (idx == 0)
@@ -148,18 +166,11 @@ const char *ll_idx_n2a(unsigned idx, char *buf)
                return im->name;
 
        if (if_indextoname(idx, buf) == NULL)
-               snprintf(buf, IFNAMSIZ, "if%d", idx);
+               snprintf(buf, IFNAMSIZ, "if%u", idx);
 
        return buf;
 }
 
-const char *ll_index_to_name(unsigned idx)
-{
-       static char nbuf[IFNAMSIZ];
-
-       return ll_idx_n2a(idx, nbuf);
-}
-
 int ll_index_to_type(unsigned idx)
 {
        const struct ll_cache *im;
@@ -196,7 +207,7 @@ unsigned ll_name_to_index(const char *name)
 
        idx = if_nametoindex(name);
        if (idx == 0)
-               sscanf(name, "if%u", &idx);
+               idx = ll_idx_a2n(name);
        return idx;
 }
 
index dadefb55096c3a3e72110993a761e1e46f4f6127..63eadc4c1d408074d42a2644cdda1f9505edfd64 100644 (file)
 
 #include "rt_names.h"
 #include "utils.h"
+#include "ll_map.h"
 #include "namespace.h"
 
 int resolve_hosts;
 int timestamp_short;
+int pretty;
 
 int read_prop(const char *dev, char *prop, long *value)
 {
@@ -867,6 +869,12 @@ void duparg2(const char *key, const char *arg)
        exit(-1);
 }
 
+int nodev(const char *dev)
+{
+       fprintf(stderr, "Cannot find device \"%s\"\n", dev);
+       return -1;
+}
+
 int check_ifname(const char *name)
 {
        /* These checks mimic kernel checks in dev_valid_name */
@@ -895,6 +903,25 @@ int get_ifname(char *buf, const char *name)
        return ret;
 }
 
+const char *get_ifname_rta(int ifindex, const struct rtattr *rta)
+{
+       const char *name;
+
+       if (rta) {
+               name = rta_getattr_str(rta);
+       } else {
+               fprintf(stderr,
+                       "BUG: device with ifindex %d has nil ifname\n",
+                       ifindex);
+               name = ll_idx_n2a(ifindex);
+       }
+
+       if (check_ifname(name))
+               return NULL;
+
+       return name;
+}
+
 int matches(const char *cmd, const char *pattern)
 {
        int len = strlen(cmd);
@@ -1284,6 +1311,54 @@ int print_timestamp(FILE *fp)
        return 0;
 }
 
+unsigned int print_name_and_link(const char *fmt,
+                                const char *name, struct rtattr *tb[])
+{
+       const char *link = NULL;
+       unsigned int m_flag = 0;
+       SPRINT_BUF(b1);
+
+       if (tb[IFLA_LINK]) {
+               int iflink = rta_getattr_u32(tb[IFLA_LINK]);
+
+               if (iflink) {
+                       if (tb[IFLA_LINK_NETNSID]) {
+                               if (is_json_context()) {
+                                       print_int(PRINT_JSON,
+                                                 "link_index", NULL, iflink);
+                               } else {
+                                       link = ll_idx_n2a(iflink);
+                               }
+                       } else {
+                               link = ll_index_to_name(iflink);
+
+                               if (is_json_context()) {
+                                       print_string(PRINT_JSON,
+                                                    "link", NULL, link);
+                                       link = NULL;
+                               }
+
+                               m_flag = ll_index_to_flags(iflink);
+                               m_flag = !(m_flag & IFF_UP);
+                       }
+               } else {
+                       if (is_json_context())
+                               print_null(PRINT_JSON, "link", NULL, NULL);
+                       else
+                               link = "NONE";
+               }
+
+               if (link) {
+                       snprintf(b1, sizeof(b1), "%s@%s", name, link);
+                       name = b1;
+               }
+       }
+
+       print_color_string(PRINT_ANY, COLOR_IFNAME, "ifname", fmt, name);
+
+       return m_flag;
+}
+
 int cmdlineno;
 
 /* Like glibc getline but handle continuation lines and comments */
@@ -1474,6 +1549,51 @@ int get_real_family(int rtm_type, int rtm_family)
        return rtm_family;
 }
 
+/* Based on copy_rtnl_link_stats() from kernel at net/core/rtnetlink.c */
+static void copy_rtnl_link_stats64(struct rtnl_link_stats64 *stats64,
+                                  const struct rtnl_link_stats *stats)
+{
+       __u64 *a = (__u64 *)stats64;
+       const __u32 *b = (const __u32 *)stats;
+       const __u32 *e = b + sizeof(*stats) / sizeof(*b);
+
+       while (b < e)
+               *a++ = *b++;
+}
+
+int get_rtnl_link_stats_rta(struct rtnl_link_stats64 *stats64,
+                           struct rtattr *tb[])
+{
+       struct rtnl_link_stats stats;
+       void *s;
+       struct rtattr *rta;
+       int size, len;
+
+       if (tb[IFLA_STATS64]) {
+               rta = tb[IFLA_STATS64];
+               size = sizeof(struct rtnl_link_stats64);
+               s = stats64;
+       } else if (tb[IFLA_STATS]) {
+               rta = tb[IFLA_STATS];
+               size = sizeof(struct rtnl_link_stats);
+               s = &stats;
+       } else {
+               return -1;
+       }
+
+       len = RTA_PAYLOAD(rta);
+       if (len < size)
+               memset(s + len, 0, size - len);
+       else
+               len = size;
+
+       memcpy(s, RTA_DATA(rta), len);
+
+       if (s != stats64)
+               copy_rtnl_link_stats64(stats64, s);
+       return size;
+}
+
 #ifdef NEED_STRLCPY
 size_t strlcpy(char *dst, const char *src, size_t size)
 {
index d6baa819020abee01c63ec931d0ff66f4cb477e2..e7f7148315e19ddfb356839524c29976ef661715 100644 (file)
@@ -22,6 +22,8 @@ bridge \- show / manipulate bridge addresses and devices
 \fB\-s\fR[\fItatistics\fR] |
 \fB\-n\fR[\fIetns\fR] name |
 \fB\-b\fR[\fIatch\fR] filename |
+\fB\-c\fR[\folor\fR] |
+\fB\-p\fR[\fIretty\fR] |
 \fB\-j\fR[\fIson\fR] }
 
 .ti -8
@@ -59,7 +61,7 @@ bridge \- show / manipulate bridge addresses and devices
 .B dev
 .IR DEV " { "
 .BR local " | " static " | " dynamic " } [ "
-.BR self " ] [ " master " ] [ " router " ] [ " use " ] [ "
+.BR self " ] [ " master " ] [ " router " ] [ " use " ] [ " extern_learn " ] [ "
 .B dst
 .IR IPADDR " ] [ "
 .B vni
@@ -168,8 +170,17 @@ If there were any errors during execution of the commands, the application
 return code will be non zero.
 
 .TP
-.BR "\-json"
-Display results in JSON format. Currently available for vlan and fdb.
+.BR "\-c" , " -color"
+Use color output.
+
+.TP
+.BR "\-j", " \-json"
+Output results in JavaScript Object Notation (JSON).
+
+.TP
+.BR "\-p", " \-pretty"
+When combined with -j generate a pretty JSON output.
+
 
 .SH BRIDGE - COMMAND SYNTAX
 
@@ -403,6 +414,12 @@ route shortcircuit enabled.
 indicate to the kernel that the fdb entry is in use.
 .sp
 
+.B extern_learn
+- this entry was learned externally. This option can be used to
+indicate to the kernel that an entry was hardware or user-space
+controller learnt dynamic entry. Kernel will not age such an entry.
+.sp
+
 .in -8
 The next command line parameters apply only
 when the specified device
index 481589ea368ad7e25dbaaa74cdf1b471289cb205..5dee9fcd627a2a7eab6cf8c860ca674baa0a9606 100644 (file)
@@ -793,6 +793,8 @@ the following additional arguments are supported:
 ] [
 .BI "dscp inherit"
 ] [
+.BI "[no]allow-localremote"
+] [
 .BI dev " PHYS_DEV "
 ] [
 .RB external
@@ -856,6 +858,11 @@ flag is equivalent to the combination
 .BI  flowlabel " FLOWLABEL"
 - specifies a fixed flowlabel.
 
+.sp
+.BI  [no]allow-localremote
+- specifies whether to allow remote endpoint to have an address configured on
+local host.
+
 .sp
 .BI  tclass " TCLASS"
 - specifies the traffic class field on
@@ -927,6 +934,8 @@ the following additional arguments are supported:
 ] [
 .BR erspan_hwid " \fIhwid "
 ] [
+.BI "[no]allow-localremote"
+] [
 .RB external
 ]
 
@@ -964,6 +973,11 @@ traffic's source port and direction.
 .IR hwid
 is a 6-bit value for users to configure.
 
+.sp
+.BI  [no]allow-localremote
+- specifies whether to allow remote endpoint to have an address configured on
+local host.
+
 .sp
 .BR external
 - make this tunnel externally controlled (or not, which is the default).
index a5c479811927f536ae6914dd8220e3408ab047fc..1455a49a5ea573fb8c623fe387524bcd6e256928 100644 (file)
@@ -44,12 +44,26 @@ ip-rule \- routing policy database management
 .IR STRING " ] [ "
 .B  pref
 .IR NUMBER " ] [ "
-.BR l3mdev " ]"
+.IR l3mdev " ] [ "
+.B uidrange
+.IR NUMBER "-" NUMBER " ] [ "
+.B ipproto
+.IR PROTOCOL " ] [ "
+.BR sport " [ "
+.IR NUMBER " | "
+.IR NUMBER "-" NUMBER " ] ] [ "
+.BR dport " [ "
+.IR NUMBER " | "
+.IR NUMBER "-" NUMBER " ] ]"
+.BR
+
 
 .ti -8
 .IR ACTION " := [ "
 .B  table
 .IR TABLE_ID " ] [ "
+.B  protocol
+.IR PROTO " ] [ "
 .B  nat
 .IR ADDRESS " ] [ "
 .B realms
@@ -224,6 +238,24 @@ select the
 .B fwmark
 value to match.
 
+.TP
+.BI uidrange " NUMBER-NUMBER"
+select the
+.B uid
+value to match.
+
+.TP
+.BI ipproto " PROTOCOL"
+select the ip protocol value to match.
+
+.TP
+.BI sport " NUMBER | NUMBER-NUMBER"
+select the source port value to match. supports port range.
+
+.TP
+.BI dport " NUMBER | NUMBER-NUMBER"
+select the destination port value to match. supports port range.
+
 .TP
 .BI priority " PREFERENCE"
 the priority of this rule.
@@ -240,6 +272,10 @@ The options preference and order are synonyms with priority.
 the routing table identifier to lookup if the rule selector matches.
 It is also possible to use lookup instead of table.
 
+.TP
+.BI protocol " PROTO"
+the routing protocol who installed the rule in question.  As an example when zebra installs a rule it would get RTPROT_ZEBRA as the installing protocol.
+
 .TP
 .BI suppress_prefixlength " NUMBER"
 reject routing decisions that have a prefix length of NUMBER or less.
@@ -275,7 +311,11 @@ updates, it flushes the routing cache with
 .RE
 .TP
 .B ip rule flush - also dumps all the deleted rules.
-This command has no arguments.
+.RS
+.TP
+.BI protocol " PROTO"
+Select the originating protocol.
+.RE
 .TP
 .B ip rule show - list rules
 This command has no arguments.
@@ -283,6 +323,12 @@ The options list or lst are synonyms with show.
 
 .TP
 .B ip rule save
+.RS
+.TP
+.BI protocol " PROTO"
+Select the originating protocol.
+.RE
+.TP
 save rules table information to stdout
 .RS
 This command behaves like
index 7f26582db7956faec7cee77277ec39f0d7818c98..0087d18b74706870c16684d4976eb9d9eb790632 100644 (file)
@@ -48,9 +48,10 @@ ip \- show / manipulate routing, network devices, interfaces and tunnels
 \fB\-ts\fR[\fIhort\fR] |
 \fB\-n\fR[\fIetns\fR] name |
 \fB\-a\fR[\fIll\fR] |
-\fB\-c\fR[\fIolor\fR]
-\fB\-br\fR[\fIief\fR] }
-
+\fB\-c\fR[\fIolor\fR] |
+\fB\-br\fR[\fIief\fR] |
+\fB\-j\fR[son\fR] |
+\fB\-p\fR[retty\fR] }
 
 .SH OPTIONS
 
@@ -208,10 +209,19 @@ Set the netlink socket receive buffer size, defaults to 1MB.
 print human readable rates in IEC units (e.g. 1Ki = 1024).
 
 .TP
-.BR "\-br" , "\-brief"
+.BR "\-br" , " \-brief"
 Print only basic information in a tabular format for better readability. This option is currently only supported by
 .BR "ip addr show " and " ip link show " commands.
 
+.TP
+.BR "\-j", " \-json"
+Output results in JavaScript Object Notation (JSON).
+
+.TP
+.BR "\-p", " \-pretty"
+The default JSON format is compact and more efficient to parse but hard for most users to read.
+This flag adds indentation for readability.
+
 .SH IP - COMMAND SYNTAX
 
 .SS
index 798b33d3e30141be5ffb3a6100949f4ede2a5218..fba77693e3196d8b8668f94e58d9cb4115e6b932 100644 (file)
@@ -11,6 +11,12 @@ rdma \- RDMA tool
 .BR help " }"
 .sp
 
+.ti -8
+.B rdma
+.RB "[ " -force " ] "
+.BI "-batch " filename
+.sp
+
 .ti -8
 .IR OBJECT " := { "
 .BR dev " | " link " }"
@@ -31,6 +37,16 @@ Print the version of the
 .B rdma
 tool and exit.
 
+.TP
+.BR "\-b", " \-batch " <FILENAME>
+Read commands from provided file or standard input and invoke them.
+First failure will cause termination of rdma.
+
+.TP
+.BR "\-force"
+Don't terminate rdma on errors in batch mode.
+If there were any errors during execution of the commands, the application return code will be non zero.
+
 .TP
 .BR "\-d" , " --details"
 Otuput detailed information.
index a0e50a4efa0800bbb91b1fde3c82322936d669aa..e538e940264ca1fbe0824a572842e560483063e3 100644 (file)
@@ -13,7 +13,9 @@ TIME ] [
 .B ecn
 |
 .B noecn
-]
+] [
+.B ce_threshold
+TIME ]
 
 .SH DESCRIPTION
 CoDel (pronounced "coddle") is an adaptive "no-knobs" active queue management
@@ -80,6 +82,12 @@ can be used to turn it off and vice-a-versa. By default,
 .B ecn
 is turned off.
 
+.SS ce_threshold
+sets a threshold above which all packets are marked with ECN Congestion
+Experienced. This is useful for DCTCP-style congestion control algorithms that
+require marking at very shallow queueing thresholds.
+
+
 .SH EXAMPLES
  # tc qdisc add dev eth0 root codel
  # tc -s qdisc show
index b9bf70ca32062efa149013bba6c60c57f0fe8f1a..042f840458731c15c4f006eae56349cb34c71bbd 100644 (file)
@@ -98,6 +98,17 @@ When using the ipset ematch with the "ip_set_hash:net,iface" set type,
 the interface can be queried using "src,dst (source ip address, outgoing interface) or
 "src,src" (source ip address, incoming interface) syntax.
 
+.SS ipt
+test packet against xtables matches
+
+.IR ipt "( " [-6] " "-m " " MATCH_NAME " " FLAGS " )
+
+.IR MATCH_NAME " := " string
+
+.IR FLAGS " := { " FLAG " [, " FLAGS "] }
+
+The flag options are the same as those used by the xtable match used.
+
 .SH CAVEATS
 
 The ematch syntax uses '(' and ')' to group expressions. All braces need to be
@@ -127,6 +138,10 @@ Check if packet source ip and the interface the packet arrived on is member of "
 
 # 'ipset(interactive src,src)'
 
+Check if packet matches an IPSec state with reqid 1:
+
+# 'ipt(-m policy --dir in --pol ipsec --reqid 1)'
+
 .SH "AUTHOR"
 
 The extended match infrastructure was added by Thomas Graf.
index 768eda3d52bdcffbd419577c5e701175f6a6e851..a561443b9978bee55142f7dfed6b46106f7b9baf 100644 (file)
@@ -258,8 +258,12 @@ is a 16 bit UDP dst port.
 .BI ip_flags " IP_FLAGS"
 .I IP_FLAGS
 may be either
-.BR frag " or " nofrag
-to match on fragmented packets or not respectively.
+.BR frag ", " nofrag ", " firstfrag " or " nofirstfrag
+where frag and nofrag could be used to match on fragmented packets or not,
+respectively. firstfrag and nofirstfrag can be used to further distinguish
+fragmented packet. firstfrag can be used to indicate the first fragmented
+packet. nofirstfrag can be used to indicates subsequent fragmented packets
+or non-fragmented packets.
 .SH NOTES
 As stated above where applicable, matches of a certain layer implicitly depend
 on the matches of the next lower layer. Precisely, layer one and two matches
index a80389a1fb6abb60cf66c798702ceda5993f4950..7ee6c269ed424ddb0273740d42cedddda6cef02c 100644 (file)
@@ -17,7 +17,11 @@ BYTES ] [
 .B ecn
 |
 .B noecn
-]
+] [
+.B ce_threshold
+TIME ] [
+.B memory_limit
+BYTES ]
 
 .SH DESCRIPTION
 FQ_Codel (Fair Queuing Controlled Delay) is queuing discipline that combines Fair
@@ -35,6 +39,13 @@ and is the hard limit on the real queue size.
 When this limit is reached, incoming packets are dropped. Default is 10240
 packets.
 
+.SS memory_limit
+sets a limit on the total number of bytes that can be queued in this FQ-CoDel
+instance. The lower of the packet limit of the
+.B limit
+parameter and the memory limit will be enforced. Default is 32 MB.
+
+
 .SS flows
 is the number of flows into which the incoming packets are classified. Due to
 the stochastic nature of hashing, multiple flows may end up being hashed into
@@ -73,6 +84,11 @@ can be used to turn it off and vice-a-versa. Unlike
 .B codel, ecn
 is turned on by default.
 
+.SS ce_threshold
+sets a threshold above which all packets are marked with ECN Congestion
+Experienced. This is useful for DCTCP-style congestion control algorithms that
+require marking at very shallow queueing thresholds.
+
 .SH EXAMPLES
 #tc qdisc add   dev eth0 root fq_codel
 .br
index cc94faa9fa32c610ab7c1c39003e7a376f6bdfb1..3dc30ee489e57aea1efb005d12388273cbd7cf4d 100644 (file)
@@ -102,10 +102,11 @@ tc \- show / manipulate traffic control settings
 \fB\-s\fR[\fItatistics\fR] |
 \fB\-d\fR[\fIetails\fR] |
 \fB\-r\fR[\fIaw\fR] |
-\fB\-p\fR[\fIretty\fR] |
 \fB\-i\fR[\fIec\fR] |
 \fB\-g\fR[\fIraph\fR] |
-\fB\-j\fR[\fIjson\fR] }
+\fB\-j\fR[\fIjson\fR] |
+\fB\-p\fR[\fIretty\fR] |
+\fB\-col\fR[\fIor\fR] }
 
 .SH DESCRIPTION
 .B Tc
@@ -699,7 +700,8 @@ output raw hex values for handles.
 
 .TP
 .BR "\-p", " \-pretty"
-decode filter offset and mask values to equivalent filter commands based on TCP/IP.
+for u32 filter, decode offset and mask values to equivalent filter commands based on TCP/IP.
+In JSON output, add whitespace to improve readability.
 
 .TP
 .BR "\-iec"
@@ -713,6 +715,10 @@ option was specified. Classes can be filtered only by
 .BR "dev"
 option.
 
+.TP
+.BR "\ -color"
+Use color output.
+
 .TP
 .BR "\-j", " \-json"
 Display results in JSON format.
index ac3eff6b870a9fc7f496a1e0e2ffe673b3930e48..50b906e86d5d08e20b8d995e992634cd5f9b4be2 100644 (file)
@@ -45,7 +45,6 @@ int no_update;
 int scan_interval;
 int time_constant;
 int show_errors;
-int pretty;
 double W;
 char **patterns;
 int npatterns;
index a4dd405d43a93e86e712475eb3b9e3e733bee839..ffa14b1e159608db86a718c90582b07521d92749 100644 (file)
@@ -37,7 +37,6 @@ int reset_history;
 int ignore_history;
 int no_output;
 int json_output;
-int pretty;
 int no_update;
 int scan_interval;
 int time_constant;
index 6338820bf4a01be96052958eb12d151430b8cd04..c76ad66ef2b1d062911fc2adebe7abc1ce75b555 100644 (file)
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -3945,6 +3945,9 @@ static int packet_show_sock(const struct sockaddr_nl *addr,
                        fil++;
                }
        }
+
+       if (show_mem)
+               print_skmeminfo(tb, PACKET_DIAG_MEMINFO);
        return 0;
 }
 
index 360f09b27edd1d4ebb68373ab09e3a583662d5b7..819fcbe37506ae7252288eb711078213a3fa479c 100644 (file)
@@ -4,6 +4,7 @@ include ../config.mk
 TARGETS :=
 
 ifeq ($(HAVE_MNL),y)
+CFLAGS += -I./include/uapi/
 
 RDMA_OBJ = rdma.o utils.o dev.o link.o res.o
 
index 03ab8683332d661c9cc69faa75e7722782fd892a..e2eafe47311b0a43d48aca10e3023531a2d52644 100644 (file)
@@ -53,7 +53,8 @@ static const char *dev_caps_to_str(uint32_t idx)
        x(SG_GAPS_REG, 32) \
        x(VIRTUAL_FUNCTION, 33) \
        x(RAW_SCATTER_FCS, 34) \
-       x(RDMA_NETDEV_OPA_VNIC, 35)
+       x(RDMA_NETDEV_OPA_VNIC, 35) \
+       x(PCI_WRITE_END_PADDING, 36)
 
        enum { RDMA_DEV_FLAGS(RDMA_BITMAP_ENUM) };
 
diff --git a/rdma/include/uapi/rdma/rdma_netlink.h b/rdma/include/uapi/rdma/rdma_netlink.h
new file mode 100644 (file)
index 0000000..dbac3b8
--- /dev/null
@@ -0,0 +1,355 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _RDMA_NETLINK_H
+#define _RDMA_NETLINK_H
+
+#include <linux/types.h>
+
+enum {
+       RDMA_NL_RDMA_CM = 1,
+       RDMA_NL_IWCM,
+       RDMA_NL_RSVD,
+       RDMA_NL_LS,     /* RDMA Local Services */
+       RDMA_NL_NLDEV,  /* RDMA device interface */
+       RDMA_NL_NUM_CLIENTS
+};
+
+enum {
+       RDMA_NL_GROUP_CM = 1,
+       RDMA_NL_GROUP_IWPM,
+       RDMA_NL_GROUP_LS,
+       RDMA_NL_NUM_GROUPS
+};
+
+#define RDMA_NL_GET_CLIENT(type) ((type & (((1 << 6) - 1) << 10)) >> 10)
+#define RDMA_NL_GET_OP(type) (type & ((1 << 10) - 1))
+#define RDMA_NL_GET_TYPE(client, op) ((client << 10) + op)
+
+enum {
+       RDMA_NL_RDMA_CM_ID_STATS = 0,
+       RDMA_NL_RDMA_CM_NUM_OPS
+};
+
+enum {
+       RDMA_NL_RDMA_CM_ATTR_SRC_ADDR = 1,
+       RDMA_NL_RDMA_CM_ATTR_DST_ADDR,
+       RDMA_NL_RDMA_CM_NUM_ATTR,
+};
+
+/* iwarp port mapper op-codes */
+enum {
+       RDMA_NL_IWPM_REG_PID = 0,
+       RDMA_NL_IWPM_ADD_MAPPING,
+       RDMA_NL_IWPM_QUERY_MAPPING,
+       RDMA_NL_IWPM_REMOVE_MAPPING,
+       RDMA_NL_IWPM_REMOTE_INFO,
+       RDMA_NL_IWPM_HANDLE_ERR,
+       RDMA_NL_IWPM_MAPINFO,
+       RDMA_NL_IWPM_MAPINFO_NUM,
+       RDMA_NL_IWPM_NUM_OPS
+};
+
+struct rdma_cm_id_stats {
+       __u32   qp_num;
+       __u32   bound_dev_if;
+       __u32   port_space;
+       __s32   pid;
+       __u8    cm_state;
+       __u8    node_type;
+       __u8    port_num;
+       __u8    qp_type;
+};
+
+enum {
+       IWPM_NLA_REG_PID_UNSPEC = 0,
+       IWPM_NLA_REG_PID_SEQ,
+       IWPM_NLA_REG_IF_NAME,
+       IWPM_NLA_REG_IBDEV_NAME,
+       IWPM_NLA_REG_ULIB_NAME,
+       IWPM_NLA_REG_PID_MAX
+};
+
+enum {
+       IWPM_NLA_RREG_PID_UNSPEC = 0,
+       IWPM_NLA_RREG_PID_SEQ,
+       IWPM_NLA_RREG_IBDEV_NAME,
+       IWPM_NLA_RREG_ULIB_NAME,
+       IWPM_NLA_RREG_ULIB_VER,
+       IWPM_NLA_RREG_PID_ERR,
+       IWPM_NLA_RREG_PID_MAX
+
+};
+
+enum {
+       IWPM_NLA_MANAGE_MAPPING_UNSPEC = 0,
+       IWPM_NLA_MANAGE_MAPPING_SEQ,
+       IWPM_NLA_MANAGE_ADDR,
+       IWPM_NLA_MANAGE_MAPPED_LOC_ADDR,
+       IWPM_NLA_RMANAGE_MAPPING_ERR,
+       IWPM_NLA_RMANAGE_MAPPING_MAX
+};
+
+#define IWPM_NLA_MANAGE_MAPPING_MAX 3
+#define IWPM_NLA_QUERY_MAPPING_MAX  4
+#define IWPM_NLA_MAPINFO_SEND_MAX   3
+
+enum {
+       IWPM_NLA_QUERY_MAPPING_UNSPEC = 0,
+       IWPM_NLA_QUERY_MAPPING_SEQ,
+       IWPM_NLA_QUERY_LOCAL_ADDR,
+       IWPM_NLA_QUERY_REMOTE_ADDR,
+       IWPM_NLA_RQUERY_MAPPED_LOC_ADDR,
+       IWPM_NLA_RQUERY_MAPPED_REM_ADDR,
+       IWPM_NLA_RQUERY_MAPPING_ERR,
+       IWPM_NLA_RQUERY_MAPPING_MAX
+};
+
+enum {
+       IWPM_NLA_MAPINFO_REQ_UNSPEC = 0,
+       IWPM_NLA_MAPINFO_ULIB_NAME,
+       IWPM_NLA_MAPINFO_ULIB_VER,
+       IWPM_NLA_MAPINFO_REQ_MAX
+};
+
+enum {
+       IWPM_NLA_MAPINFO_UNSPEC = 0,
+       IWPM_NLA_MAPINFO_LOCAL_ADDR,
+       IWPM_NLA_MAPINFO_MAPPED_ADDR,
+       IWPM_NLA_MAPINFO_MAX
+};
+
+enum {
+       IWPM_NLA_MAPINFO_NUM_UNSPEC = 0,
+       IWPM_NLA_MAPINFO_SEQ,
+       IWPM_NLA_MAPINFO_SEND_NUM,
+       IWPM_NLA_MAPINFO_ACK_NUM,
+       IWPM_NLA_MAPINFO_NUM_MAX
+};
+
+enum {
+       IWPM_NLA_ERR_UNSPEC = 0,
+       IWPM_NLA_ERR_SEQ,
+       IWPM_NLA_ERR_CODE,
+       IWPM_NLA_ERR_MAX
+};
+
+/*
+ * Local service operations:
+ *   RESOLVE - The client requests the local service to resolve a path.
+ *   SET_TIMEOUT - The local service requests the client to set the timeout.
+ *   IP_RESOLVE - The client requests the local service to resolve an IP to GID.
+ */
+enum {
+       RDMA_NL_LS_OP_RESOLVE = 0,
+       RDMA_NL_LS_OP_SET_TIMEOUT,
+       RDMA_NL_LS_OP_IP_RESOLVE,
+       RDMA_NL_LS_NUM_OPS
+};
+
+/* Local service netlink message flags */
+#define RDMA_NL_LS_F_ERR       0x0100  /* Failed response */
+
+/*
+ * Local service resolve operation family header.
+ * The layout for the resolve operation:
+ *    nlmsg header
+ *    family header
+ *    attributes
+ */
+
+/*
+ * Local service path use:
+ * Specify how the path(s) will be used.
+ *   ALL - For connected CM operation (6 pathrecords)
+ *   UNIDIRECTIONAL - For unidirectional UD (1 pathrecord)
+ *   GMP - For miscellaneous GMP like operation (at least 1 reversible
+ *         pathrecord)
+ */
+enum {
+       LS_RESOLVE_PATH_USE_ALL = 0,
+       LS_RESOLVE_PATH_USE_UNIDIRECTIONAL,
+       LS_RESOLVE_PATH_USE_GMP,
+       LS_RESOLVE_PATH_USE_MAX
+};
+
+#define LS_DEVICE_NAME_MAX 64
+
+struct rdma_ls_resolve_header {
+       __u8 device_name[LS_DEVICE_NAME_MAX];
+       __u8 port_num;
+       __u8 path_use;
+};
+
+struct rdma_ls_ip_resolve_header {
+       __u32 ifindex;
+};
+
+/* Local service attribute type */
+#define RDMA_NLA_F_MANDATORY   (1 << 13)
+#define RDMA_NLA_TYPE_MASK     (~(NLA_F_NESTED | NLA_F_NET_BYTEORDER | \
+                                 RDMA_NLA_F_MANDATORY))
+
+/*
+ * Local service attributes:
+ *   Attr Name       Size                       Byte order
+ *   -----------------------------------------------------
+ *   PATH_RECORD     struct ib_path_rec_data
+ *   TIMEOUT         u32                        cpu
+ *   SERVICE_ID      u64                        cpu
+ *   DGID            u8[16]                     BE
+ *   SGID            u8[16]                     BE
+ *   TCLASS          u8
+ *   PKEY            u16                        cpu
+ *   QOS_CLASS       u16                        cpu
+ *   IPV4            u32                        BE
+ *   IPV6            u8[16]                     BE
+ */
+enum {
+       LS_NLA_TYPE_UNSPEC = 0,
+       LS_NLA_TYPE_PATH_RECORD,
+       LS_NLA_TYPE_TIMEOUT,
+       LS_NLA_TYPE_SERVICE_ID,
+       LS_NLA_TYPE_DGID,
+       LS_NLA_TYPE_SGID,
+       LS_NLA_TYPE_TCLASS,
+       LS_NLA_TYPE_PKEY,
+       LS_NLA_TYPE_QOS_CLASS,
+       LS_NLA_TYPE_IPV4,
+       LS_NLA_TYPE_IPV6,
+       LS_NLA_TYPE_MAX
+};
+
+/* Local service DGID/SGID attribute: big endian */
+struct rdma_nla_ls_gid {
+       __u8            gid[16];
+};
+
+enum rdma_nldev_command {
+       RDMA_NLDEV_CMD_UNSPEC,
+
+       RDMA_NLDEV_CMD_GET, /* can dump */
+
+       /* 2 - 4 are free to use */
+
+       RDMA_NLDEV_CMD_PORT_GET = 5, /* can dump */
+
+       /* 6 - 8 are free to use */
+
+       RDMA_NLDEV_CMD_RES_GET = 9, /* can dump */
+
+       RDMA_NLDEV_CMD_RES_QP_GET, /* can dump */
+
+       RDMA_NLDEV_NUM_OPS
+};
+
+enum rdma_nldev_attr {
+       /* don't change the order or add anything between, this is ABI! */
+       RDMA_NLDEV_ATTR_UNSPEC,
+
+       /* Identifier for ib_device */
+       RDMA_NLDEV_ATTR_DEV_INDEX,              /* u32 */
+
+       RDMA_NLDEV_ATTR_DEV_NAME,               /* string */
+       /*
+        * Device index together with port index are identifiers
+        * for port/link properties.
+        *
+        * For RDMA_NLDEV_CMD_GET commamnd, port index will return number
+        * of available ports in ib_device, while for port specific operations,
+        * it will be real port index as it appears in sysfs. Port index follows
+        * sysfs notation and starts from 1 for the first port.
+        */
+       RDMA_NLDEV_ATTR_PORT_INDEX,             /* u32 */
+
+       /*
+        * Device and port capabilities
+        */
+       RDMA_NLDEV_ATTR_CAP_FLAGS,              /* u64 */
+
+       /*
+        * FW version
+        */
+       RDMA_NLDEV_ATTR_FW_VERSION,             /* string */
+
+       /*
+        * Node GUID (in host byte order) associated with the RDMA device.
+        */
+       RDMA_NLDEV_ATTR_NODE_GUID,                      /* u64 */
+
+       /*
+        * System image GUID (in host byte order) associated with
+        * this RDMA device and other devices which are part of a
+        * single system.
+        */
+       RDMA_NLDEV_ATTR_SYS_IMAGE_GUID,         /* u64 */
+
+       /*
+        * Subnet prefix (in host byte order)
+        */
+       RDMA_NLDEV_ATTR_SUBNET_PREFIX,          /* u64 */
+
+       /*
+        * Local Identifier (LID),
+        * According to IB specification, It is 16-bit address assigned
+        * by the Subnet Manager. Extended to be 32-bit for OmniPath users.
+        */
+       RDMA_NLDEV_ATTR_LID,                    /* u32 */
+       RDMA_NLDEV_ATTR_SM_LID,                 /* u32 */
+
+       /*
+        * LID mask control (LMC)
+        */
+       RDMA_NLDEV_ATTR_LMC,                    /* u8 */
+
+       RDMA_NLDEV_ATTR_PORT_STATE,             /* u8 */
+       RDMA_NLDEV_ATTR_PORT_PHYS_STATE,        /* u8 */
+
+       RDMA_NLDEV_ATTR_DEV_NODE_TYPE,          /* u8 */
+
+       RDMA_NLDEV_ATTR_RES_SUMMARY,            /* nested table */
+       RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY,      /* nested table */
+       RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME, /* string */
+       RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR, /* u64 */
+
+       RDMA_NLDEV_ATTR_RES_QP,                 /* nested table */
+       RDMA_NLDEV_ATTR_RES_QP_ENTRY,           /* nested table */
+       /*
+        * Local QPN
+        */
+       RDMA_NLDEV_ATTR_RES_LQPN,               /* u32 */
+       /*
+        * Remote QPN,
+        * Applicable for RC and UC only IBTA 11.2.5.3 QUERY QUEUE PAIR
+        */
+       RDMA_NLDEV_ATTR_RES_RQPN,               /* u32 */
+       /*
+        * Receive Queue PSN,
+        * Applicable for RC and UC only 11.2.5.3 QUERY QUEUE PAIR
+        */
+       RDMA_NLDEV_ATTR_RES_RQ_PSN,             /* u32 */
+       /*
+        * Send Queue PSN
+        */
+       RDMA_NLDEV_ATTR_RES_SQ_PSN,             /* u32 */
+       RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE,     /* u8 */
+       /*
+        * QP types as visible to RDMA/core, the reserved QPT
+        * are not exported through this interface.
+        */
+       RDMA_NLDEV_ATTR_RES_TYPE,               /* u8 */
+       RDMA_NLDEV_ATTR_RES_STATE,              /* u8 */
+       /*
+        * Process ID which created object,
+        * in case of kernel origin, PID won't exist.
+        */
+       RDMA_NLDEV_ATTR_RES_PID,                /* u32 */
+       /*
+        * The name of process created following resource.
+        * It will exist only for kernel objects.
+        * For user created objects, the user is supposed
+        * to read /proc/PID/comm file.
+        */
+       RDMA_NLDEV_ATTR_RES_KERN_NAME,          /* string */
+
+       RDMA_NLDEV_ATTR_MAX
+};
+#endif /* _RDMA_NETLINK_H */
index 19608f41faa518b8e83c8508ef7323d6a82f6228..ab2c96084b0399fb51090150f06ac203f53159ec 100644 (file)
@@ -15,8 +15,9 @@
 static void help(char *name)
 {
        pr_out("Usage: %s [ OPTIONS ] OBJECT { COMMAND | help }\n"
+              "       %s [ -f[orce] ] -b[atch] filename\n"
               "where  OBJECT := { dev | link | resource | help }\n"
-              "       OPTIONS := { -V[ersion] | -d[etails] | -j[son] | -p[retty]}\n", name);
+              "       OPTIONS := { -V[ersion] | -d[etails] | -j[son] | -p[retty]}\n", name, name);
 }
 
 static int cmd_help(struct rd *rd)
@@ -25,7 +26,7 @@ static int cmd_help(struct rd *rd)
        return 0;
 }
 
-static int rd_cmd(struct rd *rd)
+static int rd_cmd(struct rd *rd, int argc, char **argv)
 {
        const struct rd_cmd cmds[] = {
                { NULL,         cmd_help },
@@ -36,17 +37,54 @@ static int rd_cmd(struct rd *rd)
                { 0 }
        };
 
+       rd->argc = argc;
+       rd->argv = argv;
+
        return rd_exec_cmd(rd, cmds, "object");
 }
 
-static int rd_init(struct rd *rd, int argc, char **argv, char *filename)
+static int rd_batch(struct rd *rd, const char *name, bool force)
+{
+       char *line = NULL;
+       size_t len = 0;
+       int ret = 0;
+
+       if (name && strcmp(name, "-") != 0) {
+               if (!freopen(name, "r", stdin)) {
+                       pr_err("Cannot open file \"%s\" for reading: %s\n",
+                              name, strerror(errno));
+                       return errno;
+               }
+       }
+
+       cmdlineno = 0;
+       while (getcmdline(&line, &len, stdin) != -1) {
+               char *largv[512];
+               int largc;
+
+               largc = makeargs(line, largv, ARRAY_SIZE(largv));
+               if (!largc)
+                       continue;       /* blank line */
+
+               ret = rd_cmd(rd, largc, largv);
+               if (ret) {
+                       pr_err("Command failed %s:%d\n", name, cmdlineno);
+                       if (!force)
+                               break;
+               }
+       }
+
+       free(line);
+
+       return ret;
+}
+
+static int rd_init(struct rd *rd, char *filename)
 {
        uint32_t seq;
        int ret;
 
        rd->filename = filename;
-       rd->argc = argc;
-       rd->argv = argv;
        INIT_LIST_HEAD(&rd->dev_map_list);
        INIT_LIST_HEAD(&rd->filter_list);
 
@@ -87,11 +125,15 @@ int main(int argc, char **argv)
                { "json",               no_argument,            NULL, 'j' },
                { "pretty",             no_argument,            NULL, 'p' },
                { "details",            no_argument,            NULL, 'd' },
+               { "force",              no_argument,            NULL, 'f' },
+               { "batch",              required_argument,      NULL, 'b' },
                { NULL, 0, NULL, 0 }
        };
+       const char *batch_file = NULL;
        bool pretty_output = false;
        bool show_details = false;
        bool json_output = false;
+       bool force = false;
        char *filename;
        struct rd rd;
        int opt;
@@ -99,7 +141,7 @@ int main(int argc, char **argv)
 
        filename = basename(argv[0]);
 
-       while ((opt = getopt_long(argc, argv, "Vhdpj",
+       while ((opt = getopt_long(argc, argv, ":Vhdpjfb:",
                                  long_options, NULL)) >= 0) {
                switch (opt) {
                case 'V':
@@ -115,9 +157,18 @@ int main(int argc, char **argv)
                case 'j':
                        json_output = true;
                        break;
+               case 'f':
+                       force = true;
+                       break;
+               case 'b':
+                       batch_file = optarg;
+                       break;
                case 'h':
                        help(filename);
                        return EXIT_SUCCESS;
+               case ':':
+                       pr_err("-%c option requires an argument\n", optopt);
+                       return EXIT_FAILURE;
                default:
                        pr_err("Unknown option.\n");
                        help(filename);
@@ -132,11 +183,14 @@ int main(int argc, char **argv)
        rd.json_output = json_output;
        rd.pretty_output = pretty_output;
 
-       err = rd_init(&rd, argc, argv, filename);
+       err = rd_init(&rd, filename);
        if (err)
                goto out;
 
-       err = rd_cmd(&rd);
+       if (batch_file)
+               err = rd_batch(&rd, batch_file, force);
+       else
+               err = rd_cmd(&rd, argc, argv);
 out:
        /* Always cleanup */
        rd_cleanup(&rd);
index 3716dd6a28de09b9045caf2eaf83834496931bd6..dfd00267d7070a53ae85c74c0ab5dcb9ff472fca 100644 (file)
@@ -80,6 +80,7 @@ endif
 ifneq ($(TC_CONFIG_NO_XT),y)
   ifeq ($(TC_CONFIG_XT),y)
     TCSO += m_xt.so
+    TCMODULES += em_ipt.o
     ifeq ($(TC_CONFIG_IPSET),y)
       TCMODULES += em_ipset.o
     endif
@@ -163,6 +164,12 @@ m_xt_old.so: m_xt_old.c
 
 em_ipset.o: CFLAGS += $$($(PKG_CONFIG) xtables --cflags)
 
+em_ipt.o: CFLAGS += $$($(PKG_CONFIG) xtables --cflags)
+
+ifeq ($(TC_CONFIG_XT),y)
+  LDFLAGS += $$($(PKG_CONFIG) xtables --libs)
+endif
+
 %.yacc.c: %.y
        $(QUIET_YACC)$(YACC) $(YACCFLAGS) -o $@ $<
 
diff --git a/tc/em_ipt.c b/tc/em_ipt.c
new file mode 100644 (file)
index 0000000..aa2edd6
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * em_ipt.c            IPtables extenstions matching Ematch
+ *
+ * (C) 2018 Eyal Birger <eyal.birger@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <getopt.h>
+
+#include <linux/tc_ematch/tc_em_ipt.h>
+#include <linux/pkt_cls.h>
+#include <xtables.h>
+#include "m_ematch.h"
+
+static void em_ipt_print_usage(FILE *fd)
+{
+       fprintf(fd,
+               "Usage: ipt([-6] -m MATCH_NAME [MATCH_OPTS])\n"
+               "Example: 'ipt(-m policy --reqid 1 --pol ipsec --dir in)'\n");
+}
+
+static struct option original_opts[] = {
+       {
+               .name = "match",
+               .has_arg = 1,
+               .val = 'm'
+       },
+       {
+               .name = "ipv6",
+               .val = '6'
+       },
+       {}
+};
+
+static struct xtables_globals em_tc_ipt_globals = {
+       .option_offset = 0,
+       .program_name = "tc-em-ipt",
+       .program_version = "0.1",
+       .orig_opts = original_opts,
+       .opts = original_opts,
+#if (XTABLES_VERSION_CODE >= 11)
+       .compat_rev = xtables_compatible_revision,
+#endif
+};
+
+static struct xt_entry_match *fake_xt_entry_match(int data_size, void *data)
+{
+       struct xt_entry_match *m;
+
+       m = xtables_calloc(1, XT_ALIGN(sizeof(*m)) + data_size);
+       if (!m)
+               return NULL;
+
+       if (data)
+               memcpy(m->data, data, data_size);
+
+       m->u.user.match_size = data_size;
+       return m;
+}
+
+static void scrub_match(struct xtables_match *match)
+{
+       match->mflags = 0;
+       free(match->m);
+       match->m = NULL;
+}
+
+/* IPv4 and IPv6 share the same hooking enumeration */
+#define HOOK_PRE_ROUTING 0
+#define HOOK_POST_ROUTING 4
+
+static __u32 em_ipt_hook(struct nlmsghdr *n)
+{
+       struct tcmsg *t = NLMSG_DATA(n);
+
+       if (t->tcm_parent != TC_H_ROOT &&
+           t->tcm_parent == TC_H_MAJ(TC_H_INGRESS))
+               return HOOK_PRE_ROUTING;
+
+       return HOOK_POST_ROUTING;
+}
+
+static int em_ipt_parse_eopt_argv(struct nlmsghdr *n,
+                                 struct tcf_ematch_hdr *hdr,
+                                 int argc, char **argv)
+{
+       struct xtables_globals tmp_tcipt_globals = em_tc_ipt_globals;
+       struct xtables_match *match = NULL;
+       __u8 nfproto = NFPROTO_IPV4;
+
+       while (1) {
+               struct option *opts;
+               int c;
+
+               c = getopt_long(argc, argv, "6m:", tmp_tcipt_globals.opts,
+                               NULL);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'm':
+                       xtables_init_all(&tmp_tcipt_globals, nfproto);
+
+                       match = xtables_find_match(optarg, XTF_TRY_LOAD, NULL);
+                       if (!match || !match->x6_parse) {
+                               fprintf(stderr, " failed to find match %s\n\n",
+                                       optarg);
+                               return -1;
+                       }
+
+                       match->m = fake_xt_entry_match(match->size, NULL);
+                       if (!match->m) {
+                               printf(" %s error\n", match->name);
+                               return -1;
+                       }
+
+                       if (match->init)
+                               match->init(match->m);
+
+                       opts = xtables_options_xfrm(tmp_tcipt_globals.orig_opts,
+                                                   tmp_tcipt_globals.opts,
+                                                   match->x6_options,
+                                                   &match->option_offset);
+                       if (!opts) {
+                               scrub_match(match);
+                               return -1;
+                       }
+
+                       tmp_tcipt_globals.opts = opts;
+                       break;
+
+               case '6':
+                       nfproto = NFPROTO_IPV6;
+                       break;
+
+               default:
+                       if (!match) {
+                               fprintf(stderr, "failed to find match %s\n\n",
+                                       optarg);
+                               return -1;
+
+                       }
+                       xtables_option_mpcall(c, argv, 0, match, NULL);
+                       break;
+               }
+       }
+
+       if (!match) {
+               fprintf(stderr, " failed to parse parameters (%s)\n", *argv);
+               return -1;
+       }
+
+       /* check that we passed the correct parameters to the match */
+       xtables_option_mfcall(match);
+
+       addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
+       addattr32(n, MAX_MSG, TCA_EM_IPT_HOOK, em_ipt_hook(n));
+       addattrstrz(n, MAX_MSG, TCA_EM_IPT_MATCH_NAME, match->name);
+       addattr8(n, MAX_MSG, TCA_EM_IPT_MATCH_REVISION, match->revision);
+       addattr8(n, MAX_MSG, TCA_EM_IPT_NFPROTO, nfproto);
+       addattr_l(n, MAX_MSG, TCA_EM_IPT_MATCH_DATA, match->m->data,
+                 match->size);
+
+       xtables_free_opts(1);
+
+       scrub_match(match);
+       return 0;
+}
+
+static int em_ipt_print_epot(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
+                            int data_len)
+{
+       struct rtattr *tb[TCA_EM_IPT_MAX + 1];
+       struct xtables_match *match;
+       const char *mname;
+       __u8 nfproto;
+
+       if (parse_rtattr(tb, TCA_EM_IPT_MAX, data, data_len) < 0)
+               return -1;
+
+       nfproto = rta_getattr_u8(tb[TCA_EM_IPT_NFPROTO]);
+
+       xtables_init_all(&em_tc_ipt_globals, nfproto);
+
+       mname = rta_getattr_str(tb[TCA_EM_IPT_MATCH_NAME]);
+       match = xtables_find_match(mname, XTF_TRY_LOAD, NULL);
+       if (!match)
+               return -1;
+
+       match->m = fake_xt_entry_match(RTA_PAYLOAD(tb[TCA_EM_IPT_MATCH_DATA]),
+                                      RTA_DATA(tb[TCA_EM_IPT_MATCH_DATA]));
+       if (!match->m)
+               return -1;
+
+       match->print(NULL, match->m, 0);
+
+       scrub_match(match);
+       return 0;
+}
+
+struct ematch_util ipt_ematch_util = {
+       .kind = "ipt",
+       .kind_num = TCF_EM_IPT,
+       .parse_eopt_argv = em_ipt_parse_eopt_argv,
+       .print_eopt = em_ipt_print_epot,
+       .print_usage = em_ipt_print_usage
+};
index b15710497d1244fe3cac97d8bc282c28f07d0132..badeaa2907285db2ad55c7e8639ec06b304cc124 100644 (file)
@@ -147,8 +147,7 @@ static int flow_parse_opt(struct filter_util *fu, char *handle,
                }
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 4096, TCA_OPTIONS);
 
        while (argc > 0) {
                if (matches(*argv, "map") == 0) {
@@ -259,7 +258,7 @@ static int flow_parse_opt(struct filter_util *fu, char *handle,
                addattr32(n, 4096, TCA_FLOW_XOR, xor);
        }
 
-       tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
index 5a4ec832bc190da4086617371462e6e477a3adcd..9d4bfd2f808ba6f89ec418950186d25f4e8b9416 100644 (file)
@@ -155,6 +155,7 @@ struct flag_to_string {
 
 static struct flag_to_string flags_str[] = {
        { TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT, FLOWER_IP_FLAGS, "frag" },
+       { TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST, FLOWER_IP_FLAGS, "firstfrag" },
 };
 
 static int flower_parse_matching_flags(char *str,
index 77474849952a7ae5ca3a3b763c0a1494caadc39c..adce2bdb7d8af353133af9a852b0494e2dd36e15 100644 (file)
--- a/tc/f_fw.c
+++ b/tc/f_fw.c
@@ -67,8 +67,7 @@ static int fw_parse_opt(struct filter_util *qu, char *handle, int argc, char **a
        if (argc == 0)
                return 0;
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 4096, TCA_OPTIONS);
 
        if (mask_set)
                addattr32(n, MAX_MSG, TCA_FW_MASK, mask);
@@ -119,7 +118,7 @@ static int fw_parse_opt(struct filter_util *qu, char *handle, int argc, char **a
                }
                argc--; argv++;
        }
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
index 655321f9fa4f4f3e9283ef475471168d8527f204..e52da6441fb0897cc09448280fb028e8f8629616 100644 (file)
@@ -50,8 +50,7 @@ static int route_parse_opt(struct filter_util *qu, char *handle, int argc, char
        if (argc == 0)
                return 0;
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 4096, TCA_OPTIONS);
 
        while (argc > 0) {
                if (matches(*argv, "to") == 0) {
@@ -128,7 +127,7 @@ static int route_parse_opt(struct filter_util *qu, char *handle, int argc, char
                }
                argc--; argv++;
        }
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        if (order) {
                fh &= ~0x7F00;
                fh |= (order<<8)&0x7F00;
index 1ce37340e9ef830918d3c05aac8387539221a303..bddd4740501a07bd77ab6fa6ffd96d60de03ec67 100644 (file)
@@ -188,8 +188,7 @@ static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc,
        if (argc == 0)
                return 0;
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 4096, TCA_OPTIONS);
 
        while (argc > 0) {
                if (matches(*argv, "session") == 0) {
@@ -294,7 +293,7 @@ static int rsvp_parse_opt(struct filter_util *qu, char *handle, int argc,
 
        if (pinfo_ok)
                addattr_l(n, 4096, TCA_RSVP_PINFO, &pinfo, sizeof(pinfo));
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
index 749273dbd9abb4c3cfe0838a73f392ac7d58763e..159cf41461b5b35c02a415a384668dafc78f7a47 100644 (file)
@@ -37,8 +37,7 @@ static int tcindex_parse_opt(struct filter_util *qu, char *handle, int argc,
                }
        }
        if (!argc) return 0;
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 4096, TCA_OPTIONS);
        while (argc) {
                if (!strcmp(*argv, "hash")) {
                        int hash;
@@ -113,7 +112,7 @@ static int tcindex_parse_opt(struct filter_util *qu, char *handle, int argc,
                argc--;
                argv++;
        }
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
index 1fafb4af7eb5bba3e6602a6281f4dfeff1f2f0df..b6064cdb94cba5987238880f6c5765bad92aa04a 100644 (file)
@@ -25,8 +25,6 @@
 #include "utils.h"
 #include "tc_util.h"
 
-extern int show_pretty;
-
 static void explain(void)
 {
        fprintf(stderr,
@@ -965,7 +963,7 @@ static void show_keys(FILE *f, const struct tc_u32_key *key)
 {
        int i = 0;
 
-       if (!show_pretty)
+       if (!pretty)
                goto show_k;
 
        for (i = 0; i < ARRAY_SIZE(u32_pprinters); i++) {
@@ -1003,8 +1001,7 @@ static int u32_parse_opt(struct filter_util *qu, char *handle,
        if (argc == 0)
                return 0;
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, MAX_MSG, TCA_OPTIONS);
 
        while (argc > 0) {
                if (matches(*argv, "match") == 0) {
@@ -1197,7 +1194,7 @@ static int u32_parse_opt(struct filter_util *qu, char *handle,
                addattr_l(n, MAX_MSG, TCA_U32_FLAGS, &flags, 4);
        }
 
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
index 148f1372d41458844450a9ede7098500c28face9..6c3049c7db8849163d403f299154855f68125e2d 100644 (file)
@@ -166,9 +166,7 @@ int parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
        if (argc <= 0)
                return -1;
 
-       tail = tail2 = NLMSG_TAIL(n);
-
-       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       tail2 = addattr_nest(n, MAX_MSG, tca_id);
 
        while (argc > 0) {
 
@@ -213,8 +211,7 @@ done0:
                                goto bad_val;
 
 
-                       tail = NLMSG_TAIL(n);
-                       addattr_l(n, MAX_MSG, ++prio, NULL, 0);
+                       tail = addattr_nest(n, MAX_MSG, ++prio);
                        addattr_l(n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1);
 
                        ret = a->parse_aopt(a, &argc, &argv, TCA_ACT_OPTIONS,
@@ -252,7 +249,7 @@ done0:
                                addattr_l(n, MAX_MSG, TCA_ACT_COOKIE,
                                          &act_ck, act_ck_len);
 
-                       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+                       addattr_nest_end(n, tail);
                        ok++;
                }
        }
@@ -262,7 +259,7 @@ done0:
                goto bad_val;
        }
 
-       tail2->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail2;
+       addattr_nest_end(n, tail2);
 
 done:
        *argc_p = argc;
@@ -468,8 +465,7 @@ static int tc_action_gd(int cmd, unsigned int flags,
        argv += 1;
 
 
-       tail = NLMSG_TAIL(&req.n);
-       addattr_l(&req.n, MAX_MSG, TCA_ACT_TAB, NULL, 0);
+       tail = addattr_nest(&req.n, MAX_MSG, TCA_ACT_TAB);
 
        while (argc > 0) {
                if (strcmp(*argv, "action") == 0) {
@@ -518,16 +514,15 @@ static int tc_action_gd(int cmd, unsigned int flags,
                        goto bad_val;
                }
 
-               tail2 = NLMSG_TAIL(&req.n);
-               addattr_l(&req.n, MAX_MSG, ++prio, NULL, 0);
+               tail2 = addattr_nest(&req.n, MAX_MSG, ++prio);
                addattr_l(&req.n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1);
                if (i > 0)
                        addattr32(&req.n, MAX_MSG, TCA_ACT_INDEX, i);
-               tail2->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail2;
+               addattr_nest_end(&req.n, tail2);
 
        }
 
-       tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail;
+       addattr_nest_end(&req.n, tail);
 
        req.n.nlmsg_seq = rth.dump = ++rth.seq;
 
@@ -626,8 +621,7 @@ static int tc_act_list_or_flush(int *argc_p, char ***argv_p, int event)
                .t.tca_family = AF_UNSPEC,
        };
 
-       tail = NLMSG_TAIL(&req.n);
-       addattr_l(&req.n, MAX_MSG, TCA_ACT_TAB, NULL, 0);
+       tail = addattr_nest(&req.n, MAX_MSG, TCA_ACT_TAB);
        tail2 = NLMSG_TAIL(&req.n);
 
        strncpy(k, *argv, sizeof(k) - 1);
@@ -659,7 +653,7 @@ static int tc_act_list_or_flush(int *argc_p, char ***argv_p, int event)
        addattr_l(&req.n, MAX_MSG, ++prio, NULL, 0);
        addattr_l(&req.n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1);
        tail2->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail2;
-       tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail;
+       addattr_nest_end(&req.n, tail);
 
        tail3 = NLMSG_TAIL(&req.n);
        flag_select.value |= TCA_FLAG_LARGE_DUMP_ON;
index 1c1f71cdb83f9ac6522658315b6cf1671fb1f97b..7c6f8c298abd4454e49c9b51f9f25fb062aa271d 100644 (file)
@@ -90,8 +90,7 @@ static int bpf_parse_opt(struct action_util *a, int *ptr_argc, char ***ptr_argv,
 
        NEXT_ARG();
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       tail = addattr_nest(n, MAX_MSG, tca_id);
 
        while (argc > 0) {
                if (matches(*argv, "run") == 0) {
@@ -143,7 +142,7 @@ opt_bpf:
        }
 
        addattr_l(n, MAX_MSG, TCA_ACT_BPF_PARMS, &parm, sizeof(parm));
-       tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+       addattr_nest_end(n, tail);
 
        if (bpf_uds_name)
                ret = bpf_send_map_fds(bpf_uds_name, bpf_obj);
index d5b140cbb7bdc260ad484c13bf8461d944bf3173..bcce413913984ad7ce7ac43db4137c3dd207ee61 100644 (file)
@@ -95,10 +95,9 @@ parse_connmark(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
                }
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       tail = addattr_nest(n, MAX_MSG, tca_id);
        addattr_l(n, MAX_MSG, TCA_CONNMARK_PARMS, &sel, sizeof(sel));
-       tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+       addattr_nest_end(n, tail);
 
        *argc_p = argc;
        *argv_p = argv;
index 7b156734f64c5581fe60fb7fdf012114b15971fd..8391071d73f2396ed30c426790cac82e4dfbd4fb 100644 (file)
@@ -138,10 +138,9 @@ parse_csum(struct action_util *a, int *argc_p,
                }
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       tail = addattr_nest(n, MAX_MSG, tca_id);
        addattr_l(n, MAX_MSG, TCA_CSUM_PARMS, &sel, sizeof(sel));
-       tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+       addattr_nest_end(n, tail);
 
        *argc_p = argc;
        *argv_p = argv;
index d2bb5c38038202e439ab48d6776f1e9fadaace21..61f8fb3fc4545d722445d18e1d6e0b766d91035a 100644 (file)
@@ -169,19 +169,44 @@ static struct ematch_util *get_ematch_kind_num(__u16 kind)
        return get_ematch_kind(name);
 }
 
+static int em_parse_call(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
+                        struct ematch_util *e, struct ematch *t)
+{
+       if (e->parse_eopt_argv) {
+               int argc = 0, i = 0, ret;
+               struct bstr *args;
+               char **argv;
+
+               for (args = t->args; args; args = bstr_next(args))
+                       argc++;
+               argv = calloc(argc, sizeof(char *));
+               if (!argv)
+                       return -1;
+               for (args = t->args; args; args = bstr_next(args))
+                       argv[i++] = args->data;
+
+               ret = e->parse_eopt_argv(n, hdr, argc, argv);
+
+               free(argv);
+               return ret;
+       }
+
+       return e->parse_eopt(n, hdr, t->args->next);
+}
+
 static int parse_tree(struct nlmsghdr *n, struct ematch *tree)
 {
        int index = 1;
        struct ematch *t;
 
        for (t = tree; t; t = t->next) {
-               struct rtattr *tail = NLMSG_TAIL(n);
+               struct rtattr *tail;
                struct tcf_ematch_hdr hdr = { .flags = t->relation };
 
                if (t->inverted)
                        hdr.flags |= TCF_EM_INVERT;
 
-               addattr_l(n, MAX_MSG, index++, NULL, 0);
+               tail = addattr_nest(n, MAX_MSG, index++);
 
                if (t->child) {
                        __u32 r = t->child_ref;
@@ -212,11 +237,11 @@ static int parse_tree(struct nlmsghdr *n, struct ematch *tree)
                        }
 
                        hdr.kind = num;
-                       if (e->parse_eopt(n, &hdr, t->args->next) < 0)
+                       if (em_parse_call(n, &hdr, e, t) < 0)
                                return -1;
                }
 
-               tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+               addattr_nest_end(n, tail);
        }
 
        return 0;
@@ -341,18 +366,16 @@ int parse_ematch(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
                        .progid = TCF_EM_PROG_TC
                };
 
-               tail = NLMSG_TAIL(n);
-               addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+               tail = addattr_nest(n, MAX_MSG, tca_id);
                addattr_l(n, MAX_MSG, TCA_EMATCH_TREE_HDR, &hdr, sizeof(hdr));
 
-               tail_list = NLMSG_TAIL(n);
-               addattr_l(n, MAX_MSG, TCA_EMATCH_TREE_LIST, NULL, 0);
+               tail_list = addattr_nest(n, MAX_MSG, TCA_EMATCH_TREE_LIST);
 
                if (parse_tree(n, ematch_root) < 0)
                        return -1;
 
-               tail_list->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail_list;
-               tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+               addattr_nest_end(n, tail_list);
+               addattr_nest_end(n, tail);
        }
 
        *argc_p = ematch_argc;
index fa6e214a44c6dbc32625dd1fcb97753608c9014f..f634f19164faf17bd75ca8a0ed5a7b429937b774 100644 (file)
@@ -88,6 +88,8 @@ struct ematch_util
        int                     kind_num;
        int     (*parse_eopt)(struct nlmsghdr *,struct tcf_ematch_hdr *,
                              struct bstr *);
+       int     (*parse_eopt_argv)(struct nlmsghdr *, struct tcf_ematch_hdr *,
+                                  int, char **);
        int     (*print_eopt)(FILE *, struct tcf_ematch_hdr *, void *, int);
        void    (*print_usage)(FILE *);
        struct ematch_util      *next;
index 16c4413f4217d3a6d6af1a7f07edfcad121fbb9d..a0a3c33d23dac4e9149062b6956b00069e6d8d37 100644 (file)
@@ -145,14 +145,13 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p,
                }
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       tail = addattr_nest(n, MAX_MSG, tca_id);
        addattr_l(n, MAX_MSG, TCA_GACT_PARMS, &p, sizeof(p));
 #ifdef CONFIG_GACT_PROB
        if (rd)
                addattr_l(n, MAX_MSG, TCA_GACT_PROB, &pp, sizeof(pp));
 #endif
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
 
        *argc_p = argc;
        *argv_p = argv;
index 205efc9f1d9a73a4a3bedff91d49ff6799cd9992..d7e61703f666536dbb308c48426f83cdc61ec1b2 100644 (file)
@@ -177,8 +177,7 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p,
                ife_usage();
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       tail = addattr_nest(n, MAX_MSG, tca_id);
        addattr_l(n, MAX_MSG, TCA_IFE_PARMS, &p, sizeof(p));
 
        if (!(p.flags & IFE_ENCODE))
@@ -193,8 +192,7 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p,
        if (saddr)
                addattr_l(n, MAX_MSG, TCA_IFE_SMAC, sbuf, ETH_ALEN);
 
-       tail2 = NLMSG_TAIL(n);
-       addattr_l(n, MAX_MSG, TCA_IFE_METALST, NULL, 0);
+       tail2 = addattr_nest(n, MAX_MSG, TCA_IFE_METALST);
        if (ife_mark || ife_mark_v) {
                if (ife_mark_v)
                        addattr_l(n, MAX_MSG, IFE_META_SKBMARK, &ife_mark_v, 4);
@@ -215,10 +213,10 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p,
                        addattr_l(n, MAX_MSG, IFE_META_TCINDEX, NULL, 0);
        }
 
-       tail2->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail2;
+       addattr_nest_end(n, tail2);
 
 skip_encode:
-       tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
+       addattr_nest_end(n, tail);
 
        *argc_p = argc;
        *argv_p = argv;
index 1c3c240f6fc3ab4c679470a5e6655cf263e232b6..b48cc0a9c85f93e78b7b7ab5287098a117d2bfae 100644 (file)
@@ -383,8 +383,7 @@ static int parse_ipt(struct action_util *a, int *argc_p,
                }
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       tail = addattr_nest(n, MAX_MSG, tca_id);
        fprintf(stdout, "tablename: %s hook: %s\n ", tname, ipthooks[hook]);
        fprintf(stdout, "\ttarget: ");
 
@@ -405,7 +404,7 @@ static int parse_ipt(struct action_util *a, int *argc_p,
        addattr_l(n, MAX_MSG, TCA_IPT_INDEX, &index, 4);
        if (m)
                addattr_l(n, MAX_MSG, TCA_IPT_TARG, m->t, m->t->u.target_size);
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
 
        argc -= optind;
        argv += optind;
index 14e5c88d44d539fecae0ab0ea5e23f92c8b3e1bc..c7f7318b8413ffc0f6b2d0efef1d63bfb4ba565c 100644 (file)
@@ -194,10 +194,8 @@ parse_direction(struct action_util *a, int *argc_p, char ***argv_p,
                ll_init_map(&rth);
 
                idx = ll_name_to_index(d);
-               if (idx == 0) {
-                       fprintf(stderr, "Cannot find device \"%s\"\n", d);
-                       return -1;
-               }
+               if (!idx)
+                       return nodev(d);
 
                p.ifindex = idx;
        }
@@ -224,10 +222,9 @@ parse_direction(struct action_util *a, int *argc_p, char ***argv_p,
                }
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       tail = addattr_nest(n, MAX_MSG, tca_id);
        addattr_l(n, MAX_MSG, TCA_MIRRED_PARMS, &p, sizeof(p));
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
 
        *argc_p = argc;
        *argv_p = argv;
index 1e4ff51fe75aea6bd815928ac8311a619bfb76d1..daa1f572c046ed347219b9e4aa693e93298351f8 100644 (file)
@@ -128,10 +128,9 @@ parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct
                }
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       tail = addattr_nest(n, MAX_MSG, tca_id);
        addattr_l(n, MAX_MSG, TCA_NAT_PARMS, &sel, sizeof(sel));
-       tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+       addattr_nest_end(n, tail);
 
        *argc_p = argc;
        *argv_p = argv;
index 26549eeea8995a001d51a02826dcbf63a0068f9e..b9cb5ffbca2e9eff45c2c8c82b1fa4299e756db3 100644 (file)
@@ -685,8 +685,7 @@ int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
                }
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       tail = addattr_nest(n, MAX_MSG, tca_id);
        if (!sel.extended) {
                addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS, &sel,
                          sizeof(sel.sel) +
@@ -699,7 +698,7 @@ int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
                pedit_keys_ex_addattr(&sel, n);
        }
 
-       tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
+       addattr_nest_end(n, tail);
 
        *argc_p = argc;
        *argv_p = argv;
index 055b50ee5c2d122a1a8914d851269cb06d6fa299..f3b07f7b0439c172413144b9d8e3a73cbca624a8 100644 (file)
@@ -232,8 +232,7 @@ action_ctrl_ok:
                }
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       tail = addattr_nest(n, MAX_MSG, tca_id);
        addattr_l(n, MAX_MSG, TCA_POLICE_TBF, &p, sizeof(p));
        if (p.rate.rate)
                addattr_l(n, MAX_MSG, TCA_POLICE_RATE, rtab, 1024);
@@ -244,7 +243,7 @@ action_ctrl_ok:
        if (presult)
                addattr32(n, MAX_MSG, TCA_POLICE_RESULT, presult);
 
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        res = 0;
 
        *argc_p = argc;
index 01763cb4c3561fa347ffe39bf3b049b305da1933..1e18c5154fe688236199c61f78df94dfb68f5d4b 100644 (file)
@@ -121,8 +121,7 @@ static int parse_sample(struct action_util *a, int *argc_p, char ***argv_p,
                usage();
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       tail = addattr_nest(n, MAX_MSG, tca_id);
        addattr_l(n, MAX_MSG, TCA_SAMPLE_PARMS, &p, sizeof(p));
        if (rate_set)
                addattr32(n, MAX_MSG, TCA_SAMPLE_RATE, rate);
@@ -131,7 +130,7 @@ static int parse_sample(struct action_util *a, int *argc_p, char ***argv_p,
        if (trunc_set)
                addattr32(n, MAX_MSG, TCA_SAMPLE_TRUNC_SIZE, trunc);
 
-       tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+       addattr_nest_end(n, tail);
 
        *argc_p = argc;
        *argv_p = argv;
index a687b9f83f658b88ac23eaa86030b1ae1c113406..886606f9f8b4e754c035d3c74932f753126abd89 100644 (file)
@@ -146,12 +146,11 @@ parse_simple(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
 
        sel.action = TC_ACT_PIPE;
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       tail = addattr_nest(n, MAX_MSG, tca_id);
        addattr_l(n, MAX_MSG, TCA_DEF_PARMS, &sel, sizeof(sel));
        if (simpdata)
                addattr_l(n, MAX_MSG, TCA_DEF_DATA, simpdata, SIMP_MAX_DATA);
-       tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+       addattr_nest_end(n, tail);
 
        *argc_p = argc;
        *argv_p = argv;
index aa374fcb33ed9b46da3c46cf48eff7a59b56cb5d..db5c64caf2ba8031d3a377b404fd80d689f1879e 100644 (file)
@@ -142,8 +142,7 @@ parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
        }
 
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       tail = addattr_nest(n, MAX_MSG, tca_id);
        addattr_l(n, MAX_MSG, TCA_SKBEDIT_PARMS, &sel, sizeof(sel));
        if (flags & SKBEDIT_F_QUEUE_MAPPING)
                addattr_l(n, MAX_MSG, TCA_SKBEDIT_QUEUE_MAPPING,
@@ -157,7 +156,7 @@ parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
        if (flags & SKBEDIT_F_PTYPE)
                addattr_l(n, MAX_MSG, TCA_SKBEDIT_PTYPE,
                          &ptype, sizeof(ptype));
-       tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+       addattr_nest_end(n, tail);
 
        *argc_p = argc;
        *argv_p = argv;
index 561b73fb8264783b6188b3e0eecbe3c9c4aa519e..2dd1bb7e3d6dbe0e584703b4ecd6bb30769703a7 100644 (file)
@@ -142,8 +142,7 @@ static int parse_skbmod(struct action_util *a, int *argc_p, char ***argv_p,
                skbmod_usage();
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       tail = addattr_nest(n, MAX_MSG, tca_id);
        addattr_l(n, MAX_MSG, TCA_SKBMOD_PARMS, &p, sizeof(p));
 
        if (daddr)
@@ -153,7 +152,7 @@ static int parse_skbmod(struct action_util *a, int *argc_p, char ***argv_p,
        if (saddr)
                addattr_l(n, MAX_MSG, TCA_SKBMOD_SMAC, sbuf, ETH_ALEN);
 
-       tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
+       addattr_nest_end(n, tail);
 
        *argc_p = argc;
        *argv_p = argv;
index 1cdd03560c3573bf1142713e4310cdea4477edc7..bac3c07fa90b5d3c25f81062a12c612ea7c85674 100644 (file)
@@ -98,8 +98,7 @@ static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
        if (matches(*argv, "tunnel_key") != 0)
                return -1;
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       tail = addattr_nest(n, MAX_MSG, tca_id);
 
        NEXT_ARG();
 
@@ -196,7 +195,7 @@ static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
 
        parm.t_action = action;
        addattr_l(n, MAX_MSG, TCA_TUNNEL_KEY_PARMS, &parm, sizeof(parm));
-       tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+       addattr_nest_end(n, tail);
 
        *argc_p = argc;
        *argv_p = argv;
index 161759fd40630734dd775f8911654ef949175137..412f6aa1000e86fd2fff02039dace7912a997c45 100644 (file)
@@ -151,8 +151,7 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p,
        }
 
        parm.v_action = action;
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       tail = addattr_nest(n, MAX_MSG, tca_id);
        addattr_l(n, MAX_MSG, TCA_VLAN_PARMS, &parm, sizeof(parm));
        if (id_set)
                addattr_l(n, MAX_MSG, TCA_VLAN_PUSH_VLAN_ID, &id, 2);
@@ -169,7 +168,7 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p,
        if (prio_set)
                addattr8(n, MAX_MSG, TCA_VLAN_PUSH_VLAN_PRIORITY, prio);
 
-       tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+       addattr_nest_end(n, tail);
 
        *argc_p = argc;
        *argv_p = argv;
index a1137be9614f1f28636882292433f0bb16fc45a1..29574bd41f93eefb46214e969cec8772f568e72c 100644 (file)
--- a/tc/m_xt.c
+++ b/tc/m_xt.c
@@ -264,8 +264,7 @@ static int parse_ipt(struct action_util *a, int *argc_p,
                }
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       tail = addattr_nest(n, MAX_MSG, tca_id);
        fprintf(stdout, "tablename: %s hook: %s\n ", tname, ipthooks[hook]);
        fprintf(stdout, "\ttarget: ");
 
@@ -290,7 +289,7 @@ static int parse_ipt(struct action_util *a, int *argc_p,
        addattr_l(n, MAX_MSG, TCA_IPT_INDEX, &index, 4);
        if (m)
                addattr_l(n, MAX_MSG, TCA_IPT_TARG, m->t, m->t->u.target_size);
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
 
        argv += optind;
        *argc_p -= argc;
index 21d90877357c595eaa07048d486923bb5febf385..313bea61cc7e05bb8ed24168b48dd320c63a31bb 100644 (file)
@@ -308,8 +308,7 @@ static int parse_ipt(struct action_util *a, int *argc_p,
                }
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+       tail = addattr_nest(n, MAX_MSG, tca_id);
        fprintf(stdout, "tablename: %s hook: %s\n ", tname, ipthooks[hook]);
        fprintf(stdout, "\ttarget: ");
 
@@ -330,7 +329,7 @@ static int parse_ipt(struct action_util *a, int *argc_p,
        addattr_l(n, MAX_MSG, TCA_IPT_INDEX, &index, 4);
        if (m)
                addattr_l(n, MAX_MSG, TCA_IPT_TARG, m->t, m->t->u.target_size);
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
 
        argc -= optind;
        argv += optind;
index 3ea4cf4eb986f66192709699f56143e30ff66338..f8215f06507a69d4862abc69c73274c9bec49730 100644 (file)
@@ -167,12 +167,13 @@ static int atm_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
                        perror("ioctl ATMARP_MKIP");
                        return -1;
                }
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        addattr_l(n, 1024, TCA_ATM_FD, &s, sizeof(s));
-       if (excess) addattr_l(n, 1024, TCA_ATM_EXCESS, &excess, sizeof(excess));
-       if (hdr_len != -1) addattr_l(n, 1024, TCA_ATM_HDR, hdr, hdr_len);
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       if (excess)
+               addattr_l(n, 1024, TCA_ATM_EXCESS, &excess, sizeof(excess));
+       if (hdr_len != -1)
+               addattr_l(n, 1024, TCA_ATM_HDR, hdr, hdr_len);
+       addattr_nest_end(n, tail);
        return 0;
 }
 
index d05fe9c88808d79f696656d4d5c97ec912d32781..e7f1a3bfaf5dbb2565d4f1bafdab9639d8a2ec06 100644 (file)
@@ -165,8 +165,7 @@ static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
        lss.change = TCF_CBQ_LSS_MAXIDLE|TCF_CBQ_LSS_EWMA|TCF_CBQ_LSS_AVPKT;
        lss.avpkt = avpkt;
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        addattr_l(n, 1024, TCA_CBQ_RATE, &r, sizeof(r));
        addattr_l(n, 1024, TCA_CBQ_LSSOPT, &lss, sizeof(lss));
        addattr_l(n, 3024, TCA_CBQ_RTAB, rtab, 1024);
@@ -177,7 +176,7 @@ static int cbq_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
                        printf("%u ", rtab[i]);
                printf("\n");
        }
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
@@ -419,8 +418,7 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
                lss.change |= TCF_CBQ_LSS_EWMA;
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        if (lss.change) {
                lss.change |= TCF_CBQ_LSS_FLAGS;
                addattr_l(n, 1024, TCA_CBQ_LSSOPT, &lss, sizeof(lss));
@@ -440,7 +438,7 @@ static int cbq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
                        printf("\n");
                }
        }
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
index b57390571e181811deb2f35d6fe2c97564194263..a2ffb1db385247a66a96602b1840181c795bc1c9 100644 (file)
@@ -102,10 +102,9 @@ static int cbs_parse_opt(struct qdisc_util *qu, int argc,
                argc--; argv++;
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        addattr_l(n, 2024, TCA_CBS_PARMS, &opt, sizeof(opt));
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
index 50ac4ad4ecb8093e00b46e439fd50a7f10186c5f..b269b1338b6d92377645cc65dc542c6a454dc2a6 100644 (file)
@@ -156,13 +156,12 @@ static int choke_parse_opt(struct qdisc_util *qu, int argc, char **argv,
        if (ecn_ok)
                opt.flags |= TC_RED_ECN;
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        addattr_l(n, 1024, TCA_CHOKE_PARMS, &opt, sizeof(opt));
        addattr_l(n, 1024, TCA_CHOKE_STAB, sbuf, 256);
        max_P = probability * pow(2, 32);
        addattr_l(n, 1024, TCA_CHOKE_MAX_P, &max_P, sizeof(max_P));
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
index 62d6dd68a0998cb6f0f0e79bb58105f960f3e911..8a2a871671cbe89382db378e913947855074eef1 100644 (file)
@@ -107,8 +107,7 @@ static int codel_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                argc--; argv++;
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        if (limit)
                addattr_l(n, 1024, TCA_CODEL_LIMIT, &limit, sizeof(limit));
        if (interval)
@@ -121,7 +120,7 @@ static int codel_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                addattr_l(n, 1024, TCA_CODEL_CE_THRESHOLD,
                          &ce_threshold, sizeof(ce_threshold));
 
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
index 5e541c09abe11b433e879f5df323230027ec8281..f9c90f3035f388163d8dcb41331fabd726bde2fc 100644 (file)
@@ -55,8 +55,7 @@ static int drr_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
        struct rtattr *tail;
        __u32 tmp;
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
 
        while (argc > 0) {
                if (strcmp(*argv, "quantum") == 0) {
@@ -77,7 +76,7 @@ static int drr_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
                argc--; argv++;
        }
 
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *)tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
index 967fd89214156f990f3b915cae77c0eec198b0a4..d3e8292d777cc2be5385cde5a13bdeb5c966aabc 100644 (file)
@@ -64,16 +64,16 @@ static int dsmark_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                explain();
                return -1;
        }
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        addattr_l(n, 1024, TCA_DSMARK_INDICES, &ind, sizeof(ind));
        if (dflt != -1) {
            __u16 tmp = dflt;
 
            addattr_l(n, 1024, TCA_DSMARK_DEFAULT_INDEX, &tmp, sizeof(tmp));
        }
-       if (set_tc_index) addattr_l(n, 1024, TCA_DSMARK_SET_TC_INDEX, NULL, 0);
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       if (set_tc_index)
+               addattr_l(n, 1024, TCA_DSMARK_SET_TC_INDEX, NULL, 0);
+       addattr_nest_end(n, tail);
        return 0;
 }
 
@@ -91,8 +91,7 @@ static int dsmark_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
        __u8 tmp;
        char *end;
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        while (argc > 0) {
                if (!strcmp(*argv, "mask")) {
                        NEXT_ARG();
@@ -117,7 +116,7 @@ static int dsmark_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
                argc--;
                argv++;
        }
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
index 51b5bc367cab4d7a3a0cb558609498bc50f10721..f3dbf2ba0c6f520ec1080b90fa4f08c968325102 100644 (file)
--- a/tc/q_fq.c
+++ b/tc/q_fq.c
@@ -190,8 +190,7 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                argc--; argv++;
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        if (buckets) {
                unsigned int log = ilog2(buckets);
 
@@ -227,7 +226,7 @@ static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
        if (set_orphan_mask)
                addattr_l(n, 1024, TCA_FQ_ORPHAN_MASK,
                          &orphan_mask, sizeof(refill_delay));
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
index fd1f59c89f50d3e9e5924f1b702e60e9180542de..02ad2214110b460d5e3c6233525cf1de13f1a667 100644 (file)
@@ -50,6 +50,7 @@
 static void explain(void)
 {
        fprintf(stderr, "Usage: ... fq_codel [ limit PACKETS ] [ flows NUMBER ]\n");
+       fprintf(stderr, "                    [ memory_limit BYTES ]\n");
        fprintf(stderr, "                    [ target TIME ] [ interval TIME ]\n");
        fprintf(stderr, "                    [ quantum BYTES ] [ [no]ecn ]\n");
        fprintf(stderr, "                    [ ce_threshold TIME ]\n");
@@ -126,8 +127,7 @@ static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                argc--; argv++;
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        if (limit)
                addattr_l(n, 1024, TCA_FQ_CODEL_LIMIT, &limit, sizeof(limit));
        if (flows)
@@ -147,7 +147,7 @@ static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                addattr_l(n, 1024, TCA_FQ_CODEL_MEMORY_LIMIT,
                          &memory, sizeof(memory));
 
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
@@ -239,35 +239,50 @@ static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f,
                st = &_st;
        }
        if (st->type == TCA_FQ_CODEL_XSTATS_QDISC) {
-               fprintf(f, "  maxpacket %u drop_overlimit %u new_flow_count %u ecn_mark %u",
-                       st->qdisc_stats.maxpacket,
-                       st->qdisc_stats.drop_overlimit,
-                       st->qdisc_stats.new_flow_count,
+               print_uint(PRINT_ANY, "maxpacket", "  maxpacket %u",
+                       st->qdisc_stats.maxpacket);
+               print_uint(PRINT_ANY, "drop_overlimit", " drop_overlimit %u",
+                       st->qdisc_stats.drop_overlimit);
+               print_uint(PRINT_ANY, "new_flow_count", " new_flow_count %u",
+                       st->qdisc_stats.new_flow_count);
+               print_uint(PRINT_ANY, "ecn_mark", " ecn_mark %u",
                        st->qdisc_stats.ecn_mark);
                if (st->qdisc_stats.ce_mark)
-                       fprintf(f, " ce_mark %u", st->qdisc_stats.ce_mark);
+                       print_uint(PRINT_ANY, "ce_mark", " ce_mark %u",
+                               st->qdisc_stats.ce_mark);
                if (st->qdisc_stats.memory_usage)
-                       fprintf(f, " memory_used %u", st->qdisc_stats.memory_usage);
+                       print_uint(PRINT_ANY, "memory_used", " memory_used %u",
+                               st->qdisc_stats.memory_usage);
                if (st->qdisc_stats.drop_overmemory)
-                       fprintf(f, " drop_overmemory %u", st->qdisc_stats.drop_overmemory);
-               fprintf(f, "\n  new_flows_len %u old_flows_len %u",
-                       st->qdisc_stats.new_flows_len,
+                       print_uint(PRINT_ANY, "drop_overmemory", " drop_overmemory %u",
+                               st->qdisc_stats.drop_overmemory);
+               print_uint(PRINT_ANY, "new_flows_len", "\n  new_flows_len %u",
+                       st->qdisc_stats.new_flows_len);
+               print_uint(PRINT_ANY, "old_flows_len", " old_flows_len %u",
                        st->qdisc_stats.old_flows_len);
        }
        if (st->type == TCA_FQ_CODEL_XSTATS_CLASS) {
-               fprintf(f, "  deficit %d count %u lastcount %u ldelay %s",
-                       st->class_stats.deficit,
-                       st->class_stats.count,
-                       st->class_stats.lastcount,
+               print_uint(PRINT_ANY, "deficit", "  deficit %u",
+                       st->class_stats.deficit);
+               print_uint(PRINT_ANY, "count", " count %u",
+                       st->class_stats.count);
+               print_uint(PRINT_ANY, "lastcount", " lastcount %u",
+                       st->class_stats.lastcount);
+               print_uint(PRINT_JSON, "ldelay", NULL,
+                       st->class_stats.ldelay);
+               print_string(PRINT_FP, NULL, " ldelay %s",
                        sprint_time(st->class_stats.ldelay, b1));
                if (st->class_stats.dropping) {
-                       fprintf(f, " dropping");
+                       print_bool(PRINT_ANY, "dropping", " dropping", true);
                        if (st->class_stats.drop_next < 0)
-                               fprintf(f, " drop_next -%s",
+                               print_string(PRINT_FP, NULL, " drop_next -%s",
                                        sprint_time(-st->class_stats.drop_next, b1));
-                       else
-                               fprintf(f, " drop_next %s",
+                       else {
+                               print_uint(PRINT_JSON, "drop_next", NULL,
+                                       st->class_stats.drop_next);
+                               print_string(PRINT_FP, NULL, " drop_next %s",
                                        sprint_time(st->class_stats.drop_next, b1));
+                       }
                }
        }
        return 0;
index 5b5761eebd05e307319a05adb469a2c3b5e78dd4..e63fac72a883d690762b62d51f6d44b345e384ec 100644 (file)
@@ -105,12 +105,11 @@ static int init_gred(struct qdisc_util *qu, int argc, char **argv,
 
        DPRINTF("TC_GRED: sending DPs=%u def_DP=%u\n", opt.DPs, opt.def_DP);
        n->nlmsg_flags |= NLM_F_CREATE;
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        addattr_l(n, 1024, TCA_GRED_DPS, &opt, sizeof(struct tc_gred_sopt));
        if (limit)
                addattr32(n, 1024, TCA_GRED_LIMIT, limit);
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 /*
@@ -257,13 +256,12 @@ static int gred_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct n
        }
        opt.Scell_log = parm;
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        addattr_l(n, 1024, TCA_GRED_PARMS, &opt, sizeof(opt));
        addattr_l(n, 1024, TCA_GRED_STAB, sbuf, 256);
        max_P = probability * pow(2, 32);
        addattr32(n, 1024, TCA_GRED_MAX_P, max_P);
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
index c19e87f98761ea472871f9018b07de6d6224fffa..f34b1b2fe2a98f10c5f65ac4f20b26686fcbae4f 100644 (file)
@@ -201,9 +201,7 @@ hfsc_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
                return -1;
        }
 
-       tail = NLMSG_TAIL(n);
-
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        if (rsc_ok)
                addattr_l(n, 1024, TCA_HFSC_RSC, &rsc, sizeof(rsc));
        if (fsc_ok)
@@ -211,7 +209,7 @@ hfsc_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
        if (usc_ok)
                addattr_l(n, 1024, TCA_HFSC_USC, &usc, sizeof(usc));
 
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
index 66c7188663547ec21f31574977649476750aab20..21186a92c017ab6e1bd7c30b4178122c1a6a4456 100644 (file)
@@ -91,8 +91,7 @@ static int hhf_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                argc--; argv++;
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        if (limit)
                addattr_l(n, 1024, TCA_HHF_BACKLOG_LIMIT, &limit,
                          sizeof(limit));
@@ -113,7 +112,7 @@ static int hhf_parse_opt(struct qdisc_util *qu, int argc, char **argv,
        if (non_hh_weight)
                addattr_l(n, 1024, TCA_HHF_NON_HH_WEIGHT, &non_hh_weight,
                          sizeof(non_hh_weight));
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
index 3fc2acb3be3265dd2f639343241185946cb15a74..7d5f6ce4477393c16359a1e37df79f8b96a97c47 100644 (file)
@@ -98,13 +98,12 @@ static int htb_parse_opt(struct qdisc_util *qu, int argc,
                }
                argc--; argv++;
        }
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        addattr_l(n, 2024, TCA_HTB_INIT, &opt, NLMSG_ALIGN(sizeof(opt)));
        if (direct_qlen != ~0U)
                addattr_l(n, 2024, TCA_HTB_DIRECT_QLEN,
                          &direct_qlen, sizeof(direct_qlen));
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
@@ -254,8 +253,7 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
        }
        opt.cbuffer = tc_calc_xmittime(ceil64, cbuffer);
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
 
        if (rate64 >= (1ULL << 32))
                addattr_l(n, 1124, TCA_HTB_RATE64, &rate64, sizeof(rate64));
@@ -266,7 +264,7 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
        addattr_l(n, 2024, TCA_HTB_PARMS, &opt, sizeof(opt));
        addattr_l(n, 3024, TCA_HTB_RTAB, rtab, 1024);
        addattr_l(n, 4024, TCA_HTB_CTAB, ctab, 1024);
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
index 89b460020e27ea8e63e07c2d98eff04ef5819ac3..207d6441d8fa35adb8c68dcde68b1ba270702c28 100644 (file)
@@ -173,8 +173,7 @@ static int mqprio_parse_opt(struct qdisc_util *qu, int argc,
                argc--; argv++;
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
+       tail = addattr_nest_compat(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
 
        if (flags & TC_MQPRIO_F_MODE)
                addattr_l(n, 1024, TCA_MQPRIO_MODE,
@@ -209,7 +208,7 @@ static int mqprio_parse_opt(struct qdisc_util *qu, int argc,
                addattr_nest_end(n, start);
        }
 
-       tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
+       addattr_nest_compat_end(n, tail);
 
        return 0;
 }
index 9f9a9b3df255f89fac5269c3f1a43ddb86a8cf71..623ec9038ad37ae09b91b7936c8f5b6050761009 100644 (file)
@@ -422,8 +422,6 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                }
        }
 
-       tail = NLMSG_TAIL(n);
-
        if (reorder.probability) {
                if (opt.latency == 0) {
                        fprintf(stderr, "reordering not possible without specifying some delay\n");
@@ -452,8 +450,7 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                return -1;
        }
 
-       if (addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)) < 0)
-               return -1;
+       tail = addattr_nest_compat(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
 
        if (present[TCA_NETEM_CORR] &&
            addattr_l(n, 1024, TCA_NETEM_CORR, &cor, sizeof(cor)) < 0)
@@ -512,7 +509,7 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                        return -1;
                free(dist_data);
        }
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_compat_end(n, tail);
        return 0;
 }
 
index b89f53c73a44987641928d547762f38ade23ed84..f7924ef5e76cbc275729b745d22763007caba4ac 100644 (file)
@@ -103,8 +103,7 @@ static int pie_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                argv++;
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        if (limit)
                addattr_l(n, 1024, TCA_PIE_LIMIT, &limit, sizeof(limit));
        if (tupdate)
@@ -121,7 +120,7 @@ static int pie_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                addattr_l(n, 1024, TCA_PIE_BYTEMODE, &bytemode,
                          sizeof(bytemode));
 
-       tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
index d70ca1ba817e25199fbeac9c5616ce110bd1e22e..eb8fa4b849273c4771a1a6d00db8a354d045e0a5 100644 (file)
@@ -53,8 +53,7 @@ static int qfq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
        struct rtattr *tail;
        __u32 tmp;
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 4096, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 4096, TCA_OPTIONS);
 
        while (argc > 0) {
                if (matches(*argv, "weight") == 0) {
@@ -80,7 +79,7 @@ static int qfq_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
                argc--; argv++;
        }
 
-       tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
+       addattr_nest_end(n, tail);
 
        return 0;
 }
index 40ba7c3e07c174a61dd0780e021fddad914d25a3..49fd4ac8051309189526a48d5c008a83687bfa90 100644 (file)
@@ -148,13 +148,12 @@ static int red_parse_opt(struct qdisc_util *qu, int argc, char **argv,
        }
        opt.Scell_log = parm;
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        addattr_l(n, 1024, TCA_RED_PARMS, &opt, sizeof(opt));
        addattr_l(n, 1024, TCA_RED_STAB, sbuf, 256);
        max_P = probability * pow(2, 32);
        addattr_l(n, 1024, TCA_RED_MAX_P, &max_P, sizeof(max_P));
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
index 4b366ddd915c967a88774ba63212922f43ac83b5..7f48c6e0ef393f703dd8639227b7041f6165bf8f 100644 (file)
@@ -132,10 +132,9 @@ static int sfb_parse_opt(struct qdisc_util *qu, int argc, char **argv,
        if (opt.bin_size == 0)
                opt.bin_size = (opt.max * 4 + 3) / 5;
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        addattr_l(n, 1024, TCA_SFB_PARMS, &opt, sizeof(opt));
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
index dfaa5d383ae596b8104e3772e080ed45a0599539..b9465b20d2beadafef3bce9729f08cf86f158672 100644 (file)
@@ -241,8 +241,7 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                opt.mtu = tc_calc_xmittime(opt.peakrate.rate, mtu);
        }
 
-       tail = NLMSG_TAIL(n);
-       addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+       tail = addattr_nest(n, 1024, TCA_OPTIONS);
        addattr_l(n, 2024, TCA_TBF_PARMS, &opt, sizeof(opt));
        addattr_l(n, 2124, TCA_TBF_BURST, &buffer, sizeof(buffer));
        if (rate64 >= (1ULL << 32))
@@ -254,7 +253,7 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv,
                addattr_l(n, 3224, TCA_TBF_PBURST, &mtu, sizeof(mtu));
                addattr_l(n, 4096, TCA_TBF_PTAB, ptab, 1024);
        }
-       tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+       addattr_nest_end(n, tail);
        return 0;
 }
 
diff --git a/tc/tc.c b/tc/tc.c
index 63e64fece87dc8b950b3784060e444f344d05053..a31f075d1ffe640c236192150d71432280e69613 100644 (file)
--- a/tc/tc.c
+++ b/tc/tc.c
@@ -33,7 +33,6 @@
 int show_stats;
 int show_details;
 int show_raw;
-int show_pretty;
 int show_graph;
 int timestamp;
 
@@ -42,6 +41,7 @@ int use_iec;
 int force;
 bool use_names;
 int json;
+int color;
 
 static char *conf_file;
 
@@ -187,10 +187,11 @@ noexist:
 static void usage(void)
 {
        fprintf(stderr, "Usage: tc [ OPTIONS ] OBJECT { COMMAND | help }\n"
-                       "       tc [-force] -batch filename\n"
-                       "where  OBJECT := { qdisc | class | filter | action | monitor | exec }\n"
-                       "       OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -p[retty] | -b[atch] [filename] | -n[etns] name |\n"
-                       "                    -nm | -nam[es] | { -cf | -conf } path } | -j[son]\n");
+               "       tc [-force] -batch filename\n"
+               "where  OBJECT := { qdisc | class | filter | action | monitor | exec }\n"
+               "       OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] | -b[atch] [filename] | -n[etns] name |\n"
+               "                    -nm | -nam[es] | { -cf | -conf } path } |\n"
+               "                    -j[son] -p[retty] -c[olor]\n");
 }
 
 static int do_cmd(int argc, char **argv, void *buf, size_t buflen)
@@ -448,7 +449,7 @@ int main(int argc, char **argv)
                } else if (matches(argv[1], "-raw") == 0) {
                        ++show_raw;
                } else if (matches(argv[1], "-pretty") == 0) {
-                       ++show_pretty;
+                       ++pretty;
                } else if (matches(argv[1], "-graph") == 0) {
                        show_graph = 1;
                } else if (matches(argv[1], "-Version") == 0) {
@@ -477,6 +478,8 @@ int main(int argc, char **argv)
                                matches(argv[1], "-conf") == 0) {
                        NEXT_ARG();
                        conf_file = argv[1];
+               } else if (matches(argv[1], "-color") == 0) {
+                       ++color;
                } else if (matches(argv[1], "-timestamp") == 0) {
                        timestamp++;
                } else if (matches(argv[1], "-tshort") == 0) {
@@ -491,6 +494,9 @@ int main(int argc, char **argv)
                argc--; argv++;
        }
 
+       if (color & !json)
+               enable_color();
+
        if (batch_file)
                return batch(batch_file);
 
index 1b214b82c702baa1eb781ad9fa8b10e0cca40442..e1ca29cfa9a4305bf0422ccaf5c1de0a6916b670 100644 (file)
@@ -142,10 +142,9 @@ static int tc_class_modify(int cmd, unsigned int flags, int argc, char **argv)
        if (d[0])  {
                ll_init_map(&rth);
 
-               if ((req.t.tcm_ifindex = ll_name_to_index(d)) == 0) {
-                       fprintf(stderr, "Cannot find device \"%s\"\n", d);
-                       return 1;
-               }
+               req.t.tcm_ifindex = ll_name_to_index(d);
+               if (!req.t.tcm_ifindex)
+                       return -nodev(d);
        }
 
        if (rtnl_talk(&rth, &req.n, NULL) < 0)
@@ -440,10 +439,9 @@ static int tc_class_list(int argc, char **argv)
        ll_init_map(&rth);
 
        if (d[0]) {
-               if ((t.tcm_ifindex = ll_name_to_index(d)) == 0) {
-                       fprintf(stderr, "Cannot find device \"%s\"\n", d);
-                       return 1;
-               }
+               t.tcm_ifindex = ll_name_to_index(d);
+               if (!t.tcm_ifindex)
+                       return -nodev(d);
                filter_ifindex = t.tcm_ifindex;
        }
 
index 5c31a4cea658b229fb21b6888634b773acb699d0..c5bb0bffe19b2df23eaef3ec152533528ed74fae 100644 (file)
@@ -198,10 +198,8 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv,
                ll_init_map(&rth);
 
                req->t.tcm_ifindex = ll_name_to_index(d);
-               if (req->t.tcm_ifindex == 0) {
-                       fprintf(stderr, "Cannot find device \"%s\"\n", d);
-                       return 1;
-               }
+               if (!req->t.tcm_ifindex)
+                       return -nodev(d);
        } else if (block_index) {
                req->t.tcm_ifindex = TCM_IFINDEX_MAGIC_BLOCK;
                req->t.tcm_block_index = block_index;
@@ -303,8 +301,7 @@ int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                                   t->tcm_block_index);
        } else {
                if (!filter_ifindex || filter_ifindex != t->tcm_ifindex)
-                       print_string(PRINT_ANY, "dev", "dev %s ",
-                                    ll_index_to_name(t->tcm_ifindex));
+                       print_devname(PRINT_ANY, t->tcm_ifindex);
 
                if (!filter_parent || filter_parent != t->tcm_parent) {
                        if (t->tcm_parent == TC_H_ROOT)
@@ -530,10 +527,8 @@ static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv)
                ll_init_map(&rth);
 
                req.t.tcm_ifindex = ll_name_to_index(d);
-               if (req.t.tcm_ifindex  == 0) {
-                       fprintf(stderr, "Cannot find device \"%s\"\n", d);
-                       return 1;
-               }
+               if (!req.t.tcm_ifindex)
+                       return -nodev(d);
                filter_ifindex = req.t.tcm_ifindex;
        } else if (block_index) {
                req.t.tcm_ifindex = TCM_IFINDEX_MAGIC_BLOCK;
@@ -696,10 +691,8 @@ static int tc_filter_list(int argc, char **argv)
 
        if (d[0]) {
                req.t.tcm_ifindex = ll_name_to_index(d);
-               if (req.t.tcm_ifindex == 0) {
-                       fprintf(stderr, "Cannot find device \"%s\"\n", d);
-                       return 1;
-               }
+               if (!req.t.tcm_ifindex)
+                       return -nodev(d);
                filter_ifindex = req.t.tcm_ifindex;
        } else if (block_index) {
                if (!tc_qdisc_block_exists(block_index)) {
index 8cc4b73d9d10733191db898d90d6d73b4ee66de1..c1d2df0171a75077a9d7981ca4ecbea6e881e83a 100644 (file)
@@ -182,14 +182,13 @@ static int tc_qdisc_modify(int cmd, unsigned int flags, int argc, char **argv)
                        return -1;
                }
 
-               tail = NLMSG_TAIL(&req.n);
-               addattr_l(&req.n, sizeof(req), TCA_STAB, NULL, 0);
+               tail = addattr_nest(&req.n, sizeof(req), TCA_STAB);
                addattr_l(&req.n, sizeof(req), TCA_STAB_BASE, &stab.szopts,
                          sizeof(stab.szopts));
                if (stab.data)
                        addattr_l(&req.n, sizeof(req), TCA_STAB_DATA, stab.data,
                                  stab.szopts.tsize * sizeof(__u16));
-               tail->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail;
+               addattr_nest_end(&req.n, tail);
                if (stab.data)
                        free(stab.data);
        }
@@ -200,10 +199,8 @@ static int tc_qdisc_modify(int cmd, unsigned int flags, int argc, char **argv)
                ll_init_map(&rth);
 
                idx = ll_name_to_index(d);
-               if (idx == 0) {
-                       fprintf(stderr, "Cannot find device \"%s\"\n", d);
-                       return 1;
-               }
+               if (!idx)
+                       return -nodev(d);
                req.t.tcm_ifindex = idx;
        }
 
@@ -271,8 +268,7 @@ int print_qdisc(const struct sockaddr_nl *who,
        print_string(PRINT_FP, NULL, " ", NULL);
 
        if (filter_ifindex == 0)
-               print_string(PRINT_ANY, "dev", "dev %s ",
-                            ll_index_to_name(t->tcm_ifindex));
+               print_devname(PRINT_ANY, t->tcm_ifindex);
 
        if (t->tcm_parent == TC_H_ROOT)
                print_bool(PRINT_ANY, "root", "root ", true);
@@ -380,10 +376,8 @@ static int tc_qdisc_list(int argc, char **argv)
 
        if (d[0]) {
                t.tcm_ifindex = ll_name_to_index(d);
-               if (t.tcm_ifindex == 0) {
-                       fprintf(stderr, "Cannot find device \"%s\"\n", d);
-                       return 1;
-               }
+               if (!t.tcm_ifindex)
+                       return -nodev(d);
                filter_ifindex = t.tcm_ifindex;
        }
 
index 8eadbbcf29b6b51e9da97b02e6940891d989182a..e0c96291ade02746c3966d75836edc9b1a4bd099 100644 (file)
@@ -444,6 +444,17 @@ int get_size_and_cell(unsigned int *size, int *cell_log, char *str)
        return 0;
 }
 
+void print_devname(enum output_type type, int ifindex)
+{
+       const char *ifname = ll_index_to_name(ifindex);
+
+       if (!is_json_context())
+               printf("dev ");
+
+       print_color_string(type, COLOR_IFNAME,
+                          "dev", "%s ", ifname);
+}
+
 void print_size(char *buf, int len, __u32 sz)
 {
        double tmp = sz;
index cd2ff5964e19938adf1eae0db81b09049278cf13..6632c4f9c528265a2568f94f5e17249c3f94551e 100644 (file)
@@ -89,6 +89,7 @@ void print_size(char *buf, int len, __u32 size);
 void print_qdisc_handle(char *buf, int len, __u32 h);
 void print_time(char *buf, int len, __u32 time);
 void print_linklayer(char *buf, int len, unsigned int linklayer);
+void print_devname(enum output_type type, int ifindex);
 
 char *sprint_rate(__u64 rate, char *buf);
 char *sprint_size(__u32 size, char *buf);