]> git.proxmox.com Git - mirror_iproute2.git/commitdiff
Merge branch 'master' into net-next
authorStephen Hemminger <stephen@networkplumber.org>
Tue, 22 Aug 2017 00:14:19 +0000 (17:14 -0700)
committerStephen Hemminger <stephen@networkplumber.org>
Tue, 22 Aug 2017 00:14:19 +0000 (17:14 -0700)
60 files changed:
bridge/mdb.c
include/color.h
include/json_writer.h
include/linux/bpf.h
include/linux/inet_diag.h
include/linux/ipv6.h [deleted file]
include/linux/lwtunnel.h
include/linux/netlink.h
include/linux/pfkeyv2.h [new file with mode: 0644]
include/linux/rtnetlink.h
include/linux/seg6_local.h [new file with mode: 0644]
include/linux/tcp.h
include/linux/xfrm.h
include/utils.h
ip/Makefile
ip/ip.c
ip/ip_common.h
ip/ip_print.c [new file with mode: 0644]
ip/ipaddress.c
ip/iplink.c
ip/iplink_bond.c
ip/iplink_bond_slave.c
ip/iplink_bridge.c
ip/iplink_bridge_slave.c
ip/iplink_can.c
ip/iplink_geneve.c
ip/iplink_hsr.c
ip/iplink_ipoib.c
ip/iplink_ipvlan.c
ip/iplink_macvlan.c
ip/iplink_vlan.c
ip/iplink_vrf.c
ip/iplink_vxlan.c
ip/iplink_xdp.c
ip/ipmacsec.c
ip/iproute.c
ip/iproute_lwtunnel.c
ip/link_gre.c
ip/link_gre6.c
ip/link_ip6tnl.c
ip/link_iptnl.c
ip/link_vti.c
ip/link_vti6.c
lib/color.c
lib/json_writer.c
man/man8/ip-route.8.in
man/man8/tc-actions.8
tc/f_basic.c
tc/f_bpf.c
tc/f_cgroup.c
tc/f_flow.c
tc/f_flower.c
tc/f_fw.c
tc/f_matchall.c
tc/f_route.c
tc/f_rsvp.c
tc/f_tcindex.c
tc/f_u32.c
tc/m_action.c
tc/tc_util.h

index e60ff3ef3f48548bd6f03295e173ecc9aafa56f3..748091b8d83a7e7886c1cbe75aa2515c27f47d18 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/if_ether.h>
 #include <string.h>
 #include <arpa/inet.h>
+#include <json_writer.h>
 
 #include "libnetlink.h"
 #include "br_common.h"
@@ -25,6 +26,9 @@
 #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)
 {
@@ -49,13 +53,26 @@ static void __print_router_port_stats(FILE *f, struct rtattr *pattr)
        if (tb[MDBA_ROUTER_PATTR_TIMER]) {
                __jiffies_to_tv(&tv,
                                rta_getattr_u32(tb[MDBA_ROUTER_PATTR_TIMER]));
-               fprintf(f, " %4i.%.2i",
-                       (int)tv.tv_sec, (int)tv.tv_usec/10000);
+               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);
+               }
        }
        if (tb[MDBA_ROUTER_PATTR_TYPE]) {
                type = rta_getattr_u8(tb[MDBA_ROUTER_PATTR_TYPE]);
-               fprintf(f, " %s",
-                       is_temp_mcast_rtr(type) ? "temp" : "permanent");
+               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");
        }
 }
 
@@ -65,24 +82,50 @@ static void br_print_router_ports(FILE *f, struct rtattr *attr, __u32 brifidx)
        struct rtattr *i;
        int rem;
 
-       if (!show_stats)
-               fprintf(f, "router ports on %s: ", ll_index_to_name(brifidx));
-
        rem = RTA_PAYLOAD(attr);
-       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 (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 (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)
+                       fprintf(f, "\n");
        }
-       if (!show_stats)
-               fprintf(f, "\n");
+}
+
+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,
@@ -91,28 +134,70 @@ static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e,
        SPRINT_BUF(abuf);
        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 (n->nlmsg_type == RTM_DELMDB)
-               fprintf(f, "Deleted ");
-       fprintf(f, "dev %s port %s grp %s %s %s", ll_index_to_name(ifindex),
-               ll_index_to_name(e->ifindex),
-               inet_ntop(af, src, abuf, sizeof(abuf)),
-               (e->state & MDB_PERMANENT) ? "permanent" : "temp",
-               (e->flags & MDB_FLAGS_OFFLOAD) ? "offload" : "");
-       if (e->vid)
-               fprintf(f, " vid %hu", e->vid);
+       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);
+       }
        if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) {
                struct timeval tv;
 
                __jiffies_to_tv(&tv, rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER]));
-               fprintf(f, "%4i.%.2i", (int)tv.tv_sec, (int)tv.tv_usec/10000);
+               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);
+               }
        }
-       fprintf(f, "\n");
+       if (jw_global)
+               jsonw_end_object(jw_global);
+       else
+               fprintf(f, "\n");
 }
 
 static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr,
@@ -157,14 +242,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]) {
+       if (tb[MDBA_MDB] && print_mdb_entries) {
                int rem = RTA_PAYLOAD(tb[MDBA_MDB]);
 
                for (i = RTA_DATA(tb[MDBA_MDB]); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
                        br_print_mdb_entry(fp, r->ifindex, i, n);
        }
 
-       if (tb[MDBA_ROUTER]) {
+       if (tb[MDBA_ROUTER] && print_mdb_router) {
                if (n->nlmsg_type == RTM_GETMDB) {
                        if (show_details)
                                br_print_router_ports(fp, tb[MDBA_ROUTER],
@@ -174,15 +259,33 @@ int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 
                        i = RTA_DATA(tb[MDBA_ROUTER]);
                        port_ifindex = RTA_DATA(i);
-                       if (n->nlmsg_type == RTM_DELMDB)
-                               fprintf(fp, "Deleted ");
-                       fprintf(fp, "router port dev %s master %s\n",
-                               ll_index_to_name(*port_ifindex),
-                               ll_index_to_name(r->ifindex));
+                       if (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));
+                       }
                }
        }
 
-       fflush(fp);
+       if (!jw_global)
+               fflush(fp);
 
        return 0;
 }
@@ -215,15 +318,54 @@ static int mdb_show(int argc, char **argv)
                }
        }
 
+       /* 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);
 
        return 0;
 }
index ba0b237eb04c841375588e328538e1b5575476ff..1cd6f7d2ceaf203f3c86552b3791dcdd96f9eea2 100644 (file)
@@ -2,6 +2,7 @@
 #define __COLOR_H__ 1
 
 enum color_attr {
+       COLOR_NONE,
        COLOR_IFNAME,
        COLOR_MAC,
        COLOR_INET,
@@ -12,6 +13,7 @@ enum color_attr {
 };
 
 void enable_color(void);
+void check_if_color_enabled(void);
 void set_color_palette(void);
 int color_fprintf(FILE *fp, enum color_attr attr, const char *fmt, ...);
 enum color_attr ifa_family_color(__u8 ifa_family);
index ab9a008a67994289635499ff1b312ef127bfbc2a..1516aafba59df7303da7bc590cfee667430a11e0 100644 (file)
@@ -33,20 +33,29 @@ void jsonw_pretty(json_writer_t *self, bool on);
 void jsonw_name(json_writer_t *self, const char *name);
 
 /* Add value  */
+void jsonw_printf(json_writer_t *self, const char *fmt, ...);
 void jsonw_string(json_writer_t *self, const char *value);
 void jsonw_bool(json_writer_t *self, bool value);
 void jsonw_float(json_writer_t *self, double number);
+void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num);
 void jsonw_uint(json_writer_t *self, uint64_t number);
+void jsonw_hu(json_writer_t *self, unsigned short number);
 void jsonw_int(json_writer_t *self, int64_t number);
 void jsonw_null(json_writer_t *self);
+void jsonw_lluint(json_writer_t *self, unsigned long long int num);
 
 /* Useful Combinations of name and value */
 void jsonw_string_field(json_writer_t *self, const char *prop, const char *val);
 void jsonw_bool_field(json_writer_t *self, const char *prop, bool value);
 void jsonw_float_field(json_writer_t *self, const char *prop, double num);
 void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num);
+void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num);
 void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num);
 void jsonw_null_field(json_writer_t *self, const char *prop);
+void jsonw_lluint_field(json_writer_t *self, const char *prop,
+                       unsigned long long int num);
+void jsonw_float_field_fmt(json_writer_t *self, const char *prop,
+                          const char *fmt, double val);
 
 /* Collections */
 void jsonw_start_object(json_writer_t *self);
index fb84d2c29199bffc2b3317fa6bab35f9d926cce0..cb84069134ca7ed8f0b9855ac9232b47a8bc4644 100644 (file)
 #define BPF_FROM_LE    BPF_TO_LE
 #define BPF_FROM_BE    BPF_TO_BE
 
+/* jmp encodings */
 #define BPF_JNE                0x50    /* jump != */
+#define BPF_JLT                0xa0    /* LT is unsigned, '<' */
+#define BPF_JLE                0xb0    /* LE is unsigned, '<=' */
 #define BPF_JSGT       0x60    /* SGT is signed '>', GT in x86 */
 #define BPF_JSGE       0x70    /* SGE is signed '>=', GE in x86 */
+#define BPF_JSLT       0xc0    /* SLT is signed, '<' */
+#define BPF_JSLE       0xd0    /* SLE is signed, '<=' */
 #define BPF_CALL       0x80    /* function call */
 #define BPF_EXIT       0x90    /* function return */
 
@@ -104,6 +109,8 @@ enum bpf_map_type {
        BPF_MAP_TYPE_LPM_TRIE,
        BPF_MAP_TYPE_ARRAY_OF_MAPS,
        BPF_MAP_TYPE_HASH_OF_MAPS,
+       BPF_MAP_TYPE_DEVMAP,
+       BPF_MAP_TYPE_SOCKMAP,
 };
 
 enum bpf_prog_type {
@@ -121,6 +128,7 @@ enum bpf_prog_type {
        BPF_PROG_TYPE_LWT_OUT,
        BPF_PROG_TYPE_LWT_XMIT,
        BPF_PROG_TYPE_SOCK_OPS,
+       BPF_PROG_TYPE_SK_SKB,
 };
 
 enum bpf_attach_type {
@@ -128,11 +136,15 @@ enum bpf_attach_type {
        BPF_CGROUP_INET_EGRESS,
        BPF_CGROUP_INET_SOCK_CREATE,
        BPF_CGROUP_SOCK_OPS,
+       BPF_CGROUP_SMAP_INGRESS,
        __MAX_BPF_ATTACH_TYPE
 };
 
 #define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE
 
+/* If BPF_SOCKMAP_STRPARSER is used sockmap will use strparser on receive */
+#define BPF_SOCKMAP_STRPARSER  (1U << 0)
+
 /* If BPF_F_ALLOW_OVERRIDE flag is used in BPF_PROG_ATTACH command
  * to the given target_fd cgroup the descendent cgroup will be able to
  * override effective bpf program that was inherited from this cgroup
@@ -153,6 +165,7 @@ enum bpf_attach_type {
 #define BPF_NOEXIST    1 /* create new element if it didn't exist */
 #define BPF_EXIST      2 /* update existing element */
 
+/* flags for BPF_MAP_CREATE command */
 #define BPF_F_NO_PREALLOC      (1U << 0)
 /* Instead of having one common LRU list in the
  * BPF_MAP_TYPE_LRU_[PERCPU_]HASH map, use a percpu LRU list
@@ -161,6 +174,8 @@ enum bpf_attach_type {
  * across different LRU lists.
  */
 #define BPF_F_NO_COMMON_LRU    (1U << 1)
+/* Specify numa node during map creation */
+#define BPF_F_NUMA_NODE                (1U << 2)
 
 union bpf_attr {
        struct { /* anonymous struct used by BPF_MAP_CREATE command */
@@ -168,8 +183,13 @@ union bpf_attr {
                __u32   key_size;       /* size of key in bytes */
                __u32   value_size;     /* size of value in bytes */
                __u32   max_entries;    /* max number of entries in a map */
-               __u32   map_flags;      /* prealloc or not */
+               __u32   map_flags;      /* BPF_MAP_CREATE related
+                                        * flags defined above.
+                                        */
                __u32   inner_map_fd;   /* fd pointing to the inner map */
+               __u32   numa_node;      /* numa node (effective only if
+                                        * BPF_F_NUMA_NODE is set).
+                                        */
        };
 
        struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
@@ -204,6 +224,7 @@ union bpf_attr {
                __u32           attach_bpf_fd;  /* eBPF program to attach */
                __u32           attach_type;
                __u32           attach_flags;
+               __u32           attach_bpf_fd2;
        };
 
        struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */
@@ -344,9 +365,20 @@ union bpf_attr {
  * int bpf_redirect(ifindex, flags)
  *     redirect to another netdev
  *     @ifindex: ifindex of the net device
- *     @flags: bit 0 - if set, redirect to ingress instead of egress
- *             other bits - reserved
- *     Return: TC_ACT_REDIRECT
+ *     @flags:
+ *       cls_bpf:
+ *          bit 0 - if set, redirect to ingress instead of egress
+ *          other bits - reserved
+ *       xdp_bpf:
+ *         all bits - reserved
+ *     Return: cls_bpf: TC_ACT_REDIRECT on success or TC_ACT_SHOT on error
+ *            xdp_bfp: XDP_REDIRECT on success or XDP_ABORT on error
+ * int bpf_redirect_map(map, key, flags)
+ *     redirect to endpoint in map
+ *     @map: pointer to dev map
+ *     @key: index in map to lookup
+ *     @flags: --
+ *     Return: XDP_REDIRECT on success or XDP_ABORT on error
  *
  * u32 bpf_get_route_realm(skb)
  *     retrieve a dst's tclassid
@@ -539,6 +571,23 @@ union bpf_attr {
  *     @mode: operation mode (enum bpf_adj_room_mode)
  *     @flags: reserved for future use
  *     Return: 0 on success or negative error code
+ *
+ * int bpf_sk_redirect_map(map, key, flags)
+ *     Redirect skb to a sock in map using key as a lookup key for the
+ *     sock in map.
+ *     @map: pointer to sockmap
+ *     @key: key to lookup sock in map
+ *     @flags: reserved for future use
+ *     Return: SK_REDIRECT
+ *
+ * int bpf_sock_map_update(skops, map, key, flags, map_flags)
+ *     @skops: pointer to bpf_sock_ops
+ *     @map: pointer to sockmap to update
+ *     @key: key to insert/update sock in map
+ *     @flags: same flags as map update elem
+ *     @map_flags: sock map specific flags
+ *        bit 1: Enable strparser
+ *        other bits: reserved
  */
 #define __BPF_FUNC_MAPPER(FN)          \
        FN(unspec),                     \
@@ -591,7 +640,10 @@ union bpf_attr {
        FN(get_socket_uid),             \
        FN(set_hash),                   \
        FN(setsockopt),                 \
-       FN(skb_adjust_room),
+       FN(skb_adjust_room),            \
+       FN(redirect_map),               \
+       FN(sk_redirect_map),            \
+       FN(sock_map_update),            \
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
  * function eBPF program intends to call
@@ -668,6 +720,15 @@ struct __sk_buff {
        __u32 data;
        __u32 data_end;
        __u32 napi_id;
+
+       /* accessed by BPF_PROG_TYPE_sk_skb types */
+       __u32 family;
+       __u32 remote_ip4;       /* Stored in network byte order */
+       __u32 local_ip4;        /* Stored in network byte order */
+       __u32 remote_ip6[4];    /* Stored in network byte order */
+       __u32 local_ip6[4];     /* Stored in network byte order */
+       __u32 remote_port;      /* Stored in network byte order */
+       __u32 local_port;       /* stored in host byte order */
 };
 
 struct bpf_tunnel_key {
@@ -717,6 +778,7 @@ enum xdp_action {
        XDP_DROP,
        XDP_PASS,
        XDP_TX,
+       XDP_REDIRECT,
 };
 
 /* user accessible metadata for XDP packet hook
@@ -727,6 +789,12 @@ struct xdp_md {
        __u32 data_end;
 };
 
+enum sk_action {
+       SK_ABORTED = 0,
+       SK_DROP,
+       SK_REDIRECT,
+};
+
 #define BPF_TAG_SIZE   8
 
 struct bpf_prog_info {
index f7bf7819e9243f83436ff6cc16deea162b3089f6..c51a7051fc8d15685447fba6a19f7066b25bd75f 100644 (file)
@@ -142,6 +142,7 @@ enum {
        INET_DIAG_PAD,
        INET_DIAG_MARK,
        INET_DIAG_BBRINFO,
+       INET_DIAG_CLASS_ID,
        __INET_DIAG_MAX,
 };
 
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
deleted file mode 100644 (file)
index 5c08b22..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-#ifndef _IPV6_H
-#define _IPV6_H
-
-#include <linux/libc-compat.h>
-#include <linux/types.h>
-#include <linux/in6.h>
-#include <asm/byteorder.h>
-
-/* The latest drafts declared increase in minimal mtu up to 1280. */
-
-#define IPV6_MIN_MTU   1280
-
-/*
- *     Advanced API
- *     source interface/address selection, source routing, etc...
- *     *under construction*
- */
-
-#if __UAPI_DEF_IN6_PKTINFO
-struct in6_pktinfo {
-       struct in6_addr ipi6_addr;
-       int             ipi6_ifindex;
-};
-#endif
-
-#if __UAPI_DEF_IP6_MTUINFO
-struct ip6_mtuinfo {
-       struct sockaddr_in6     ip6m_addr;
-       __u32                   ip6m_mtu;
-};
-#endif
-
-struct in6_ifreq {
-       struct in6_addr ifr6_addr;
-       __u32           ifr6_prefixlen;
-       int             ifr6_ifindex; 
-};
-
-#define IPV6_SRCRT_STRICT      0x01    /* Deprecated; will be removed */
-#define IPV6_SRCRT_TYPE_0      0       /* Deprecated; will be removed */
-#define IPV6_SRCRT_TYPE_2      2       /* IPv6 type 2 Routing Header   */
-#define IPV6_SRCRT_TYPE_4      4       /* Segment Routing with IPv6 */
-
-/*
- *     routing header
- */
-struct ipv6_rt_hdr {
-       __u8            nexthdr;
-       __u8            hdrlen;
-       __u8            type;
-       __u8            segments_left;
-
-       /*
-        *      type specific data
-        *      variable length field
-        */
-};
-
-
-struct ipv6_opt_hdr {
-       __u8            nexthdr;
-       __u8            hdrlen;
-       /* 
-        * TLV encoded option data follows.
-        */
-} __attribute__((packed));     /* required for some archs */
-
-#define ipv6_destopt_hdr ipv6_opt_hdr
-#define ipv6_hopopt_hdr  ipv6_opt_hdr
-
-/* Router Alert option values (RFC2711) */
-#define IPV6_OPT_ROUTERALERT_MLD       0x0000  /* MLD(RFC2710) */
-
-/*
- *     routing header type 0 (used in cmsghdr struct)
- */
-
-struct rt0_hdr {
-       struct ipv6_rt_hdr      rt_hdr;
-       __u32                   reserved;
-       struct in6_addr         addr[0];
-
-#define rt0_type               rt_hdr.type
-};
-
-/*
- *     routing header type 2
- */
-
-struct rt2_hdr {
-       struct ipv6_rt_hdr      rt_hdr;
-       __u32                   reserved;
-       struct in6_addr         addr;
-
-#define rt2_type               rt_hdr.type
-};
-
-/*
- *     home address option in destination options header
- */
-
-struct ipv6_destopt_hao {
-       __u8                    type;
-       __u8                    length;
-       struct in6_addr         addr;
-} __attribute__((packed));
-
-/*
- *     IPv6 fixed header
- *
- *     BEWARE, it is incorrect. The first 4 bits of flow_lbl
- *     are glued to priority now, forming "class".
- */
-
-struct ipv6hdr {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-       __u8                    priority:4,
-                               version:4;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-       __u8                    version:4,
-                               priority:4;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-       __u8                    flow_lbl[3];
-
-       __be16                  payload_len;
-       __u8                    nexthdr;
-       __u8                    hop_limit;
-
-       struct  in6_addr        saddr;
-       struct  in6_addr        daddr;
-};
-
-
-/* index values for the variables in ipv6_devconf */
-enum {
-       DEVCONF_FORWARDING = 0,
-       DEVCONF_HOPLIMIT,
-       DEVCONF_MTU6,
-       DEVCONF_ACCEPT_RA,
-       DEVCONF_ACCEPT_REDIRECTS,
-       DEVCONF_AUTOCONF,
-       DEVCONF_DAD_TRANSMITS,
-       DEVCONF_RTR_SOLICITS,
-       DEVCONF_RTR_SOLICIT_INTERVAL,
-       DEVCONF_RTR_SOLICIT_DELAY,
-       DEVCONF_USE_TEMPADDR,
-       DEVCONF_TEMP_VALID_LFT,
-       DEVCONF_TEMP_PREFERED_LFT,
-       DEVCONF_REGEN_MAX_RETRY,
-       DEVCONF_MAX_DESYNC_FACTOR,
-       DEVCONF_MAX_ADDRESSES,
-       DEVCONF_FORCE_MLD_VERSION,
-       DEVCONF_ACCEPT_RA_DEFRTR,
-       DEVCONF_ACCEPT_RA_PINFO,
-       DEVCONF_ACCEPT_RA_RTR_PREF,
-       DEVCONF_RTR_PROBE_INTERVAL,
-       DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN,
-       DEVCONF_PROXY_NDP,
-       DEVCONF_OPTIMISTIC_DAD,
-       DEVCONF_ACCEPT_SOURCE_ROUTE,
-       DEVCONF_MC_FORWARDING,
-       DEVCONF_DISABLE_IPV6,
-       DEVCONF_ACCEPT_DAD,
-       DEVCONF_FORCE_TLLAO,
-       DEVCONF_NDISC_NOTIFY,
-       DEVCONF_MLDV1_UNSOLICITED_REPORT_INTERVAL,
-       DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL,
-       DEVCONF_SUPPRESS_FRAG_NDISC,
-       DEVCONF_ACCEPT_RA_FROM_LOCAL,
-       DEVCONF_USE_OPTIMISTIC,
-       DEVCONF_ACCEPT_RA_MTU,
-       DEVCONF_STABLE_SECRET,
-       DEVCONF_USE_OIF_ADDRS_ONLY,
-       DEVCONF_ACCEPT_RA_MIN_HOP_LIMIT,
-       DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN,
-       DEVCONF_DROP_UNICAST_IN_L2_MULTICAST,
-       DEVCONF_DROP_UNSOLICITED_NA,
-       DEVCONF_KEEP_ADDR_ON_DOWN,
-       DEVCONF_RTR_SOLICIT_MAX_INTERVAL,
-       DEVCONF_SEG6_ENABLED,
-       DEVCONF_SEG6_REQUIRE_HMAC,
-       DEVCONF_ENHANCED_DAD,
-       DEVCONF_ADDR_GEN_MODE,
-       DEVCONF_DISABLE_POLICY,
-       DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN,
-       DEVCONF_MAX
-};
-
-
-#endif /* _IPV6_H */
index faa6eabee2040fafcb5a2adae389642688666466..329842627162ba5270e385a8abcbe7e14f62979a 100644 (file)
@@ -11,6 +11,7 @@ enum lwtunnel_encap_types {
        LWTUNNEL_ENCAP_IP6,
        LWTUNNEL_ENCAP_SEG6,
        LWTUNNEL_ENCAP_BPF,
+       LWTUNNEL_ENCAP_SEG6_LOCAL,
        __LWTUNNEL_ENCAP_MAX,
 };
 
index 3a53b9aaafc55004231e2a07a54f0be3454a8771..654f08adb7e8855b961186ab10cb139640cf12cd 100644 (file)
@@ -222,5 +222,22 @@ struct nlattr {
 #define NLA_ALIGN(len)         (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
 #define NLA_HDRLEN             ((int) NLA_ALIGN(sizeof(struct nlattr)))
 
+/* Generic 32 bitflags attribute content sent to the kernel.
+ *
+ * The value is a bitmap that defines the values being set
+ * The selector is a bitmask that defines which value is legit
+ *
+ * Examples:
+ *  value = 0x0, and selector = 0x1
+ *  implies we are selecting bit 1 and we want to set its value to 0.
+ *
+ *  value = 0x2, and selector = 0x2
+ *  implies we are selecting bit 2 and we want to set its value to 1.
+ *
+ */
+struct nla_bitfield32 {
+       __u32 value;
+       __u32 selector;
+};
 
 #endif /* __LINUX_NETLINK_H */
diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h
new file mode 100644 (file)
index 0000000..ada7f01
--- /dev/null
@@ -0,0 +1,383 @@
+/* PF_KEY user interface, this is defined by rfc2367 so
+ * do not make arbitrary modifications or else this header
+ * file will not be compliant.
+ */
+
+#ifndef _LINUX_PFKEY2_H
+#define _LINUX_PFKEY2_H
+
+#include <linux/types.h>
+
+#define PF_KEY_V2              2
+#define PFKEYV2_REVISION       199806L
+
+struct sadb_msg {
+       __u8            sadb_msg_version;
+       __u8            sadb_msg_type;
+       __u8            sadb_msg_errno;
+       __u8            sadb_msg_satype;
+       __u16   sadb_msg_len;
+       __u16   sadb_msg_reserved;
+       __u32   sadb_msg_seq;
+       __u32   sadb_msg_pid;
+} __attribute__((packed));
+/* sizeof(struct sadb_msg) == 16 */
+
+struct sadb_ext {
+       __u16   sadb_ext_len;
+       __u16   sadb_ext_type;
+} __attribute__((packed));
+/* sizeof(struct sadb_ext) == 4 */
+
+struct sadb_sa {
+       __u16   sadb_sa_len;
+       __u16   sadb_sa_exttype;
+       __be32          sadb_sa_spi;
+       __u8            sadb_sa_replay;
+       __u8            sadb_sa_state;
+       __u8            sadb_sa_auth;
+       __u8            sadb_sa_encrypt;
+       __u32   sadb_sa_flags;
+} __attribute__((packed));
+/* sizeof(struct sadb_sa) == 16 */
+
+struct sadb_lifetime {
+       __u16   sadb_lifetime_len;
+       __u16   sadb_lifetime_exttype;
+       __u32   sadb_lifetime_allocations;
+       __u64   sadb_lifetime_bytes;
+       __u64   sadb_lifetime_addtime;
+       __u64   sadb_lifetime_usetime;
+} __attribute__((packed));
+/* sizeof(struct sadb_lifetime) == 32 */
+
+struct sadb_address {
+       __u16   sadb_address_len;
+       __u16   sadb_address_exttype;
+       __u8            sadb_address_proto;
+       __u8            sadb_address_prefixlen;
+       __u16   sadb_address_reserved;
+} __attribute__((packed));
+/* sizeof(struct sadb_address) == 8 */
+
+struct sadb_key {
+       __u16   sadb_key_len;
+       __u16   sadb_key_exttype;
+       __u16   sadb_key_bits;
+       __u16   sadb_key_reserved;
+} __attribute__((packed));
+/* sizeof(struct sadb_key) == 8 */
+
+struct sadb_ident {
+       __u16   sadb_ident_len;
+       __u16   sadb_ident_exttype;
+       __u16   sadb_ident_type;
+       __u16   sadb_ident_reserved;
+       __u64   sadb_ident_id;
+} __attribute__((packed));
+/* sizeof(struct sadb_ident) == 16 */
+
+struct sadb_sens {
+       __u16   sadb_sens_len;
+       __u16   sadb_sens_exttype;
+       __u32   sadb_sens_dpd;
+       __u8            sadb_sens_sens_level;
+       __u8            sadb_sens_sens_len;
+       __u8            sadb_sens_integ_level;
+       __u8            sadb_sens_integ_len;
+       __u32   sadb_sens_reserved;
+} __attribute__((packed));
+/* sizeof(struct sadb_sens) == 16 */
+
+/* followed by:
+       __u64   sadb_sens_bitmap[sens_len];
+       __u64   sadb_integ_bitmap[integ_len];  */
+
+struct sadb_prop {
+       __u16   sadb_prop_len;
+       __u16   sadb_prop_exttype;
+       __u8            sadb_prop_replay;
+       __u8            sadb_prop_reserved[3];
+} __attribute__((packed));
+/* sizeof(struct sadb_prop) == 8 */
+
+/* followed by:
+       struct sadb_comb sadb_combs[(sadb_prop_len +
+               sizeof(__u64) - sizeof(struct sadb_prop)) /
+               sizeof(struct sadb_comb)]; */
+
+struct sadb_comb {
+       __u8            sadb_comb_auth;
+       __u8            sadb_comb_encrypt;
+       __u16   sadb_comb_flags;
+       __u16   sadb_comb_auth_minbits;
+       __u16   sadb_comb_auth_maxbits;
+       __u16   sadb_comb_encrypt_minbits;
+       __u16   sadb_comb_encrypt_maxbits;
+       __u32   sadb_comb_reserved;
+       __u32   sadb_comb_soft_allocations;
+       __u32   sadb_comb_hard_allocations;
+       __u64   sadb_comb_soft_bytes;
+       __u64   sadb_comb_hard_bytes;
+       __u64   sadb_comb_soft_addtime;
+       __u64   sadb_comb_hard_addtime;
+       __u64   sadb_comb_soft_usetime;
+       __u64   sadb_comb_hard_usetime;
+} __attribute__((packed));
+/* sizeof(struct sadb_comb) == 72 */
+
+struct sadb_supported {
+       __u16   sadb_supported_len;
+       __u16   sadb_supported_exttype;
+       __u32   sadb_supported_reserved;
+} __attribute__((packed));
+/* sizeof(struct sadb_supported) == 8 */
+
+/* followed by:
+       struct sadb_alg sadb_algs[(sadb_supported_len +
+               sizeof(__u64) - sizeof(struct sadb_supported)) /
+               sizeof(struct sadb_alg)]; */
+
+struct sadb_alg {
+       __u8            sadb_alg_id;
+       __u8            sadb_alg_ivlen;
+       __u16   sadb_alg_minbits;
+       __u16   sadb_alg_maxbits;
+       __u16   sadb_alg_reserved;
+} __attribute__((packed));
+/* sizeof(struct sadb_alg) == 8 */
+
+struct sadb_spirange {
+       __u16   sadb_spirange_len;
+       __u16   sadb_spirange_exttype;
+       __u32   sadb_spirange_min;
+       __u32   sadb_spirange_max;
+       __u32   sadb_spirange_reserved;
+} __attribute__((packed));
+/* sizeof(struct sadb_spirange) == 16 */
+
+struct sadb_x_kmprivate {
+       __u16   sadb_x_kmprivate_len;
+       __u16   sadb_x_kmprivate_exttype;
+       __u32   sadb_x_kmprivate_reserved;
+} __attribute__((packed));
+/* sizeof(struct sadb_x_kmprivate) == 8 */
+
+struct sadb_x_sa2 {
+       __u16   sadb_x_sa2_len;
+       __u16   sadb_x_sa2_exttype;
+       __u8            sadb_x_sa2_mode;
+       __u8            sadb_x_sa2_reserved1;
+       __u16   sadb_x_sa2_reserved2;
+       __u32   sadb_x_sa2_sequence;
+       __u32   sadb_x_sa2_reqid;
+} __attribute__((packed));
+/* sizeof(struct sadb_x_sa2) == 16 */
+
+struct sadb_x_policy {
+       __u16   sadb_x_policy_len;
+       __u16   sadb_x_policy_exttype;
+       __u16   sadb_x_policy_type;
+       __u8            sadb_x_policy_dir;
+       __u8            sadb_x_policy_reserved;
+       __u32   sadb_x_policy_id;
+       __u32   sadb_x_policy_priority;
+} __attribute__((packed));
+/* sizeof(struct sadb_x_policy) == 16 */
+
+struct sadb_x_ipsecrequest {
+       __u16   sadb_x_ipsecrequest_len;
+       __u16   sadb_x_ipsecrequest_proto;
+       __u8            sadb_x_ipsecrequest_mode;
+       __u8            sadb_x_ipsecrequest_level;
+       __u16   sadb_x_ipsecrequest_reserved1;
+       __u32   sadb_x_ipsecrequest_reqid;
+       __u32   sadb_x_ipsecrequest_reserved2;
+} __attribute__((packed));
+/* sizeof(struct sadb_x_ipsecrequest) == 16 */
+
+/* This defines the TYPE of Nat Traversal in use.  Currently only one
+ * type of NAT-T is supported, draft-ietf-ipsec-udp-encaps-06
+ */
+struct sadb_x_nat_t_type {
+       __u16   sadb_x_nat_t_type_len;
+       __u16   sadb_x_nat_t_type_exttype;
+       __u8            sadb_x_nat_t_type_type;
+       __u8            sadb_x_nat_t_type_reserved[3];
+} __attribute__((packed));
+/* sizeof(struct sadb_x_nat_t_type) == 8 */
+
+/* Pass a NAT Traversal port (Source or Dest port) */
+struct sadb_x_nat_t_port {
+       __u16   sadb_x_nat_t_port_len;
+       __u16   sadb_x_nat_t_port_exttype;
+       __be16          sadb_x_nat_t_port_port;
+       __u16   sadb_x_nat_t_port_reserved;
+} __attribute__((packed));
+/* sizeof(struct sadb_x_nat_t_port) == 8 */
+
+/* Generic LSM security context */
+struct sadb_x_sec_ctx {
+       __u16   sadb_x_sec_len;
+       __u16   sadb_x_sec_exttype;
+       __u8            sadb_x_ctx_alg;  /* LSMs: e.g., selinux == 1 */
+       __u8            sadb_x_ctx_doi;
+       __u16   sadb_x_ctx_len;
+} __attribute__((packed));
+/* sizeof(struct sadb_sec_ctx) = 8 */
+
+/* Used by MIGRATE to pass addresses IKE will use to perform
+ * negotiation with the peer */
+struct sadb_x_kmaddress {
+       __u16   sadb_x_kmaddress_len;
+       __u16   sadb_x_kmaddress_exttype;
+       __u32   sadb_x_kmaddress_reserved;
+} __attribute__((packed));
+/* sizeof(struct sadb_x_kmaddress) == 8 */
+
+/* To specify the SA dump filter */
+struct sadb_x_filter {
+       __u16   sadb_x_filter_len;
+       __u16   sadb_x_filter_exttype;
+       __u32   sadb_x_filter_saddr[4];
+       __u32   sadb_x_filter_daddr[4];
+       __u16   sadb_x_filter_family;
+       __u8    sadb_x_filter_splen;
+       __u8    sadb_x_filter_dplen;
+} __attribute__((packed));
+/* sizeof(struct sadb_x_filter) == 40 */
+
+/* Message types */
+#define SADB_RESERVED          0
+#define SADB_GETSPI            1
+#define SADB_UPDATE            2
+#define SADB_ADD               3
+#define SADB_DELETE            4
+#define SADB_GET               5
+#define SADB_ACQUIRE           6
+#define SADB_REGISTER          7
+#define SADB_EXPIRE            8
+#define SADB_FLUSH             9
+#define SADB_DUMP              10
+#define SADB_X_PROMISC         11
+#define SADB_X_PCHANGE         12
+#define SADB_X_SPDUPDATE       13
+#define SADB_X_SPDADD          14
+#define SADB_X_SPDDELETE       15
+#define SADB_X_SPDGET          16
+#define SADB_X_SPDACQUIRE      17
+#define SADB_X_SPDDUMP         18
+#define SADB_X_SPDFLUSH                19
+#define SADB_X_SPDSETIDX       20
+#define SADB_X_SPDEXPIRE       21
+#define SADB_X_SPDDELETE2      22
+#define SADB_X_NAT_T_NEW_MAPPING       23
+#define SADB_X_MIGRATE         24
+#define SADB_MAX               24
+
+/* Security Association flags */
+#define SADB_SAFLAGS_PFS       1
+#define SADB_SAFLAGS_NOPMTUDISC        0x20000000
+#define SADB_SAFLAGS_DECAP_DSCP        0x40000000
+#define SADB_SAFLAGS_NOECN     0x80000000
+
+/* Security Association states */
+#define SADB_SASTATE_LARVAL    0
+#define SADB_SASTATE_MATURE    1
+#define SADB_SASTATE_DYING     2
+#define SADB_SASTATE_DEAD      3
+#define SADB_SASTATE_MAX       3
+
+/* Security Association types */
+#define SADB_SATYPE_UNSPEC     0
+#define SADB_SATYPE_AH         2
+#define SADB_SATYPE_ESP                3
+#define SADB_SATYPE_RSVP       5
+#define SADB_SATYPE_OSPFV2     6
+#define SADB_SATYPE_RIPV2      7
+#define SADB_SATYPE_MIP                8
+#define SADB_X_SATYPE_IPCOMP   9
+#define SADB_SATYPE_MAX                9
+
+/* Authentication algorithms */
+#define SADB_AALG_NONE                 0
+#define SADB_AALG_MD5HMAC              2
+#define SADB_AALG_SHA1HMAC             3
+#define SADB_X_AALG_SHA2_256HMAC       5
+#define SADB_X_AALG_SHA2_384HMAC       6
+#define SADB_X_AALG_SHA2_512HMAC       7
+#define SADB_X_AALG_RIPEMD160HMAC      8
+#define SADB_X_AALG_AES_XCBC_MAC       9
+#define SADB_X_AALG_NULL               251     /* kame */
+#define SADB_AALG_MAX                  251
+
+/* Encryption algorithms */
+#define SADB_EALG_NONE                 0
+#define SADB_EALG_DESCBC               2
+#define SADB_EALG_3DESCBC              3
+#define SADB_X_EALG_CASTCBC            6
+#define SADB_X_EALG_BLOWFISHCBC                7
+#define SADB_EALG_NULL                 11
+#define SADB_X_EALG_AESCBC             12
+#define SADB_X_EALG_AESCTR             13
+#define SADB_X_EALG_AES_CCM_ICV8       14
+#define SADB_X_EALG_AES_CCM_ICV12      15
+#define SADB_X_EALG_AES_CCM_ICV16      16
+#define SADB_X_EALG_AES_GCM_ICV8       18
+#define SADB_X_EALG_AES_GCM_ICV12      19
+#define SADB_X_EALG_AES_GCM_ICV16      20
+#define SADB_X_EALG_CAMELLIACBC                22
+#define SADB_X_EALG_NULL_AES_GMAC      23
+#define SADB_EALG_MAX                   253 /* last EALG */
+/* private allocations should use 249-255 (RFC2407) */
+#define SADB_X_EALG_SERPENTCBC  252     /* draft-ietf-ipsec-ciph-aes-cbc-00 */
+#define SADB_X_EALG_TWOFISHCBC  253     /* draft-ietf-ipsec-ciph-aes-cbc-00 */
+
+/* Compression algorithms */
+#define SADB_X_CALG_NONE               0
+#define SADB_X_CALG_OUI                        1
+#define SADB_X_CALG_DEFLATE            2
+#define SADB_X_CALG_LZS                        3
+#define SADB_X_CALG_LZJH               4
+#define SADB_X_CALG_MAX                        4
+
+/* Extension Header values */
+#define SADB_EXT_RESERVED              0
+#define SADB_EXT_SA                    1
+#define SADB_EXT_LIFETIME_CURRENT      2
+#define SADB_EXT_LIFETIME_HARD         3
+#define SADB_EXT_LIFETIME_SOFT         4
+#define SADB_EXT_ADDRESS_SRC           5
+#define SADB_EXT_ADDRESS_DST           6
+#define SADB_EXT_ADDRESS_PROXY         7
+#define SADB_EXT_KEY_AUTH              8
+#define SADB_EXT_KEY_ENCRYPT           9
+#define SADB_EXT_IDENTITY_SRC          10
+#define SADB_EXT_IDENTITY_DST          11
+#define SADB_EXT_SENSITIVITY           12
+#define SADB_EXT_PROPOSAL              13
+#define SADB_EXT_SUPPORTED_AUTH                14
+#define SADB_EXT_SUPPORTED_ENCRYPT     15
+#define SADB_EXT_SPIRANGE              16
+#define SADB_X_EXT_KMPRIVATE           17
+#define SADB_X_EXT_POLICY              18
+#define SADB_X_EXT_SA2                 19
+/* The next four entries are for setting up NAT Traversal */
+#define SADB_X_EXT_NAT_T_TYPE          20
+#define SADB_X_EXT_NAT_T_SPORT         21
+#define SADB_X_EXT_NAT_T_DPORT         22
+#define SADB_X_EXT_NAT_T_OA            23
+#define SADB_X_EXT_SEC_CTX             24
+/* Used with MIGRATE to pass @ to IKE for negotiation */
+#define SADB_X_EXT_KMADDRESS           25
+#define SADB_X_EXT_FILTER              26
+#define SADB_EXT_MAX                   26
+
+/* Identity Extension values */
+#define SADB_IDENTTYPE_RESERVED        0
+#define SADB_IDENTTYPE_PREFIX  1
+#define SADB_IDENTTYPE_FQDN    2
+#define SADB_IDENTTYPE_USERFQDN        3
+#define SADB_IDENTTYPE_MAX     3
+
+#endif /* !(_LINUX_PFKEY2_H) */
index 1d62dad0dbc7bd978df56b323970c0d9041f10a4..813e9e0767d3361f4eec0ea853e9e651644967a2 100644 (file)
@@ -681,10 +681,29 @@ struct tcamsg {
        unsigned char   tca__pad1;
        unsigned short  tca__pad2;
 };
+
+enum {
+       TCA_ROOT_UNSPEC,
+       TCA_ROOT_TAB,
+#define TCA_ACT_TAB TCA_ROOT_TAB
+#define TCAA_MAX TCA_ROOT_TAB
+       TCA_ROOT_FLAGS,
+       TCA_ROOT_COUNT,
+       TCA_ROOT_TIME_DELTA, /* in msecs */
+       __TCA_ROOT_MAX,
+#define        TCA_ROOT_MAX (__TCA_ROOT_MAX - 1)
+};
+
 #define TA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcamsg))))
 #define TA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcamsg))
-#define TCA_ACT_TAB 1 /* attr type must be >=1 */      
-#define TCAA_MAX 1
+/* tcamsg flags stored in attribute TCA_ROOT_FLAGS
+ *
+ * TCA_FLAG_LARGE_DUMP_ON user->kernel to request for larger than TCA_ACT_MAX_PRIO
+ * actions in a dump. All dump responses will contain the number of actions
+ * being dumped stored in for user app's consumption in TCA_ROOT_COUNT
+ *
+ */
+#define TCA_FLAG_LARGE_DUMP_ON         (1 << 0)
 
 /* New extended info filters for IFLA_EXT_MASK */
 #define RTEXT_FILTER_VF                (1 << 0)
diff --git a/include/linux/seg6_local.h b/include/linux/seg6_local.h
new file mode 100644 (file)
index 0000000..76b90d6
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ *  SR-IPv6 implementation
+ *
+ *  Author:
+ *  David Lebrun <david.lebrun@uclouvain.be>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_SEG6_LOCAL_H
+#define _LINUX_SEG6_LOCAL_H
+
+#include <linux/seg6.h>
+
+enum {
+       SEG6_LOCAL_UNSPEC,
+       SEG6_LOCAL_ACTION,
+       SEG6_LOCAL_SRH,
+       SEG6_LOCAL_TABLE,
+       SEG6_LOCAL_NH4,
+       SEG6_LOCAL_NH6,
+       SEG6_LOCAL_IIF,
+       SEG6_LOCAL_OIF,
+       __SEG6_LOCAL_MAX,
+};
+#define SEG6_LOCAL_MAX (__SEG6_LOCAL_MAX - 1)
+
+enum {
+       SEG6_LOCAL_ACTION_UNSPEC        = 0,
+       /* node segment */
+       SEG6_LOCAL_ACTION_END           = 1,
+       /* adjacency segment (IPv6 cross-connect) */
+       SEG6_LOCAL_ACTION_END_X         = 2,
+       /* lookup of next seg NH in table */
+       SEG6_LOCAL_ACTION_END_T         = 3,
+       /* decap and L2 cross-connect */
+       SEG6_LOCAL_ACTION_END_DX2       = 4,
+       /* decap and IPv6 cross-connect */
+       SEG6_LOCAL_ACTION_END_DX6       = 5,
+       /* decap and IPv4 cross-connect */
+       SEG6_LOCAL_ACTION_END_DX4       = 6,
+       /* decap and lookup of DA in v6 table */
+       SEG6_LOCAL_ACTION_END_DT6       = 7,
+       /* decap and lookup of DA in v4 table */
+       SEG6_LOCAL_ACTION_END_DT4       = 8,
+       /* binding segment with insertion */
+       SEG6_LOCAL_ACTION_END_B6        = 9,
+       /* binding segment with encapsulation */
+       SEG6_LOCAL_ACTION_END_B6_ENCAP  = 10,
+       /* binding segment with MPLS encap */
+       SEG6_LOCAL_ACTION_END_BM        = 11,
+       /* lookup last seg in table */
+       SEG6_LOCAL_ACTION_END_S         = 12,
+       /* forward to SR-unaware VNF with static proxy */
+       SEG6_LOCAL_ACTION_END_AS        = 13,
+       /* forward to SR-unaware VNF with masquerading */
+       SEG6_LOCAL_ACTION_END_AM        = 14,
+
+       __SEG6_LOCAL_ACTION_MAX,
+};
+
+#define SEG6_LOCAL_ACTION_MAX (__SEG6_LOCAL_ACTION_MAX - 1)
+
+#endif
index 79b2d6fc9d72be32ae893b9d2387f4202526b17b..8d0545e6396cf4034ef4691794a37e938787f1a1 100644 (file)
@@ -231,6 +231,14 @@ enum {
        TCP_NLA_SNDBUF_LIMITED, /* Time (usec) limited by send buffer */
        TCP_NLA_DATA_SEGS_OUT,  /* Data pkts sent including retransmission */
        TCP_NLA_TOTAL_RETRANS,  /* Data pkts retransmitted */
+       TCP_NLA_PACING_RATE,    /* Pacing rate in bytes per second */
+       TCP_NLA_DELIVERY_RATE,  /* Delivery rate in bytes per second */
+       TCP_NLA_SND_CWND,       /* Sending congestion window */
+       TCP_NLA_REORDERING,     /* Reordering metric */
+       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 ? */
+
 };
 
 /* for TCP_MD5SIG socket option */
index 3af99e027dccc1e31ef664e04ab944731e320457..5790293b7fc46a3835f6223feb936b8313764906 100644 (file)
@@ -304,6 +304,7 @@ enum xfrm_attr_type_t {
        XFRMA_ADDRESS_FILTER,   /* struct xfrm_address_filter */
        XFRMA_PAD,
        XFRMA_OFFLOAD_DEV,      /* struct xfrm_state_offload */
+       XFRMA_OUTPUT_MARK,      /* __u32 */
        __XFRMA_MAX
 
 #define XFRMA_MAX (__XFRMA_MAX - 1)
index 7a3b3fd24058f8546ac76f611be0599d38677edd..1bb6d6a23da9bbc6dcd70556fce6e3394f29a318 100644 (file)
@@ -20,6 +20,7 @@ extern int show_raw;
 extern int resolve_hosts;
 extern int oneline;
 extern int brief;
+extern int json;
 extern int timestamp;
 extern int timestamp_short;
 extern const char * _SL_;
index a754c04d2dbb27be092564ed9fb89ecf8527ec1b..8ed2686c63d1d649202bd07683922d798855256d 100644 (file)
@@ -9,7 +9,7 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \
     link_iptnl.o link_gre6.o iplink_bond.o iplink_bond_slave.o iplink_hsr.o \
     iplink_bridge.o iplink_bridge_slave.o ipfou.o iplink_ipvlan.o \
     iplink_geneve.o iplink_vrf.o iproute_lwtunnel.o ipmacsec.o ipila.o \
-    ipvrf.o iplink_xstats.o ipseg6.o
+    ipvrf.o iplink_xstats.o ipseg6.o ip_print.o
 
 RTMONOBJ=rtmon.o
 
diff --git a/ip/ip.c b/ip/ip.c
index 7c14a8ec18c0073125994d2459a68c4dff71a944..e66f69700105e82eb55a469b037aaf1107e15c42 100644 (file)
--- a/ip/ip.c
+++ b/ip/ip.c
@@ -33,6 +33,7 @@ int show_details;
 int resolve_hosts;
 int oneline;
 int brief;
+int json;
 int timestamp;
 const char *_SL_;
 int force;
@@ -258,6 +259,8 @@ int main(int argc, char **argv)
                        batch_file = argv[1];
                } else if (matches(opt, "-brief") == 0) {
                        ++brief;
+               } else if (matches(opt, "-json") == 0) {
+                       ++json;
                } else if (matches(opt, "-rcvbuf") == 0) {
                        unsigned int size;
 
@@ -292,6 +295,9 @@ int main(int argc, char **argv)
 
        _SL_ = oneline ? "\\" : "\n";
 
+       if (json)
+               check_if_color_enabled();
+
        if (batch_file)
                return batch(batch_file);
 
index 77e9dd06b8641f53931f9b56d234e287b5960e7d..efc789cb974d2d07584d413aaf8121b847a8ac15 100644 (file)
@@ -140,3 +140,59 @@ int name_is_vrf(const char *name);
 #endif
 
 void print_num(FILE *fp, unsigned int width, uint64_t count);
+
+#include "json_writer.h"
+
+json_writer_t   *get_json_writer(void);
+/*
+ * use:
+ *      - PRINT_ANY for context based output
+ *      - PRINT_FP for non json specific output
+ *      - PRINT_JSON for json specific output
+ */
+enum output_type {
+       PRINT_FP = 1,
+       PRINT_JSON = 2,
+       PRINT_ANY = 4,
+};
+
+void new_json_obj(int json, FILE *fp);
+void delete_json_obj(void);
+
+bool is_json_context(void);
+
+void set_current_fp(FILE *fp);
+
+void fflush_fp(void);
+
+void open_json_object(const char *str);
+void close_json_object(void);
+void open_json_array(enum output_type type, const char *delim);
+void close_json_array(enum output_type type, const char *delim);
+
+#include "color.h"
+
+#define _PRINT_FUNC(type_name, type)                                   \
+       void print_color_##type_name(enum output_type t,                \
+                                    enum color_attr color,             \
+                                    const char *key,                   \
+                                    const char *fmt,                   \
+                                    type value);                       \
+                                                                       \
+       static inline void print_##type_name(enum output_type t,        \
+                                            const char *key,           \
+                                            const char *fmt,           \
+                                            type value)                \
+       {                                                               \
+               print_color_##type_name(t, -1, key, fmt, value);        \
+       }
+_PRINT_FUNC(int, int);
+_PRINT_FUNC(bool, bool);
+_PRINT_FUNC(null, const char*);
+_PRINT_FUNC(string, const char*);
+_PRINT_FUNC(uint, uint64_t);
+_PRINT_FUNC(hu, unsigned short);
+_PRINT_FUNC(hex, unsigned int);
+_PRINT_FUNC(0xhex, unsigned int);
+_PRINT_FUNC(lluint, unsigned long long int);
+#undef _PRINT_FUNC
diff --git a/ip/ip_print.c b/ip/ip_print.c
new file mode 100644 (file)
index 0000000..4cd6a0b
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * ip_print.c          "ip print regular or json output".
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ *
+ * Authors:    Julien Fortin, <julien@cumulusnetworks.com>
+ *
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "utils.h"
+#include "ip_common.h"
+#include "json_writer.h"
+
+static json_writer_t *_jw;
+static FILE *_fp;
+
+#define _IS_JSON_CONTEXT(type) ((type & PRINT_JSON || type & PRINT_ANY) && _jw)
+#define _IS_FP_CONTEXT(type) (!_jw && (type & PRINT_FP || type & PRINT_ANY))
+
+void new_json_obj(int json, FILE *fp)
+{
+       if (json) {
+               _jw = jsonw_new(fp);
+               if (!_jw) {
+                       perror("json object");
+                       exit(1);
+               }
+               jsonw_pretty(_jw, true);
+               jsonw_start_array(_jw);
+       }
+       set_current_fp(fp);
+}
+
+void delete_json_obj(void)
+{
+       if (_jw) {
+               jsonw_end_array(_jw);
+               jsonw_destroy(&_jw);
+       }
+}
+
+bool is_json_context(void)
+{
+       return _jw != NULL;
+}
+
+void set_current_fp(FILE *fp)
+{
+       if (!fp) {
+               fprintf(stderr, "Error: invalid file pointer.\n");
+               exit(1);
+       }
+       _fp = fp;
+}
+
+json_writer_t *get_json_writer(void)
+{
+       return _jw;
+}
+
+void open_json_object(const char *str)
+{
+       if (_IS_JSON_CONTEXT(PRINT_JSON)) {
+               if (str)
+                       jsonw_name(_jw, str);
+               jsonw_start_object(_jw);
+       }
+}
+
+void close_json_object(void)
+{
+       if (_IS_JSON_CONTEXT(PRINT_JSON))
+               jsonw_end_object(_jw);
+}
+
+/*
+ * Start json array or string array using
+ * the provided string as json key (if not null)
+ * or as array delimiter in non-json context.
+ */
+void open_json_array(enum output_type type, const char *str)
+{
+       if (_IS_JSON_CONTEXT(type)) {
+               if (str)
+                       jsonw_name(_jw, str);
+               jsonw_start_array(_jw);
+       } else if (_IS_FP_CONTEXT(type)) {
+               fprintf(_fp, "%s", str);
+       }
+}
+
+/*
+ * End json array or string array
+ */
+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)) {
+               fprintf(_fp, "%s", str);
+       }
+}
+
+/*
+ * pre-processor directive to generate similar
+ * functions handling different types
+ */
+#define _PRINT_FUNC(type_name, type)                                   \
+       void print_color_##type_name(enum output_type t,                \
+                                    enum color_attr color,             \
+                                    const char *key,                   \
+                                    const char *fmt,                   \
+                                    type value)                        \
+       {                                                               \
+               if (_IS_JSON_CONTEXT(t)) {                              \
+                       if (!key)                                       \
+                               jsonw_##type_name(_jw, value);          \
+                       else                                            \
+                               jsonw_##type_name##_field(_jw, key, value); \
+               } else if (_IS_FP_CONTEXT(t)) {                         \
+                       color_fprintf(_fp, color, fmt, value);          \
+               }                                                       \
+       }
+_PRINT_FUNC(int, int);
+_PRINT_FUNC(hu, unsigned short);
+_PRINT_FUNC(uint, uint64_t);
+_PRINT_FUNC(lluint, unsigned long long int);
+#undef _PRINT_FUNC
+
+void print_color_string(enum output_type type,
+                       enum color_attr color,
+                       const char *key,
+                       const char *fmt,
+                       const char *value)
+{
+       if (_IS_JSON_CONTEXT(type)) {
+               if (key && !value)
+                       jsonw_name(_jw, key);
+               else if (!key && value)
+                       jsonw_string(_jw, value);
+               else
+                       jsonw_string_field(_jw, key, value);
+       } else if (_IS_FP_CONTEXT(type)) {
+               color_fprintf(_fp, color, fmt, value);
+       }
+}
+
+/*
+ * value's type is bool. When using this function in FP context you can't pass
+ * a value to it, you will need to use "is_json_context()" to have different
+ * branch for json and regular output. grep -r "print_bool" for example
+ */
+void print_color_bool(enum output_type type,
+                     enum color_attr color,
+                     const char *key,
+                     const char *fmt,
+                     bool value)
+{
+       if (_IS_JSON_CONTEXT(type)) {
+               if (key)
+                       jsonw_bool_field(_jw, key, value);
+               else
+                       jsonw_bool(_jw, value);
+       } else if (_IS_FP_CONTEXT(type)) {
+               color_fprintf(_fp, color, fmt, value ? "true" : "false");
+       }
+}
+
+/*
+ * In JSON context uses hardcode %#x format: 42 -> 0x2a
+ */
+void print_color_0xhex(enum output_type type,
+                      enum color_attr color,
+                      const char *key,
+                      const char *fmt,
+                      unsigned int hex)
+{
+       if (_IS_JSON_CONTEXT(type)) {
+               SPRINT_BUF(b1);
+
+               snprintf(b1, sizeof(b1), "%#x", hex);
+               print_string(PRINT_JSON, key, NULL, b1);
+       } else if (_IS_FP_CONTEXT(type)) {
+               color_fprintf(_fp, color, fmt, hex);
+       }
+}
+
+void print_color_hex(enum output_type type,
+                    enum color_attr color,
+                    const char *key,
+                    const char *fmt,
+                    unsigned int hex)
+{
+       if (_IS_JSON_CONTEXT(type)) {
+               SPRINT_BUF(b1);
+
+               snprintf(b1, sizeof(b1), "%x", hex);
+               if (key)
+                       jsonw_string_field(_jw, key, b1);
+               else
+                       jsonw_string(_jw, b1);
+       } else if (_IS_FP_CONTEXT(type)) {
+               color_fprintf(_fp, color, fmt, hex);
+       }
+}
+
+/*
+ * In JSON context we don't use the argument "value" we simply call jsonw_null
+ * whereas FP context can use "value" to output anything
+ */
+void print_color_null(enum output_type type,
+                     enum color_attr color,
+                     const char *key,
+                     const char *fmt,
+                     const char *value)
+{
+       if (_IS_JSON_CONTEXT(type)) {
+               if (key)
+                       jsonw_null_field(_jw, key);
+               else
+                       jsonw_null(_jw);
+       } else if (_IS_FP_CONTEXT(type)) {
+               color_fprintf(_fp, color, fmt, value);
+       }
+}
index 4d37c5e045071341e35053dba1f1ae35ac8a301a..81a5888f8bc71900a47c63ba60eebf399db5fc9a 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/sockios.h>
 #include <linux/net_namespace.h>
 
+#include "utils.h"
 #include "rt_names.h"
 #include "utils.h"
 #include "ll_map.h"
@@ -84,13 +85,14 @@ static void usage(void)
 
 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);
@@ -111,10 +113,10 @@ static void print_link_flags(FILE *fp, unsigned int flags, unsigned int mdown)
        _PF(ECHO);
 #undef _PF
        if (flags)
-               fprintf(fp, "%x", flags);
+               print_hex(PRINT_ANY, NULL, "%x", flags);
        if (mdown)
-               fprintf(fp, ",M-DOWN");
-       fprintf(fp, "> ");
+               print_string(PRINT_ANY, NULL, ",%s", "M-DOWN");
+       close_json_array(PRINT_ANY, "> ");
 }
 
 static const char *oper_states[] = {
@@ -125,14 +127,26 @@ static const char *oper_states[] = {
 static void print_operstate(FILE *f, __u8 state)
 {
        if (state >= ARRAY_SIZE(oper_states)) {
-               fprintf(f, "state %#x ", state);
+               if (is_json_context())
+                       print_uint(PRINT_JSON, "operstate_index", NULL, state);
+               else
+                       print_0xhex(PRINT_FP, NULL, "state %#x", state);
        } else if (brief) {
-               color_fprintf(f, oper_state_color(state),
-                             "%-14s ", oper_states[state]);
+               print_color_string(PRINT_ANY,
+                                  oper_state_color(state),
+                                  "operstate",
+                                  "%-14s ",
+                                  oper_states[state]);
        } else {
-               fprintf(f, "state ");
-               color_fprintf(f, oper_state_color(state),
-                             "%s ", oper_states[state]);
+               if (is_json_context())
+                       print_string(PRINT_JSON,
+                                    "operstate",
+                                    NULL, oper_states[state]);
+               else {
+                       fprintf(f, "state ");
+                       color_fprintf(f, oper_state_color(state),
+                                     "%s ", oper_states[state]);
+               }
        }
 }
 
@@ -169,7 +183,7 @@ static void print_queuelen(FILE *f, struct rtattr *tb[IFLA_MAX + 1])
                qlen = ifr.ifr_qlen;
        }
        if (qlen)
-               fprintf(f, "qlen %d", qlen);
+               print_int(PRINT_ANY, "txqlen", "qlen %d", qlen);
 }
 
 static const char *link_modes[] = {
@@ -181,9 +195,15 @@ static void print_linkmode(FILE *f, struct rtattr *tb)
        unsigned int mode = rta_getattr_u8(tb);
 
        if (mode >= ARRAY_SIZE(link_modes))
-               fprintf(f, "mode %d ", mode);
+               print_int(PRINT_ANY,
+                         "linkmode_index",
+                         "mode %d ",
+                         mode);
        else
-               fprintf(f, "mode %s ", link_modes[mode]);
+               print_string(PRINT_ANY,
+                            "linkmode",
+                            "mode %s "
+                            , link_modes[mode]);
 }
 
 static char *parse_link_kind(struct rtattr *tb, bool slave)
@@ -215,13 +235,14 @@ static void print_linktype(FILE *fp, struct rtattr *tb)
        char slave[32];
 
        parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb);
+       open_json_object("linkinfo");
 
        if (linkinfo[IFLA_INFO_KIND]) {
                const char *kind
                        = rta_getattr_str(linkinfo[IFLA_INFO_KIND]);
 
-               fprintf(fp, "%s", _SL_);
-               fprintf(fp, "    %s ", kind);
+               print_string(PRINT_FP, NULL, "%s", _SL_);
+               print_string(PRINT_ANY, "info_kind", "    %s ", kind);
 
                lu = get_link_kind(kind);
                if (lu && lu->print_opt) {
@@ -232,11 +253,16 @@ static void print_linktype(FILE *fp, struct rtattr *tb)
                                                    linkinfo[IFLA_INFO_DATA]);
                                data = attr;
                        }
+                       open_json_object("info_data");
                        lu->print_opt(lu, fp, data);
+                       close_json_object();
 
                        if (linkinfo[IFLA_INFO_XSTATS] && show_stats &&
-                           lu->print_xstats)
+                           lu->print_xstats) {
+                               open_json_object("info_xstats");
                                lu->print_xstats(lu, fp, linkinfo[IFLA_INFO_XSTATS]);
+                               close_json_object();
+                       }
                }
        }
 
@@ -244,8 +270,12 @@ static void print_linktype(FILE *fp, struct rtattr *tb)
                const char *slave_kind
                        = rta_getattr_str(linkinfo[IFLA_INFO_SLAVE_KIND]);
 
-               fprintf(fp, "%s", _SL_);
-               fprintf(fp, "    %s_slave ", slave_kind);
+               print_string(PRINT_FP, NULL, "%s", _SL_);
+               print_string(PRINT_ANY,
+                            "info_slave_kind",
+                            "    %s_slave ",
+                            slave_kind);
+
                snprintf(slave, sizeof(slave), "%s_slave", slave_kind);
 
                slave_lu = get_link_kind(slave);
@@ -257,9 +287,12 @@ static void print_linktype(FILE *fp, struct rtattr *tb)
                                                    linkinfo[IFLA_INFO_SLAVE_DATA]);
                                data = attr;
                        }
+                       open_json_object("info_slave_data");
                        slave_lu->print_opt(slave_lu, fp, data);
+                       close_json_object();
                }
        }
+       close_json_object();
 }
 
 static void print_af_spec(FILE *fp, struct rtattr *af_spec_attr)
@@ -275,22 +308,39 @@ static void print_af_spec(FILE *fp, struct rtattr *af_spec_attr)
 
        if (tb[IFLA_INET6_ADDR_GEN_MODE]) {
                __u8 mode = rta_getattr_u8(tb[IFLA_INET6_ADDR_GEN_MODE]);
+               SPRINT_BUF(b1);
 
                switch (mode) {
                case IN6_ADDR_GEN_MODE_EUI64:
-                       fprintf(fp, "addrgenmode eui64 ");
+                       print_string(PRINT_ANY,
+                                    "inet6_addr_gen_mode",
+                                    "addrgenmode %s ",
+                                    "eui64");
                        break;
                case IN6_ADDR_GEN_MODE_NONE:
-                       fprintf(fp, "addrgenmode none ");
+                       print_string(PRINT_ANY,
+                                    "inet6_addr_gen_mode",
+                                    "addrgenmode %s ",
+                                    "none");
                        break;
                case IN6_ADDR_GEN_MODE_STABLE_PRIVACY:
-                       fprintf(fp, "addrgenmode stable_secret ");
+                       print_string(PRINT_ANY,
+                                    "inet6_addr_gen_mode",
+                                    "addrgenmode %s ",
+                                    "stable_secret");
                        break;
                case IN6_ADDR_GEN_MODE_RANDOM:
-                       fprintf(fp, "addrgenmode random ");
+                       print_string(PRINT_ANY,
+                                    "inet6_addr_gen_mode",
+                                    "addrgenmode %s ",
+                                    "random");
                        break;
                default:
-                       fprintf(fp, "addrgenmode %#.2hhx ", mode);
+                       snprintf(b1, sizeof(b1), "%#.2hhx", mode);
+                       print_string(PRINT_ANY,
+                                    "inet6_addr_gen_mode",
+                                    "addrgenmode %s ",
+                                    b1);
                        break;
                }
        }
@@ -316,83 +366,135 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
        vf_mac = RTA_DATA(vf[IFLA_VF_MAC]);
        vf_tx_rate = RTA_DATA(vf[IFLA_VF_TX_RATE]);
 
-       fprintf(fp, "%s    vf %d MAC %s", _SL_, vf_mac->vf,
-               ll_addr_n2a((unsigned char *)&vf_mac->mac,
-                           ETH_ALEN, 0, b1, sizeof(b1)));
+       print_string(PRINT_FP, NULL, "%s    ", _SL_);
+       print_int(PRINT_ANY, "vf", "vf %d ", vf_mac->vf);
+       print_string(PRINT_ANY, "mac", "MAC %s",
+                    ll_addr_n2a((unsigned char *) &vf_mac->mac,
+                                ETH_ALEN, 0, b1, sizeof(b1)));
+
        if (vf[IFLA_VF_VLAN_LIST]) {
                struct rtattr *i, *vfvlanlist = vf[IFLA_VF_VLAN_LIST];
                int rem = RTA_PAYLOAD(vfvlanlist);
 
+               open_json_array(PRINT_JSON, "vlan_list");
                for (i = RTA_DATA(vfvlanlist);
-                     RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
-                       struct ifla_vf_vlan_info *vf_vlan_info =
-                                       RTA_DATA(i);
+                    RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+                       struct ifla_vf_vlan_info *vf_vlan_info = RTA_DATA(i);
                        SPRINT_BUF(b2);
 
+                       open_json_object(NULL);
                        if (vf_vlan_info->vlan)
-                               fprintf(fp, ", vlan %d", vf_vlan_info->vlan);
+                               print_int(PRINT_ANY,
+                                         "vlan",
+                                         ", vlan %d",
+                                         vf_vlan_info->vlan);
                        if (vf_vlan_info->qos)
-                               fprintf(fp, ", qos %d", vf_vlan_info->qos);
+                               print_int(PRINT_ANY,
+                                         "qos",
+                                         ", qos %d",
+                                         vf_vlan_info->qos);
                        if (vf_vlan_info->vlan_proto &&
                            vf_vlan_info->vlan_proto != htons(ETH_P_8021Q))
-                               fprintf(fp, ", vlan protocol %s",
-                                       ll_proto_n2a(vf_vlan_info->vlan_proto,
+                               print_string(PRINT_ANY,
+                                            "protocol",
+                                            ", vlan protocol %s",
+                                            ll_proto_n2a(
+                                                    vf_vlan_info->vlan_proto,
                                                     b2, sizeof(b2)));
-
+                       close_json_object();
                }
+               close_json_array(PRINT_JSON, NULL);
        } else {
                struct ifla_vf_vlan *vf_vlan = RTA_DATA(vf[IFLA_VF_VLAN]);
 
                if (vf_vlan->vlan)
-                       fprintf(fp, ", vlan %d", vf_vlan->vlan);
+                       print_int(PRINT_ANY,
+                                 "vlan",
+                                 ", vlan %d",
+                                 vf_vlan->vlan);
                if (vf_vlan->qos)
-                       fprintf(fp, ", qos %d", vf_vlan->qos);
+                       print_int(PRINT_ANY, "qos", ", qos %d", vf_vlan->qos);
        }
+
        if (vf_tx_rate->rate)
-               fprintf(fp, ", tx rate %d (Mbps)", vf_tx_rate->rate);
+               print_int(PRINT_ANY,
+                         "tx_rate",
+                         ", tx rate %d (Mbps)",
+                         vf_tx_rate->rate);
 
        if (vf[IFLA_VF_RATE]) {
                struct ifla_vf_rate *vf_rate = RTA_DATA(vf[IFLA_VF_RATE]);
-
-               if (vf_rate->max_tx_rate)
-                       fprintf(fp, ", max_tx_rate %dMbps", vf_rate->max_tx_rate);
-               if (vf_rate->min_tx_rate)
-                       fprintf(fp, ", min_tx_rate %dMbps", vf_rate->min_tx_rate);
+               int max_tx = vf_rate->max_tx_rate;
+               int min_tx = vf_rate->min_tx_rate;
+
+               if (is_json_context()) {
+                       open_json_object("rate");
+                       print_int(PRINT_JSON, "max_tx", NULL, max_tx);
+                       print_int(PRINT_ANY, "min_tx", NULL, min_tx);
+                       close_json_object();
+               } else {
+                       if (max_tx)
+                               fprintf(fp, ", max_tx_rate %dMbps", max_tx);
+                       if (min_tx)
+                               fprintf(fp, ", min_tx_rate %dMbps", min_tx);
+               }
        }
+
        if (vf[IFLA_VF_SPOOFCHK]) {
                struct ifla_vf_spoofchk *vf_spoofchk =
                        RTA_DATA(vf[IFLA_VF_SPOOFCHK]);
 
                if (vf_spoofchk->setting != -1)
-                       fprintf(fp, ", spoof checking %s",
-                               vf_spoofchk->setting ? "on" : "off");
+                       print_bool(PRINT_ANY,
+                                  "spoofchk",
+                                  vf_spoofchk->setting ?
+                                  ", spoof checking on" : ", spoof checking off",
+                                  vf_spoofchk->setting);
        }
+
        if (vf[IFLA_VF_LINK_STATE]) {
                struct ifla_vf_link_state *vf_linkstate =
                        RTA_DATA(vf[IFLA_VF_LINK_STATE]);
 
                if (vf_linkstate->link_state == IFLA_VF_LINK_STATE_AUTO)
-                       fprintf(fp, ", link-state auto");
+                       print_string(PRINT_ANY,
+                                    "link_state",
+                                    ", link-state %s",
+                                    "auto");
                else if (vf_linkstate->link_state == IFLA_VF_LINK_STATE_ENABLE)
-                       fprintf(fp, ", link-state enable");
+                       print_string(PRINT_ANY,
+                                    "link_state",
+                                    ", link-state %s",
+                                    "enable");
                else
-                       fprintf(fp, ", link-state disable");
+                       print_string(PRINT_ANY,
+                                    "link_state",
+                                    ", link-state %s",
+                                    "disable");
        }
+
        if (vf[IFLA_VF_TRUST]) {
                struct ifla_vf_trust *vf_trust = RTA_DATA(vf[IFLA_VF_TRUST]);
 
                if (vf_trust->setting != -1)
-                       fprintf(fp, ", trust %s",
-                               vf_trust->setting ? "on" : "off");
+                       print_bool(PRINT_ANY,
+                                  "trust",
+                                  vf_trust->setting ? ", trust on" : ", trust off",
+                                  vf_trust->setting);
        }
+
        if (vf[IFLA_VF_RSS_QUERY_EN]) {
                struct ifla_vf_rss_query_en *rss_query =
                        RTA_DATA(vf[IFLA_VF_RSS_QUERY_EN]);
 
                if (rss_query->setting != -1)
-                       fprintf(fp, ", query_rss %s",
-                               rss_query->setting ? "on" : "off");
+                       print_bool(PRINT_ANY,
+                                  "query_rss_en",
+                                  rss_query->setting ? ", query_rss on"
+                                  : ", query_rss off",
+                                  rss_query->setting);
        }
+
        if (vf[IFLA_VF_STATS] && show_stats)
                print_vf_stats64(fp, vf[IFLA_VF_STATS]);
 }
@@ -432,7 +534,7 @@ void print_num(FILE *fp, unsigned int width, uint64_t count)
        }
 
        snprintf(buf, sizeof(buf), "%.*f%c%s", precision,
-               (double) count / powi, *prefix, use_iec ? "i" : "");
+                (double) count / powi, *prefix, use_iec ? "i" : "");
 
        fprintf(fp, "%-*s ", width, buf);
 }
@@ -448,155 +550,339 @@ static void print_vf_stats64(FILE *fp, struct rtattr *vfstats)
 
        parse_rtattr_nested(vf, IFLA_VF_MAX, vfstats);
 
-       /* RX stats */
-       fprintf(fp, "%s", _SL_);
-       fprintf(fp, "    RX: bytes  packets  mcast   bcast %s", _SL_);
-       fprintf(fp, "    ");
+       if (is_json_context()) {
+               open_json_object("stats");
+
+               /* RX stats */
+               open_json_object("rx");
+               print_uint(PRINT_JSON, "bytes", NULL,
+                          rta_getattr_u64(vf[IFLA_VF_STATS_RX_BYTES]));
+               print_uint(PRINT_JSON, "packets", NULL,
+                          rta_getattr_u64(vf[IFLA_VF_STATS_RX_PACKETS]));
+               print_uint(PRINT_JSON, "multicast", NULL,
+                          rta_getattr_u64(vf[IFLA_VF_STATS_MULTICAST]));
+               print_uint(PRINT_JSON, "broadcast", NULL,
+                          rta_getattr_u64(vf[IFLA_VF_STATS_BROADCAST]));
+               close_json_object();
+
+               /* TX stats */
+               open_json_object("tx");
+               print_uint(PRINT_JSON, "tx_bytes", NULL,
+                          rta_getattr_u64(vf[IFLA_VF_STATS_TX_BYTES]));
+               print_uint(PRINT_JSON, "tx_packets", NULL,
+                          rta_getattr_u64(vf[IFLA_VF_STATS_TX_PACKETS]));
+               close_json_object();
+               close_json_object();
+       } else {
+               /* RX stats */
+               fprintf(fp, "%s", _SL_);
+               fprintf(fp, "    RX: bytes  packets  mcast   bcast %s", _SL_);
+               fprintf(fp, "    ");
 
-       print_num(fp, 10,  rta_getattr_u64(vf[IFLA_VF_STATS_RX_BYTES]));
-       print_num(fp, 8, rta_getattr_u64(vf[IFLA_VF_STATS_RX_PACKETS]));
-       print_num(fp, 7, rta_getattr_u64(vf[IFLA_VF_STATS_MULTICAST]));
-       print_num(fp, 7, rta_getattr_u64(vf[IFLA_VF_STATS_BROADCAST]));
+               print_num(fp, 10, rta_getattr_u64(vf[IFLA_VF_STATS_RX_BYTES]));
+               print_num(fp, 8, rta_getattr_u64(vf[IFLA_VF_STATS_RX_PACKETS]));
+               print_num(fp, 7, rta_getattr_u64(vf[IFLA_VF_STATS_MULTICAST]));
+               print_num(fp, 7, rta_getattr_u64(vf[IFLA_VF_STATS_BROADCAST]));
 
-       /* TX stats */
-       fprintf(fp, "%s", _SL_);
-       fprintf(fp, "    TX: bytes  packets %s", _SL_);
-       fprintf(fp, "    ");
+               /* TX stats */
+               fprintf(fp, "%s", _SL_);
+               fprintf(fp, "    TX: bytes  packets %s", _SL_);
+               fprintf(fp, "    ");
 
-       print_num(fp, 10, rta_getattr_u64(vf[IFLA_VF_STATS_TX_BYTES]));
-       print_num(fp, 8, rta_getattr_u64(vf[IFLA_VF_STATS_TX_PACKETS]));
+               print_num(fp, 10, rta_getattr_u64(vf[IFLA_VF_STATS_TX_BYTES]));
+               print_num(fp, 8, rta_getattr_u64(vf[IFLA_VF_STATS_TX_PACKETS]));
+       }
 }
 
 static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s,
                               const struct rtattr *carrier_changes)
 {
-       /* 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);
+       if (is_json_context()) {
+               open_json_object("stats644");
+
+               /* 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_uint(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_uint(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_uint(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();
 
-       }
-       fprintf(fp, "%s", _SL_);
+       } 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);
 
-       /* 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));
+               /* 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)
 {
-       /* 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_);
+       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));
+               }
 
-       /* 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");
+               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_);
 
-               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));
+               /* 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));
+               }
        }
 }
 
@@ -694,44 +980,50 @@ int print_linkinfo_brief(const struct sockaddr_nl *who,
                return -1;
 
        if (n->nlmsg_type == RTM_DELLINK)
-               fprintf(fp, "Deleted ");
+               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)
+               if (iflink == 0) {
                        snprintf(buf, sizeof(buf), "%s@NONE", name);
-               else {
-                       snprintf(buf, sizeof(buf),
-                                "%s@%s", name, ll_idx_n2a(iflink, b1));
+                       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);
 
-       fprintf(fp, "%-16s ", buf);
+       print_string(PRINT_FP, NULL, "%-16s ", buf);
+       print_string(PRINT_JSON, "ifname", NULL, name);
 
        if (tb[IFLA_OPERSTATE])
                print_operstate(fp, rta_getattr_u8(tb[IFLA_OPERSTATE]));
 
        if (pfilter->family == AF_PACKET) {
                SPRINT_BUF(b1);
+
                if (tb[IFLA_ADDRESS]) {
-                       color_fprintf(fp, COLOR_MAC, "%s ",
-                                       ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]),
-                                               RTA_PAYLOAD(tb[IFLA_ADDRESS]),
-                                               ifi->ifi_type,
-                                               b1, sizeof(b1)));
+                       print_color_string(PRINT_ANY, COLOR_MAC,
+                                          "address", "%s ",
+                                          ll_addr_n2a(
+                                                  RTA_DATA(tb[IFLA_ADDRESS]),
+                                                  RTA_PAYLOAD(tb[IFLA_ADDRESS]),
+                                                  ifi->ifi_type,
+                                                  b1, sizeof(b1)));
                }
        }
 
-       if (pfilter->family == AF_PACKET)
+       if (pfilter->family == AF_PACKET) {
                print_link_flags(fp, ifi->ifi_flags, m_flag);
-
-       if (pfilter->family == AF_PACKET)
-               fprintf(fp, "\n");
+               print_string(PRINT_FP, NULL, "%s", "\n");
+       }
        fflush(fp);
        return 0;
 }
@@ -749,10 +1041,12 @@ static const char *link_events[] = {
 static void print_link_event(FILE *f, __u32 event)
 {
        if (event >= ARRAY_SIZE(link_events))
-               fprintf(f, "event %d ", event);
+               print_int(PRINT_ANY, "event", "event %d ", event);
        else {
                if (event)
-                       fprintf(f, "event %s ", link_events[event]);
+                       print_string(PRINT_ANY,
+                                    "event", "event %s ",
+                                    link_events[event]);
        }
 }
 
@@ -808,41 +1102,63 @@ int print_linkinfo(const struct sockaddr_nl *who,
                return -1;
 
        if (n->nlmsg_type == RTM_DELLINK)
-               fprintf(fp, "Deleted ");
-
-       fprintf(fp, "%d: ", ifi->ifi_index);
-       color_fprintf(fp, COLOR_IFNAME, "%s",
-                     tb[IFLA_IFNAME] ? rta_getattr_str(tb[IFLA_IFNAME]) : "<nil>");
+               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]) {
-               SPRINT_BUF(b1);
                int iflink = rta_getattr_u32(tb[IFLA_LINK]);
 
                if (iflink == 0)
-                       fprintf(fp, "@NONE: ");
+                       print_null(PRINT_ANY, "link", "@%s: ", "NONE");
                else {
                        if (tb[IFLA_LINK_NETNSID])
-                               fprintf(fp, "@if%d: ", iflink);
+                               print_int(PRINT_ANY,
+                                         "link_index", "@if%d: ", iflink);
                        else {
-                               fprintf(fp, "@%s: ", ll_idx_n2a(iflink, b1));
+                               SPRINT_BUF(b1);
+
+                               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 {
-               fprintf(fp, ": ");
+               print_string(PRINT_FP, NULL, ": ", NULL);
        }
        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_XDP])
                xdp_dump(fp, tb[IFLA_XDP]);
        if (tb[IFLA_QDISC])
-               fprintf(fp, "qdisc %s ", rta_getattr_str(tb[IFLA_QDISC]));
+               print_string(PRINT_ANY,
+                            "qdisc",
+                            "qdisc %s ",
+                            rta_getattr_str(tb[IFLA_QDISC]));
        if (tb[IFLA_MASTER]) {
                SPRINT_BUF(b1);
-               fprintf(fp, "master %s ", ll_idx_n2a(rta_getattr_u32(tb[IFLA_MASTER]), b1));
+
+               print_string(PRINT_ANY,
+                            "master",
+                            "master %s ",
+                            ll_idx_n2a(rta_getattr_u32(tb[IFLA_MASTER]), b1));
        }
 
        if (tb[IFLA_OPERSTATE])
@@ -855,7 +1171,10 @@ int print_linkinfo(const struct sockaddr_nl *who,
                SPRINT_BUF(b1);
                int group = rta_getattr_u32(tb[IFLA_GROUP]);
 
-               fprintf(fp, "group %s ", rtnl_group_n2a(group, b1, sizeof(b1)));
+               print_string(PRINT_ANY,
+                            "group",
+                            "group %s ",
+                            rtnl_group_n2a(group, b1, sizeof(b1)));
        }
 
        if (filter.showqueue)
@@ -866,47 +1185,68 @@ int print_linkinfo(const struct sockaddr_nl *who,
 
        if (!filter.family || filter.family == AF_PACKET || show_details) {
                SPRINT_BUF(b1);
-               fprintf(fp, "%s", _SL_);
-               fprintf(fp, "    link/%s ", ll_type_n2a(ifi->ifi_type, b1, sizeof(b1)));
 
+               print_string(PRINT_FP, NULL, "%s", _SL_);
+               print_string(PRINT_ANY,
+                            "link_type",
+                            "    link/%s ",
+                            ll_type_n2a(ifi->ifi_type, b1, sizeof(b1)));
                if (tb[IFLA_ADDRESS]) {
-                       color_fprintf(fp, COLOR_MAC, "%s",
-                                     ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]),
-                                                 RTA_PAYLOAD(tb[IFLA_ADDRESS]),
-                                                 ifi->ifi_type,
-                                                 b1, sizeof(b1)));
+                       print_color_string(PRINT_ANY,
+                                          COLOR_MAC,
+                                          "address",
+                                          "%s",
+                                          ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]),
+                                                      RTA_PAYLOAD(tb[IFLA_ADDRESS]),
+                                                      ifi->ifi_type,
+                                                      b1, sizeof(b1)));
                }
                if (tb[IFLA_BROADCAST]) {
-                       if (ifi->ifi_flags&IFF_POINTOPOINT)
-                               fprintf(fp, " peer ");
-                       else
-                               fprintf(fp, " brd ");
-                       color_fprintf(fp, COLOR_MAC, "%s",
-                                     ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]),
-                                                 RTA_PAYLOAD(tb[IFLA_BROADCAST]),
-                                                 ifi->ifi_type,
-                                                 b1, sizeof(b1)));
+                       if (ifi->ifi_flags&IFF_POINTOPOINT) {
+                               print_string(PRINT_FP, NULL, " peer ", NULL);
+                               print_bool(PRINT_JSON,
+                                          "link_pointtopoint", NULL, true);
+                       } else {
+                               print_string(PRINT_FP, NULL, " brd ", NULL);
+                       }
+                       print_color_string(PRINT_ANY,
+                                          COLOR_MAC,
+                                          "broadcast",
+                                          "%s",
+                                          ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]),
+                                                      RTA_PAYLOAD(tb[IFLA_BROADCAST]),
+                                                      ifi->ifi_type,
+                                                      b1, sizeof(b1)));
                }
        }
 
        if (tb[IFLA_LINK_NETNSID]) {
                int id = rta_getattr_u32(tb[IFLA_LINK_NETNSID]);
 
-               if (id >= 0)
-                       fprintf(fp, " link-netnsid %d", id);
-               else
-                       fprintf(fp, " link-netnsid unknown");
+               if (is_json_context()) {
+                       print_int(PRINT_JSON, "link_netnsid", NULL, id);
+               } else {
+                       if (id >= 0)
+                               print_int(PRINT_FP, NULL,
+                                         " link-netnsid %d", id);
+                       else
+                               print_string(PRINT_FP, NULL,
+                                            " link-netnsid %s", "unknown");
+               }
        }
 
        if (tb[IFLA_PROTO_DOWN]) {
                if (rta_getattr_u8(tb[IFLA_PROTO_DOWN]))
-                       fprintf(fp, " protodown on ");
+                       print_bool(PRINT_ANY,
+                                  "proto_down", " protodown on ", true);
        }
 
        if (show_details) {
                if (tb[IFLA_PROMISCUITY])
-                       fprintf(fp, " promiscuity %u ",
-                               rta_getattr_u32(tb[IFLA_PROMISCUITY]));
+                       print_uint(PRINT_ANY,
+                                  "promiscuity",
+                                  " promiscuity %u ",
+                                  rta_getattr_u32(tb[IFLA_PROMISCUITY]));
 
                if (tb[IFLA_LINKINFO])
                        print_linktype(fp, tb[IFLA_LINKINFO]);
@@ -915,50 +1255,68 @@ int print_linkinfo(const struct sockaddr_nl *who,
                        print_af_spec(fp, tb[IFLA_AF_SPEC]);
 
                if (tb[IFLA_NUM_TX_QUEUES])
-                       fprintf(fp, "numtxqueues %u ",
-                               rta_getattr_u32(tb[IFLA_NUM_TX_QUEUES]));
+                       print_uint(PRINT_ANY,
+                                  "num_tx_queues",
+                                  "numtxqueues %u ",
+                                  rta_getattr_u32(tb[IFLA_NUM_TX_QUEUES]));
 
                if (tb[IFLA_NUM_RX_QUEUES])
-                       fprintf(fp, "numrxqueues %u ",
-                               rta_getattr_u32(tb[IFLA_NUM_RX_QUEUES]));
+                       print_uint(PRINT_ANY,
+                                  "num_rx_queues",
+                                  "numrxqueues %u ",
+                                  rta_getattr_u32(tb[IFLA_NUM_RX_QUEUES]));
 
                if (tb[IFLA_GSO_MAX_SIZE])
-                       fprintf(fp, "gso_max_size %u ",
-                               rta_getattr_u32(tb[IFLA_GSO_MAX_SIZE]));
+                       print_uint(PRINT_ANY,
+                                  "gso_max_size",
+                                  "gso_max_size %u ",
+                                  rta_getattr_u32(tb[IFLA_GSO_MAX_SIZE]));
 
                if (tb[IFLA_GSO_MAX_SEGS])
-                       fprintf(fp, "gso_max_segs %u ",
-                               rta_getattr_u32(tb[IFLA_GSO_MAX_SEGS]));
+                       print_uint(PRINT_ANY,
+                                  "gso_max_segs",
+                                  "gso_max_segs %u ",
+                                  rta_getattr_u32(tb[IFLA_GSO_MAX_SEGS]));
 
                if (tb[IFLA_PHYS_PORT_NAME])
-                       fprintf(fp, "portname %s ",
-                               rta_getattr_str(tb[IFLA_PHYS_PORT_NAME]));
+                       print_string(PRINT_ANY,
+                                    "phys_port_name",
+                                    "portname %s ",
+                                    rta_getattr_str(tb[IFLA_PHYS_PORT_NAME]));
 
                if (tb[IFLA_PHYS_PORT_ID]) {
                        SPRINT_BUF(b1);
-                       fprintf(fp, "portid %s ",
-                               hexstring_n2a(RTA_DATA(tb[IFLA_PHYS_PORT_ID]),
-                                             RTA_PAYLOAD(tb[IFLA_PHYS_PORT_ID]),
-                                             b1, sizeof(b1)));
+                       print_string(PRINT_ANY,
+                                    "phys_port_id",
+                                    "portid %s ",
+                                    hexstring_n2a(
+                                            RTA_DATA(tb[IFLA_PHYS_PORT_ID]),
+                                            RTA_PAYLOAD(tb[IFLA_PHYS_PORT_ID]),
+                                            b1, sizeof(b1)));
                }
 
                if (tb[IFLA_PHYS_SWITCH_ID]) {
                        SPRINT_BUF(b1);
-                       fprintf(fp, "switchid %s ",
-                               hexstring_n2a(RTA_DATA(tb[IFLA_PHYS_SWITCH_ID]),
-                                             RTA_PAYLOAD(tb[IFLA_PHYS_SWITCH_ID]),
-                                             b1, sizeof(b1)));
+                       print_string(PRINT_ANY,
+                                    "phys_switch_id",
+                                    "switchid %s ",
+                                    hexstring_n2a(RTA_DATA(tb[IFLA_PHYS_SWITCH_ID]),
+                                                  RTA_PAYLOAD(tb[IFLA_PHYS_SWITCH_ID]),
+                                                  b1, sizeof(b1)));
                }
        }
 
 
        if ((do_link || show_details) && tb[IFLA_IFALIAS]) {
-               fprintf(fp, "%s    alias %s", _SL_,
-                       rta_getattr_str(tb[IFLA_IFALIAS]));
+               print_string(PRINT_FP, NULL, "%s    ", _SL_);
+               print_string(PRINT_ANY,
+                            "ifalias",
+                            "alias %s",
+                            rta_getattr_str(tb[IFLA_IFALIAS]));
        }
 
        if (do_link && show_stats) {
-               fprintf(fp, "%s", _SL_);
+               print_string(PRINT_FP, NULL, "%s", _SL_);
                __print_link_stats(fp, tb);
        }
 
@@ -966,11 +1324,16 @@ int print_linkinfo(const struct sockaddr_nl *who,
                struct rtattr *i, *vflist = tb[IFLA_VFINFO_LIST];
                int rem = RTA_PAYLOAD(vflist);
 
-               for (i = RTA_DATA(vflist); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
+               open_json_array(PRINT_JSON, "vfinfo_list");
+               for (i = RTA_DATA(vflist); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+                       open_json_object(NULL);
                        print_vfinfo(fp, i);
+                       close_json_object();
+               }
+               close_json_array(PRINT_JSON, NULL);
        }
 
-       fprintf(fp, "\n");
+       print_string(PRINT_FP, NULL, "\n", NULL);
        fflush(fp);
        return 1;
 }
@@ -1009,7 +1372,7 @@ static unsigned int get_ifa_flags(struct ifaddrmsg *ifa,
                                  struct rtattr *ifa_flags_attr)
 {
        return ifa_flags_attr ? rta_getattr_u32(ifa_flags_attr) :
-                               ifa->ifa_flags;
+               ifa->ifa_flags;
 }
 
 /* Mapping from argument to address flag mask */
@@ -1042,20 +1405,34 @@ static void print_ifa_flags(FILE *fp, const struct ifaddrmsg *ifa,
 
                if (mask == IFA_F_PERMANENT) {
                        if (!(flags & mask))
-                               fprintf(fp, "dynamic ");
+                               print_bool(PRINT_ANY,
+                                          "dynamic", "dynamic ", true);
                } else if (flags & mask) {
                        if (mask == IFA_F_SECONDARY &&
-                           ifa->ifa_family == AF_INET6)
-                               fprintf(fp, "temporary ");
-                       else
-                               fprintf(fp, "%s ", ifa_flag_names[i].name);
+                           ifa->ifa_family == AF_INET6) {
+                               print_bool(PRINT_ANY,
+                                          "temporary", "temporary ", true);
+                       } else {
+                               print_string(PRINT_FP, NULL,
+                                            "%s ", ifa_flag_names[i].name);
+                               print_bool(PRINT_JSON,
+                                          ifa_flag_names[i].name, NULL, true);
+                       }
                }
 
                flags &= ~mask;
        }
 
-       if (flags)
-               fprintf(fp, "flags %02x ", flags);
+       if (flags) {
+               if (is_json_context()) {
+                       SPRINT_BUF(b1);
+
+                       snprintf(b1, sizeof(b1), "%02x", flags);
+                       print_string(PRINT_JSON, "ifa_flags", NULL, b1);
+               } else {
+                       fprintf(fp, "flags %02x ", flags);
+               }
+       }
 
 }
 
@@ -1176,80 +1553,130 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
        }
 
        if (n->nlmsg_type == RTM_DELADDR)
-               fprintf(fp, "Deleted ");
+               print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 
        if (!brief) {
-               if (filter.oneline || filter.flushb)
-                       fprintf(fp, "%u: %s", ifa->ifa_index, ll_index_to_name(ifa->ifa_index));
+               if (filter.oneline || filter.flushb) {
+                       const char *dev = ll_index_to_name(ifa->ifa_index);
+
+                       if (is_json_context()) {
+                               print_int(PRINT_JSON,
+                                         "index", NULL, ifa->ifa_index);
+                               print_string(PRINT_JSON, "dev", NULL, dev);
+                       } else {
+                               fprintf(fp, "%u: %s", ifa->ifa_index, dev);
+                       }
+               }
+
+               int family = ifa->ifa_family;
+
                if (ifa->ifa_family == AF_INET)
-                       fprintf(fp, "    inet ");
+                       print_string(PRINT_ANY, "family", "    %s ", "inet");
                else if (ifa->ifa_family == AF_INET6)
-                       fprintf(fp, "    inet6 ");
+                       print_string(PRINT_ANY, "family", "    %s ", "inet6");
                else if (ifa->ifa_family == AF_DECnet)
-                       fprintf(fp, "    dnet ");
+                       print_string(PRINT_ANY, "family", "    %s ", "dnet");
                else if (ifa->ifa_family == AF_IPX)
-                       fprintf(fp, "     ipx ");
+                       print_string(PRINT_ANY, "family", "     %s ", "ipx");
                else
-                       fprintf(fp, "    family %d ", ifa->ifa_family);
+                       print_int(PRINT_ANY,
+                                 "family_index",
+                                 "    family %d ", family);
        }
 
        if (rta_tb[IFA_LOCAL]) {
-               color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s",
-                             format_host_rta(ifa->ifa_family,
-                                             rta_tb[IFA_LOCAL]));
+               print_color_string(PRINT_ANY,
+                                  ifa_family_color(ifa->ifa_family),
+                                  "local", "%s",
+                                  format_host_rta(ifa->ifa_family,
+                                                  rta_tb[IFA_LOCAL]));
                if (rta_tb[IFA_ADDRESS] &&
                    memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]),
                           RTA_DATA(rta_tb[IFA_LOCAL]),
                           ifa->ifa_family == AF_INET ? 4 : 16)) {
-                       fprintf(fp, " peer ");
-                       color_fprintf(fp, ifa_family_color(ifa->ifa_family),
-                                     "%s", format_host_rta(ifa->ifa_family,
-                                     rta_tb[IFA_ADDRESS]));
+                       print_string(PRINT_FP, NULL, " %s ", "peer");
+                       print_color_string(PRINT_ANY,
+                                          ifa_family_color(ifa->ifa_family),
+                                          "address",
+                                          "%s",
+                                          format_host_rta(ifa->ifa_family,
+                                                          rta_tb[IFA_ADDRESS]));
                }
-               fprintf(fp, "/%d ", ifa->ifa_prefixlen);
+               print_int(PRINT_ANY, "prefixlen", "/%d", ifa->ifa_prefixlen);
        }
 
        if (brief)
                goto brief_exit;
 
        if (rta_tb[IFA_BROADCAST]) {
-               fprintf(fp, "brd ");
-               color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s ",
-                             format_host_rta(ifa->ifa_family,
-                                             rta_tb[IFA_BROADCAST]));
+               print_string(PRINT_FP, NULL, "%s ", "brd");
+               print_color_string(PRINT_ANY,
+                                  ifa_family_color(ifa->ifa_family),
+                                  "broadcast",
+                                  "%s ",
+                                  format_host_rta(ifa->ifa_family,
+                                                  rta_tb[IFA_BROADCAST]));
        }
+
        if (rta_tb[IFA_ANYCAST]) {
-               fprintf(fp, "any ");
-               color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s ",
-                             format_host_rta(ifa->ifa_family,
-                                             rta_tb[IFA_ANYCAST]));
+               print_string(PRINT_FP, NULL, "%s ", "any");
+               print_color_string(PRINT_ANY,
+                                  ifa_family_color(ifa->ifa_family),
+                                  "anycast",
+                                  "%s ",
+                                  format_host_rta(ifa->ifa_family,
+                                                  rta_tb[IFA_ANYCAST]));
        }
-       fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1)));
+
+       print_string(PRINT_ANY,
+                    "scope",
+                    "scope %s ",
+                    rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1)));
 
        print_ifa_flags(fp, ifa, ifa_flags);
 
        if (rta_tb[IFA_LABEL])
-               fprintf(fp, "%s", rta_getattr_str(rta_tb[IFA_LABEL]));
+               print_string(PRINT_ANY,
+                            "label",
+                            "%s",
+                            rta_getattr_str(rta_tb[IFA_LABEL]));
+
        if (rta_tb[IFA_CACHEINFO]) {
                struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]);
 
-               fprintf(fp, "%s", _SL_);
-               fprintf(fp, "       valid_lft ");
-               if (ci->ifa_valid == INFINITY_LIFE_TIME)
-                       fprintf(fp, "forever");
-               else
-                       fprintf(fp, "%usec", ci->ifa_valid);
-               fprintf(fp, " preferred_lft ");
-               if (ci->ifa_prefered == INFINITY_LIFE_TIME)
-                       fprintf(fp, "forever");
-               else {
+               print_string(PRINT_FP, NULL, "%s", _SL_);
+               print_string(PRINT_FP, NULL, "       valid_lft ", NULL);
+
+               if (ci->ifa_valid == INFINITY_LIFE_TIME) {
+                       print_uint(PRINT_JSON,
+                                  "valid_life_time",
+                                  NULL, INFINITY_LIFE_TIME);
+                       print_string(PRINT_FP, NULL, "%s", "forever");
+               } else {
+                       print_uint(PRINT_ANY,
+                                  "valid_life_time", "%usec", ci->ifa_valid);
+               }
+
+               print_string(PRINT_FP, NULL, " preferred_lft ", NULL);
+               if (ci->ifa_prefered == INFINITY_LIFE_TIME) {
+                       print_uint(PRINT_JSON,
+                                  "preferred_life_time",
+                                  NULL, INFINITY_LIFE_TIME);
+                       print_string(PRINT_FP, NULL, "%s", "forever");
+               } else {
                        if (ifa_flags & IFA_F_DEPRECATED)
-                               fprintf(fp, "%dsec", ci->ifa_prefered);
+                               print_int(PRINT_ANY,
+                                         "preferred_life_time",
+                                         "%dsec",
+                                         ci->ifa_prefered);
                        else
-                               fprintf(fp, "%usec", ci->ifa_prefered);
+                               print_uint(PRINT_ANY,
+                                          "preferred_life_time",
+                                          "%usec",
+                                          ci->ifa_prefered);
                }
        }
-       fprintf(fp, "\n");
+       print_string(PRINT_FP, NULL, "%s", "\n");
 brief_exit:
        fflush(fp);
        return 0;
@@ -1258,6 +1685,7 @@ brief_exit:
 static int print_selected_addrinfo(struct ifinfomsg *ifi,
                                   struct nlmsg_list *ainfo, FILE *fp)
 {
+       open_json_array(PRINT_JSON, "addr_info");
        for ( ; ainfo ;  ainfo = ainfo->next) {
                struct nlmsghdr *n = &ainfo->h;
                struct ifaddrmsg *ifa = NLMSG_DATA(n);
@@ -1275,10 +1703,14 @@ static int print_selected_addrinfo(struct ifinfomsg *ifi,
                if (filter.up && !(ifi->ifi_flags&IFF_UP))
                        continue;
 
+               open_json_object(NULL);
                print_addrinfo(NULL, n, fp);
+               close_json_object();
        }
+       close_json_array(PRINT_JSON, NULL);
+
        if (brief) {
-               fprintf(fp, "\n");
+               print_string(PRINT_FP, NULL, "%s", "\n");
                fflush(fp);
        }
        return 0;
@@ -1724,6 +2156,12 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
                exit(0);
        }
 
+       /*
+        * Initialize a json_writer and open an array object
+        * if -json was specified.
+        */
+       new_json_obj(json, stdout);
+
        /*
         * If only filter_dev present and none of the other
         * link filters are present, use RTM_GETLINK to get
@@ -1732,8 +2170,10 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
        if (filter_dev && filter.group == -1 && do_link == 1) {
                if (iplink_get(0, filter_dev, RTEXT_FILTER_VF) < 0) {
                        perror("Cannot send link get request");
+                       delete_json_obj();
                        exit(1);
                }
+               delete_json_obj();
                exit(0);
        }
 
@@ -1755,6 +2195,7 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
                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)
@@ -1763,13 +2204,14 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
                                                                ainfo->head,
                                                                stdout);
                } else if (no_link ||
-                         (res = print_linkinfo(NULL, &l->h, stdout)) >= 0) {
+                          (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);
                }
+               close_json_object();
        }
        fflush(stdout);
 
@@ -1777,7 +2219,7 @@ out:
        if (ainfo)
                free_nlmsg_chain(ainfo);
        free_nlmsg_chain(&linfo);
-
+       delete_json_obj();
        return 0;
 }
 
index 5aff2fde38dae1526cdbcd39f68b40dc9c18e555..19bda1b99f55833c6b5feb17ac27e9a5c50a61fe 100644 (file)
@@ -1041,10 +1041,12 @@ int iplink_get(unsigned int flags, char *name, __u32 filt_mask)
        if (rtnl_talk(&rth, &req.n, &answer.n, sizeof(answer)) < 0)
                return -2;
 
+       open_json_object(NULL);
        if (brief)
                print_linkinfo_brief(NULL, &answer.n, stdout, NULL);
        else
                print_linkinfo(NULL, &answer.n, stdout);
+       close_json_object();
 
        return 0;
 }
index 772b05fd89eaf6ec11deda04391257b46c2e93c1..2b5cf4f6f4cfd12fc14c691d7175360762137458 100644 (file)
@@ -376,8 +376,8 @@ static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
 
        if (tb[IFLA_BOND_MODE]) {
                const char *mode = get_name(mode_tbl,
-                       rta_getattr_u8(tb[IFLA_BOND_MODE]));
-               fprintf(f, "mode %s ", mode);
+                                           rta_getattr_u8(tb[IFLA_BOND_MODE]));
+               print_string(PRINT_ANY, "mode", "mode %s ", mode);
        }
 
        if (tb[IFLA_BOND_ACTIVE_SLAVE] &&
@@ -386,61 +386,97 @@ static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                const char *n = if_indextoname(ifindex, buf);
 
                if (n)
-                       fprintf(f, "active_slave %s ", n);
+                       print_string(PRINT_ANY,
+                                    "active_slave",
+                                    "active_slave %s ",
+                                    n);
                else
-                       fprintf(f, "active_slave %u ", ifindex);
+                       print_uint(PRINT_ANY,
+                                  "active_slave_index",
+                                  "active_slave %u ",
+                                  ifindex);
        }
 
        if (tb[IFLA_BOND_MIIMON])
-               fprintf(f, "miimon %u ", rta_getattr_u32(tb[IFLA_BOND_MIIMON]));
+               print_uint(PRINT_ANY,
+                          "miimon",
+                          "miimon %u ",
+                          rta_getattr_u32(tb[IFLA_BOND_MIIMON]));
 
        if (tb[IFLA_BOND_UPDELAY])
-               fprintf(f, "updelay %u ", rta_getattr_u32(tb[IFLA_BOND_UPDELAY]));
+               print_uint(PRINT_ANY,
+                          "updelay",
+                          "updelay %u ",
+                          rta_getattr_u32(tb[IFLA_BOND_UPDELAY]));
 
        if (tb[IFLA_BOND_DOWNDELAY])
-               fprintf(f, "downdelay %u ",
-                       rta_getattr_u32(tb[IFLA_BOND_DOWNDELAY]));
+               print_uint(PRINT_ANY,
+                          "downdelay",
+                          "downdelay %u ",
+                          rta_getattr_u32(tb[IFLA_BOND_DOWNDELAY]));
 
        if (tb[IFLA_BOND_USE_CARRIER])
-               fprintf(f, "use_carrier %u ",
-                       rta_getattr_u8(tb[IFLA_BOND_USE_CARRIER]));
+               print_uint(PRINT_ANY,
+                          "use_carrier",
+                          "use_carrier %u ",
+                          rta_getattr_u8(tb[IFLA_BOND_USE_CARRIER]));
 
        if (tb[IFLA_BOND_ARP_INTERVAL])
-               fprintf(f, "arp_interval %u ",
-                       rta_getattr_u32(tb[IFLA_BOND_ARP_INTERVAL]));
+               print_uint(PRINT_ANY,
+                          "arp_interval",
+                          "arp_interval %u ",
+                          rta_getattr_u32(tb[IFLA_BOND_ARP_INTERVAL]));
 
        if (tb[IFLA_BOND_ARP_IP_TARGET]) {
                struct rtattr *iptb[BOND_MAX_ARP_TARGETS + 1];
                int i;
 
                parse_rtattr_nested(iptb, BOND_MAX_ARP_TARGETS,
-                       tb[IFLA_BOND_ARP_IP_TARGET]);
+                                   tb[IFLA_BOND_ARP_IP_TARGET]);
 
-               if (iptb[0])
-                       fprintf(f, "arp_ip_target ");
+               if (iptb[0]) {
+                       open_json_array(PRINT_JSON, "arp_ip_target");
+                       print_string(PRINT_FP, NULL, "arp_ip_target ", NULL);
+               }
 
                for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
                        if (iptb[i])
-                               fprintf(f, "%s",
-                                       rt_addr_n2a_rta(AF_INET, iptb[i]));
-                       if (i < BOND_MAX_ARP_TARGETS-1 && iptb[i+1])
+                               print_string(PRINT_ANY,
+                                            NULL,
+                                            "%s",
+                                            rt_addr_n2a_rta(AF_INET, iptb[i]));
+                       if (!is_json_context()
+                           && i < BOND_MAX_ARP_TARGETS-1
+                           && iptb[i+1])
                                fprintf(f, ",");
                }
 
-               if (iptb[0])
-                       fprintf(f, " ");
+               if (iptb[0]) {
+                       print_string(PRINT_FP, NULL, " ", NULL);
+                       close_json_array(PRINT_JSON, NULL);
+               }
        }
 
        if (tb[IFLA_BOND_ARP_VALIDATE]) {
-               const char *arp_validate = get_name(arp_validate_tbl,
-                       rta_getattr_u32(tb[IFLA_BOND_ARP_VALIDATE]));
-               fprintf(f, "arp_validate %s ", arp_validate);
+               __u32 arp_v = rta_getattr_u32(tb[IFLA_BOND_ARP_VALIDATE]);
+               const char *arp_validate = get_name(arp_validate_tbl, arp_v);
+
+               if (!arp_v && is_json_context())
+                       print_null(PRINT_JSON, "arp_validate", NULL, NULL);
+               else
+                       print_string(PRINT_ANY,
+                                    "arp_validate",
+                                    "arp_validate %s ",
+                                    arp_validate);
        }
 
        if (tb[IFLA_BOND_ARP_ALL_TARGETS]) {
                const char *arp_all_targets = get_name(arp_all_targets_tbl,
-                       rta_getattr_u32(tb[IFLA_BOND_ARP_ALL_TARGETS]));
-               fprintf(f, "arp_all_targets %s ", arp_all_targets);
+                                                      rta_getattr_u32(tb[IFLA_BOND_ARP_ALL_TARGETS]));
+               print_string(PRINT_ANY,
+                            "arp_all_targets",
+                            "arp_all_targets %s ",
+                            arp_all_targets);
        }
 
        if (tb[IFLA_BOND_PRIMARY] &&
@@ -449,123 +485,176 @@ static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                const char *n = if_indextoname(ifindex, buf);
 
                if (n)
-                       fprintf(f, "primary %s ", n);
+                       print_string(PRINT_ANY, "primary", "primary %s ", n);
                else
-                       fprintf(f, "primary %u ", ifindex);
+                       print_uint(PRINT_ANY,
+                                  "primary_index",
+                                  "primary %u ",
+                                  ifindex);
        }
 
        if (tb[IFLA_BOND_PRIMARY_RESELECT]) {
                const char *primary_reselect = get_name(primary_reselect_tbl,
-                       rta_getattr_u8(tb[IFLA_BOND_PRIMARY_RESELECT]));
-               fprintf(f, "primary_reselect %s ", primary_reselect);
+                                                       rta_getattr_u8(tb[IFLA_BOND_PRIMARY_RESELECT]));
+               print_string(PRINT_ANY,
+                            "primary_reselect",
+                            "primary_reselect %s ",
+                            primary_reselect);
        }
 
        if (tb[IFLA_BOND_FAIL_OVER_MAC]) {
                const char *fail_over_mac = get_name(fail_over_mac_tbl,
-                       rta_getattr_u8(tb[IFLA_BOND_FAIL_OVER_MAC]));
-               fprintf(f, "fail_over_mac %s ", fail_over_mac);
+                                                    rta_getattr_u8(tb[IFLA_BOND_FAIL_OVER_MAC]));
+               print_string(PRINT_ANY,
+                            "fail_over_mac",
+                            "fail_over_mac %s ",
+                            fail_over_mac);
        }
 
        if (tb[IFLA_BOND_XMIT_HASH_POLICY]) {
                const char *xmit_hash_policy = get_name(xmit_hash_policy_tbl,
-                       rta_getattr_u8(tb[IFLA_BOND_XMIT_HASH_POLICY]));
-               fprintf(f, "xmit_hash_policy %s ", xmit_hash_policy);
+                                                       rta_getattr_u8(tb[IFLA_BOND_XMIT_HASH_POLICY]));
+               print_string(PRINT_ANY,
+                            "xmit_hash_policy",
+                            "xmit_hash_policy %s ",
+                            xmit_hash_policy);
        }
 
        if (tb[IFLA_BOND_RESEND_IGMP])
-               fprintf(f, "resend_igmp %u ",
-                       rta_getattr_u32(tb[IFLA_BOND_RESEND_IGMP]));
+               print_uint(PRINT_ANY,
+                          "resend_igmp",
+                          "resend_igmp %u ",
+                          rta_getattr_u32(tb[IFLA_BOND_RESEND_IGMP]));
 
        if (tb[IFLA_BOND_NUM_PEER_NOTIF])
-               fprintf(f, "num_grat_arp %u ",
-                       rta_getattr_u8(tb[IFLA_BOND_NUM_PEER_NOTIF]));
+               print_uint(PRINT_ANY,
+                          "num_peer_notif",
+                          "num_grat_arp %u ",
+                          rta_getattr_u8(tb[IFLA_BOND_NUM_PEER_NOTIF]));
 
        if (tb[IFLA_BOND_ALL_SLAVES_ACTIVE])
-               fprintf(f, "all_slaves_active %u ",
-                       rta_getattr_u8(tb[IFLA_BOND_ALL_SLAVES_ACTIVE]));
+               print_uint(PRINT_ANY,
+                          "all_slaves_active",
+                          "all_slaves_active %u ",
+                          rta_getattr_u8(tb[IFLA_BOND_ALL_SLAVES_ACTIVE]));
 
        if (tb[IFLA_BOND_MIN_LINKS])
-               fprintf(f, "min_links %u ",
-                       rta_getattr_u32(tb[IFLA_BOND_MIN_LINKS]));
+               print_uint(PRINT_ANY,
+                          "min_links",
+                          "min_links %u ",
+                          rta_getattr_u32(tb[IFLA_BOND_MIN_LINKS]));
 
        if (tb[IFLA_BOND_LP_INTERVAL])
-               fprintf(f, "lp_interval %u ",
-                       rta_getattr_u32(tb[IFLA_BOND_LP_INTERVAL]));
+               print_uint(PRINT_ANY,
+                          "lp_interval",
+                          "lp_interval %u ",
+                          rta_getattr_u32(tb[IFLA_BOND_LP_INTERVAL]));
 
        if (tb[IFLA_BOND_PACKETS_PER_SLAVE])
-               fprintf(f, "packets_per_slave %u ",
-                       rta_getattr_u32(tb[IFLA_BOND_PACKETS_PER_SLAVE]));
+               print_uint(PRINT_ANY,
+                          "packets_per_slave",
+                          "packets_per_slave %u ",
+                          rta_getattr_u32(tb[IFLA_BOND_PACKETS_PER_SLAVE]));
 
        if (tb[IFLA_BOND_AD_LACP_RATE]) {
                const char *lacp_rate = get_name(lacp_rate_tbl,
-                       rta_getattr_u8(tb[IFLA_BOND_AD_LACP_RATE]));
-               fprintf(f, "lacp_rate %s ", lacp_rate);
+                                                rta_getattr_u8(tb[IFLA_BOND_AD_LACP_RATE]));
+               print_string(PRINT_ANY,
+                            "ad_lacp_rate",
+                            "lacp_rate %s ",
+                            lacp_rate);
        }
 
        if (tb[IFLA_BOND_AD_SELECT]) {
                const char *ad_select = get_name(ad_select_tbl,
-                       rta_getattr_u8(tb[IFLA_BOND_AD_SELECT]));
-               fprintf(f, "ad_select %s ", ad_select);
+                                                rta_getattr_u8(tb[IFLA_BOND_AD_SELECT]));
+               print_string(PRINT_ANY,
+                            "ad_select",
+                            "ad_select %s ",
+                            ad_select);
        }
 
        if (tb[IFLA_BOND_AD_INFO]) {
                struct rtattr *adtb[IFLA_BOND_AD_INFO_MAX + 1];
 
                parse_rtattr_nested(adtb, IFLA_BOND_AD_INFO_MAX,
-                       tb[IFLA_BOND_AD_INFO]);
+                                   tb[IFLA_BOND_AD_INFO]);
+
+               open_json_object("ad_info");
 
                if (adtb[IFLA_BOND_AD_INFO_AGGREGATOR])
-                       fprintf(f, "ad_aggregator %d ",
-                         rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_AGGREGATOR]));
+                       print_int(PRINT_ANY,
+                                 "aggregator",
+                                 "ad_aggregator %d ",
+                                 rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_AGGREGATOR]));
 
                if (adtb[IFLA_BOND_AD_INFO_NUM_PORTS])
-                       fprintf(f, "ad_num_ports %d ",
-                         rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_NUM_PORTS]));
+                       print_int(PRINT_ANY,
+                                 "num_ports",
+                                 "ad_num_ports %d ",
+                                 rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_NUM_PORTS]));
 
                if (adtb[IFLA_BOND_AD_INFO_ACTOR_KEY])
-                       fprintf(f, "ad_actor_key %d ",
-                         rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_ACTOR_KEY]));
+                       print_int(PRINT_ANY,
+                                 "actor_key",
+                                 "ad_actor_key %d ",
+                                 rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_ACTOR_KEY]));
 
                if (adtb[IFLA_BOND_AD_INFO_PARTNER_KEY])
-                       fprintf(f, "ad_partner_key %d ",
-                         rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_PARTNER_KEY]));
+                       print_int(PRINT_ANY,
+                                 "partner_key",
+                                 "ad_partner_key %d ",
+                                 rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_PARTNER_KEY]));
 
                if (adtb[IFLA_BOND_AD_INFO_PARTNER_MAC]) {
                        unsigned char *p =
                                RTA_DATA(adtb[IFLA_BOND_AD_INFO_PARTNER_MAC]);
                        SPRINT_BUF(b);
-                       fprintf(f, "ad_partner_mac %s ",
-                               ll_addr_n2a(p, ETH_ALEN, 0, b, sizeof(b)));
+                       print_string(PRINT_ANY,
+                                    "partner_mac",
+                                    "ad_partner_mac %s ",
+                                    ll_addr_n2a(p, ETH_ALEN, 0, b, sizeof(b)));
                }
+
+               close_json_object();
        }
 
        if (tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]) {
-               fprintf(f, "ad_actor_sys_prio %u ",
-                       rta_getattr_u16(tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]));
+               print_uint(PRINT_ANY,
+                          "ad_actor_sys_prio",
+                          "ad_actor_sys_prio %u ",
+                          rta_getattr_u16(tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]));
        }
 
        if (tb[IFLA_BOND_AD_USER_PORT_KEY]) {
-               fprintf(f, "ad_user_port_key %u ",
-                       rta_getattr_u16(tb[IFLA_BOND_AD_USER_PORT_KEY]));
+               print_uint(PRINT_ANY,
+                          "ad_user_port_key",
+                          "ad_user_port_key %u ",
+                          rta_getattr_u16(tb[IFLA_BOND_AD_USER_PORT_KEY]));
        }
 
        if (tb[IFLA_BOND_AD_ACTOR_SYSTEM]) {
                /* We assume the l2 address is an Ethernet MAC address */
                SPRINT_BUF(b1);
-               fprintf(f, "ad_actor_system %s ",
-                       ll_addr_n2a(RTA_DATA(tb[IFLA_BOND_AD_ACTOR_SYSTEM]),
-                                   RTA_PAYLOAD(tb[IFLA_BOND_AD_ACTOR_SYSTEM]),
-                                   1 /*ARPHDR_ETHER*/, b1, sizeof(b1)));
+
+               print_string(PRINT_ANY,
+                            "ad_actor_system",
+                            "ad_actor_system %s ",
+                            ll_addr_n2a(RTA_DATA(tb[IFLA_BOND_AD_ACTOR_SYSTEM]),
+                                        RTA_PAYLOAD(tb[IFLA_BOND_AD_ACTOR_SYSTEM]),
+                                        1 /*ARPHDR_ETHER*/, b1, sizeof(b1)));
        }
 
        if (tb[IFLA_BOND_TLB_DYNAMIC_LB]) {
-               fprintf(f, "tlb_dynamic_lb %u ",
-                       rta_getattr_u8(tb[IFLA_BOND_TLB_DYNAMIC_LB]));
+               print_uint(PRINT_ANY,
+                          "tlb_dynamic_lb",
+                          "tlb_dynamic_lb %u ",
+                          rta_getattr_u8(tb[IFLA_BOND_TLB_DYNAMIC_LB]));
        }
 }
 
 static void bond_print_help(struct link_util *lu, int argc, char **argv,
-       FILE *f)
+                           FILE *f)
 {
        print_explain(f);
 }
index 877e2d9ef817cf261b4a83ada6c3ba0f4e0b74bd..67219c67241be32b718cdfda55b87ef39331a8fc 100644 (file)
@@ -37,9 +37,12 @@ static void print_slave_state(FILE *f, struct rtattr *tb)
        unsigned int state = rta_getattr_u8(tb);
 
        if (state >= ARRAY_SIZE(slave_states))
-               fprintf(f, "state %d ", state);
+               print_int(PRINT_ANY, "state_index", "state %d ", state);
        else
-               fprintf(f, "state %s ", slave_states[state]);
+               print_string(PRINT_ANY,
+                            "state",
+                            "state %s ",
+                            slave_states[state]);
 }
 
 static const char *slave_mii_status[] = {
@@ -54,9 +57,15 @@ static void print_slave_mii_status(FILE *f, struct rtattr *tb)
        unsigned int status = rta_getattr_u8(tb);
 
        if (status >= ARRAY_SIZE(slave_mii_status))
-               fprintf(f, "mii_status %d ", status);
+               print_int(PRINT_ANY,
+                         "mii_status_index",
+                         "mii_status %d ",
+                         status);
        else
-               fprintf(f, "mii_status %s ", slave_mii_status[status]);
+               print_string(PRINT_ANY,
+                            "mii_status",
+                            "mii_status %s ",
+                            slave_mii_status[status]);
 }
 
 static void bond_slave_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
@@ -72,30 +81,42 @@ static void bond_slave_print_opt(struct link_util *lu, FILE *f, struct rtattr *t
                print_slave_mii_status(f, tb[IFLA_BOND_SLAVE_MII_STATUS]);
 
        if (tb[IFLA_BOND_SLAVE_LINK_FAILURE_COUNT])
-               fprintf(f, "link_failure_count %d ",
-                       rta_getattr_u32(tb[IFLA_BOND_SLAVE_LINK_FAILURE_COUNT]));
+               print_int(PRINT_ANY,
+                         "link_failure_count",
+                         "link_failure_count %d ",
+                         rta_getattr_u32(tb[IFLA_BOND_SLAVE_LINK_FAILURE_COUNT]));
 
        if (tb[IFLA_BOND_SLAVE_PERM_HWADDR])
-               fprintf(f, "perm_hwaddr %s ",
-                       ll_addr_n2a(RTA_DATA(tb[IFLA_BOND_SLAVE_PERM_HWADDR]),
-                                   RTA_PAYLOAD(tb[IFLA_BOND_SLAVE_PERM_HWADDR]),
-                                   0, b1, sizeof(b1)));
+               print_string(PRINT_ANY,
+                            "perm_hwaddr",
+                            "perm_hwaddr %s ",
+                            ll_addr_n2a(RTA_DATA(tb[IFLA_BOND_SLAVE_PERM_HWADDR]),
+                                        RTA_PAYLOAD(tb[IFLA_BOND_SLAVE_PERM_HWADDR]),
+                                        0, b1, sizeof(b1)));
 
        if (tb[IFLA_BOND_SLAVE_QUEUE_ID])
-               fprintf(f, "queue_id %d ",
-                       rta_getattr_u16(tb[IFLA_BOND_SLAVE_QUEUE_ID]));
+               print_int(PRINT_ANY,
+                         "queue_id",
+                         "queue_id %d ",
+                         rta_getattr_u16(tb[IFLA_BOND_SLAVE_QUEUE_ID]));
 
        if (tb[IFLA_BOND_SLAVE_AD_AGGREGATOR_ID])
-               fprintf(f, "ad_aggregator_id %d ",
-                       rta_getattr_u16(tb[IFLA_BOND_SLAVE_AD_AGGREGATOR_ID]));
+               print_int(PRINT_ANY,
+                         "ad_aggregator_id",
+                         "ad_aggregator_id %d ",
+                         rta_getattr_u16(tb[IFLA_BOND_SLAVE_AD_AGGREGATOR_ID]));
 
        if (tb[IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE])
-               fprintf(f, "ad_actor_oper_port_state %d ",
-                       rta_getattr_u8(tb[IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE]));
+               print_int(PRINT_ANY,
+                         "ad_actor_oper_port_state",
+                         "ad_actor_oper_port_state %d ",
+                         rta_getattr_u8(tb[IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE]));
 
        if (tb[IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE])
-               fprintf(f, "ad_partner_oper_port_state %d ",
-                       rta_getattr_u16(tb[IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE]));
+               print_int(PRINT_ANY,
+                         "ad_partner_oper_port_state",
+                         "ad_partner_oper_port_state %d ",
+                         rta_getattr_u16(tb[IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE]));
 }
 
 static int bond_slave_parse_opt(struct link_util *lu, int argc, char **argv,
index cccdec1c203a960c67b37294f1b8cd1b870d188a..d3250980c68d41a9ae661b322d8452597e48d6fd 100644 (file)
@@ -373,45 +373,81 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv,
        return 0;
 }
 
+static void _bridge_print_timer(FILE *f,
+                               const char *attr,
+                               struct rtattr *timer)
+{
+       struct timeval tv;
+
+       __jiffies_to_tv(&tv, rta_getattr_u64(timer));
+       if (is_json_context()) {
+               json_writer_t *jw = get_json_writer();
+
+               jsonw_name(jw, attr);
+               jsonw_printf(jw, "%i.%.2i",
+                            (int)tv.tv_sec,
+                            (int)tv.tv_usec / 10000);
+       } else {
+               fprintf(f, "%s %4i.%.2i ", attr, (int)tv.tv_sec,
+                       (int)tv.tv_usec / 10000);
+       }
+}
+
 static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
 {
        if (!tb)
                return;
 
        if (tb[IFLA_BR_FORWARD_DELAY])
-               fprintf(f, "forward_delay %u ",
-                       rta_getattr_u32(tb[IFLA_BR_FORWARD_DELAY]));
+               print_uint(PRINT_ANY,
+                          "forward_delay",
+                          "forward_delay %u ",
+                          rta_getattr_u32(tb[IFLA_BR_FORWARD_DELAY]));
 
        if (tb[IFLA_BR_HELLO_TIME])
-               fprintf(f, "hello_time %u ",
-                       rta_getattr_u32(tb[IFLA_BR_HELLO_TIME]));
+               print_uint(PRINT_ANY,
+                          "hello_time",
+                          "hello_time %u ",
+                          rta_getattr_u32(tb[IFLA_BR_HELLO_TIME]));
 
        if (tb[IFLA_BR_MAX_AGE])
-               fprintf(f, "max_age %u ",
-                       rta_getattr_u32(tb[IFLA_BR_MAX_AGE]));
+               print_uint(PRINT_ANY,
+                          "max_age",
+                          "max_age %u ",
+                          rta_getattr_u32(tb[IFLA_BR_MAX_AGE]));
 
        if (tb[IFLA_BR_AGEING_TIME])
-               fprintf(f, "ageing_time %u ",
-                       rta_getattr_u32(tb[IFLA_BR_AGEING_TIME]));
+               print_uint(PRINT_ANY,
+                          "ageing_time",
+                          "ageing_time %u ",
+                          rta_getattr_u32(tb[IFLA_BR_AGEING_TIME]));
 
        if (tb[IFLA_BR_STP_STATE])
-               fprintf(f, "stp_state %u ",
-                       rta_getattr_u32(tb[IFLA_BR_STP_STATE]));
+               print_uint(PRINT_ANY,
+                          "stp_state",
+                          "stp_state %u ",
+                          rta_getattr_u32(tb[IFLA_BR_STP_STATE]));
 
        if (tb[IFLA_BR_PRIORITY])
-               fprintf(f, "priority %u ",
-                       rta_getattr_u16(tb[IFLA_BR_PRIORITY]));
+               print_uint(PRINT_ANY,
+                          "priority",
+                          "priority %u ",
+                          rta_getattr_u16(tb[IFLA_BR_PRIORITY]));
 
        if (tb[IFLA_BR_VLAN_FILTERING])
-               fprintf(f, "vlan_filtering %u ",
-                       rta_getattr_u8(tb[IFLA_BR_VLAN_FILTERING]));
+               print_uint(PRINT_ANY,
+                          "vlan_filtering",
+                          "vlan_filtering %u ",
+                          rta_getattr_u8(tb[IFLA_BR_VLAN_FILTERING]));
 
        if (tb[IFLA_BR_VLAN_PROTOCOL]) {
                SPRINT_BUF(b1);
 
-               fprintf(f, "vlan_protocol %s ",
-                       ll_proto_n2a(rta_getattr_u16(tb[IFLA_BR_VLAN_PROTOCOL]),
-                                    b1, sizeof(b1)));
+               print_string(PRINT_ANY,
+                            "vlan_protocol",
+                            "vlan_protocol %s ",
+                            ll_proto_n2a(rta_getattr_u16(tb[IFLA_BR_VLAN_PROTOCOL]),
+                                         b1, sizeof(b1)));
        }
 
        if (tb[IFLA_BR_BRIDGE_ID]) {
@@ -419,7 +455,10 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
 
                br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), bridge_id,
                                  sizeof(bridge_id));
-               fprintf(f, "bridge_id %s ", bridge_id);
+               print_string(PRINT_ANY,
+                            "bridge_id",
+                            "bridge_id %s ",
+                            bridge_id);
        }
 
        if (tb[IFLA_BR_ROOT_ID]) {
@@ -427,163 +466,201 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
 
                br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), root_id,
                                  sizeof(root_id));
-               fprintf(f, "designated_root %s ", root_id);
+               print_string(PRINT_ANY,
+                            "root_id",
+                            "designated_root %s ",
+                            root_id);
        }
 
        if (tb[IFLA_BR_ROOT_PORT])
-               fprintf(f, "root_port %u ",
-                       rta_getattr_u16(tb[IFLA_BR_ROOT_PORT]));
+               print_uint(PRINT_ANY,
+                          "root_port",
+                          "root_port %u ",
+                          rta_getattr_u16(tb[IFLA_BR_ROOT_PORT]));
 
        if (tb[IFLA_BR_ROOT_PATH_COST])
-               fprintf(f, "root_path_cost %u ",
-                       rta_getattr_u32(tb[IFLA_BR_ROOT_PATH_COST]));
+               print_uint(PRINT_ANY,
+                          "root_path_cost",
+                          "root_path_cost %u ",
+                          rta_getattr_u32(tb[IFLA_BR_ROOT_PATH_COST]));
 
        if (tb[IFLA_BR_TOPOLOGY_CHANGE])
-               fprintf(f, "topology_change %u ",
-                       rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE]));
+               print_uint(PRINT_ANY,
+                          "topology_change",
+                          "topology_change %u ",
+                          rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE]));
 
        if (tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED])
-               fprintf(f, "topology_change_detected %u ",
-                       rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED]));
-
-       if (tb[IFLA_BR_HELLO_TIMER]) {
-               struct timeval tv;
-
-               __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_HELLO_TIMER]));
-               fprintf(f, "hello_timer %4i.%.2i ", (int)tv.tv_sec,
-                       (int)tv.tv_usec/10000);
-       }
-
-       if (tb[IFLA_BR_TCN_TIMER]) {
-               struct timeval tv;
-
-               __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_TCN_TIMER]));
-               fprintf(f, "tcn_timer %4i.%.2i ", (int)tv.tv_sec,
-                       (int)tv.tv_usec/10000);
-       }
+               print_uint(PRINT_ANY,
+                          "topology_change_detected",
+                          "topology_change_detected %u ",
+                          rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED]));
 
-       if (tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]) {
-               unsigned long jiffies;
-               struct timeval tv;
+       if (tb[IFLA_BR_HELLO_TIMER])
+               _bridge_print_timer(f, "hello_timer", tb[IFLA_BR_HELLO_TIMER]);
 
-               jiffies = rta_getattr_u64(tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]);
-               __jiffies_to_tv(&tv, jiffies);
-               fprintf(f, "topology_change_timer %4i.%.2i ", (int)tv.tv_sec,
-                       (int)tv.tv_usec/10000);
-       }
+       if (tb[IFLA_BR_TCN_TIMER])
+               _bridge_print_timer(f, "tcn_timer", tb[IFLA_BR_TCN_TIMER]);
 
-       if (tb[IFLA_BR_GC_TIMER]) {
-               struct timeval tv;
+       if (tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER])
+               _bridge_print_timer(f, "topology_change_timer",
+                                   tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]);
 
-               __jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_GC_TIMER]));
-               fprintf(f, "gc_timer %4i.%.2i ", (int)tv.tv_sec,
-                       (int)tv.tv_usec/10000);
-       }
+       if (tb[IFLA_BR_GC_TIMER])
+               _bridge_print_timer(f, "gc_timer", tb[IFLA_BR_GC_TIMER]);
 
        if (tb[IFLA_BR_VLAN_DEFAULT_PVID])
-               fprintf(f, "vlan_default_pvid %u ",
-                       rta_getattr_u16(tb[IFLA_BR_VLAN_DEFAULT_PVID]));
+               print_uint(PRINT_ANY,
+                          "vlan_default_pvid",
+                          "vlan_default_pvid %u ",
+                          rta_getattr_u16(tb[IFLA_BR_VLAN_DEFAULT_PVID]));
 
        if (tb[IFLA_BR_VLAN_STATS_ENABLED])
-               fprintf(f, "vlan_stats_enabled %u ",
-                       rta_getattr_u8(tb[IFLA_BR_VLAN_STATS_ENABLED]));
+               print_uint(PRINT_ANY,
+                          "vlan_stats_enabled",
+                          "vlan_stats_enabled %u ",
+                          rta_getattr_u8(tb[IFLA_BR_VLAN_STATS_ENABLED]));
 
        if (tb[IFLA_BR_GROUP_FWD_MASK])
-               fprintf(f, "group_fwd_mask %#x ",
-                       rta_getattr_u16(tb[IFLA_BR_GROUP_FWD_MASK]));
+               print_0xhex(PRINT_ANY,
+                           "group_fwd_mask",
+                           "group_fwd_mask %#x ",
+                           rta_getattr_u16(tb[IFLA_BR_GROUP_FWD_MASK]));
 
        if (tb[IFLA_BR_GROUP_ADDR]) {
                SPRINT_BUF(mac);
 
-               fprintf(f, "group_address %s ",
-                       ll_addr_n2a(RTA_DATA(tb[IFLA_BR_GROUP_ADDR]),
-                                   RTA_PAYLOAD(tb[IFLA_BR_GROUP_ADDR]),
-                                   1 /*ARPHDR_ETHER*/, mac, sizeof(mac)));
+               print_string(PRINT_ANY,
+                            "group_addr",
+                            "group_address %s ",
+                            ll_addr_n2a(RTA_DATA(tb[IFLA_BR_GROUP_ADDR]),
+                                        RTA_PAYLOAD(tb[IFLA_BR_GROUP_ADDR]),
+                                        1 /*ARPHDR_ETHER*/, mac, sizeof(mac)));
        }
 
        if (tb[IFLA_BR_MCAST_SNOOPING])
-               fprintf(f, "mcast_snooping %u ",
-                       rta_getattr_u8(tb[IFLA_BR_MCAST_SNOOPING]));
+               print_uint(PRINT_ANY,
+                          "mcast_snooping",
+                          "mcast_snooping %u ",
+                          rta_getattr_u8(tb[IFLA_BR_MCAST_SNOOPING]));
 
        if (tb[IFLA_BR_MCAST_ROUTER])
-               fprintf(f, "mcast_router %u ",
-                       rta_getattr_u8(tb[IFLA_BR_MCAST_ROUTER]));
+               print_uint(PRINT_ANY,
+                          "mcast_router",
+                          "mcast_router %u ",
+                          rta_getattr_u8(tb[IFLA_BR_MCAST_ROUTER]));
 
        if (tb[IFLA_BR_MCAST_QUERY_USE_IFADDR])
-               fprintf(f, "mcast_query_use_ifaddr %u ",
-                       rta_getattr_u8(tb[IFLA_BR_MCAST_QUERY_USE_IFADDR]));
+               print_uint(PRINT_ANY,
+                          "mcast_query_use_ifaddr",
+                          "mcast_query_use_ifaddr %u ",
+                          rta_getattr_u8(tb[IFLA_BR_MCAST_QUERY_USE_IFADDR]));
 
        if (tb[IFLA_BR_MCAST_QUERIER])
-               fprintf(f, "mcast_querier %u ",
-                       rta_getattr_u8(tb[IFLA_BR_MCAST_QUERIER]));
+               print_uint(PRINT_ANY,
+                          "mcast_querier",
+                          "mcast_querier %u ",
+                          rta_getattr_u8(tb[IFLA_BR_MCAST_QUERIER]));
 
        if (tb[IFLA_BR_MCAST_HASH_ELASTICITY])
-               fprintf(f, "mcast_hash_elasticity %u ",
-                       rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_ELASTICITY]));
+               print_uint(PRINT_ANY,
+                          "mcast_hash_elasticity",
+                          "mcast_hash_elasticity %u ",
+                          rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_ELASTICITY]));
 
        if (tb[IFLA_BR_MCAST_HASH_MAX])
-               fprintf(f, "mcast_hash_max %u ",
-                       rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_MAX]));
+               print_uint(PRINT_ANY,
+                          "mcast_hash_max",
+                          "mcast_hash_max %u ",
+                          rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_MAX]));
 
        if (tb[IFLA_BR_MCAST_LAST_MEMBER_CNT])
-               fprintf(f, "mcast_last_member_count %u ",
-                       rta_getattr_u32(tb[IFLA_BR_MCAST_LAST_MEMBER_CNT]));
+               print_uint(PRINT_ANY,
+                          "mcast_last_member_cnt",
+                          "mcast_last_member_count %u ",
+                          rta_getattr_u32(tb[IFLA_BR_MCAST_LAST_MEMBER_CNT]));
 
        if (tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT])
-               fprintf(f, "mcast_startup_query_count %u ",
-                       rta_getattr_u32(tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT]));
+               print_uint(PRINT_ANY,
+                          "mcast_startup_query_cnt",
+                          "mcast_startup_query_count %u ",
+                          rta_getattr_u32(tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT]));
 
        if (tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL])
-               fprintf(f, "mcast_last_member_interval %llu ",
-                       rta_getattr_u64(tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL]));
+               print_lluint(PRINT_ANY,
+                            "mcast_last_member_intvl",
+                            "mcast_last_member_interval %llu ",
+                            rta_getattr_u64(tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL]));
 
        if (tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL])
-               fprintf(f, "mcast_membership_interval %llu ",
-                       rta_getattr_u64(tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL]));
+               print_lluint(PRINT_ANY,
+                            "mcast_membership_intvl",
+                            "mcast_membership_interval %llu ",
+                            rta_getattr_u64(tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL]));
 
        if (tb[IFLA_BR_MCAST_QUERIER_INTVL])
-               fprintf(f, "mcast_querier_interval %llu ",
-                       rta_getattr_u64(tb[IFLA_BR_MCAST_QUERIER_INTVL]));
+               print_lluint(PRINT_ANY,
+                            "mcast_querier_intvl",
+                            "mcast_querier_interval %llu ",
+                            rta_getattr_u64(tb[IFLA_BR_MCAST_QUERIER_INTVL]));
 
        if (tb[IFLA_BR_MCAST_QUERY_INTVL])
-               fprintf(f, "mcast_query_interval %llu ",
-                       rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_INTVL]));
+               print_lluint(PRINT_ANY,
+                            "mcast_query_intvl",
+                            "mcast_query_interval %llu ",
+                            rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_INTVL]));
 
        if (tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL])
-               fprintf(f, "mcast_query_response_interval %llu ",
-                       rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]));
+               print_lluint(PRINT_ANY,
+                            "mcast_query_response_intvl",
+                            "mcast_query_response_interval %llu ",
+                            rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]));
 
        if (tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL])
-               fprintf(f, "mcast_startup_query_interval %llu ",
-                       rta_getattr_u64(tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]));
+               print_lluint(PRINT_ANY,
+                            "mcast_startup_query_intvl",
+                            "mcast_startup_query_interval %llu ",
+                            rta_getattr_u64(tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]));
 
        if (tb[IFLA_BR_MCAST_STATS_ENABLED])
-               fprintf(f, "mcast_stats_enabled %u ",
-                       rta_getattr_u8(tb[IFLA_BR_MCAST_STATS_ENABLED]));
+               print_uint(PRINT_ANY,
+                          "mcast_stats_enabled",
+                          "mcast_stats_enabled %u ",
+                          rta_getattr_u8(tb[IFLA_BR_MCAST_STATS_ENABLED]));
 
        if (tb[IFLA_BR_MCAST_IGMP_VERSION])
-               fprintf(f, "mcast_igmp_version %u ",
-                       rta_getattr_u8(tb[IFLA_BR_MCAST_IGMP_VERSION]));
+               print_uint(PRINT_ANY,
+                          "mcast_igmp_version",
+                          "mcast_igmp_version %u ",
+                          rta_getattr_u8(tb[IFLA_BR_MCAST_IGMP_VERSION]));
 
        if (tb[IFLA_BR_MCAST_MLD_VERSION])
-               fprintf(f, "mcast_mld_version %u ",
-                       rta_getattr_u8(tb[IFLA_BR_MCAST_MLD_VERSION]));
+               print_uint(PRINT_ANY,
+                          "mcast_mld_version",
+                          "mcast_mld_version %u ",
+                          rta_getattr_u8(tb[IFLA_BR_MCAST_MLD_VERSION]));
 
        if (tb[IFLA_BR_NF_CALL_IPTABLES])
-               fprintf(f, "nf_call_iptables %u ",
-                       rta_getattr_u8(tb[IFLA_BR_NF_CALL_IPTABLES]));
+               print_uint(PRINT_ANY,
+                          "nf_call_iptables",
+                          "nf_call_iptables %u ",
+                          rta_getattr_u8(tb[IFLA_BR_NF_CALL_IPTABLES]));
 
        if (tb[IFLA_BR_NF_CALL_IP6TABLES])
-               fprintf(f, "nf_call_ip6tables %u ",
-                       rta_getattr_u8(tb[IFLA_BR_NF_CALL_IP6TABLES]));
+               print_uint(PRINT_ANY,
+                          "nf_call_ip6tables",
+                          "nf_call_ip6tables %u ",
+                          rta_getattr_u8(tb[IFLA_BR_NF_CALL_IP6TABLES]));
 
        if (tb[IFLA_BR_NF_CALL_ARPTABLES])
-               fprintf(f, "nf_call_arptables %u ",
-                       rta_getattr_u8(tb[IFLA_BR_NF_CALL_ARPTABLES]));
+               print_uint(PRINT_ANY,
+                          "nf_call_arptables",
+                          "nf_call_arptables %u ",
+                          rta_getattr_u8(tb[IFLA_BR_NF_CALL_ARPTABLES]));
 }
 
 static void bridge_print_help(struct link_util *lu, int argc, char **argv,
-               FILE *f)
+                             FILE *f)
 {
        print_explain(f);
 }
index 3e883328ae0cc232e8f1910ecbc2af15129353b9..80272b0941104dbfaca01e8a0457b60231d6de88 100644 (file)
@@ -56,14 +56,52 @@ static const char *port_states[] = {
 static void print_portstate(FILE *f, __u8 state)
 {
        if (state <= BR_STATE_BLOCKING)
-               fprintf(f, "state %s ", port_states[state]);
+               print_string(PRINT_ANY,
+                            "state",
+                            "state %s ",
+                            port_states[state]);
        else
-               fprintf(f, "state (%d) ", state);
+               print_int(PRINT_ANY, "state_index", "state (%d) ", state);
 }
 
-static void print_onoff(FILE *f, char *flag, __u8 val)
+static void _print_onoff(FILE *f, char *json_flag, char *flag, __u8 val)
 {
-       fprintf(f, "%s %s ", flag, val ? "on" : "off");
+       if (is_json_context())
+               print_bool(PRINT_JSON, flag, NULL, val);
+       else
+               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;
+
+       __jiffies_to_tv(&tv, rta_getattr_u64(timer));
+       if (is_json_context()) {
+               json_writer_t *jw = get_json_writer();
+
+               jsonw_name(jw, attr);
+               jsonw_printf(jw, "%i.%.2i",
+                            (int)tv.tv_sec, (int)tv.tv_usec / 10000);
+       } else {
+               fprintf(f, "%s %4i.%.2i ", attr, (int)tv.tv_sec,
+                       (int)tv.tv_usec / 10000);
+       }
 }
 
 static void bridge_slave_print_opt(struct link_util *lu, FILE *f,
@@ -76,59 +114,70 @@ static void bridge_slave_print_opt(struct link_util *lu, FILE *f,
                print_portstate(f, rta_getattr_u8(tb[IFLA_BRPORT_STATE]));
 
        if (tb[IFLA_BRPORT_PRIORITY])
-               fprintf(f, "priority %d ",
-                       rta_getattr_u16(tb[IFLA_BRPORT_PRIORITY]));
+               print_int(PRINT_ANY,
+                         "priority",
+                         "priority %d ",
+                         rta_getattr_u16(tb[IFLA_BRPORT_PRIORITY]));
 
        if (tb[IFLA_BRPORT_COST])
-               fprintf(f, "cost %d ",
-                       rta_getattr_u32(tb[IFLA_BRPORT_COST]));
+               print_int(PRINT_ANY,
+                         "cost",
+                         "cost %d ",
+                         rta_getattr_u32(tb[IFLA_BRPORT_COST]));
 
        if (tb[IFLA_BRPORT_MODE])
-               print_onoff(f, "hairpin",
-                           rta_getattr_u8(tb[IFLA_BRPORT_MODE]));
+               _print_onoff(f, "mode", "hairpin",
+                            rta_getattr_u8(tb[IFLA_BRPORT_MODE]));
 
        if (tb[IFLA_BRPORT_GUARD])
-               print_onoff(f, "guard",
-                           rta_getattr_u8(tb[IFLA_BRPORT_GUARD]));
+               _print_onoff(f, "guard", "guard",
+                            rta_getattr_u8(tb[IFLA_BRPORT_GUARD]));
 
        if (tb[IFLA_BRPORT_PROTECT])
-               print_onoff(f, "root_block",
-                           rta_getattr_u8(tb[IFLA_BRPORT_PROTECT]));
+               _print_onoff(f, "protect", "root_block",
+                            rta_getattr_u8(tb[IFLA_BRPORT_PROTECT]));
 
        if (tb[IFLA_BRPORT_FAST_LEAVE])
-               print_onoff(f, "fastleave",
-                           rta_getattr_u8(tb[IFLA_BRPORT_FAST_LEAVE]));
+               _print_onoff(f, "fast_leave", "fastleave",
+                            rta_getattr_u8(tb[IFLA_BRPORT_FAST_LEAVE]));
 
        if (tb[IFLA_BRPORT_LEARNING])
-               print_onoff(f, "learning",
-                       rta_getattr_u8(tb[IFLA_BRPORT_LEARNING]));
+               _print_onoff(f, "learning", "learning",
+                            rta_getattr_u8(tb[IFLA_BRPORT_LEARNING]));
 
        if (tb[IFLA_BRPORT_UNICAST_FLOOD])
-               print_onoff(f, "flood",
-                       rta_getattr_u8(tb[IFLA_BRPORT_UNICAST_FLOOD]));
+               _print_onoff(f, "unicast_flood", "flood",
+                            rta_getattr_u8(tb[IFLA_BRPORT_UNICAST_FLOOD]));
 
        if (tb[IFLA_BRPORT_ID])
-               fprintf(f, "port_id 0x%x ",
-                       rta_getattr_u16(tb[IFLA_BRPORT_ID]));
+               _print_hex(f, "id", "port_id",
+                          rta_getattr_u16(tb[IFLA_BRPORT_ID]));
 
        if (tb[IFLA_BRPORT_NO])
-               fprintf(f, "port_no 0x%x ",
-                       rta_getattr_u16(tb[IFLA_BRPORT_NO]));
+               _print_hex(f, "no", "port_no",
+                          rta_getattr_u16(tb[IFLA_BRPORT_NO]));
 
        if (tb[IFLA_BRPORT_DESIGNATED_PORT])
-               fprintf(f, "designated_port %u ",
-                       rta_getattr_u16(tb[IFLA_BRPORT_DESIGNATED_PORT]));
+               print_uint(PRINT_ANY,
+                          "designated_port",
+                          "designated_port %u ",
+                          rta_getattr_u16(tb[IFLA_BRPORT_DESIGNATED_PORT]));
 
        if (tb[IFLA_BRPORT_DESIGNATED_COST])
-               fprintf(f, "designated_cost %u ",
-                       rta_getattr_u16(tb[IFLA_BRPORT_DESIGNATED_COST]));
+               print_uint(PRINT_ANY,
+                          "designated_cost",
+                          "designated_cost %u ",
+                          rta_getattr_u16(tb[IFLA_BRPORT_DESIGNATED_COST]));
 
        if (tb[IFLA_BRPORT_BRIDGE_ID]) {
                char bridge_id[32];
 
                br_dump_bridge_id(RTA_DATA(tb[IFLA_BRPORT_BRIDGE_ID]),
                                  bridge_id, sizeof(bridge_id));
-               fprintf(f, "designated_bridge %s ", bridge_id);
+               print_string(PRINT_ANY,
+                            "bridge_id",
+                            "designated_bridge %s ",
+                            bridge_id);
        }
 
        if (tb[IFLA_BRPORT_ROOT_ID]) {
@@ -136,65 +185,59 @@ static void bridge_slave_print_opt(struct link_util *lu, FILE *f,
 
                br_dump_bridge_id(RTA_DATA(tb[IFLA_BRPORT_ROOT_ID]),
                                  root_id, sizeof(root_id));
-               fprintf(f, "designated_root %s ", root_id);
-       }
-
-       if (tb[IFLA_BRPORT_HOLD_TIMER]) {
-               struct timeval tv;
-               __u64 htimer;
-
-               htimer = rta_getattr_u64(tb[IFLA_BRPORT_HOLD_TIMER]);
-               __jiffies_to_tv(&tv, htimer);
-               fprintf(f, "hold_timer %4i.%.2i ", (int)tv.tv_sec,
-                       (int)tv.tv_usec/10000);
+               print_string(PRINT_ANY,
+                            "root_id",
+                            "designated_root %s ", root_id);
        }
 
-       if (tb[IFLA_BRPORT_MESSAGE_AGE_TIMER]) {
-               struct timeval tv;
-               __u64 agetimer;
+       if (tb[IFLA_BRPORT_HOLD_TIMER])
+               _print_timer(f, "hold_timer", tb[IFLA_BRPORT_HOLD_TIMER]);
 
-               agetimer = rta_getattr_u64(tb[IFLA_BRPORT_MESSAGE_AGE_TIMER]);
-               __jiffies_to_tv(&tv, agetimer);
-               fprintf(f, "message_age_timer %4i.%.2i ", (int)tv.tv_sec,
-                       (int)tv.tv_usec/10000);
-       }
-
-       if (tb[IFLA_BRPORT_FORWARD_DELAY_TIMER]) {
-               struct timeval tv;
-               __u64 fwdtimer;
+       if (tb[IFLA_BRPORT_MESSAGE_AGE_TIMER])
+               _print_timer(f, "message_age_timer",
+                            tb[IFLA_BRPORT_MESSAGE_AGE_TIMER]);
 
-               fwdtimer = rta_getattr_u64(tb[IFLA_BRPORT_FORWARD_DELAY_TIMER]);
-               __jiffies_to_tv(&tv, fwdtimer);
-               fprintf(f, "forward_delay_timer %4i.%.2i ", (int)tv.tv_sec,
-                       (int)tv.tv_usec/10000);
-       }
+       if (tb[IFLA_BRPORT_FORWARD_DELAY_TIMER])
+               _print_timer(f, "forward_delay_timer",
+                            tb[IFLA_BRPORT_FORWARD_DELAY_TIMER]);
 
        if (tb[IFLA_BRPORT_TOPOLOGY_CHANGE_ACK])
-               fprintf(f, "topology_change_ack %u ",
-                       rta_getattr_u8(tb[IFLA_BRPORT_TOPOLOGY_CHANGE_ACK]));
+               print_uint(PRINT_ANY,
+                          "topology_change_ack",
+                          "topology_change_ack %u ",
+                          rta_getattr_u8(tb[IFLA_BRPORT_TOPOLOGY_CHANGE_ACK]));
 
        if (tb[IFLA_BRPORT_CONFIG_PENDING])
-               fprintf(f, "config_pending %u ",
-                       rta_getattr_u8(tb[IFLA_BRPORT_CONFIG_PENDING]));
+               print_uint(PRINT_ANY,
+                          "config_pending",
+                          "config_pending %u ",
+                          rta_getattr_u8(tb[IFLA_BRPORT_CONFIG_PENDING]));
+
        if (tb[IFLA_BRPORT_PROXYARP])
-               print_onoff(f, "proxy_arp",
-                           rta_getattr_u8(tb[IFLA_BRPORT_PROXYARP]));
+               _print_onoff(f, "proxyarp", "proxy_arp",
+                            rta_getattr_u8(tb[IFLA_BRPORT_PROXYARP]));
 
        if (tb[IFLA_BRPORT_PROXYARP_WIFI])
-               print_onoff(f, "proxy_arp_wifi",
-                           rta_getattr_u8(tb[IFLA_BRPORT_PROXYARP_WIFI]));
+               _print_onoff(f, "proxyarp_wifi", "proxy_arp_wifi",
+                            rta_getattr_u8(tb[IFLA_BRPORT_PROXYARP_WIFI]));
 
        if (tb[IFLA_BRPORT_MULTICAST_ROUTER])
-               fprintf(f, "mcast_router %u ",
-                       rta_getattr_u8(tb[IFLA_BRPORT_MULTICAST_ROUTER]));
+               print_uint(PRINT_ANY,
+                          "multicast_router",
+                          "mcast_router %u ",
+                          rta_getattr_u8(tb[IFLA_BRPORT_MULTICAST_ROUTER]));
 
        if (tb[IFLA_BRPORT_FAST_LEAVE])
-               print_onoff(f, "mcast_fast_leave",
-                           rta_getattr_u8(tb[IFLA_BRPORT_FAST_LEAVE]));
+               // not printing any json here because
+               // we already printed fast_leave before
+               print_string(PRINT_FP,
+                            NULL,
+                            "mcast_fast_leave %s ",
+                            rta_getattr_u8(tb[IFLA_BRPORT_FAST_LEAVE]) ? "on" : "off");
 
        if (tb[IFLA_BRPORT_MCAST_FLOOD])
-               print_onoff(f, "mcast_flood",
-                       rta_getattr_u8(tb[IFLA_BRPORT_MCAST_FLOOD]));
+               _print_onoff(f, "mcast_flood", "mcast_flood",
+                            rta_getattr_u8(tb[IFLA_BRPORT_MCAST_FLOOD]));
 }
 
 static void bridge_slave_parse_on_off(char *arg_name, char *arg_val,
index 5df56b2bbbb3be7a0a637dc134e596134b8dc4c9..f415558a9b3962823050cc65f627506c56944a9f 100644 (file)
@@ -89,11 +89,11 @@ static void set_ctrlmode(char *name, char *arg,
 
 static void print_ctrlmode(FILE *f, __u32 cm)
 {
-       fprintf(f, "<");
-#define _PF(cmflag, cmname)                                    \
-       if (cm & cmflag) {                                      \
-               cm &= ~cmflag;                                  \
-               fprintf(f, "%s%s", cmname, cm ? "," : "");      \
+       open_json_array(PRINT_ANY, is_json_context() ? "ctrlmode" : "<");
+#define _PF(cmflag, cmname)                                            \
+       if (cm & cmflag) {                                              \
+               cm &= ~cmflag;                                          \
+               print_string(PRINT_ANY, NULL, cm ? "%s," : "%s", cmname); \
        }
        _PF(CAN_CTRLMODE_LOOPBACK, "LOOPBACK");
        _PF(CAN_CTRLMODE_LISTENONLY, "LISTEN-ONLY");
@@ -105,8 +105,8 @@ static void print_ctrlmode(FILE *f, __u32 cm)
        _PF(CAN_CTRLMODE_PRESUME_ACK, "PRESUME-ACK");
 #undef _PF
        if (cm)
-               fprintf(f, "%x", cm);
-       fprintf(f, "> ");
+               print_hex(PRINT_ANY, NULL, "%x", cm);
+       close_json_array(PRINT_ANY, "> ");
 }
 
 static int can_parse_opt(struct link_util *lu, int argc, char **argv,
@@ -260,6 +260,14 @@ static const char *can_state_names[] = {
        [CAN_STATE_SLEEPING] = "SLEEPING"
 };
 
+static void can_print_json_timing_min_max(const char *attr, int min, int max)
+{
+       open_json_object(attr);
+       print_int(PRINT_JSON, "min", NULL, min);
+       print_int(PRINT_JSON, "max", NULL, max);
+       close_json_object();
+}
+
 static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
 {
        if (!tb)
@@ -275,32 +283,64 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
        if (tb[IFLA_CAN_STATE]) {
                uint32_t state = rta_getattr_u32(tb[IFLA_CAN_STATE]);
 
-               fprintf(f, "state %s ", state <= CAN_STATE_MAX ?
-                       can_state_names[state] : "UNKNOWN");
+               if (state <= CAN_STATE_MAX)
+                       print_string(PRINT_ANY, "state", "state %s ",
+                                    can_state_names[state]);
+               else
+                       print_null(PRINT_ANY, "state", "state UNKNOWN", NULL);
        }
 
        if (tb[IFLA_CAN_BERR_COUNTER]) {
                struct can_berr_counter *bc =
                        RTA_DATA(tb[IFLA_CAN_BERR_COUNTER]);
 
-               fprintf(f, "(berr-counter tx %d rx %d) ", bc->txerr, bc->rxerr);
+               if (is_json_context()) {
+                       open_json_object("berr_counter");
+                       print_int(PRINT_JSON, "tx", NULL, bc->txerr);
+                       print_int(PRINT_JSON, "rx", NULL, bc->rxerr);
+                       close_json_object();
+               } else {
+                       fprintf(f, "(berr-counter tx %d rx %d) ",
+                               bc->txerr, bc->rxerr);
+               }
        }
 
        if (tb[IFLA_CAN_RESTART_MS]) {
                __u32 *restart_ms = RTA_DATA(tb[IFLA_CAN_RESTART_MS]);
 
-               fprintf(f, "restart-ms %d ", *restart_ms);
+               print_int(PRINT_ANY,
+                         "restart_ms",
+                         "restart-ms %d ",
+                         *restart_ms);
        }
 
        /* bittiming is irrelevant if fixed bitrate is defined */
        if (tb[IFLA_CAN_BITTIMING] && !tb[IFLA_CAN_BITRATE_CONST]) {
                struct can_bittiming *bt = RTA_DATA(tb[IFLA_CAN_BITTIMING]);
 
-               fprintf(f, "\n    bitrate %d sample-point %.3f ",
-                       bt->bitrate, (float)bt->sample_point / 1000.);
-               fprintf(f, "\n    tq %d prop-seg %d phase-seg1 %d phase-seg2 %d sjw %d",
-                       bt->tq, bt->prop_seg, bt->phase_seg1, bt->phase_seg2,
-                       bt->sjw);
+               if (is_json_context()) {
+                       open_json_object("bittiming");
+                       print_int(PRINT_ANY, "bitrate", NULL, bt->bitrate);
+                       jsonw_float_field_fmt(get_json_writer(),
+                                             "sample_point", "%.3f",
+                                             (float) bt->sample_point / 1000.);
+                       print_int(PRINT_ANY, "tq", NULL, bt->tq);
+                       print_int(PRINT_ANY, "prop_seg", NULL, bt->prop_seg);
+                       print_int(PRINT_ANY, "phase_seg1",
+                                 NULL, bt->phase_seg1);
+                       print_int(PRINT_ANY, "phase_seg2",
+                                 NULL, bt->phase_seg2);
+                       print_int(PRINT_ANY, "sjw", NULL, bt->sjw);
+                       close_json_object();
+               } else {
+                       fprintf(f, "\n    bitrate %d sample-point %.3f ",
+                               bt->bitrate, (float) bt->sample_point / 1000.);
+                       fprintf(f,
+                               "\n       tq %d prop-seg %d phase-seg1 %d phase-seg2 %d sjw %d",
+                               bt->tq, bt->prop_seg,
+                               bt->phase_seg1, bt->phase_seg2,
+                               bt->sjw);
+               }
        }
 
        /* bittiming const is irrelevant if fixed bitrate is defined */
@@ -308,40 +348,68 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                struct can_bittiming_const *btc =
                        RTA_DATA(tb[IFLA_CAN_BITTIMING_CONST]);
 
-               fprintf(f, "\n    %s: tseg1 %d..%d tseg2 %d..%d "
-                       "sjw 1..%d brp %d..%d brp-inc %d",
-                       btc->name, btc->tseg1_min, btc->tseg1_max,
-                       btc->tseg2_min, btc->tseg2_max, btc->sjw_max,
-                       btc->brp_min, btc->brp_max, btc->brp_inc);
+               if (is_json_context()) {
+                       open_json_object("bittiming_const");
+                       print_string(PRINT_JSON, "name", NULL, btc->name);
+                       can_print_json_timing_min_max("tseg1",
+                                                     btc->tseg1_min,
+                                                     btc->tseg1_max);
+                       can_print_json_timing_min_max("tseg2",
+                                                     btc->tseg2_min,
+                                                     btc->tseg2_max);
+                       can_print_json_timing_min_max("sjw", 1, btc->sjw_max);
+                       can_print_json_timing_min_max("brp",
+                                                     btc->brp_min,
+                                                     btc->brp_max);
+                       print_int(PRINT_JSON, "brp_inc", NULL, btc->brp_inc);
+                       close_json_object();
+               } else {
+                       fprintf(f, "\n    %s: tseg1 %d..%d tseg2 %d..%d "
+                               "sjw 1..%d brp %d..%d brp-inc %d",
+                               btc->name, btc->tseg1_min, btc->tseg1_max,
+                               btc->tseg2_min, btc->tseg2_max, btc->sjw_max,
+                               btc->brp_min, btc->brp_max, btc->brp_inc);
+               }
        }
 
        if (tb[IFLA_CAN_BITRATE_CONST]) {
                __u32 *bitrate_const = RTA_DATA(tb[IFLA_CAN_BITRATE_CONST]);
                int bitrate_cnt = RTA_PAYLOAD(tb[IFLA_CAN_BITRATE_CONST]) /
-                                 sizeof(*bitrate_const);
+                       sizeof(*bitrate_const);
                int i;
                __u32 bitrate = 0;
 
                if (tb[IFLA_CAN_BITTIMING]) {
                        struct can_bittiming *bt =
-                           RTA_DATA(tb[IFLA_CAN_BITTIMING]);
+                               RTA_DATA(tb[IFLA_CAN_BITTIMING]);
                        bitrate = bt->bitrate;
                }
 
-               fprintf(f, "\n    bitrate %u", bitrate);
-               fprintf(f, "\n       [");
+               if (is_json_context()) {
+                       print_uint(PRINT_JSON,
+                                  "bittiming_bitrate",
+                                  NULL, bitrate);
+                       open_json_array(PRINT_JSON, "bitrate_const");
+                       for (i = 0; i < bitrate_cnt; ++i)
+                               print_uint(PRINT_JSON, NULL, NULL,
+                                          bitrate_const[i]);
+                       close_json_array(PRINT_JSON, NULL);
+               } else {
+                       fprintf(f, "\n    bitrate %u", bitrate);
+                       fprintf(f, "\n       [");
+
+                       for (i = 0; i < bitrate_cnt - 1; ++i) {
+                               /* This will keep lines below 80 signs */
+                               if (!(i % 6) && i)
+                                       fprintf(f, "\n        ");
+
+                               fprintf(f, "%8u, ", bitrate_const[i]);
+                       }
 
-               for (i = 0; i < bitrate_cnt - 1; ++i) {
-                       /* This will keep lines below 80 signs */
                        if (!(i % 6) && i)
                                fprintf(f, "\n        ");
-
-                       fprintf(f, "%8u, ", bitrate_const[i]);
+                       fprintf(f, "%8u ]", bitrate_const[i]);
                }
-
-               if (!(i % 6) && i)
-                       fprintf(f, "\n        ");
-               fprintf(f, "%8u ]", bitrate_const[i]);
        }
 
        /* data bittiming is irrelevant if fixed bitrate is defined */
@@ -349,12 +417,30 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                struct can_bittiming *dbt =
                        RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING]);
 
-               fprintf(f, "\n    dbitrate %d dsample-point %.3f ",
-                       dbt->bitrate, (float)dbt->sample_point / 1000.);
-               fprintf(f, "\n    dtq %d dprop-seg %d dphase-seg1 %d "
-                       "dphase-seg2 %d dsjw %d",
-                       dbt->tq, dbt->prop_seg, dbt->phase_seg1,
-                       dbt->phase_seg2, dbt->sjw);
+               if (is_json_context()) {
+                       open_json_object("data_bittiming");
+                       print_int(PRINT_JSON, "bitrate", NULL, dbt->bitrate);
+                       jsonw_float_field_fmt(get_json_writer(),
+                                             "sample_point",
+                                             "%.3f",
+                                             (float) dbt->sample_point / 1000.);
+                       print_int(PRINT_JSON, "tq", NULL, dbt->tq);
+                       print_int(PRINT_JSON, "prop_seg", NULL, dbt->prop_seg);
+                       print_int(PRINT_JSON, "phase_seg1",
+                                 NULL, dbt->phase_seg1);
+                       print_int(PRINT_JSON, "phase_seg2",
+                                 NULL, dbt->phase_seg2);
+                       print_int(PRINT_JSON, "sjw", NULL, dbt->sjw);
+                       close_json_object();
+               } else {
+                       fprintf(f, "\n    dbitrate %d dsample-point %.3f ",
+                               dbt->bitrate,
+                               (float) dbt->sample_point / 1000.);
+                       fprintf(f, "\n    dtq %d dprop-seg %d dphase-seg1 %d "
+                               "dphase-seg2 %d dsjw %d",
+                               dbt->tq, dbt->prop_seg, dbt->phase_seg1,
+                               dbt->phase_seg2, dbt->sjw);
+               }
        }
 
        /* data bittiming const is irrelevant if fixed bitrate is defined */
@@ -363,63 +449,102 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                struct can_bittiming_const *dbtc =
                        RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING_CONST]);
 
-               fprintf(f, "\n    %s: dtseg1 %d..%d dtseg2 %d..%d "
-                       "dsjw 1..%d dbrp %d..%d dbrp-inc %d",
-                       dbtc->name, dbtc->tseg1_min, dbtc->tseg1_max,
-                       dbtc->tseg2_min, dbtc->tseg2_max, dbtc->sjw_max,
-                       dbtc->brp_min, dbtc->brp_max, dbtc->brp_inc);
+               if (is_json_context()) {
+                       open_json_object("data_bittiming_const");
+                       print_string(PRINT_JSON, "name", NULL, dbtc->name);
+                       can_print_json_timing_min_max("tseg1",
+                                                     dbtc->tseg1_min,
+                                                     dbtc->tseg1_max);
+                       can_print_json_timing_min_max("tseg2",
+                                                     dbtc->tseg2_min,
+                                                     dbtc->tseg2_max);
+                       can_print_json_timing_min_max("sjw", 1, dbtc->sjw_max);
+                       can_print_json_timing_min_max("brp",
+                                                     dbtc->brp_min,
+                                                     dbtc->brp_max);
+
+                       print_int(PRINT_JSON, "brp_inc", NULL, dbtc->brp_inc);
+                       close_json_object();
+               } else {
+                       fprintf(f, "\n    %s: dtseg1 %d..%d dtseg2 %d..%d "
+                               "dsjw 1..%d dbrp %d..%d dbrp-inc %d",
+                               dbtc->name, dbtc->tseg1_min, dbtc->tseg1_max,
+                               dbtc->tseg2_min, dbtc->tseg2_max, dbtc->sjw_max,
+                               dbtc->brp_min, dbtc->brp_max, dbtc->brp_inc);
+               }
        }
 
        if (tb[IFLA_CAN_DATA_BITRATE_CONST]) {
                __u32 *dbitrate_const =
-                   RTA_DATA(tb[IFLA_CAN_DATA_BITRATE_CONST]);
+                       RTA_DATA(tb[IFLA_CAN_DATA_BITRATE_CONST]);
                int dbitrate_cnt =
-                   RTA_PAYLOAD(tb[IFLA_CAN_DATA_BITRATE_CONST]) /
-                   sizeof(*dbitrate_const);
+                       RTA_PAYLOAD(tb[IFLA_CAN_DATA_BITRATE_CONST]) /
+                       sizeof(*dbitrate_const);
                int i;
                __u32 dbitrate = 0;
 
                if (tb[IFLA_CAN_DATA_BITTIMING]) {
                        struct can_bittiming *dbt =
-                           RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING]);
+                               RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING]);
                        dbitrate = dbt->bitrate;
                }
 
-               fprintf(f, "\n    dbitrate %u", dbitrate);
-               fprintf(f, "\n       [");
+               if (is_json_context()) {
+                       print_uint(PRINT_JSON, "data_bittiming_bitrate",
+                                  NULL, dbitrate);
+                       open_json_array(PRINT_JSON, "data_bitrate_const");
+                       for (i = 0; i < dbitrate_cnt; ++i)
+                               print_uint(PRINT_JSON, NULL, NULL,
+                                          dbitrate_const[i]);
+                       close_json_array(PRINT_JSON, NULL);
+               } else {
+                       fprintf(f, "\n    dbitrate %u", dbitrate);
+                       fprintf(f, "\n       [");
+
+                       for (i = 0; i < dbitrate_cnt - 1; ++i) {
+                               /* This will keep lines below 80 signs */
+                               if (!(i % 6) && i)
+                                       fprintf(f, "\n        ");
+
+                               fprintf(f, "%8u, ", dbitrate_const[i]);
+                       }
 
-               for (i = 0; i < dbitrate_cnt - 1; ++i) {
-                       /* This will keep lines below 80 signs */
                        if (!(i % 6) && i)
                                fprintf(f, "\n        ");
-
-                       fprintf(f, "%8u, ", dbitrate_const[i]);
+                       fprintf(f, "%8u ]", dbitrate_const[i]);
                }
-
-               if (!(i % 6) && i)
-                       fprintf(f, "\n        ");
-               fprintf(f, "%8u ]", dbitrate_const[i]);
        }
 
        if (tb[IFLA_CAN_TERMINATION_CONST] && tb[IFLA_CAN_TERMINATION]) {
                __u16 *trm = RTA_DATA(tb[IFLA_CAN_TERMINATION]);
                __u16 *trm_const = RTA_DATA(tb[IFLA_CAN_TERMINATION_CONST]);
                int trm_cnt = RTA_PAYLOAD(tb[IFLA_CAN_TERMINATION_CONST]) /
-                             sizeof(*trm_const);
+                       sizeof(*trm_const);
                int i;
 
-               fprintf(f, "\n    termination %hu [ ", *trm);
+               if (is_json_context()) {
+                       print_hu(PRINT_JSON, "termination", NULL, *trm);
+                       open_json_array(PRINT_JSON, "termination_const");
+                       for (i = 0; i < trm_cnt; ++i)
+                               print_hu(PRINT_JSON, NULL, NULL, trm_const[i]);
+                       close_json_array(PRINT_JSON, NULL);
+               } else {
+                       fprintf(f, "\n    termination %hu [ ", *trm);
 
-               for (i = 0; i < trm_cnt - 1; ++i)
-                       fprintf(f, "%hu, ", trm_const[i]);
+                       for (i = 0; i < trm_cnt - 1; ++i)
+                               fprintf(f, "%hu, ", trm_const[i]);
 
-               fprintf(f, "%hu ]", trm_const[i]);
+                       fprintf(f, "%hu ]", trm_const[i]);
+               }
        }
 
        if (tb[IFLA_CAN_CLOCK]) {
                struct can_clock *clock = RTA_DATA(tb[IFLA_CAN_CLOCK]);
 
-               fprintf(f, "\n    clock %d", clock->freq);
+               print_int(PRINT_ANY,
+                         "clock",
+                         "\n     clock %d",
+                         clock->freq);
        }
 
 }
@@ -431,17 +556,32 @@ static void can_print_xstats(struct link_util *lu,
 
        if (xstats && RTA_PAYLOAD(xstats) == sizeof(*stats)) {
                stats = RTA_DATA(xstats);
-               fprintf(f, "\n    re-started bus-errors arbit-lost "
-                       "error-warn error-pass bus-off");
-               fprintf(f, "\n    %-10d %-10d %-10d %-10d %-10d %-10d",
-                       stats->restarts, stats->bus_error,
-                       stats->arbitration_lost, stats->error_warning,
-                       stats->error_passive, stats->bus_off);
+
+               if (is_json_context()) {
+                       print_int(PRINT_JSON, "restarts",
+                                 NULL, stats->restarts);
+                       print_int(PRINT_JSON, "bus_error",
+                                 NULL, stats->bus_error);
+                       print_int(PRINT_JSON, "arbitration_lost",
+                                 NULL, stats->arbitration_lost);
+                       print_int(PRINT_JSON, "error_warning",
+                                 NULL, stats->error_warning);
+                       print_int(PRINT_JSON, "error_passive",
+                                 NULL, stats->error_passive);
+                       print_int(PRINT_JSON, "bus_off", NULL, stats->bus_off);
+               } else {
+                       fprintf(f, "\n    re-started bus-errors arbit-lost "
+                               "error-warn error-pass bus-off");
+                       fprintf(f, "\n    %-10d %-10d %-10d %-10d %-10d %-10d",
+                               stats->restarts, stats->bus_error,
+                               stats->arbitration_lost, stats->error_warning,
+                               stats->error_passive, stats->bus_off);
+               }
        }
 }
 
 static void can_print_help(struct link_util *lu, int argc, char **argv,
-       FILE *f)
+                          FILE *f)
 {
        print_usage(f);
 }
index 594a3e590e0551d449cd178ef073efbf1b77c994..f0f1d1c76e3a1e25288c3da8c36d4ff2f2f3f2d7 100644 (file)
@@ -237,22 +237,28 @@ static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                return;
 
        vni = rta_getattr_u32(tb[IFLA_GENEVE_ID]);
-       fprintf(f, "id %u ", vni);
+       print_uint(PRINT_ANY, "id", "id %u ", vni);
 
        if (tb[IFLA_GENEVE_REMOTE]) {
                __be32 addr = rta_getattr_u32(tb[IFLA_GENEVE_REMOTE]);
 
                if (addr)
-                       fprintf(f, "remote %s ",
-                               format_host(AF_INET, 4, &addr));
+                       print_string(PRINT_ANY,
+                                    "remote",
+                                    "remote %s ",
+                                    format_host(AF_INET, 4, &addr));
        } else if (tb[IFLA_GENEVE_REMOTE6]) {
                struct in6_addr addr;
 
                memcpy(&addr, RTA_DATA(tb[IFLA_GENEVE_REMOTE6]), sizeof(struct in6_addr));
                if (!IN6_IS_ADDR_UNSPECIFIED(&addr)) {
                        if (!IN6_IS_ADDR_MULTICAST(&addr))
-                               fprintf(f, "remote %s ",
-                                       format_host(AF_INET6, sizeof(struct in6_addr), &addr));
+                               print_string(PRINT_ANY,
+                                            "remote6",
+                                            "remote %s ",
+                                            format_host(AF_INET6,
+                                                        sizeof(struct in6_addr),
+                                                        &addr));
                }
        }
 
@@ -260,47 +266,81 @@ static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                __u8 ttl = rta_getattr_u8(tb[IFLA_GENEVE_TTL]);
 
                if (ttl)
-                       fprintf(f, "ttl %d ", ttl);
+                       print_int(PRINT_ANY, "ttl", "ttl %d ", ttl);
        }
 
        if (tb[IFLA_GENEVE_TOS] &&
            (tos = rta_getattr_u8(tb[IFLA_GENEVE_TOS]))) {
-               if (tos == 1)
-                       fprintf(f, "tos inherit ");
-               else
-                       fprintf(f, "tos %#x ", tos);
+               if (is_json_context()) {
+                       print_0xhex(PRINT_JSON, "tos", "%#x", tos);
+               } else {
+                       if (tos == 1) {
+                               print_string(PRINT_FP,
+                                            "tos",
+                                            "tos %s ",
+                                            "inherit");
+                       } else {
+                               fprintf(f, "tos %#x ", tos);
+                       }
+               }
        }
 
        if (tb[IFLA_GENEVE_LABEL]) {
                __u32 label = rta_getattr_u32(tb[IFLA_GENEVE_LABEL]);
 
                if (label)
-                       fprintf(f, "flowlabel %#x ", ntohl(label));
+                       print_0xhex(PRINT_ANY,
+                                   "label",
+                                   "flowlabel %#x ",
+                                   ntohl(label));
        }
 
        if (tb[IFLA_GENEVE_PORT])
-               fprintf(f, "dstport %u ",
-                       rta_getattr_be16(tb[IFLA_GENEVE_PORT]));
+               print_uint(PRINT_ANY,
+                          "port",
+                          "dstport %u ",
+                          rta_getattr_be16(tb[IFLA_GENEVE_PORT]));
 
        if (tb[IFLA_GENEVE_COLLECT_METADATA])
-               fputs("external ", f);
+               print_bool(PRINT_ANY, "collect_metadata", "external ", true);
 
        if (tb[IFLA_GENEVE_UDP_CSUM]) {
-               if (!rta_getattr_u8(tb[IFLA_GENEVE_UDP_CSUM]))
-                       fputs("no", f);
-               fputs("udpcsum ", f);
+               if (is_json_context()) {
+                       print_bool(PRINT_JSON,
+                                  "udp_csum",
+                                  NULL,
+                                  rta_getattr_u8(tb[IFLA_GENEVE_UDP_CSUM]));
+               } else {
+                       if (!rta_getattr_u8(tb[IFLA_GENEVE_UDP_CSUM]))
+                               fputs("no", f);
+                       fputs("udpcsum ", f);
+               }
        }
 
        if (tb[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]) {
-               if (!rta_getattr_u8(tb[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]))
-                       fputs("no", f);
-               fputs("udp6zerocsumtx ", f);
+               if (is_json_context()) {
+                       print_bool(PRINT_JSON,
+                                  "udp_zero_csum6_tx",
+                                  NULL,
+                                  rta_getattr_u8(tb[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]));
+               } else {
+                       if (!rta_getattr_u8(tb[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]))
+                               fputs("no", f);
+                       fputs("udp6zerocsumtx ", f);
+               }
        }
 
        if (tb[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]) {
-               if (!rta_getattr_u8(tb[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]))
-                       fputs("no", f);
-               fputs("udp6zerocsumrx ", f);
+               if (is_json_context()) {
+                       print_bool(PRINT_JSON,
+                                  "udp_zero_csum6_rx",
+                                  NULL,
+                                  rta_getattr_u8(tb[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]));
+               } else {
+                       if (!rta_getattr_u8(tb[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]))
+                               fputs("no", f);
+                       fputs("udp6zerocsumrx ", f);
+               }
        }
 }
 
index 696b2c91369789b16e76fd6afdf0eb71f747bce1..c673ccf7727197a8d97ba2a90427f7a7ee774c04 100644 (file)
@@ -110,30 +110,36 @@ static void hsr_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
            RTA_PAYLOAD(tb[IFLA_HSR_SUPERVISION_ADDR]) < ETH_ALEN)
                return;
 
-       fprintf(f, "slave1 ");
        if (tb[IFLA_HSR_SLAVE1])
-               fprintf(f, "%s ",
-                       ll_index_to_name(rta_getattr_u32(tb[IFLA_HSR_SLAVE1])));
+               print_string(PRINT_ANY,
+                            "slave1",
+                            "slave1 %s ",
+                            ll_index_to_name(rta_getattr_u32(tb[IFLA_HSR_SLAVE1])));
        else
-               fprintf(f, "<none> ");
+               print_null(PRINT_ANY, "slave1", "slave1 %s ", "<none>");
 
-       fprintf(f, "slave2 ");
        if (tb[IFLA_HSR_SLAVE2])
-               fprintf(f, "%s ",
-                       ll_index_to_name(rta_getattr_u32(tb[IFLA_HSR_SLAVE2])));
+               print_string(PRINT_ANY,
+                            "slave2",
+                            "slave2 %s ",
+                            ll_index_to_name(rta_getattr_u32(tb[IFLA_HSR_SLAVE2])));
        else
-               fprintf(f, "<none> ");
+               print_null(PRINT_ANY, "slave2", "slave2 %s ", "<none>");
 
        if (tb[IFLA_HSR_SEQ_NR])
-               fprintf(f, "sequence %d ",
-                       rta_getattr_u16(tb[IFLA_HSR_SEQ_NR]));
+               print_int(PRINT_ANY,
+                         "seq_nr",
+                         "sequence %d ",
+                         rta_getattr_u16(tb[IFLA_HSR_SEQ_NR]));
 
        if (tb[IFLA_HSR_SUPERVISION_ADDR])
-               fprintf(f, "supervision %s ",
-                       ll_addr_n2a(RTA_DATA(tb[IFLA_HSR_SUPERVISION_ADDR]),
-                                   RTA_PAYLOAD(tb[IFLA_HSR_SUPERVISION_ADDR]),
-                                   ARPHRD_VOID,
-                                   b1, sizeof(b1)));
+               print_string(PRINT_ANY,
+                            "supervision_addr",
+                            "supervision %s ",
+                            ll_addr_n2a(RTA_DATA(tb[IFLA_HSR_SUPERVISION_ADDR]),
+                                        RTA_PAYLOAD(tb[IFLA_HSR_SUPERVISION_ADDR]),
+                                        ARPHRD_VOID,
+                                        b1, sizeof(b1)));
 }
 
 static void hsr_print_help(struct link_util *lu, int argc, char **argv,
index 86dc65caa5e0186de2599fd03c32142cb99ac648..e69bda0e8628b65e6498f65336ce8915f7a0f21b 100644 (file)
@@ -91,23 +91,43 @@ static void ipoib_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
            RTA_PAYLOAD(tb[IFLA_IPOIB_PKEY]) < sizeof(__u16))
                return;
 
-       fprintf(f, "pkey  %#.4x ", rta_getattr_u16(tb[IFLA_IPOIB_PKEY]));
+       __u16 pkey = rta_getattr_u16(tb[IFLA_IPOIB_PKEY]);
+
+       if (is_json_context()) {
+               SPRINT_BUF(b1);
+
+               snprintf(b1, sizeof(b1), "%#.4x", pkey);
+               print_string(PRINT_JSON, "key", NULL, b1);
+       } else {
+               fprintf(f, "pkey  %#.4x ", pkey);
+       }
 
        if (!tb[IFLA_IPOIB_MODE] ||
            RTA_PAYLOAD(tb[IFLA_IPOIB_MODE]) < sizeof(__u16))
                return;
 
        mode = rta_getattr_u16(tb[IFLA_IPOIB_MODE]);
-       fprintf(f, "mode  %s ",
+
+       const char *mode_str =
                mode == IPOIB_MODE_DATAGRAM ? "datagram" :
-               mode == IPOIB_MODE_CONNECTED ? "connected" :
-               "unknown");
+               mode == IPOIB_MODE_CONNECTED ? "connected" : "unknown";
+
+       print_string(PRINT_ANY, "mode", "mode  %s ", mode_str);
 
        if (!tb[IFLA_IPOIB_UMCAST] ||
            RTA_PAYLOAD(tb[IFLA_IPOIB_UMCAST]) < sizeof(__u16))
                return;
 
-       fprintf(f, "umcast  %.4x ", rta_getattr_u16(tb[IFLA_IPOIB_UMCAST]));
+       __u16 umcast = rta_getattr_u16(tb[IFLA_IPOIB_UMCAST]);
+
+       if (is_json_context()) {
+               SPRINT_BUF(b1);
+
+               snprintf(b1, sizeof(b1), "%.4x", umcast);
+               print_string(PRINT_JSON, "umcast", NULL, b1);
+       } else {
+               fprintf(f, "umcast  %.4x ", umcast);
+       }
 }
 
 static void ipoib_print_help(struct link_util *lu, int argc, char **argv,
index f7735f3a13eff5b7eaa94c362be68e00cf444ef5..9f48309ee030b1847400fea60a35e5f9ab3be5cf 100644 (file)
@@ -68,11 +68,11 @@ static void ipvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
        if (tb[IFLA_IPVLAN_MODE]) {
                if (RTA_PAYLOAD(tb[IFLA_IPVLAN_MODE]) == sizeof(__u16)) {
                        __u16 mode = rta_getattr_u16(tb[IFLA_IPVLAN_MODE]);
-
-                       fprintf(f, " mode %s ",
-                               mode == IPVLAN_MODE_L2 ? "l2" :
+                       const char *mode_str = mode == IPVLAN_MODE_L2 ? "l2" :
                                mode == IPVLAN_MODE_L3 ? "l3" :
-                               mode == IPVLAN_MODE_L3S ? "l3s" : "unknown");
+                               mode == IPVLAN_MODE_L3S ? "l3s" : "unknown";
+
+                       print_string(PRINT_ANY, "mode", " mode %s ", mode_str);
                }
        }
 }
index 662eb6ff9507c7935168ac161a1fda6084b28b52..b966a6151bc7b87442d7fdf08d20edb102a78d86 100644 (file)
@@ -193,13 +193,15 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]
                return;
 
        mode = rta_getattr_u32(tb[IFLA_MACVLAN_MODE]);
-       fprintf(f, "mode %s ",
-                 mode == MACVLAN_MODE_PRIVATE ? "private"
-               : mode == MACVLAN_MODE_VEPA    ? "vepa"
-               : mode == MACVLAN_MODE_BRIDGE  ? "bridge"
-               : mode == MACVLAN_MODE_PASSTHRU  ? "passthru"
-               : mode == MACVLAN_MODE_SOURCE  ? "source"
-               :                                "unknown");
+       print_string(PRINT_ANY,
+                    "mode",
+                    "mode %s ",
+                    mode == MACVLAN_MODE_PRIVATE ? "private"
+                    : mode == MACVLAN_MODE_VEPA    ? "vepa"
+                    : mode == MACVLAN_MODE_BRIDGE  ? "bridge"
+                    : mode == MACVLAN_MODE_PASSTHRU  ? "passthru"
+                    : mode == MACVLAN_MODE_SOURCE  ? "source"
+                    :                           "unknown");
 
        if (!tb[IFLA_MACVLAN_FLAGS] ||
            RTA_PAYLOAD(tb[IFLA_MACVLAN_FLAGS]) < sizeof(__u16))
@@ -208,7 +210,7 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]
                flags = rta_getattr_u16(tb[IFLA_MACVLAN_FLAGS]);
 
        if (flags & MACVLAN_FLAG_NOPROMISC)
-               fprintf(f, "nopromisc ");
+               print_bool(PRINT_ANY, "nopromisc", "nopromisc ", true);
 
        /* in source mode, there are more options to print */
 
@@ -220,7 +222,7 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]
                return;
 
        count = rta_getattr_u32(tb[IFLA_MACVLAN_MACADDR_COUNT]);
-       fprintf(f, "remotes (%d) ", count);
+       print_int(PRINT_ANY, "macaddr_count", "remotes (%d) ", count);
 
        if (!tb[IFLA_MACVLAN_MACADDR_DATA])
                return;
@@ -228,18 +230,29 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]
        rta = RTA_DATA(tb[IFLA_MACVLAN_MACADDR_DATA]);
        len = RTA_PAYLOAD(tb[IFLA_MACVLAN_MACADDR_DATA]);
 
+       open_json_array(PRINT_JSON, "macaddr_data");
        for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
                if (rta->rta_type != IFLA_MACVLAN_MACADDR ||
                    RTA_PAYLOAD(rta) < 6)
                        continue;
                addr = RTA_DATA(rta);
-               fprintf(f, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x ", addr[0],
-                       addr[1], addr[2], addr[3], addr[4], addr[5]);
+               if (is_json_context()) {
+                       SPRINT_BUF(b1);
+
+                       snprintf(b1, sizeof(b1),
+                                "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", addr[0],
+                                addr[1], addr[2], addr[3], addr[4], addr[5]);
+                       print_string(PRINT_JSON, NULL, NULL, b1);
+               } else {
+                       fprintf(f, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x ", addr[0],
+                               addr[1], addr[2], addr[3], addr[4], addr[5]);
+               }
        }
+       close_json_array(PRINT_JSON, NULL);
 }
 
 static void macvlan_print_help(struct link_util *lu, int argc, char **argv,
-       FILE *f)
+                              FILE *f)
 {
        print_explain(lu, f);
 }
index b47236d8054de52918947f1bc99cb30f5b5d2d49..4d78cf9e4b3a9fe4ed6b27b5e1621f241c9db877 100644 (file)
@@ -164,37 +164,51 @@ static int vlan_parse_opt(struct link_util *lu, int argc, char **argv,
        return 0;
 }
 
-static void vlan_print_map(FILE *f, char *name, struct rtattr *attr)
+static void vlan_print_map(FILE *f,
+                          const char *name_json,
+                          const char *name_fp,
+                          struct rtattr *attr)
 {
        struct ifla_vlan_qos_mapping *m;
        struct rtattr *i;
        int rem;
 
-       fprintf(f, "\n      %s { ", name);
+       open_json_array(PRINT_JSON, name_json);
+       print_string(PRINT_FP, NULL, "\n      %s { ", name_fp);
 
        rem = RTA_PAYLOAD(attr);
        for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
                m = RTA_DATA(i);
-               fprintf(f, "%u:%u ", m->from, m->to);
+
+               if (is_json_context()) {
+                       open_json_object(NULL);
+                       print_uint(PRINT_JSON, "from", NULL, m->from);
+                       print_uint(PRINT_JSON, "to", NULL, m->to);
+                       close_json_object();
+               } else {
+                       fprintf(f, "%u:%u ", m->from, m->to);
+               }
        }
-       fprintf(f, "} ");
+
+       close_json_array(PRINT_JSON, NULL);
+       print_string(PRINT_FP, NULL, "%s ", "}");
 }
 
 static void vlan_print_flags(FILE *fp, __u32 flags)
 {
-       fprintf(fp, "<");
-#define _PF(f) if (flags & VLAN_FLAG_##f) { \
-                       flags &= ~VLAN_FLAG_##f; \
-                       fprintf(fp, #f "%s", flags ? "," : ""); \
-               }
+       open_json_array(PRINT_ANY, is_json_context() ? "flags" : "<");
+#define _PF(f) if (flags & VLAN_FLAG_##f) {                            \
+               flags &= ~VLAN_FLAG_##f;                                \
+               print_string(PRINT_ANY, NULL, flags ? "%s," : "%s", #f); \
+       }
        _PF(REORDER_HDR);
        _PF(GVRP);
        _PF(MVRP);
        _PF(LOOSE_BINDING);
 #undef _PF
        if (flags)
-               fprintf(fp, "%x", flags);
-       fprintf(fp, "> ");
+               print_hex(PRINT_ANY, NULL, "%x", flags);
+       close_json_array(PRINT_ANY, "> ");
 }
 
 static void vlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
@@ -214,13 +228,19 @@ static void vlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                return;
 
        if (tb[IFLA_VLAN_PROTOCOL])
-               fprintf(f, "protocol %s ",
-                       ll_proto_n2a(rta_getattr_u16(tb[IFLA_VLAN_PROTOCOL]),
+               print_string(PRINT_ANY,
+                            "protocol",
+                            "protocol %s ",
+                            ll_proto_n2a(
+                                    rta_getattr_u16(tb[IFLA_VLAN_PROTOCOL]),
                                     b1, sizeof(b1)));
        else
-               fprintf(f, "protocol 802.1q ");
+               print_string(PRINT_ANY, "protocol", "protocol %s ", "802.1q");
 
-       fprintf(f, "id %u ", rta_getattr_u16(tb[IFLA_VLAN_ID]));
+       print_uint(PRINT_ANY,
+                  "id",
+                  "id %u ",
+                  rta_getattr_u16(tb[IFLA_VLAN_ID]));
 
        if (tb[IFLA_VLAN_FLAGS]) {
                if (RTA_PAYLOAD(tb[IFLA_VLAN_FLAGS]) < sizeof(*flags))
@@ -229,13 +249,19 @@ static void vlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                vlan_print_flags(f, flags->flags);
        }
        if (tb[IFLA_VLAN_INGRESS_QOS])
-               vlan_print_map(f, "ingress-qos-map", tb[IFLA_VLAN_INGRESS_QOS]);
+               vlan_print_map(f,
+                              "ingress_qos",
+                              "ingress-qos-map",
+                              tb[IFLA_VLAN_INGRESS_QOS]);
        if (tb[IFLA_VLAN_EGRESS_QOS])
-               vlan_print_map(f, "egress-qos-map", tb[IFLA_VLAN_EGRESS_QOS]);
+               vlan_print_map(f,
+                              "egress_qos",
+                              "egress-qos-map",
+                              tb[IFLA_VLAN_EGRESS_QOS]);
 }
 
 static void vlan_print_help(struct link_util *lu, int argc, char **argv,
-       FILE *f)
+                           FILE *f)
 {
        print_explain(f);
 }
index 917630e8533758a62d8566cd877388c3101d5529..f13b1d24359ca1a5f1e5bcadb48bf2d1408f2ffe 100644 (file)
@@ -62,7 +62,10 @@ static void vrf_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                return;
 
        if (tb[IFLA_VRF_TABLE])
-               fprintf(f, "table %u ", rta_getattr_u32(tb[IFLA_VRF_TABLE]));
+               print_uint(PRINT_ANY,
+                          "table",
+                          "table %u ",
+                          rta_getattr_u32(tb[IFLA_VRF_TABLE]));
 }
 
 static void vrf_slave_print_opt(struct link_util *lu, FILE *f,
@@ -72,13 +75,15 @@ static void vrf_slave_print_opt(struct link_util *lu, FILE *f,
                return;
 
        if (tb[IFLA_VRF_PORT_TABLE]) {
-               fprintf(f, "table %u ",
-                       rta_getattr_u32(tb[IFLA_VRF_PORT_TABLE]));
+               print_uint(PRINT_ANY,
+                          "table",
+                          "table %u ",
+                          rta_getattr_u32(tb[IFLA_VRF_PORT_TABLE]));
        }
 }
 
 static void vrf_print_help(struct link_util *lu, int argc, char **argv,
-                             FILE *f)
+                          FILE *f)
 {
        vrf_explain(f);
 }
index 2bd619d461c3f009d5759309c5c1ed6fc7fb4246..a0530dda9d1bb81b927cf458a52af9fe76a818f1 100644 (file)
@@ -406,18 +406,22 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                return;
 
        vni = rta_getattr_u32(tb[IFLA_VXLAN_ID]);
-       fprintf(f, "id %u ", vni);
+       print_uint(PRINT_ANY, "id", "id %u ", vni);
 
        if (tb[IFLA_VXLAN_GROUP]) {
                __be32 addr = rta_getattr_u32(tb[IFLA_VXLAN_GROUP]);
 
                if (addr) {
                        if (IN_MULTICAST(ntohl(addr)))
-                               fprintf(f, "group %s ",
-                                       format_host(AF_INET, 4, &addr));
+                               print_string(PRINT_ANY,
+                                            "group",
+                                            "group %s ",
+                                            format_host(AF_INET, 4, &addr));
                        else
-                               fprintf(f, "remote %s ",
-                                       format_host(AF_INET, 4, &addr));
+                               print_string(PRINT_ANY,
+                                            "remote",
+                                            "remote %s ",
+                                            format_host(AF_INET, 4, &addr));
                }
        } else if (tb[IFLA_VXLAN_GROUP6]) {
                struct in6_addr addr;
@@ -425,11 +429,19 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                memcpy(&addr, RTA_DATA(tb[IFLA_VXLAN_GROUP6]), sizeof(struct in6_addr));
                if (!IN6_IS_ADDR_UNSPECIFIED(&addr)) {
                        if (IN6_IS_ADDR_MULTICAST(&addr))
-                               fprintf(f, "group %s ",
-                                       format_host(AF_INET6, sizeof(struct in6_addr), &addr));
+                               print_string(PRINT_ANY,
+                                            "group6",
+                                            "group %s ",
+                                            format_host(AF_INET6,
+                                                        sizeof(struct in6_addr),
+                                                        &addr));
                        else
-                               fprintf(f, "remote %s ",
-                                       format_host(AF_INET6, sizeof(struct in6_addr), &addr));
+                               print_string(PRINT_ANY,
+                                            "remote6",
+                                            "remote %s ",
+                                            format_host(AF_INET6,
+                                                        sizeof(struct in6_addr),
+                                                        &addr));
                }
        }
 
@@ -437,15 +449,21 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                __be32 addr = rta_getattr_u32(tb[IFLA_VXLAN_LOCAL]);
 
                if (addr)
-                       fprintf(f, "local %s ",
-                               format_host(AF_INET, 4, &addr));
+                       print_string(PRINT_ANY,
+                                    "local",
+                                    "local %s ",
+                                    format_host(AF_INET, 4, &addr));
        } else if (tb[IFLA_VXLAN_LOCAL6]) {
                struct in6_addr addr;
 
                memcpy(&addr, RTA_DATA(tb[IFLA_VXLAN_LOCAL6]), sizeof(struct in6_addr));
                if (!IN6_IS_ADDR_UNSPECIFIED(&addr))
-                       fprintf(f, "local %s ",
-                               format_host(AF_INET6, sizeof(struct in6_addr), &addr));
+                       print_string(PRINT_ANY,
+                                    "local6",
+                                    "local %s ",
+                                    format_host(AF_INET6,
+                                                sizeof(struct in6_addr),
+                                                &addr));
        }
 
        if (tb[IFLA_VXLAN_LINK] &&
@@ -453,110 +471,155 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                const char *n = if_indextoname(link, s2);
 
                if (n)
-                       fprintf(f, "dev %s ", n);
+                       print_string(PRINT_ANY, "link", "dev %s ", n);
                else
-                       fprintf(f, "dev %u ", link);
+                       print_uint(PRINT_ANY, "link_index", "dev %u ", link);
        }
 
        if (tb[IFLA_VXLAN_PORT_RANGE]) {
                const struct ifla_vxlan_port_range *r
                        = RTA_DATA(tb[IFLA_VXLAN_PORT_RANGE]);
-               fprintf(f, "srcport %u %u ", ntohs(r->low), ntohs(r->high));
+               if (is_json_context()) {
+                       open_json_object("port_range");
+                       print_uint(PRINT_JSON, "low", NULL, ntohs(r->low));
+                       print_uint(PRINT_JSON, "high", NULL, ntohs(r->high));
+                       close_json_object();
+               } else {
+                       fprintf(f, "srcport %u %u ",
+                               ntohs(r->low), ntohs(r->high));
+               }
        }
 
        if (tb[IFLA_VXLAN_PORT])
-               fprintf(f, "dstport %u ",
-                       rta_getattr_be16(tb[IFLA_VXLAN_PORT]));
+               print_uint(PRINT_ANY,
+                          "port",
+                          "dstport %u ",
+                          rta_getattr_be16(tb[IFLA_VXLAN_PORT]));
 
-       if (tb[IFLA_VXLAN_LEARNING] &&
-           !rta_getattr_u8(tb[IFLA_VXLAN_LEARNING]))
-               fputs("nolearning ", f);
+       if (tb[IFLA_VXLAN_LEARNING]) {
+               __u8 learning = rta_getattr_u8(tb[IFLA_VXLAN_LEARNING]);
+
+               print_bool(PRINT_JSON, "learning", NULL, learning);
+               if (!learning)
+                       print_bool(PRINT_FP, NULL, "nolearning ", true);
+       }
 
        if (tb[IFLA_VXLAN_PROXY] && rta_getattr_u8(tb[IFLA_VXLAN_PROXY]))
-               fputs("proxy ", f);
+               print_bool(PRINT_ANY, "proxy", "proxy ", true);
 
        if (tb[IFLA_VXLAN_RSC] && rta_getattr_u8(tb[IFLA_VXLAN_RSC]))
-               fputs("rsc ", f);
+               print_bool(PRINT_ANY, "rsc", "rsc ", true);
 
        if (tb[IFLA_VXLAN_L2MISS] && rta_getattr_u8(tb[IFLA_VXLAN_L2MISS]))
-               fputs("l2miss ", f);
+               print_bool(PRINT_ANY, "l2miss", "l2miss ", true);
 
        if (tb[IFLA_VXLAN_L3MISS] && rta_getattr_u8(tb[IFLA_VXLAN_L3MISS]))
-               fputs("l3miss ", f);
+               print_bool(PRINT_ANY, "l3miss", "l3miss ", true);
 
        if (tb[IFLA_VXLAN_TOS] &&
            (tos = rta_getattr_u8(tb[IFLA_VXLAN_TOS]))) {
-               if (tos == 1)
-                       fprintf(f, "tos inherit ");
-               else
-                       fprintf(f, "tos %#x ", tos);
+               if (is_json_context()) {
+                       print_0xhex(PRINT_JSON, "tos", "%#x", tos);
+               } else {
+                       if (tos == 1)
+                               fprintf(f, "tos %s ", "inherit");
+                       else
+                               fprintf(f, "tos %#x ", tos);
+               }
        }
 
        if (tb[IFLA_VXLAN_TTL]) {
                __u8 ttl = rta_getattr_u8(tb[IFLA_VXLAN_TTL]);
 
                if (ttl)
-                       fprintf(f, "ttl %d ", ttl);
+                       print_int(PRINT_ANY, "ttl", "ttl %d ", ttl);
+               else
+                       print_int(PRINT_JSON, "ttl", NULL, ttl);
        }
 
        if (tb[IFLA_VXLAN_LABEL]) {
                __u32 label = rta_getattr_u32(tb[IFLA_VXLAN_LABEL]);
 
                if (label)
-                       fprintf(f, "flowlabel %#x ", ntohl(label));
+                       print_0xhex(PRINT_ANY,
+                                   "label",
+                                   "flowlabel %#x ",
+                                   ntohl(label));
        }
 
        if (tb[IFLA_VXLAN_AGEING]) {
                __u32 age = rta_getattr_u32(tb[IFLA_VXLAN_AGEING]);
 
                if (age == 0)
-                       fprintf(f, "ageing none ");
+                       print_uint(PRINT_ANY, "ageing", "ageing none ", 0);
                else
-                       fprintf(f, "ageing %u ", age);
+                       print_uint(PRINT_ANY, "ageing", "ageing %u ", age);
        }
 
        if (tb[IFLA_VXLAN_LIMIT] &&
            ((maxaddr = rta_getattr_u32(tb[IFLA_VXLAN_LIMIT])) != 0))
-                   fprintf(f, "maxaddr %u ", maxaddr);
+               print_uint(PRINT_ANY, "limit", "maxaddr %u ", maxaddr);
 
        if (tb[IFLA_VXLAN_UDP_CSUM]) {
-               if (!rta_getattr_u8(tb[IFLA_VXLAN_UDP_CSUM]))
-                       fputs("no", f);
-               fputs("udpcsum ", f);
+               __u8 udp_csum = rta_getattr_u8(tb[IFLA_VXLAN_UDP_CSUM]);
+
+               if (is_json_context()) {
+                       print_bool(PRINT_ANY, "udp_csum", NULL, udp_csum);
+               } else {
+                       if (!udp_csum)
+                               fputs("no", f);
+                       fputs("udpcsum ", f);
+               }
        }
 
        if (tb[IFLA_VXLAN_UDP_ZERO_CSUM6_TX]) {
-               if (!rta_getattr_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_TX]))
-                       fputs("no", f);
-               fputs("udp6zerocsumtx ", f);
+               __u8 csum6 = rta_getattr_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_TX]);
+
+               if (is_json_context()) {
+                       print_bool(PRINT_ANY,
+                                  "udp_zero_csum6_tx", NULL, csum6);
+               } else {
+                       if (!csum6)
+                               fputs("no", f);
+                       fputs("udp6zerocsumtx ", f);
+               }
        }
 
        if (tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]) {
-               if (!rta_getattr_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]))
-                       fputs("no", f);
-               fputs("udp6zerocsumrx ", f);
+               __u8 csum6 = rta_getattr_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]);
+
+               if (is_json_context()) {
+                       print_bool(PRINT_ANY,
+                                  "udp_zero_csum6_rx",
+                                  NULL,
+                                  csum6);
+               } else {
+                       if (!csum6)
+                               fputs("no", f);
+                       fputs("udp6zerocsumrx ", f);
+               }
        }
 
        if (tb[IFLA_VXLAN_REMCSUM_TX] &&
            rta_getattr_u8(tb[IFLA_VXLAN_REMCSUM_TX]))
-               fputs("remcsumtx ", f);
+               print_bool(PRINT_ANY, "remcsum_tx", "remcsumtx ", true);
 
        if (tb[IFLA_VXLAN_REMCSUM_RX] &&
            rta_getattr_u8(tb[IFLA_VXLAN_REMCSUM_RX]))
-               fputs("remcsumrx ", f);
+               print_bool(PRINT_ANY, "remcsum_rx", "remcsumrx ", true);
 
        if (tb[IFLA_VXLAN_COLLECT_METADATA] &&
            rta_getattr_u8(tb[IFLA_VXLAN_COLLECT_METADATA]))
-               fputs("external ", f);
+               print_bool(PRINT_ANY, "collect_metadata", "external ", true);
 
        if (tb[IFLA_VXLAN_GBP])
-               fputs("gbp ", f);
+               print_bool(PRINT_ANY, "gbp", "gbp ", true);
        if (tb[IFLA_VXLAN_GPE])
-               fputs("gpe ", f);
+               print_bool(PRINT_ANY, "gpe", "gpe ", true);
 }
 
 static void vxlan_print_help(struct link_util *lu, int argc, char **argv,
-       FILE *f)
+                            FILE *f)
 {
        print_explain(f);
 }
index 9ae9ee5d06650cee5bb4f4ce607a7d3e0247eb06..3a61076e02117fc1e951552037ae7336d7a98172 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "xdp.h"
 #include "bpf_util.h"
+#include "ip_common.h"
 
 extern int force;
 
@@ -92,20 +93,24 @@ void xdp_dump(FILE *fp, struct rtattr *xdp)
                return;
 
        mode = rta_getattr_u8(tb[IFLA_XDP_ATTACHED]);
-       if (mode == XDP_ATTACHED_NONE)
-               return;
-       else if (mode == XDP_ATTACHED_DRV)
-               fprintf(fp, "xdp");
-       else if (mode == XDP_ATTACHED_SKB)
-               fprintf(fp, "xdpgeneric");
-       else if (mode == XDP_ATTACHED_HW)
-               fprintf(fp, "xdpoffload");
-       else
-               fprintf(fp, "xdp[%u]", mode);
+       if (is_json_context()) {
+               print_uint(PRINT_JSON, "attached", NULL, mode);
+       } else {
+               if (mode == XDP_ATTACHED_NONE)
+                       return;
+               else if (mode == XDP_ATTACHED_DRV)
+                       fprintf(fp, "xdp");
+               else if (mode == XDP_ATTACHED_SKB)
+                       fprintf(fp, "xdpgeneric");
+               else if (mode == XDP_ATTACHED_HW)
+                       fprintf(fp, "xdpoffload");
+               else
+                       fprintf(fp, "xdp[%u]", mode);
+       }
 
        if (tb[IFLA_XDP_PROG_ID])
-               fprintf(fp, "/id:%u",
-                       rta_getattr_u32(tb[IFLA_XDP_PROG_ID]));
+               print_uint(PRINT_ANY, "prog_id", "/id:%u",
+                                  rta_getattr_u32(tb[IFLA_XDP_PROG_ID]));
 
-       fprintf(fp, " ");
+       print_string(PRINT_FP, NULL, "%c", " ");
 }
index aa89a00f5aad632a1d2f3f7a58a7ba5dae02b910..ecc371a51a207fffd2122d34d3c07532d9b3f1d1 100644 (file)
@@ -561,9 +561,14 @@ static int validate_secy_dump(struct rtattr **attrs)
 static void print_flag(FILE *f, struct rtattr *attrs[], const char *desc,
                       int field)
 {
-       if (attrs[field])
-               fprintf(f, "%s %s ", desc,
-                       values_on_off[!!rta_getattr_u8(attrs[field])]);
+       if (attrs[field]) {
+               const char *v = values_on_off[!!rta_getattr_u8(attrs[field])];
+
+               if (is_json_context())
+                       print_string(PRINT_JSON, desc, NULL, v);
+               else
+                       fprintf(f, "%s %s ", desc, v);
+       }
 }
 
 #define DEFAULT_CIPHER_NAME "GCM-AES-128"
@@ -1017,8 +1022,16 @@ static void macsec_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                return;
 
        if (tb[IFLA_MACSEC_SCI]) {
-               fprintf(f, "sci %016llx ",
-                       ntohll(rta_getattr_u64(tb[IFLA_MACSEC_SCI])));
+               if (is_json_context()) {
+                       SPRINT_BUF(b1);
+
+                       snprintf(b1, sizeof(b1), "%016llx",
+                                ntohll(rta_getattr_u64(tb[IFLA_MACSEC_SCI])));
+                       print_string(PRINT_JSON, "sci", NULL, b1);
+               } else {
+                       fprintf(f, "sci %016llx ",
+                               ntohll(rta_getattr_u64(tb[IFLA_MACSEC_SCI])));
+               }
        }
 
        print_flag(f, tb, "protect", IFLA_MACSEC_PROTECT);
@@ -1026,35 +1039,70 @@ static void macsec_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
        if (tb[IFLA_MACSEC_CIPHER_SUITE]) {
                __u64 csid = rta_getattr_u64(tb[IFLA_MACSEC_CIPHER_SUITE]);
 
-               fprintf(f, "cipher %s ", cs_id_to_name(csid));
+               print_string(PRINT_ANY,
+                            "cipher_suite",
+                            "cipher %s ",
+                            cs_id_to_name(csid));
        }
 
        if (tb[IFLA_MACSEC_ICV_LEN]) {
-               fprintf(f, "icvlen %hhu ",
-                       rta_getattr_u8(tb[IFLA_MACSEC_ICV_LEN]));
+               if (is_json_context()) {
+                       char b2[4];
+
+                       snprintf(b2, sizeof(b2), "%hhu",
+                                rta_getattr_u8(tb[IFLA_MACSEC_ICV_LEN]));
+                       print_uint(PRINT_JSON, "icv_len", NULL, atoi(b2));
+               } else {
+                       fprintf(f, "icvlen %hhu ",
+                               rta_getattr_u8(tb[IFLA_MACSEC_ICV_LEN]));
+               }
        }
 
        if (tb[IFLA_MACSEC_ENCODING_SA]) {
-               fprintf(f, "encodingsa %hhu ",
-                       rta_getattr_u8(tb[IFLA_MACSEC_ENCODING_SA]));
+               if (is_json_context()) {
+                       char b2[4];
+
+                       snprintf(b2, sizeof(b2), "%hhu",
+                                rta_getattr_u8(tb[IFLA_MACSEC_ENCODING_SA]));
+                       print_uint(PRINT_JSON, "encoding_sa", NULL, atoi(b2));
+               } else {
+                       fprintf(f, "encodingsa %hhu ",
+                               rta_getattr_u8(tb[IFLA_MACSEC_ENCODING_SA]));
+               }
        }
 
        if (tb[IFLA_MACSEC_VALIDATION]) {
                __u8 val = rta_getattr_u8(tb[IFLA_MACSEC_VALIDATION]);
 
-               fprintf(f, "validate %s ", VALIDATE_STR[val]);
+               print_string(PRINT_ANY,
+                            "validation",
+                            "validate %s ",
+                            VALIDATE_STR[val]);
+       }
+
+       const char *inc_sci, *es, *replay;
+
+       if (is_json_context()) {
+               inc_sci = "inc_sci";
+               replay = "replay_protect";
+               es = "es";
+       } else {
+               inc_sci = "send_sci";
+               es = "end_station";
+               replay = "replay";
        }
 
        print_flag(f, tb, "encrypt", IFLA_MACSEC_ENCRYPT);
-       print_flag(f, tb, "send_sci", IFLA_MACSEC_INC_SCI);
-       print_flag(f, tb, "end_station", IFLA_MACSEC_ES);
+       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(f, tb, "replay", IFLA_MACSEC_REPLAY_PROTECT);
-       if (tb[IFLA_MACSEC_WINDOW]) {
-               fprintf(f, "window %d ",
-                       rta_getattr_u32(tb[IFLA_MACSEC_WINDOW]));
-       }
+       if (tb[IFLA_MACSEC_WINDOW])
+               print_int(PRINT_ANY,
+                         "window",
+                         "window %d ",
+                         rta_getattr_u32(tb[IFLA_MACSEC_WINDOW]));
 }
 
 static bool check_txsc_flags(bool es, bool scb, bool sci)
index 89caac124f4897c445bec4fb503c9630dcab68ae..621b5ca9dc7c779dcf1d7ab9960935a983921c7a 100644 (file)
@@ -100,7 +100,7 @@ static void usage(void)
        fprintf(stderr, "TIME := NUMBER[s|ms]\n");
        fprintf(stderr, "BOOL := [1|0]\n");
        fprintf(stderr, "FEATURES := ecn\n");
-       fprintf(stderr, "ENCAPTYPE := [ mpls | ip | ip6 | seg6 ]\n");
+       fprintf(stderr, "ENCAPTYPE := [ mpls | ip | ip6 | seg6 | seg6local ]\n");
        fprintf(stderr, "ENCAPHDR := [ MPLSLABEL | SEG6HDR ]\n");
        fprintf(stderr, "SEG6HDR := [ mode SEGMODE ] segs ADDR1,ADDRi,ADDRn [hmac HMACKEYID] [cleanup]\n");
        fprintf(stderr, "SEGMODE := [ encap | inline ]\n");
@@ -698,6 +698,8 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
                                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);
index 1a3dc4d4c0ed96003afccb91d56986b02cb2c601..14294c605a90b1472bcc235711ec102f33d7ee06 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/seg6.h>
 #include <linux/seg6_iptunnel.h>
 #include <linux/seg6_hmac.h>
+#include <linux/seg6_local.h>
+#include <net/if.h>
 
 static const char *format_encap_type(int type)
 {
@@ -45,6 +47,8 @@ static const char *format_encap_type(int type)
                return "bpf";
        case LWTUNNEL_ENCAP_SEG6:
                return "seg6";
+       case LWTUNNEL_ENCAP_SEG6_LOCAL:
+               return "seg6local";
        default:
                return "unknown";
        }
@@ -77,18 +81,39 @@ static int read_encap_type(const char *name)
                return LWTUNNEL_ENCAP_BPF;
        else if (strcmp(name, "seg6") == 0)
                return LWTUNNEL_ENCAP_SEG6;
+       else if (strcmp(name, "seg6local") == 0)
+               return LWTUNNEL_ENCAP_SEG6_LOCAL;
        else if (strcmp(name, "help") == 0)
                encap_type_usage();
 
        return LWTUNNEL_ENCAP_NONE;
 }
 
+static void print_srh(FILE *fp, struct ipv6_sr_hdr *srh)
+{
+       int i;
+
+       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]));
+
+       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));
+       }
+}
+
 static void print_encap_seg6(FILE *fp, struct rtattr *encap)
 {
        struct rtattr *tb[SEG6_IPTUNNEL_MAX+1];
        struct seg6_iptunnel_encap *tuninfo;
-       struct ipv6_sr_hdr *srh;
-       int i;
 
        parse_rtattr_nested(tb, SEG6_IPTUNNEL_MAX, encap);
 
@@ -99,22 +124,94 @@ static void print_encap_seg6(FILE *fp, struct rtattr *encap)
        fprintf(fp, "mode %s ",
                (tuninfo->mode == SEG6_IPTUN_MODE_ENCAP) ? "encap" : "inline");
 
-       srh = tuninfo->srh;
+       print_srh(fp, tuninfo->srh);
+}
+
+static const char *seg6_action_names[SEG6_LOCAL_ACTION_MAX + 1] = {
+       [SEG6_LOCAL_ACTION_END]                 = "End",
+       [SEG6_LOCAL_ACTION_END_X]               = "End.X",
+       [SEG6_LOCAL_ACTION_END_T]               = "End.T",
+       [SEG6_LOCAL_ACTION_END_DX2]             = "End.DX2",
+       [SEG6_LOCAL_ACTION_END_DX6]             = "End.DX6",
+       [SEG6_LOCAL_ACTION_END_DX4]             = "End.DX4",
+       [SEG6_LOCAL_ACTION_END_DT6]             = "End.DT6",
+       [SEG6_LOCAL_ACTION_END_DT4]             = "End.DT4",
+       [SEG6_LOCAL_ACTION_END_B6]              = "End.B6",
+       [SEG6_LOCAL_ACTION_END_B6_ENCAP]        = "End.B6.Encaps",
+       [SEG6_LOCAL_ACTION_END_BM]              = "End.BM",
+       [SEG6_LOCAL_ACTION_END_S]               = "End.S",
+       [SEG6_LOCAL_ACTION_END_AS]              = "End.AS",
+       [SEG6_LOCAL_ACTION_END_AM]              = "End.AM",
+};
 
-       fprintf(fp, "segs %d [ ", srh->first_segment + 1);
+static const char *format_action_type(int action)
+{
+       if (action < 0 || action > SEG6_LOCAL_ACTION_MAX)
+               return "<invalid>";
 
-       for (i = srh->first_segment; i >= 0; i--)
-               fprintf(fp, "%s ",
-                       rt_addr_n2a(AF_INET6, 16, &srh->segments[i]));
+       return seg6_action_names[action] ?: "<unknown>";
+}
 
-       fprintf(fp, "] ");
+static int read_action_type(const char *name)
+{
+       int i;
 
-       if (sr_has_hmac(srh)) {
-               unsigned int offset = ((srh->hdrlen + 1) << 3) - 40;
-               struct sr6_tlv_hmac *tlv;
+       for (i = 0; i < SEG6_LOCAL_ACTION_MAX + 1; i++) {
+               if (!seg6_action_names[i])
+                       continue;
 
-               tlv = (struct sr6_tlv_hmac *)((char *)srh + offset);
-               fprintf(fp, "hmac 0x%X ", ntohl(tlv->hmackeyid));
+               if (strcmp(seg6_action_names[i], name) == 0)
+                       return i;
+       }
+
+       return SEG6_LOCAL_ACTION_UNSPEC;
+}
+
+static void print_encap_seg6local(FILE *fp, struct rtattr *encap)
+{
+       struct rtattr *tb[SEG6_LOCAL_MAX + 1];
+       char ifbuf[IFNAMSIZ];
+       int action;
+
+       parse_rtattr_nested(tb, SEG6_LOCAL_MAX, encap);
+
+       if (!tb[SEG6_LOCAL_ACTION])
+               return;
+
+       action = rta_getattr_u32(tb[SEG6_LOCAL_ACTION]);
+
+       fprintf(fp, "action %s ", format_action_type(action));
+
+       if (tb[SEG6_LOCAL_SRH]) {
+               fprintf(fp, "srh ");
+               print_srh(fp, RTA_DATA(tb[SEG6_LOCAL_SRH]));
+       }
+
+       if (tb[SEG6_LOCAL_TABLE])
+               fprintf(fp, "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]));
+       }
+
+       if (tb[SEG6_LOCAL_NH6]) {
+               fprintf(fp, "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 ",
+                       if_indextoname(iif, ifbuf) ?: "<unknown>");
+       }
+
+       if (tb[SEG6_LOCAL_OIF]) {
+               int oif = rta_getattr_u32(tb[SEG6_LOCAL_OIF]);
+
+               fprintf(fp, "oif %s ",
+                       if_indextoname(oif, ifbuf) ?: "<unknown>");
        }
 }
 
@@ -287,9 +384,61 @@ void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
        case LWTUNNEL_ENCAP_SEG6:
                print_encap_seg6(fp, encap);
                break;
+       case LWTUNNEL_ENCAP_SEG6_LOCAL:
+               print_encap_seg6local(fp, encap);
+               break;
        }
 }
 
+static struct ipv6_sr_hdr *parse_srh(char *segbuf, int hmac, bool encap)
+{
+       struct ipv6_sr_hdr *srh;
+       int nsegs = 0;
+       int srhlen;
+       char *s;
+       int i;
+
+       s = segbuf;
+       for (i = 0; *s; *s++ == ',' ? i++ : *s);
+       nsegs = i + 1;
+
+       if (!encap)
+               nsegs++;
+
+       srhlen = 8 + 16*nsegs;
+
+       if (hmac)
+               srhlen += 40;
+
+       srh = malloc(srhlen);
+       memset(srh, 0, srhlen);
+
+       srh->hdrlen = (srhlen >> 3) - 1;
+       srh->type = 4;
+       srh->segments_left = nsegs - 1;
+       srh->first_segment = nsegs - 1;
+
+       if (hmac)
+               srh->flags |= SR6_FLAG1_HMAC;
+
+       i = srh->first_segment;
+       for (s = strtok(segbuf, ","); s; s = strtok(NULL, ",")) {
+               inet_get_addr(s, NULL, &srh->segments[i]);
+               i--;
+       }
+
+       if (hmac) {
+               struct sr6_tlv_hmac *tlv;
+
+               tlv = (struct sr6_tlv_hmac *)((char *)srh + srhlen - 40);
+               tlv->tlvhdr.type = SR6_TLV_HMAC;
+               tlv->tlvhdr.len = 38;
+               tlv->hmackeyid = htonl(hmac);
+       }
+
+       return srh;
+}
+
 static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp,
                            char ***argvp)
 {
@@ -301,10 +450,7 @@ static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp,
        int argc = *argcp;
        int encap = -1;
        __u32 hmac = 0;
-       int nsegs = 0;
        int srhlen;
-       char *s;
-       int i;
 
        while (argc > 0) {
                if (strcmp(*argv, "mode") == 0) {
@@ -338,17 +484,8 @@ static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp,
                argc--; argv++;
        }
 
-       s = segbuf;
-       for (i = 0; *s; *s++ == ',' ? i++ : *s);
-       nsegs = i + 1;
-
-       if (!encap)
-               nsegs++;
-
-       srhlen = 8 + 16*nsegs;
-
-       if (hmac)
-               srhlen += 40;
+       srh = parse_srh(segbuf, hmac, encap);
+       srhlen = (srh->hdrlen + 1) << 3;
 
        tuninfo = malloc(sizeof(*tuninfo) + srhlen);
        memset(tuninfo, 0, sizeof(*tuninfo) + srhlen);
@@ -358,33 +495,121 @@ static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp,
        else
                tuninfo->mode = SEG6_IPTUN_MODE_INLINE;
 
-       srh = tuninfo->srh;
-       srh->hdrlen = (srhlen >> 3) - 1;
-       srh->type = 4;
-       srh->segments_left = nsegs - 1;
-       srh->first_segment = nsegs - 1;
+       memcpy(tuninfo->srh, srh, srhlen);
 
-       if (hmac)
-               srh->flags |= SR6_FLAG1_HMAC;
+       rta_addattr_l(rta, len, SEG6_IPTUNNEL_SRH, tuninfo,
+                     sizeof(*tuninfo) + srhlen);
 
-       i = srh->first_segment;
-       for (s = strtok(segbuf, ","); s; s = strtok(NULL, ",")) {
-               inet_get_addr(s, NULL, &srh->segments[i]);
-               i--;
-       }
+       free(tuninfo);
+       free(srh);
 
-       if (hmac) {
-               struct sr6_tlv_hmac *tlv;
+       *argcp = argc + 1;
+       *argvp = argv - 1;
 
-               tlv = (struct sr6_tlv_hmac *)((char *)srh + srhlen - 40);
-               tlv->tlvhdr.type = SR6_TLV_HMAC;
-               tlv->tlvhdr.len = 38;
-               tlv->hmackeyid = htonl(hmac);
+       return 0;
+}
+
+static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
+                                char ***argvp)
+{
+       int segs_ok = 0, hmac_ok = 0, table_ok = 0, nh4_ok = 0, nh6_ok = 0;
+       int iif_ok = 0, oif_ok = 0, action_ok = 0, srh_ok = 0;
+       __u32 action = 0, table, iif, oif;
+       struct ipv6_sr_hdr *srh;
+       char **argv = *argvp;
+       int argc = *argcp;
+       char segbuf[1024];
+       inet_prefix addr;
+       __u32 hmac = 0;
+
+       while (argc > 0) {
+               if (strcmp(*argv, "action") == 0) {
+                       NEXT_ARG();
+                       if (action_ok++)
+                               duparg2("action", *argv);
+                       action = read_action_type(*argv);
+                       if (!action)
+                               invarg("\"action\" value is invalid\n", *argv);
+                       rta_addattr32(rta, len, SEG6_LOCAL_ACTION, action);
+               } else if (strcmp(*argv, "table") == 0) {
+                       NEXT_ARG();
+                       if (table_ok++)
+                               duparg2("table", *argv);
+                       get_u32(&table, *argv, 0);
+                       rta_addattr32(rta, len, SEG6_LOCAL_TABLE, table);
+               } else if (strcmp(*argv, "nh4") == 0) {
+                       NEXT_ARG();
+                       if (nh4_ok++)
+                               duparg2("nh4", *argv);
+                       get_addr(&addr, *argv, AF_INET);
+                       rta_addattr_l(rta, len, SEG6_LOCAL_NH4, &addr.data,
+                                     addr.bytelen);
+               } else if (strcmp(*argv, "nh6") == 0) {
+                       NEXT_ARG();
+                       if (nh6_ok++)
+                               duparg2("nh6", *argv);
+                       get_addr(&addr, *argv, AF_INET6);
+                       rta_addattr_l(rta, len, SEG6_LOCAL_NH6, &addr.data,
+                                     addr.bytelen);
+               } else if (strcmp(*argv, "iif") == 0) {
+                       NEXT_ARG();
+                       if (iif_ok++)
+                               duparg2("iif", *argv);
+                       iif = if_nametoindex(*argv);
+                       if (!iif)
+                               invarg("\"iif\" interface not found\n", *argv);
+                       rta_addattr32(rta, len, SEG6_LOCAL_IIF, iif);
+               } else if (strcmp(*argv, "oif") == 0) {
+                       NEXT_ARG();
+                       if (oif_ok++)
+                               duparg2("oif", *argv);
+                       oif = if_nametoindex(*argv);
+                       if (!oif)
+                               invarg("\"oif\" interface not found\n", *argv);
+                       rta_addattr32(rta, len, SEG6_LOCAL_OIF, oif);
+               } else if (strcmp(*argv, "srh") == 0) {
+                       NEXT_ARG();
+                       if (srh_ok++)
+                               duparg2("srh", *argv);
+                       if (strcmp(*argv, "segs") != 0)
+                               invarg("missing \"segs\" attribute for srh\n",
+                                       *argv);
+                       NEXT_ARG();
+                       if (segs_ok++)
+                               duparg2("segs", *argv);
+                       strncpy(segbuf, *argv, 1024);
+                       segbuf[1023] = 0;
+                       if (!NEXT_ARG_OK())
+                               break;
+                       NEXT_ARG();
+                       if (strcmp(*argv, "hmac") == 0) {
+                               NEXT_ARG();
+                               if (hmac_ok++)
+                                       duparg2("hmac", *argv);
+                               get_u32(&hmac, *argv, 0);
+                       } else {
+                               continue;
+                       }
+               } else {
+                       break;
+               }
+               argc--; argv++;
        }
 
-       rta_addattr_l(rta, len, SEG6_IPTUNNEL_SRH, tuninfo,
-                     sizeof(*tuninfo) + srhlen);
-       free(tuninfo);
+       if (!action) {
+               fprintf(stderr, "Missing action type\n");
+               exit(-1);
+       }
+
+       if (srh_ok) {
+               int srhlen;
+
+               srh = parse_srh(segbuf, hmac,
+                               action == SEG6_LOCAL_ACTION_END_B6_ENCAP);
+               srhlen = (srh->hdrlen + 1) << 3;
+               rta_addattr_l(rta, len, SEG6_LOCAL_SRH, srh, srhlen);
+               free(srh);
+       }
 
        *argcp = argc + 1;
        *argvp = argv - 1;
@@ -752,6 +977,9 @@ int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
        case LWTUNNEL_ENCAP_SEG6:
                parse_encap_seg6(rta, len, &argc, &argv);
                break;
+       case LWTUNNEL_ENCAP_SEG6_LOCAL:
+               parse_encap_seg6local(rta, len, &argc, &argv);
+               break;
        default:
                fprintf(stderr, "Error: unsupported encap type\n");
                break;
index c2ec5f26902ffc27b1f8aad1a67ed52964a53610..3c9f8194e6c69dfd347bb68a88c99dd949df40ff 100644 (file)
@@ -389,7 +389,7 @@ static void gre_print_direct_opt(FILE *f, struct rtattr *tb[])
                        remote = format_host(AF_INET, 4, &addr);
        }
 
-       fprintf(f, "remote %s ", remote);
+       print_string(PRINT_ANY, "remote", "remote %s ", remote);
 
        if (tb[IFLA_GRE_LOCAL]) {
                unsigned int addr = rta_getattr_u32(tb[IFLA_GRE_LOCAL]);
@@ -398,36 +398,52 @@ static void gre_print_direct_opt(FILE *f, struct rtattr *tb[])
                        local = format_host(AF_INET, 4, &addr);
        }
 
-       fprintf(f, "local %s ", local);
+       print_string(PRINT_ANY, "local", "local %s ", local);
 
        if (tb[IFLA_GRE_LINK] && rta_getattr_u32(tb[IFLA_GRE_LINK])) {
                unsigned int link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
                const char *n = if_indextoname(link, s2);
 
                if (n)
-                       fprintf(f, "dev %s ", n);
+                       print_string(PRINT_ANY, "link", "dev %s ", n);
                else
-                       fprintf(f, "dev %u ", link);
+                       print_uint(PRINT_ANY, "link_index", "dev %u ", link);
        }
 
-       if (tb[IFLA_GRE_TTL] && rta_getattr_u8(tb[IFLA_GRE_TTL]))
-               fprintf(f, "ttl %d ", rta_getattr_u8(tb[IFLA_GRE_TTL]));
-       else
-               fprintf(f, "ttl inherit ");
+       if (tb[IFLA_GRE_TTL]) {
+               __u8 ttl = rta_getattr_u8(tb[IFLA_GRE_TTL]);
+
+               if (ttl)
+                       print_int(PRINT_ANY, "ttl", "ttl %d ", ttl);
+               else
+                       print_int(PRINT_JSON, "ttl", NULL, ttl);
+       } else {
+               print_string(PRINT_FP, NULL, "ttl %s ", "inherit");
+       }
 
        if (tb[IFLA_GRE_TOS] && rta_getattr_u8(tb[IFLA_GRE_TOS])) {
                int tos = rta_getattr_u8(tb[IFLA_GRE_TOS]);
 
-               fputs("tos ", f);
-               if (tos == 1)
-                       fputs("inherit ", f);
-               else
-                       fprintf(f, "0x%x ", tos);
+               if (is_json_context()) {
+                       SPRINT_BUF(b1);
+
+                       snprintf(b1, sizeof(b1), "0x%x", tos);
+                       print_string(PRINT_JSON, "tos", NULL, b1);
+               } else {
+                       fputs("tos ", f);
+                       if (tos == 1)
+                               fputs("inherit ", f);
+                       else
+                               fprintf(f, "0x%x ", tos);
+               }
        }
 
-       if (tb[IFLA_GRE_PMTUDISC] &&
-           !rta_getattr_u8(tb[IFLA_GRE_PMTUDISC]))
-               fputs("nopmtudisc ", f);
+       if (tb[IFLA_GRE_PMTUDISC]) {
+               if (!rta_getattr_u8(tb[IFLA_GRE_PMTUDISC]))
+                       print_bool(PRINT_ANY, "pmtudisc", "nopmtudisc ", false);
+               else
+                       print_bool(PRINT_JSON, "pmtudisc", NULL, true);
+       }
 
        if (tb[IFLA_GRE_IFLAGS])
                iflags = rta_getattr_u16(tb[IFLA_GRE_IFLAGS]);
@@ -437,26 +453,31 @@ static void gre_print_direct_opt(FILE *f, struct rtattr *tb[])
 
        if ((iflags & GRE_KEY) && tb[IFLA_GRE_IKEY]) {
                inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2));
-               fprintf(f, "ikey %s ", s2);
+               print_string(PRINT_ANY, "ikey", "ikey %s ", s2);
        }
 
        if ((oflags & GRE_KEY) && tb[IFLA_GRE_OKEY]) {
                inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2));
-               fprintf(f, "okey %s ", s2);
+               print_string(PRINT_ANY, "okey", "okey %s ", s2);
        }
 
        if (iflags & GRE_SEQ)
-               fputs("iseq ", f);
+               print_bool(PRINT_ANY, "iseq", "iseq ", true);
        if (oflags & GRE_SEQ)
-               fputs("oseq ", f);
+               print_bool(PRINT_ANY, "oseq", "oseq ", true);
        if (iflags & GRE_CSUM)
-               fputs("icsum ", f);
+               print_bool(PRINT_ANY, "icsum", "icsum ", true);
        if (oflags & GRE_CSUM)
-               fputs("ocsum ", f);
+               print_bool(PRINT_ANY, "ocsum", "ocsum ", true);
+
+       if (tb[IFLA_GRE_FWMARK]) {
+               __u32 fwmark = rta_getattr_u32(tb[IFLA_GRE_FWMARK]);
+
+               if (fwmark) {
+                       snprintf(s2, sizeof(s2), "0x%x", fwmark);
 
-       if (tb[IFLA_GRE_FWMARK] && rta_getattr_u32(tb[IFLA_GRE_FWMARK])) {
-               fprintf(f, "fwmark 0x%x ",
-                       rta_getattr_u32(tb[IFLA_GRE_FWMARK]));
+                       print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2);
+               }
        }
 }
 
@@ -468,10 +489,10 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
        if (!tb[IFLA_GRE_COLLECT_METADATA])
                gre_print_direct_opt(f, tb);
        else
-               fputs("external ", f);
+               print_bool(PRINT_ANY, "external", "external ", true);
 
        if (tb[IFLA_GRE_IGNORE_DF] && rta_getattr_u8(tb[IFLA_GRE_IGNORE_DF]))
-               fputs("ignore-df ", f);
+               print_bool(PRINT_ANY, "ignore_df", "ignore-df ", true);
 
        if (tb[IFLA_GRE_ENCAP_TYPE] &&
            rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) {
@@ -480,45 +501,73 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                __u16 sport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_SPORT]);
                __u16 dport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_DPORT]);
 
-               fputs("encap ", f);
+
+               open_json_object("encap");
+               print_string(PRINT_FP, NULL, "encap ", NULL);
+
                switch (type) {
                case TUNNEL_ENCAP_FOU:
-                       fputs("fou ", f);
+                       print_string(PRINT_ANY, "type", "%s ", "fou");
                        break;
                case TUNNEL_ENCAP_GUE:
-                       fputs("gue ", f);
+                       print_string(PRINT_ANY, "type", "%s ", "gue");
                        break;
                default:
-                       fputs("unknown ", f);
+                       print_null(PRINT_ANY, "type", "%s ", "unknown");
                        break;
                }
 
-               if (sport == 0)
-                       fputs("encap-sport auto ", f);
-               else
-                       fprintf(f, "encap-sport %u", ntohs(sport));
+               if (is_json_context()) {
+                       print_uint(PRINT_JSON,
+                                  "sport",
+                                  NULL,
+                                  sport ? ntohs(sport) : 0);
+                       print_uint(PRINT_JSON, "dport", NULL, ntohs(dport));
+
+                       print_bool(PRINT_JSON,
+                                  "csum",
+                                  NULL,
+                                  flags & TUNNEL_ENCAP_FLAG_CSUM);
+
+                       print_bool(PRINT_JSON,
+                                  "csum6",
+                                  NULL,
+                                  flags & TUNNEL_ENCAP_FLAG_CSUM6);
+
+                       print_bool(PRINT_JSON,
+                                  "remcsum",
+                                  NULL,
+                                  flags & TUNNEL_ENCAP_FLAG_REMCSUM);
+
+                       close_json_object();
+               } else {
+                       if (sport == 0)
+                               fputs("encap-sport auto ", f);
+                       else
+                               fprintf(f, "encap-sport %u", ntohs(sport));
 
-               fprintf(f, "encap-dport %u ", ntohs(dport));
+                       fprintf(f, "encap-dport %u ", ntohs(dport));
 
-               if (flags & TUNNEL_ENCAP_FLAG_CSUM)
-                       fputs("encap-csum ", f);
-               else
-                       fputs("noencap-csum ", f);
+                       if (flags & TUNNEL_ENCAP_FLAG_CSUM)
+                               fputs("encap-csum ", f);
+                       else
+                               fputs("noencap-csum ", f);
 
-               if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
-                       fputs("encap-csum6 ", f);
-               else
-                       fputs("noencap-csum6 ", f);
+                       if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
+                               fputs("encap-csum6 ", f);
+                       else
+                               fputs("noencap-csum6 ", f);
 
-               if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
-                       fputs("encap-remcsum ", f);
-               else
-                       fputs("noencap-remcsum ", f);
+                       if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
+                               fputs("encap-remcsum ", f);
+                       else
+                               fputs("noencap-remcsum ", f);
+               }
        }
 }
 
 static void gre_print_help(struct link_util *lu, int argc, char **argv,
-       FILE *f)
+                          FILE *f)
 {
        print_usage(f);
 }
index 4d3d4b54210b964d291d2aaca0723726bc1cbb00..957853d6e6e4143acdda4555d69be4113475102d 100644 (file)
@@ -423,7 +423,7 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                        remote = format_host(AF_INET6, sizeof(addr), &addr);
        }
 
-       fprintf(f, "remote %s ", remote);
+       print_string(PRINT_ANY, "remote", "remote %s ", remote);
 
        if (tb[IFLA_GRE_LOCAL]) {
                struct in6_addr addr;
@@ -434,36 +434,65 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                        local = format_host(AF_INET6, sizeof(addr), &addr);
        }
 
-       fprintf(f, "local %s ", local);
+       print_string(PRINT_ANY, "local", "local %s ", local);
 
        if (tb[IFLA_GRE_LINK] && rta_getattr_u32(tb[IFLA_GRE_LINK])) {
                unsigned int link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
                const char *n = if_indextoname(link, s2);
 
                if (n)
-                       fprintf(f, "dev %s ", n);
+                       print_string(PRINT_ANY, "link", "dev %s ", n);
                else
-                       fprintf(f, "dev %u ", link);
+                       print_uint(PRINT_ANY, "link_index", "dev %u ", link);
        }
 
-       if (tb[IFLA_GRE_TTL] && rta_getattr_u8(tb[IFLA_GRE_TTL]))
-               fprintf(f, "hoplimit %d ", rta_getattr_u8(tb[IFLA_GRE_TTL]));
+       if (tb[IFLA_GRE_TTL]) {
+               __u8 ttl = rta_getattr_u8(tb[IFLA_GRE_TTL]);
+
+               if (ttl)
+                       print_int(PRINT_ANY, "ttl", "hoplimit %d ", ttl);
+               else
+                       print_int(PRINT_JSON, "ttl", NULL, ttl);
+       }
 
        if (flags & IP6_TNL_F_IGN_ENCAP_LIMIT)
-               fprintf(f, "encaplimit none ");
+               print_bool(PRINT_ANY,
+                          "ip6_tnl_f_ign_encap_limit",
+                          "encaplimit none ",
+                          true);
        else if (tb[IFLA_GRE_ENCAP_LIMIT]) {
                int encap_limit = rta_getattr_u8(tb[IFLA_GRE_ENCAP_LIMIT]);
 
-               fprintf(f, "encaplimit %d ", encap_limit);
+               print_int(PRINT_ANY,
+                         "encap_limit",
+                         "encaplimit %d ",
+                         encap_limit);
        }
 
-       if (flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
-               fprintf(f, "flowlabel inherit ");
-       else
-               fprintf(f, "flowlabel 0x%05x ", ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL));
+       if (flags & IP6_TNL_F_USE_ORIG_FLOWLABEL) {
+               print_bool(PRINT_ANY,
+                          "ip6_tnl_f_use_orig_flowlabel",
+                          "flowlabel inherit ",
+                          true);
+       } else {
+               if (is_json_context()) {
+                       SPRINT_BUF(b1);
+
+                       snprintf(b1, sizeof(b1), "0x%05x",
+                                ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL));
+                       print_string(PRINT_JSON, "flowlabel", NULL, b1);
+
+               } else {
+                       fprintf(f, "flowlabel 0x%05x ",
+                               ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL));
+               }
+       }
 
        if (flags & IP6_TNL_F_RCV_DSCP_COPY)
-               fprintf(f, "dscp inherit ");
+               print_bool(PRINT_ANY,
+                          "ip6_tnl_f_rcv_dscp_copy",
+                          "dscp inherit ",
+                          true);
 
        if (tb[IFLA_GRE_IFLAGS])
                iflags = rta_getattr_u16(tb[IFLA_GRE_IFLAGS]);
@@ -473,27 +502,37 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
 
        if ((iflags & GRE_KEY) && tb[IFLA_GRE_IKEY]) {
                inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2));
-               fprintf(f, "ikey %s ", s2);
+               print_string(PRINT_ANY, "ikey", "ikey %s ", s2);
        }
 
        if ((oflags & GRE_KEY) && tb[IFLA_GRE_OKEY]) {
                inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2));
-               fprintf(f, "okey %s ", s2);
+               print_string(PRINT_ANY, "okey", "okey %s ", s2);
        }
 
        if (iflags & GRE_SEQ)
-               fputs("iseq ", f);
+               print_bool(PRINT_ANY, "iseq", "iseq ", true);
        if (oflags & GRE_SEQ)
-               fputs("oseq ", f);
+               print_bool(PRINT_ANY, "oseq", "oseq ", true);
        if (iflags & GRE_CSUM)
-               fputs("icsum ", f);
+               print_bool(PRINT_ANY, "icsum", "icsum ", true);
        if (oflags & GRE_CSUM)
-               fputs("ocsum ", f);
+               print_bool(PRINT_ANY, "ocsum", "ocsum ", true);
 
        if (flags & IP6_TNL_F_USE_ORIG_FWMARK)
-               fprintf(f, "fwmark inherit ");
-       else if (tb[IFLA_GRE_FWMARK] && rta_getattr_u32(tb[IFLA_GRE_FWMARK]))
-               fprintf(f, "fwmark 0x%x ", rta_getattr_u32(tb[IFLA_GRE_FWMARK]));
+               print_bool(PRINT_ANY,
+                          "ip6_tnl_f_use_orig_fwmark",
+                          "fwmark inherit ",
+                          true);
+       else if (tb[IFLA_GRE_FWMARK]) {
+               __u32 fwmark = rta_getattr_u32(tb[IFLA_GRE_FWMARK]);
+
+               if (fwmark) {
+                       snprintf(s2, sizeof(s2), "0x%x", fwmark);
+
+                       print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2);
+               }
+       }
 
        if (tb[IFLA_GRE_ENCAP_TYPE] &&
            rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) {
@@ -502,40 +541,57 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                __u16 sport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_SPORT]);
                __u16 dport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_DPORT]);
 
-               fputs("encap ", f);
+               open_json_object("encap");
+
+               print_string(PRINT_FP, NULL, "encap ", NULL);
                switch (type) {
                case TUNNEL_ENCAP_FOU:
-                       fputs("fou ", f);
+                       print_string(PRINT_ANY, "type", "%s ", "fou");
                        break;
                case TUNNEL_ENCAP_GUE:
-                       fputs("gue ", f);
+                       print_string(PRINT_ANY, "type", "%s ", "gue");
                        break;
                default:
-                       fputs("unknown ", f);
+                       print_null(PRINT_ANY, "type", "unknown ", NULL);
                        break;
                }
 
-               if (sport == 0)
-                       fputs("encap-sport auto ", f);
-               else
-                       fprintf(f, "encap-sport %u", ntohs(sport));
+               if (is_json_context()) {
+                       print_uint(PRINT_JSON,
+                                  "sport",
+                                  NULL,
+                                  sport ? ntohs(sport) : 0);
+                       print_uint(PRINT_JSON, "dport", NULL, ntohs(dport));
+                       print_bool(PRINT_JSON, "csum", NULL,
+                                          flags & TUNNEL_ENCAP_FLAG_CSUM);
+                       print_bool(PRINT_JSON, "csum6", NULL,
+                                          flags & TUNNEL_ENCAP_FLAG_CSUM6);
+                       print_bool(PRINT_JSON, "remcsum", NULL,
+                                          flags & TUNNEL_ENCAP_FLAG_REMCSUM);
+                       close_json_object();
+               } else {
+                       if (sport == 0)
+                               fputs("encap-sport auto ", f);
+                       else
+                               fprintf(f, "encap-sport %u", ntohs(sport));
 
-               fprintf(f, "encap-dport %u ", ntohs(dport));
+                       fprintf(f, "encap-dport %u ", ntohs(dport));
 
-               if (flags & TUNNEL_ENCAP_FLAG_CSUM)
-                       fputs("encap-csum ", f);
-               else
-                       fputs("noencap-csum ", f);
+                       if (flags & TUNNEL_ENCAP_FLAG_CSUM)
+                               fputs("encap-csum ", f);
+                       else
+                               fputs("noencap-csum ", f);
 
-               if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
-                       fputs("encap-csum6 ", f);
-               else
-                       fputs("noencap-csum6 ", f);
+                       if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
+                               fputs("encap-csum6 ", f);
+                       else
+                               fputs("noencap-csum6 ", f);
 
-               if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
-                       fputs("encap-remcsum ", f);
-               else
-                       fputs("noencap-remcsum ", f);
+                       if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
+                               fputs("encap-remcsum ", f);
+                       else
+                               fputs("noencap-remcsum ", f);
+               }
        }
 }
 
index 505fb47622eda78283714063f492935f8b4737b2..a41990068f0f7258ee3a0e2bbdfed5bcac457911 100644 (file)
@@ -346,25 +346,29 @@ static void ip6tunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb
        if (tb[IFLA_IPTUN_PROTO]) {
                switch (rta_getattr_u8(tb[IFLA_IPTUN_PROTO])) {
                case IPPROTO_IPIP:
-                       fprintf(f, "ipip6 ");
+                       print_string(PRINT_ANY, "proto", "%s ", "ipip6");
                        break;
                case IPPROTO_IPV6:
-                       fprintf(f, "ip6ip6 ");
+                       print_string(PRINT_ANY, "proto", "%s ", "ip6ip6");
                        break;
                case 0:
-                       fprintf(f, "any ");
+                       print_string(PRINT_ANY, "proto", "%s ", "any");
                        break;
                }
        }
 
        if (tb[IFLA_IPTUN_REMOTE]) {
-               fprintf(f, "remote %s ",
-                       rt_addr_n2a_rta(AF_INET6, tb[IFLA_IPTUN_REMOTE]));
+               print_string(PRINT_ANY,
+                            "remote",
+                            "remote %s ",
+                            rt_addr_n2a_rta(AF_INET6, tb[IFLA_IPTUN_REMOTE]));
        }
 
        if (tb[IFLA_IPTUN_LOCAL]) {
-               fprintf(f, "local %s ",
-                       rt_addr_n2a_rta(AF_INET6, tb[IFLA_IPTUN_LOCAL]));
+               print_string(PRINT_ANY,
+                            "local",
+                            "local %s ",
+                            rt_addr_n2a_rta(AF_INET6, tb[IFLA_IPTUN_LOCAL]));
        }
 
        if (tb[IFLA_IPTUN_LINK] && rta_getattr_u32(tb[IFLA_IPTUN_LINK])) {
@@ -372,93 +376,161 @@ static void ip6tunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb
                const char *n = if_indextoname(link, s2);
 
                if (n)
-                       fprintf(f, "dev %s ", n);
+                       print_string(PRINT_ANY, "link", "dev %s ", n);
                else
-                       fprintf(f, "dev %u ", link);
+                       print_uint(PRINT_ANY, "link_index", "dev %u ", link);
        }
 
        if (flags & IP6_TNL_F_IGN_ENCAP_LIMIT)
-               printf("encaplimit none ");
+               print_bool(PRINT_ANY,
+                          "ip6_tnl_f_ign_encap_limit",
+                          "encaplimit none ",
+                          true);
        else if (tb[IFLA_IPTUN_ENCAP_LIMIT])
-               fprintf(f, "encaplimit %u ",
-                       rta_getattr_u8(tb[IFLA_IPTUN_ENCAP_LIMIT]));
+               print_uint(PRINT_ANY,
+                          "encap_limit",
+                          "encaplimit %u ",
+                          rta_getattr_u8(tb[IFLA_IPTUN_ENCAP_LIMIT]));
 
        if (tb[IFLA_IPTUN_TTL])
-               fprintf(f, "hoplimit %u ", rta_getattr_u8(tb[IFLA_IPTUN_TTL]));
+               print_uint(PRINT_ANY,
+                          "ttl",
+                          "hoplimit %u ",
+                          rta_getattr_u8(tb[IFLA_IPTUN_TTL]));
 
        if (flags & IP6_TNL_F_USE_ORIG_TCLASS)
-               printf("tclass inherit ");
+               print_bool(PRINT_ANY,
+                          "ip6_tnl_f_use_orig_tclass",
+                          "tclass inherit ",
+                          true);
        else if (tb[IFLA_IPTUN_FLOWINFO]) {
                __u32 val = ntohl(flowinfo & IP6_FLOWINFO_TCLASS);
 
-               printf("tclass 0x%02x ", (__u8)(val >> 20));
+               if (is_json_context()) {
+                       SPRINT_BUF(b1);
+
+                       snprintf(b1, sizeof(b1), "0x%02x", (__u8)(val >> 20));
+                       print_string(PRINT_JSON, "flowinfo_tclass", NULL, b1);
+               } else {
+                       printf("tclass 0x%02x ", (__u8)(val >> 20));
+               }
+       }
+
+       if (flags & IP6_TNL_F_USE_ORIG_FLOWLABEL) {
+               print_bool(PRINT_ANY,
+                          "ip6_tnl_f_use_orig_flowlabel",
+                          "flowlabel inherit ",
+                          true);
+       } else {
+               if (is_json_context()) {
+                       SPRINT_BUF(b1);
+
+                       snprintf(b1, sizeof(b1), "0x%05x",
+                                ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL));
+                       print_string(PRINT_JSON, "flowlabel", NULL, b1);
+               } else {
+                       printf("flowlabel 0x%05x ",
+                              ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL));
+               }
        }
 
-       if (flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
-               printf("flowlabel inherit ");
-       else
-               printf("flowlabel 0x%05x ", ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL));
+       if (is_json_context()) {
+               SPRINT_BUF(flwinfo);
 
-       printf("(flowinfo 0x%08x) ", ntohl(flowinfo));
+               snprintf(flwinfo, sizeof(flwinfo), "0x%08x", ntohl(flowinfo));
+               print_string(PRINT_JSON, "flowinfo", NULL, flwinfo);
+       } else {
+               printf("(flowinfo 0x%08x) ", ntohl(flowinfo));
+
+       }
 
        if (flags & IP6_TNL_F_RCV_DSCP_COPY)
-               printf("dscp inherit ");
+               print_bool(PRINT_ANY,
+                          "ip6_tnl_f_rcv_dscp_copy",
+                          "dscp inherit ",
+                          true);
 
        if (flags & IP6_TNL_F_MIP6_DEV)
-               fprintf(f, "mip6 ");
+               print_bool(PRINT_ANY, "ip6_tnl_f_mip6_dev", "mip6 ", true);
+
+       if (flags & IP6_TNL_F_USE_ORIG_FWMARK) {
+               print_bool(PRINT_ANY,
+                          "ip6_tnl_f_use_orig_fwmark",
+                          "fwmark inherit ",
+                          true);
+       } else if (tb[IFLA_IPTUN_FWMARK]) {
+               __u32 fwmark = rta_getattr_u32(tb[IFLA_IPTUN_FWMARK]);
 
-       if (flags & IP6_TNL_F_USE_ORIG_FWMARK)
-               fprintf(f, "fwmark inherit ");
-       else if (tb[IFLA_IPTUN_FWMARK] && rta_getattr_u32(tb[IFLA_IPTUN_FWMARK]))
-               fprintf(f, "fwmark 0x%x ", rta_getattr_u32(tb[IFLA_IPTUN_FWMARK]));
+               if (fwmark) {
+                       SPRINT_BUF(b1);
+
+                       snprintf(b1, sizeof(b1), "0x%x", fwmark);
+                       print_string(PRINT_ANY, "fwmark", "fwmark %s ", b1);
+               }
+       }
 
        if (tb[IFLA_IPTUN_ENCAP_TYPE] &&
-           rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_TYPE]) !=
-           TUNNEL_ENCAP_NONE) {
+           rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) {
                __u16 type = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_TYPE]);
                __u16 flags = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_FLAGS]);
                __u16 sport = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_SPORT]);
                __u16 dport = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_DPORT]);
 
-               fputs("encap ", f);
+               open_json_object("encap");
+               print_string(PRINT_FP, NULL, "encap ", NULL);
                switch (type) {
                case TUNNEL_ENCAP_FOU:
-                       fputs("fou ", f);
+                       print_string(PRINT_ANY, "type", "%s ", "fou");
                        break;
                case TUNNEL_ENCAP_GUE:
-                       fputs("gue ", f);
+                       print_string(PRINT_ANY, "type", "%s ", "gue");
                        break;
                default:
-                       fputs("unknown ", f);
+                       print_null(PRINT_ANY, "type", "unknown ", NULL);
                        break;
                }
 
-               if (sport == 0)
-                       fputs("encap-sport auto ", f);
-               else
-                       fprintf(f, "encap-sport %u", ntohs(sport));
+               if (is_json_context()) {
+                       print_uint(PRINT_JSON,
+                                  "sport",
+                                  NULL,
+                                  sport ? ntohs(sport) : 0);
+                       print_uint(PRINT_JSON, "dport", NULL, ntohs(dport));
+                       print_bool(PRINT_JSON, "csum", NULL,
+                                  flags & TUNNEL_ENCAP_FLAG_CSUM);
+                       print_bool(PRINT_JSON, "csum6", NULL,
+                                  flags & TUNNEL_ENCAP_FLAG_CSUM6);
+                       print_bool(PRINT_JSON, "remcsum", NULL,
+                                  flags & TUNNEL_ENCAP_FLAG_REMCSUM);
+                       close_json_object();
+               } else {
+                       if (sport == 0)
+                               fputs("encap-sport auto ", f);
+                       else
+                               fprintf(f, "encap-sport %u", ntohs(sport));
 
-               fprintf(f, "encap-dport %u ", ntohs(dport));
+                       fprintf(f, "encap-dport %u ", ntohs(dport));
 
-               if (flags & TUNNEL_ENCAP_FLAG_CSUM)
-                       fputs("encap-csum ", f);
-               else
-                       fputs("noencap-csum ", f);
+                       if (flags & TUNNEL_ENCAP_FLAG_CSUM)
+                               fputs("encap-csum ", f);
+                       else
+                               fputs("noencap-csum ", f);
 
-               if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
-                       fputs("encap-csum6 ", f);
-               else
-                       fputs("noencap-csum6 ", f);
+                       if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
+                               fputs("encap-csum6 ", f);
+                       else
+                               fputs("noencap-csum6 ", f);
 
-               if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
-                       fputs("encap-remcsum ", f);
-               else
-                       fputs("noencap-remcsum ", f);
+                       if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
+                               fputs("encap-remcsum ", f);
+                       else
+                               fputs("noencap-remcsum ", f);
+               }
        }
 }
 
 static void ip6tunnel_print_help(struct link_util *lu, int argc, char **argv,
-       FILE *f)
+                                FILE *f)
 {
        print_usage(f);
 }
index d24e7376d23ccdb10a34a7ad84901ba763d69c7a..6a725e91ea7065958ea429dc1fbec6434a419a45 100644 (file)
@@ -398,7 +398,7 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[
                        remote = format_host(AF_INET, 4, &addr);
        }
 
-       fprintf(f, "remote %s ", remote);
+       print_string(PRINT_ANY, "remote", "remote %s ", remote);
 
        if (tb[IFLA_IPTUN_LOCAL]) {
                unsigned int addr = rta_getattr_u32(tb[IFLA_IPTUN_LOCAL]);
@@ -407,43 +407,55 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[
                        local = format_host(AF_INET, 4, &addr);
        }
 
-       fprintf(f, "local %s ", local);
+       print_string(PRINT_ANY, "local", "local %s ", local);
 
        if (tb[IFLA_IPTUN_LINK] && rta_getattr_u32(tb[IFLA_IPTUN_LINK])) {
                unsigned int link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]);
                const char *n = if_indextoname(link, s2);
 
                if (n)
-                       fprintf(f, "dev %s ", n);
+                       print_string(PRINT_ANY, "link", "dev %s ", n);
                else
-                       fprintf(f, "dev %u ", link);
+                       print_int(PRINT_ANY, "link_index", "dev %u ", link);
        }
 
-       if (tb[IFLA_IPTUN_TTL] && rta_getattr_u8(tb[IFLA_IPTUN_TTL]))
-               fprintf(f, "ttl %d ", rta_getattr_u8(tb[IFLA_IPTUN_TTL]));
-       else
-               fprintf(f, "ttl inherit ");
+       if (tb[IFLA_IPTUN_TTL]) {
+               __u8 ttl = rta_getattr_u8(tb[IFLA_IPTUN_TTL]);
+
+               if (ttl)
+                       print_int(PRINT_ANY, "ttl", "ttl %d ", ttl);
+               else
+                       print_int(PRINT_JSON, "ttl", NULL, ttl);
+       } else {
+               print_string(PRINT_FP, NULL, "ttl %s ", "inherit");
+       }
 
-       if (tb[IFLA_IPTUN_TOS] && rta_getattr_u8(tb[IFLA_IPTUN_TOS])) {
+       if (tb[IFLA_IPTUN_TOS]) {
                int tos = rta_getattr_u8(tb[IFLA_IPTUN_TOS]);
 
-               fputs("tos ", f);
-               if (tos == 1)
-                       fputs("inherit ", f);
-               else
-                       fprintf(f, "0x%x ", tos);
+               if (tos) {
+                       if (is_json_context()) {
+                               print_0xhex(PRINT_JSON, "tos", "%#x", tos);
+                       } else {
+                               fputs("tos ", f);
+                               if (tos == 1)
+                                       fputs("inherit ", f);
+                               else
+                                       fprintf(f, "0x%x ", tos);
+                       }
+               }
        }
 
        if (tb[IFLA_IPTUN_PMTUDISC] && rta_getattr_u8(tb[IFLA_IPTUN_PMTUDISC]))
-               fprintf(f, "pmtudisc ");
+               print_bool(PRINT_ANY, "pmtudisc", "pmtudisc ", true);
        else
-               fprintf(f, "nopmtudisc ");
+               print_bool(PRINT_ANY, "pmtudisc", "nopmtudisc ", false);
 
        if (tb[IFLA_IPTUN_FLAGS]) {
                __u16 iflags = rta_getattr_u16(tb[IFLA_IPTUN_FLAGS]);
 
                if (iflags & SIT_ISATAP)
-                       fprintf(f, "isatap ");
+                       print_bool(PRINT_ANY, "isatap", "isatap ", true);
        }
 
        if (tb[IFLA_IPTUN_6RD_PREFIXLEN] &&
@@ -453,14 +465,32 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[
                __u32 relayprefix =
                        rta_getattr_u32(tb[IFLA_IPTUN_6RD_RELAY_PREFIX]);
 
-               printf("6rd-prefix %s/%u ",
-                      inet_ntop(AF_INET6, RTA_DATA(tb[IFLA_IPTUN_6RD_PREFIX]),
-                                s1, sizeof(s1)),
-                      prefixlen);
-               if (relayprefix) {
-                       printf("6rd-relay_prefix %s/%u ",
-                              format_host(AF_INET, 4, &relayprefix),
-                              relayprefixlen);
+               const char *prefix = inet_ntop(AF_INET6,
+                                              RTA_DATA(tb[IFLA_IPTUN_6RD_PREFIX]),
+                                              s1, sizeof(s1));
+
+               if (is_json_context()) {
+                       print_string(PRINT_JSON, "prefix", NULL, prefix);
+                       print_int(PRINT_JSON, "prefixlen", NULL, prefixlen);
+                       if (relayprefix) {
+                               print_string(PRINT_JSON,
+                                            "relay_prefix",
+                                            NULL,
+                                            format_host(AF_INET,
+                                                        4,
+                                                        &relayprefix));
+                               print_int(PRINT_JSON,
+                                         "relay_prefixlen",
+                                         NULL,
+                                         relayprefixlen);
+                       }
+               } else {
+                       printf("6rd-prefix %s/%u ", prefix, prefixlen);
+                       if (relayprefix) {
+                               printf("6rd-relay_prefix %s/%u ",
+                                      format_host(AF_INET, 4, &relayprefix),
+                                      relayprefixlen);
+                       }
                }
        }
 
@@ -470,45 +500,72 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[
                __u16 sport = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_SPORT]);
                __u16 dport = rta_getattr_u16(tb[IFLA_IPTUN_ENCAP_DPORT]);
 
-               fputs("encap ", f);
+               print_string(PRINT_FP, NULL, "encap ", NULL);
                switch (type) {
                case TUNNEL_ENCAP_FOU:
-                       fputs("fou ", f);
+                       print_string(PRINT_ANY, "type", "%s ", "fou");
                        break;
                case TUNNEL_ENCAP_GUE:
-                       fputs("gue ", f);
+                       print_string(PRINT_ANY, "type", "%s ", "gue");
                        break;
                default:
-                       fputs("unknown ", f);
+                       print_null(PRINT_ANY, "type", "unknown ", NULL);
                        break;
                }
 
-               if (sport == 0)
-                       fputs("encap-sport auto ", f);
-               else
-                       fprintf(f, "encap-sport %u", ntohs(sport));
+               if (is_json_context()) {
+                       print_uint(PRINT_JSON,
+                                  "sport",
+                                  NULL,
+                                  sport ? ntohs(sport) : 0);
+                       print_uint(PRINT_JSON, "dport", NULL, ntohs(dport));
+                       print_bool(PRINT_JSON,
+                                  "csum",
+                                  NULL,
+                                  flags & TUNNEL_ENCAP_FLAG_CSUM);
+                       print_bool(PRINT_JSON,
+                                  "csum6",
+                                  NULL,
+                                  flags & TUNNEL_ENCAP_FLAG_CSUM6);
+                       print_bool(PRINT_JSON,
+                                  "remcsum",
+                                  NULL,
+                                  flags & TUNNEL_ENCAP_FLAG_REMCSUM);
+                       close_json_object();
+               } else {
+                       if (sport == 0)
+                               fputs("encap-sport auto ", f);
+                       else
+                               fprintf(f, "encap-sport %u", ntohs(sport));
 
-               fprintf(f, "encap-dport %u ", ntohs(dport));
+                       fprintf(f, "encap-dport %u ", ntohs(dport));
 
-               if (flags & TUNNEL_ENCAP_FLAG_CSUM)
-                       fputs("encap-csum ", f);
-               else
-                       fputs("noencap-csum ", f);
+                       if (flags & TUNNEL_ENCAP_FLAG_CSUM)
+                               fputs("encap-csum ", f);
+                       else
+                               fputs("noencap-csum ", f);
 
-               if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
-                       fputs("encap-csum6 ", f);
-               else
-                       fputs("noencap-csum6 ", f);
+                       if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
+                               fputs("encap-csum6 ", f);
+                       else
+                               fputs("noencap-csum6 ", f);
 
-               if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
-                       fputs("encap-remcsum ", f);
-               else
-                       fputs("noencap-remcsum ", f);
+                       if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
+                               fputs("encap-remcsum ", f);
+                       else
+                               fputs("noencap-remcsum ", f);
+               }
        }
 
-       if (tb[IFLA_IPTUN_FWMARK] && rta_getattr_u32(tb[IFLA_IPTUN_FWMARK]))
-               fprintf(f, "fwmark 0x%x ",
-                       rta_getattr_u32(tb[IFLA_IPTUN_FWMARK]));
+       if (tb[IFLA_IPTUN_FWMARK]) {
+               __u32 fwmark = rta_getattr_u32(tb[IFLA_IPTUN_FWMARK]);
+
+               if (fwmark) {
+                       snprintf(s2, sizeof(s2), "0x%x", fwmark);
+
+                       print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2);
+               }
+       }
 }
 
 static void iptunnel_print_help(struct link_util *lu, int argc, char **argv,
index 3ffecfac9e8c30daf79f034b665759ef39bcd91f..8bd4d90059fc1cceb2d6a63403025330404482db 100644 (file)
@@ -224,7 +224,7 @@ static void vti_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                        remote = format_host(AF_INET, 4, &addr);
        }
 
-       fprintf(f, "remote %s ", remote);
+       print_string(PRINT_ANY, "remote", "remote %s ", remote);
 
        if (tb[IFLA_VTI_LOCAL]) {
                unsigned int addr = rta_getattr_u32(tb[IFLA_VTI_LOCAL]);
@@ -233,30 +233,36 @@ static void vti_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                        local = format_host(AF_INET, 4, &addr);
        }
 
-       fprintf(f, "local %s ", local);
+       print_string(PRINT_ANY, "local", "local %s ", local);
 
        if (tb[IFLA_VTI_LINK] &&
            (link = rta_getattr_u32(tb[IFLA_VTI_LINK]))) {
                const char *n = if_indextoname(link, s2);
 
                if (n)
-                       fprintf(f, "dev %s ", n);
+                       print_string(PRINT_ANY, "link", "dev %s ", n);
                else
-                       fprintf(f, "dev %u ", link);
+                       print_uint(PRINT_ANY, "link_index", "dev %u ", link);
        }
 
        if (tb[IFLA_VTI_IKEY] &&
            (key = rta_getattr_u32(tb[IFLA_VTI_IKEY])))
-               fprintf(f, "ikey %#x ", ntohl(key));
+               print_0xhex(PRINT_ANY, "ikey", "ikey %#x ", ntohl(key));
 
 
        if (tb[IFLA_VTI_OKEY] &&
            (key = rta_getattr_u32(tb[IFLA_VTI_OKEY])))
-               fprintf(f, "okey %#x ", ntohl(key));
+               print_0xhex(PRINT_ANY, "okey", "okey %#x ", ntohl(key));
 
-       if (tb[IFLA_VTI_FWMARK] && rta_getattr_u32(tb[IFLA_VTI_FWMARK])) {
-               fprintf(f, "fwmark 0x%x ",
-                       rta_getattr_u32(tb[IFLA_VTI_FWMARK]));
+       if (tb[IFLA_VTI_FWMARK]) {
+               __u32 fwmark = rta_getattr_u32(tb[IFLA_VTI_FWMARK]);
+
+               if (fwmark) {
+                       SPRINT_BUF(b1);
+
+                       snprintf(b1, sizeof(b1), "0x%x", fwmark);
+                       print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2);
+               }
        }
 }
 
index 6ea1fc2306cef7627e2b71bad5d510c6fcbcd715..8198d4680b93fad21c427969e4d83f5b24528014 100644 (file)
@@ -225,7 +225,7 @@ static void vti6_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                remote = format_host(AF_INET6, 16, &daddr);
        }
 
-       fprintf(f, "remote %s ", remote);
+       print_string(PRINT_ANY, "remote", "remote %s ", remote);
 
        if (tb[IFLA_VTI_LOCAL]) {
                memcpy(&saddr, RTA_DATA(tb[IFLA_VTI_LOCAL]), sizeof(saddr));
@@ -233,29 +233,35 @@ static void vti6_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
                local = format_host(AF_INET6, 16, &saddr);
        }
 
-       fprintf(f, "local %s ", local);
+       print_string(PRINT_ANY, "local", "local %s ", local);
 
        if (tb[IFLA_VTI_LINK] && (link = rta_getattr_u32(tb[IFLA_VTI_LINK]))) {
                const char *n = if_indextoname(link, s2);
 
                if (n)
-                       fprintf(f, "dev %s ", n);
+                       print_string(PRINT_ANY, "link", "dev %s ", n);
                else
-                       fprintf(f, "dev %u ", link);
+                       print_uint(PRINT_ANY, "link_index", "dev %u ", link);
        }
 
        if (tb[IFLA_VTI_IKEY]) {
                inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_IKEY]), s2, sizeof(s2));
-               fprintf(f, "ikey %s ", s2);
+               print_string(PRINT_ANY, "ikey", "ikey %s ", s2);
        }
 
        if (tb[IFLA_VTI_OKEY]) {
                inet_ntop(AF_INET, RTA_DATA(tb[IFLA_VTI_OKEY]), s2, sizeof(s2));
-               fprintf(f, "okey %s ", s2);
+               print_string(PRINT_ANY, "okey", "okey %s ", s2);
        }
 
-       if (tb[IFLA_VTI_FWMARK] && rta_getattr_u32(tb[IFLA_VTI_FWMARK])) {
-               fprintf(f, "fwmark 0x%x ", rta_getattr_u32(tb[IFLA_VTI_FWMARK]));
+       if (tb[IFLA_VTI_FWMARK]) {
+               __u32 fwmark = rta_getattr_u32(tb[IFLA_VTI_FWMARK]);
+
+               if (fwmark) {
+                       snprintf(s2, sizeof(s2), "0x%x", fwmark);
+
+                       print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2);
+               }
        }
 }
 
index 4e947500bd3b010ac5bc171ecd44167e7b101ac6..79d5e289d47acb87d37b40ebb0ba6f742045cf84 100644 (file)
@@ -89,6 +89,14 @@ void set_color_palette(void)
                is_dark_bg = 1;
 }
 
+void check_if_color_enabled(void)
+{
+       if (color_is_enabled) {
+               fprintf(stderr, "Option \"-json\" conflicts with \"-color\".\n");
+               exit(1);
+       }
+}
+
 int color_fprintf(FILE *fp, enum color_attr attr, const char *fmt, ...)
 {
        int ret = 0;
@@ -96,13 +104,13 @@ int color_fprintf(FILE *fp, enum color_attr attr, const char *fmt, ...)
 
        va_start(args, fmt);
 
-       if (!color_is_enabled) {
+       if (!color_is_enabled || attr == COLOR_NONE) {
                ret = vfprintf(fp, fmt, args);
                goto end;
        }
 
        ret += fprintf(fp, "%s",
-                      color_codes[attr_colors[is_dark_bg ? attr + 7 : attr]]);
+                      color_codes[attr_colors[is_dark_bg ? attr + 8 : attr]]);
        ret += vfprintf(fp, fmt, args);
        ret += fprintf(fp, "%s", color_codes[C_CLEAR]);
 
index 9fc05e96b605fa2ea40a6ba5bd33aa19692c962c..6b77d288cce2b3f1dfeb46d55c9a8ad81afd26a1 100644 (file)
@@ -156,7 +156,7 @@ void jsonw_name(json_writer_t *self, const char *name)
                putc(' ', self->out);
 }
 
-static void jsonw_printf(json_writer_t *self, const char *fmt, ...)
+void jsonw_printf(json_writer_t *self, const char *fmt, ...)
 {
        va_list ap;
 
@@ -199,23 +199,38 @@ void jsonw_bool(json_writer_t *self, bool val)
        jsonw_printf(self, "%s", val ? "true" : "false");
 }
 
-#ifdef notused
 void jsonw_null(json_writer_t *self)
 {
        jsonw_printf(self, "null");
 }
 
+void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num)
+{
+       jsonw_printf(self, fmt, num);
+}
+
+#ifdef notused
 void jsonw_float(json_writer_t *self, double num)
 {
        jsonw_printf(self, "%g", num);
 }
 #endif
 
+void jsonw_hu(json_writer_t *self, unsigned short num)
+{
+       jsonw_printf(self, "%hu", num);
+}
+
 void jsonw_uint(json_writer_t *self, uint64_t num)
 {
        jsonw_printf(self, "%"PRIu64, num);
 }
 
+void jsonw_lluint(json_writer_t *self, unsigned long long int num)
+{
+       jsonw_printf(self, "%llu", num);
+}
+
 void jsonw_int(json_writer_t *self, int64_t num)
 {
        jsonw_printf(self, "%"PRId64, num);
@@ -242,25 +257,46 @@ void jsonw_float_field(json_writer_t *self, const char *prop, double val)
 }
 #endif
 
+void jsonw_float_field_fmt(json_writer_t *self,
+                          const char *prop,
+                          const char *fmt,
+                          double val)
+{
+       jsonw_name(self, prop);
+       jsonw_float_fmt(self, fmt, val);
+}
+
 void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num)
 {
        jsonw_name(self, prop);
        jsonw_uint(self, num);
 }
 
+void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num)
+{
+       jsonw_name(self, prop);
+       jsonw_hu(self, num);
+}
+
+void jsonw_lluint_field(json_writer_t *self,
+                       const char *prop,
+                       unsigned long long int num)
+{
+       jsonw_name(self, prop);
+       jsonw_lluint(self, num);
+}
+
 void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num)
 {
        jsonw_name(self, prop);
        jsonw_int(self, num);
 }
 
-#ifdef notused
 void jsonw_null_field(json_writer_t *self, const char *prop)
 {
        jsonw_name(self, prop);
        jsonw_null(self);
 }
-#endif
 
 #ifdef TEST
 int main(int argc, char **argv)
index fc284921e10f391ada6059983fab36eb339b2f29..11dd9d0f8ef31e571209a688feb978513dceaec1 100644 (file)
@@ -177,7 +177,7 @@ throw " | " unreachable " | " prohibit " | " blackhole " | " nat " ]"
 
 .ti -8
 .IR ENCAP " := [ "
-.IR MPLS " | " IP " | " BPF " | " SEG6 " ] "
+.IR MPLS " | " IP " | " BPF " | " SEG6 " | " SEG6LOCAL " ] "
 
 .ti -8
 .IR ENCAP_MPLS " := "
@@ -220,6 +220,13 @@ throw " | " unreachable " | " prohibit " | " blackhole " | " nat " ]"
 .B hmac
 .IR KEYID " ]"
 
+.ti -8
+.IR ENCAP_SEG6LOCAL " := "
+.B seg6local
+.BR action
+.IR SEG6_ACTION " [ "
+.IR SEG6_ACTION_PARAM " ] "
+
 .ti -8
 .IR ROUTE_GET_FLAGS " := "
 .BR " [ "
@@ -674,6 +681,9 @@ is a string specifying the supported encapsulation type. Namely:
 .sp
 .BI seg6
 - encapsulation type IPv6 Segment Routing
+.sp
+.BI seg6local
+- local SRv6 segment processing
 
 .in -8
 .I ENCAPHDR
@@ -749,6 +759,56 @@ is a set of encapsulation attributes specific to the
 .in -2
 .sp
 
+.B seg6local
+.in +2
+.IR SEG6_ACTION " [ "
+.IR SEG6_ACTION_PARAM " ] "
+- Operation to perform on matching packets.
+The following actions are currently supported (\fB4.14+ only\fR).
+.in +2
+
+.B End
+- Regular SRv6 processing as intermediate segment endpoint.
+This action only accepts packets with a non-zero Segments Left
+value. Other matching packets are dropped.
+
+.B End.X nh6
+.I NEXTHOP
+- Regular SRv6 processing as intermediate segment endpoint.
+Additionally, forward processed packets to given next-hop.
+This action only accepts packets with a non-zero Segments Left
+value. Other matching packets are dropped.
+
+.B End.DX6 nh6
+.I NEXTHOP
+- Decapsulate inner IPv6 packet and forward it to the
+specified next-hop. If the argument is set to ::, then
+the next-hop is selected according to the local selection
+rules. This action only accepts packets with either a zero Segments
+Left value or no SRH at all, and an inner IPv6 packet. Other
+matching packets are dropped.
+
+.B End.B6 srh segs
+.IR SEGMENTS " [ "
+.B hmac
+.IR KEYID " ] "
+- Insert the specified SRH immediately after the IPv6 header,
+update the DA with the first segment of the newly inserted SRH,
+then forward the resulting packet. The original SRH is not
+modified. This action only accepts packets with a non-zero
+Segments Left value. Other matching packets are dropped.
+
+.B End.B6.Encaps srh segs
+.IR SEGMENTS " [ "
+.B hmac
+.IR KEYID " ] "
+- Regular SRv6 processing as intermediate segment endpoint.
+Additionally, encapsulate the matching packet within an outer IPv6 header
+followed by the specified SRH. The destination address of the outer IPv6
+header is set to the first segment of the new SRH. The source
+address is set as described in \fBip-sr\fR(8).
+.in -4
+
 .in -8
 
 .TP
index 51f43afeb3295825369572b068ba28358d2fde19..f46166e3f685940e04e1efafdf30f7834651ed4a 100644 (file)
@@ -1,4 +1,4 @@
-.TH "actions in tc" 8 "4 Jul 2017" "iproute2" "Linux"
+.TH "actions in tc" 8 "1 Aug 2017" "iproute2" "Linux"
 
 .SH NAME
 actions \- independently defined actions in tc
@@ -33,6 +33,9 @@ actions \- independently defined actions in tc
 .B actions
 .BR ls " | " list
 .I ACTNAMESPEC
+[
+.I ACTFILTER
+]
 
 .in +8
 .I ACTSPEC
@@ -60,6 +63,10 @@ ACTNAME
 :=
 .BI index " INDEX"
 
+.I ACTFILTER
+:=
+.BI since " MSTIME"
+
 .I COOKIESPEC
 :=
 .BI cookie " COOKIE"
@@ -71,9 +78,8 @@ ACTNAME
 .I ACTNAME
 may be any valid action type: gact, mirred, bpf, connmark, csum, police, etc.
 
-.I ACTPARAMS
-are the action-specific parameters; see the man page for the specific action
-type to be used for details.
+.I MSTIME
+Time since last update.
 
 .I CONTROL
 := {
@@ -132,6 +138,10 @@ List all the actions in the specified table. When combined with the
 option for
 .BR tc ","
 display the statistics for all actions in the specified table.
+When combined with the option
+.B since
+allows doing a millisecond time-filter since the last time an
+action was used in the datapath.
 .TP
 .B flush
 Delete all actions stored in the specified table.
@@ -176,6 +186,19 @@ As such, it can be used as a correlating value for maintaining user state.
 The value to be stored is completely arbitrary and does not require a specific
 format. It is stored inside the action structure itself.
 
+.TP
+.BI since " MSTIME"
+When dumping large number of actions, a millisecond time-filter can be
+specified
+.IR MSTIME "."
+The
+.I MSTIME
+is a millisecond count since last time a packet hit the action.
+As an example specifying "since 20000" implies to dump all actions
+that have seen packets in the last 20 seconds. This option is useful
+when the kernel has a large number of actions and you are only interested
+in recently used actions.
+
 .TP
 .I CONTROL
 The
index d663668a99685dab4f47ab8d189c1cc25c946c86..8370ea60432666bc697a1dac116be5d1a4e69698 100644 (file)
@@ -135,7 +135,7 @@ static int basic_print_opt(struct filter_util *qu, FILE *f,
        }
 
        if (tb[TCA_BASIC_ACT]) {
-               tc_print_action(f, tb[TCA_BASIC_ACT]);
+               tc_print_action(f, tb[TCA_BASIC_ACT], 0);
        }
 
        return 0;
index 2f8d12a6b148d895eced56966951d47c3d830111..c11540949c400edec38ef3612e685bb1239216d1 100644 (file)
@@ -239,7 +239,7 @@ static int bpf_print_opt(struct filter_util *qu, FILE *f,
        }
 
        if (tb[TCA_BPF_ACT])
-               tc_print_action(f, tb[TCA_BPF_ACT]);
+               tc_print_action(f, tb[TCA_BPF_ACT], 0);
 
        return 0;
 }
index ecf990998115fe2644a6cc94085539aa7e3c01b2..633700e66aa888a8f25c38deaafe70c9f805a5e6 100644 (file)
@@ -102,7 +102,7 @@ static int cgroup_print_opt(struct filter_util *qu, FILE *f,
        }
 
        if (tb[TCA_CGROUP_ACT])
-               tc_print_action(f, tb[TCA_CGROUP_ACT]);
+               tc_print_action(f, tb[TCA_CGROUP_ACT], 0);
 
        return 0;
 }
index 09ddcaa661796e606b697d5a37e6da7ac45d2de0..b15710497d1244fe3cac97d8bc282c28f07d0132 100644 (file)
@@ -347,7 +347,7 @@ static int flow_print_opt(struct filter_util *fu, FILE *f, struct rtattr *opt,
                tc_print_police(f, tb[TCA_FLOW_POLICE]);
        if (tb[TCA_FLOW_ACT]) {
                fprintf(f, "\n");
-               tc_print_action(f, tb[TCA_FLOW_ACT]);
+               tc_print_action(f, tb[TCA_FLOW_ACT], 0);
        }
        return 0;
 }
index 5be693ab7f6afc39b1e30501faa06e10e7a39972..934832e2bbe90562a90f3e739bc15e66f0c8da5d 100644 (file)
@@ -1316,7 +1316,7 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
        }
 
        if (tb[TCA_FLOWER_ACT])
-               tc_print_action(f, tb[TCA_FLOWER_ACT]);
+               tc_print_action(f, tb[TCA_FLOWER_ACT], 0);
 
        return 0;
 }
index 790bef960af157dcea03f6a295d9a5e2d850866a..c39789b345f4b5c9a2b577d68d2e459eb747fda7 100644 (file)
--- a/tc/f_fw.c
+++ b/tc/f_fw.c
@@ -160,7 +160,7 @@ static int fw_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, __u
 
        if (tb[TCA_FW_ACT]) {
                fprintf(f, "\n");
-               tc_print_action(f, tb[TCA_FW_ACT]);
+               tc_print_action(f, tb[TCA_FW_ACT], 0);
        }
        return 0;
 }
index 5a51e7553e82a1123d20db4ddb9a435dbde09882..d78660e79dbe4f94db6758ea03ebacd0f72321b8 100644 (file)
@@ -145,7 +145,7 @@ static int matchall_print_opt(struct filter_util *qu, FILE *f,
        }
 
        if (tb[TCA_MATCHALL_ACT])
-               tc_print_action(f, tb[TCA_MATCHALL_ACT]);
+               tc_print_action(f, tb[TCA_MATCHALL_ACT], 0);
 
        return 0;
 }
index 30514c4f4e3262e903892078846fb1cdeb992114..e88313f6a7d5835916c21e8f198e6fc6e801d9c9 100644 (file)
@@ -168,7 +168,7 @@ static int route_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt,
        if (tb[TCA_ROUTE4_POLICE])
                tc_print_police(f, tb[TCA_ROUTE4_POLICE]);
        if (tb[TCA_ROUTE4_ACT])
-               tc_print_action(f, tb[TCA_ROUTE4_ACT]);
+               tc_print_action(f, tb[TCA_ROUTE4_ACT], 0);
        return 0;
 }
 
index 94bfbefe8aa1c2c7476a08d4362d5e135a1bd91c..65caeb42bfe42ec6d91df32c77c29c4cdbad66e0 100644 (file)
@@ -402,7 +402,7 @@ static int rsvp_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt, _
        }
 
        if (tb[TCA_RSVP_ACT]) {
-               tc_print_action(f, tb[TCA_RSVP_ACT]);
+               tc_print_action(f, tb[TCA_RSVP_ACT], 0);
        }
        if (tb[TCA_RSVP_POLICE])
                tc_print_police(f, tb[TCA_RSVP_POLICE]);
index 784c8905931655e5374ac4b3edf79007faf8821a..dd1cb475098c8f19f7f0a3fbcdb68531abd04423 100644 (file)
@@ -173,7 +173,7 @@ static int tcindex_print_opt(struct filter_util *qu, FILE *f,
        }
        if (tb[TCA_TCINDEX_ACT]) {
                fprintf(f, "\n");
-               tc_print_action(f, tb[TCA_TCINDEX_ACT]);
+               tc_print_action(f, tb[TCA_TCINDEX_ACT], 0);
        }
        return 0;
 }
index b272c2cb83cd4383651b35eb8b9bc3bae4612a69..5815be9cd23e6c9809f375886cb54f035e537bfe 100644 (file)
@@ -1337,7 +1337,7 @@ static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt,
        }
 
        if (tb[TCA_U32_ACT])
-               tc_print_action(f, tb[TCA_U32_ACT]);
+               tc_print_action(f, tb[TCA_U32_ACT], 0);
 
        return 0;
 }
index 6ebe85e1cbe365c93a83c68d27d28aa87cb97f2d..50d16b41e469703f0a57e01e15a71686c52f1cb9 100644 (file)
@@ -346,21 +346,25 @@ tc_print_action_flush(FILE *f, const struct rtattr *arg)
 }
 
 int
-tc_print_action(FILE *f, const struct rtattr *arg)
+tc_print_action(FILE *f, const struct rtattr *arg, unsigned short tot_acts)
 {
 
        int i;
-       struct rtattr *tb[TCA_ACT_MAX_PRIO + 1];
 
        if (arg == NULL)
                return 0;
 
-       parse_rtattr_nested(tb, TCA_ACT_MAX_PRIO, arg);
+       if (!tot_acts)
+               tot_acts = TCA_ACT_MAX_PRIO;
+
+       struct rtattr *tb[tot_acts + 1];
+
+       parse_rtattr_nested(tb, tot_acts, arg);
 
        if (tab_flush && NULL != tb[0]  && NULL == tb[1])
                return tc_print_action_flush(f, tb[0]);
 
-       for (i = 0; i < TCA_ACT_MAX_PRIO; i++) {
+       for (i = 0; i < tot_acts; i++) {
                if (tb[i]) {
                        fprintf(f, "\n\taction order %d: ", i);
                        if (tc_print_one_action(f, tb[i]) < 0) {
@@ -380,7 +384,8 @@ int print_action(const struct sockaddr_nl *who,
        FILE *fp = (FILE *)arg;
        struct tcamsg *t = NLMSG_DATA(n);
        int len = n->nlmsg_len;
-       struct rtattr *tb[TCAA_MAX+1];
+       __u32 *tot_acts = NULL;
+       struct rtattr *tb[TCA_ROOT_MAX+1];
 
        len -= NLMSG_LENGTH(sizeof(*t));
 
@@ -389,8 +394,12 @@ int print_action(const struct sockaddr_nl *who,
                return -1;
        }
 
-       parse_rtattr(tb, TCAA_MAX, TA_RTA(t), len);
+       parse_rtattr(tb, TCA_ROOT_MAX, TA_RTA(t), len);
+
+       if (tb[TCA_ROOT_COUNT])
+               tot_acts = RTA_DATA(tb[TCA_ROOT_COUNT]);
 
+       fprintf(fp, "total acts %d\n", tot_acts ? *tot_acts:0);
        if (tb[TCA_ACT_TAB] == NULL) {
                if (n->nlmsg_type != RTM_GETACTION)
                        fprintf(stderr, "print_action: NULL kind\n");
@@ -414,7 +423,9 @@ int print_action(const struct sockaddr_nl *who,
                        fprintf(fp, "Replaced action ");
                }
        }
-       tc_print_action(fp, tb[TCA_ACT_TAB]);
+
+
+       tc_print_action(fp, tb[TCA_ACT_TAB], tot_acts ? *tot_acts:0);
 
        return 0;
 }
@@ -427,7 +438,7 @@ static int tc_action_gd(int cmd, unsigned int flags, int *argc_p, char ***argv_p
        char **argv = *argv_p;
        int prio = 0;
        int ret = 0;
-       __u32 i;
+       __u32 i = 0;
        struct rtattr *tail;
        struct rtattr *tail2;
        struct nlmsghdr *ans = NULL;
@@ -498,7 +509,8 @@ static int tc_action_gd(int cmd, unsigned int flags, int *argc_p, char ***argv_p
                tail2 = NLMSG_TAIL(&req.n);
                addattr_l(&req.n, MAX_MSG, ++prio, NULL, 0);
                addattr_l(&req.n, MAX_MSG, TCA_ACT_KIND, k, strlen(k) + 1);
-               addattr32(&req.n, MAX_MSG, TCA_ACT_INDEX, i);
+               if (i > 0)
+                       addattr32(&req.n, MAX_MSG, TCA_ACT_INDEX, i);
                tail2->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail2;
 
        }
@@ -561,12 +573,16 @@ static int tc_action_modify(int cmd, unsigned int flags, int *argc_p, char ***ar
        return ret;
 }
 
-static int tc_act_list_or_flush(int argc, char **argv, int event)
+static int tc_act_list_or_flush(int *argc_p, char ***argv_p, int event)
 {
+       struct rtattr *tail, *tail2, *tail3, *tail4;
        int ret = 0, prio = 0, msg_size = 0;
-       char k[16];
-       struct rtattr *tail, *tail2;
        struct action_util *a = NULL;
+       struct nla_bitfield32 flag_select = { 0 };
+       char **argv = *argv_p;
+       __u32 msec_since = 0;
+       int argc = *argc_p;
+       char k[16];
        struct {
                struct nlmsghdr         n;
                struct tcamsg           t;
@@ -597,11 +613,31 @@ static int tc_act_list_or_flush(int argc, char **argv, int event)
        }
        strncpy(k, *argv, sizeof(k) - 1);
 
+       argc -= 1;
+       argv += 1;
+
+       if (argc && (strcmp(*argv, "since") == 0)) {
+               NEXT_ARG();
+               if (get_u32(&msec_since, *argv, 0))
+                       invarg("dump time \"since\" is invalid", *argv);
+       }
+
        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;
 
+       tail3 = NLMSG_TAIL(&req.n);
+       flag_select.value |= TCA_FLAG_LARGE_DUMP_ON;
+       flag_select.selector |= TCA_FLAG_LARGE_DUMP_ON;
+       addattr_l(&req.n, MAX_MSG, TCA_ROOT_FLAGS, &flag_select,
+                 sizeof(struct nla_bitfield32));
+       tail3->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail3;
+       if (msec_since) {
+               tail4 = NLMSG_TAIL(&req.n);
+               addattr32(&req.n, MAX_MSG, TCA_ROOT_TIME_DELTA, msec_since);
+               tail4->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail4;
+       }
        msg_size = NLMSG_ALIGN(req.n.nlmsg_len) - NLMSG_ALIGN(sizeof(struct nlmsghdr));
 
        if (event == RTM_GETACTION) {
@@ -626,6 +662,8 @@ static int tc_act_list_or_flush(int argc, char **argv, int event)
 
 bad_val:
 
+       *argc_p = argc;
+       *argv_p = argv;
        return ret;
 }
 
@@ -655,13 +693,21 @@ int do_action(int argc, char **argv)
                                act_usage();
                                return -1;
                        }
-                       return tc_act_list_or_flush(argc-2, argv+2, RTM_GETACTION);
+
+                       argc -= 2;
+                       argv += 2;
+                       return tc_act_list_or_flush(&argc, &argv,
+                                                   RTM_GETACTION);
                } else if (matches(*argv, "flush") == 0) {
                        if (argc <= 2) {
                                act_usage();
                                return -1;
                        }
-                       return tc_act_list_or_flush(argc-2, argv+2, RTM_DELACTION);
+
+                       argc -= 2;
+                       argv += 2;
+                       return tc_act_list_or_flush(&argc, &argv,
+                                                   RTM_DELACTION);
                } else if (matches(*argv, "help") == 0) {
                        act_usage();
                        return -1;
index 5c54ad384eae61cb510f102d46dc1936d1978a5a..583a21a828ded9f950f52d264109d40b9ce76c21 100644 (file)
@@ -113,7 +113,7 @@ int act_parse_police(struct action_util *a, int *argc_p,
                     char ***argv_p, int tca_id, struct nlmsghdr *n);
 int print_police(struct action_util *a, FILE *f, struct rtattr *tb);
 int police_print_xstats(struct action_util *a, FILE *f, struct rtattr *tb);
-int tc_print_action(FILE *f, const struct rtattr *tb);
+int tc_print_action(FILE *f, const struct rtattr *tb, unsigned short tot_acts);
 int tc_print_ipt(FILE *f, const struct rtattr *tb);
 int parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n);
 void print_tm(FILE *f, const struct tcf_t *tm);