From f0b9b79572a01a47a1f15f1a0b09e8591bfbefe6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 17 Jul 2017 18:32:03 -0700 Subject: [PATCH 01/53] update kernel headers from net-next Just as net-next merge window opens. Signed-off-by: Stephen Hemminger --- include/linux/bpf.h | 90 ++++++++++++++++++++++++++++++++++++++++++- include/linux/magic.h | 3 ++ include/linux/sctp.h | 6 +++ 3 files changed, 98 insertions(+), 1 deletion(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 8a966ef0..49e1def7 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -104,6 +104,7 @@ 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, }; enum bpf_prog_type { @@ -120,12 +121,14 @@ enum bpf_prog_type { BPF_PROG_TYPE_LWT_IN, BPF_PROG_TYPE_LWT_OUT, BPF_PROG_TYPE_LWT_XMIT, + BPF_PROG_TYPE_SOCK_OPS, }; enum bpf_attach_type { BPF_CGROUP_INET_INGRESS, BPF_CGROUP_INET_EGRESS, BPF_CGROUP_INET_SOCK_CREATE, + BPF_CGROUP_SOCK_OPS, __MAX_BPF_ATTACH_TYPE }; @@ -345,6 +348,11 @@ union bpf_attr { * @flags: bit 0 - if set, redirect to ingress instead of egress * other bits - reserved * Return: TC_ACT_REDIRECT + * int bpf_redirect_map(key, map, flags) + * redirect to endpoint in map + * @key: index in map to lookup + * @map: fd of map to do lookup in + * @flags: -- * * u32 bpf_get_route_realm(skb) * retrieve a dst's tclassid @@ -518,6 +526,25 @@ union bpf_attr { * Set full skb->hash. * @skb: pointer to skb * @hash: hash to set + * + * int bpf_setsockopt(bpf_socket, level, optname, optval, optlen) + * Calls setsockopt. Not all opts are available, only those with + * integer optvals plus TCP_CONGESTION. + * Supported levels: SOL_SOCKET and IPROTO_TCP + * @bpf_socket: pointer to bpf_socket + * @level: SOL_SOCKET or IPROTO_TCP + * @optname: option name + * @optval: pointer to option value + * @optlen: length of optval in byes + * Return: 0 or negative error + * + * int bpf_skb_adjust_room(skb, len_diff, mode, flags) + * Grow or shrink room in sk_buff. + * @skb: pointer to skb + * @len_diff: (signed) amount of room to grow/shrink + * @mode: operation mode (enum bpf_adj_room_mode) + * @flags: reserved for future use + * Return: 0 on success or negative error code */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -568,7 +595,10 @@ union bpf_attr { FN(probe_read_str), \ FN(get_socket_cookie), \ FN(get_socket_uid), \ - FN(set_hash), + FN(set_hash), \ + FN(setsockopt), \ + FN(skb_adjust_room), \ + FN(redirect_map), /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call @@ -618,6 +648,11 @@ enum bpf_func_id { /* BPF_FUNC_perf_event_output for sk_buff input context. */ #define BPF_F_CTXLEN_MASK (0xfffffULL << 32) +/* Mode for BPF_FUNC_skb_adjust_room helper. */ +enum bpf_adj_room_mode { + BPF_ADJ_ROOM_NET, +}; + /* user accessible mirror of in-kernel sk_buff. * new fields can only be added to the end of this structure */ @@ -689,6 +724,7 @@ enum xdp_action { XDP_DROP, XDP_PASS, XDP_TX, + XDP_REDIRECT, }; /* user accessible metadata for XDP packet hook @@ -720,4 +756,56 @@ struct bpf_map_info { __u32 map_flags; } __attribute__((aligned(8))); +/* User bpf_sock_ops struct to access socket values and specify request ops + * and their replies. + * Some of this fields are in network (bigendian) byte order and may need + * to be converted before use (bpf_ntohl() defined in samples/bpf/bpf_endian.h). + * New fields can only be added at the end of this structure + */ +struct bpf_sock_ops { + __u32 op; + union { + __u32 reply; + __u32 replylong[4]; + }; + __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 */ +}; + +/* List of known BPF sock_ops operators. + * New entries can only be added at the end + */ +enum { + BPF_SOCK_OPS_VOID, + BPF_SOCK_OPS_TIMEOUT_INIT, /* Should return SYN-RTO value to use or + * -1 if default value should be used + */ + BPF_SOCK_OPS_RWND_INIT, /* Should return initial advertized + * window (in packets) or -1 if default + * value should be used + */ + BPF_SOCK_OPS_TCP_CONNECT_CB, /* Calls BPF program right before an + * active connection is initialized + */ + BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB, /* Calls BPF program when an + * active connection is + * established + */ + BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB, /* Calls BPF program when a + * passive connection is + * established + */ + BPF_SOCK_OPS_NEEDS_ECN, /* If connection's congestion control + * needs ECN + */ +}; + +#define TCP_BPF_IW 1001 /* Set TCP initial congestion window */ +#define TCP_BPF_SNDCWND_CLAMP 1002 /* Set sndcwnd_clamp */ + #endif /* __LINUX_BPF_H__ */ diff --git a/include/linux/magic.h b/include/linux/magic.h index e230af2e..e439565d 100644 --- a/include/linux/magic.h +++ b/include/linux/magic.h @@ -42,6 +42,7 @@ #define MSDOS_SUPER_MAGIC 0x4d44 /* MD */ #define NCP_SUPER_MAGIC 0x564c /* Guess, what 0x564c is :-) */ #define NFS_SUPER_MAGIC 0x6969 +#define OCFS2_SUPER_MAGIC 0x7461636f #define OPENPROM_SUPER_MAGIC 0x9fa1 #define QNX4_SUPER_MAGIC 0x002f /* qnx4 fs detection */ #define QNX6_SUPER_MAGIC 0x68191122 /* qnx6 fs detection */ @@ -80,6 +81,8 @@ #define BTRFS_TEST_MAGIC 0x73727279 #define NSFS_MAGIC 0x6e736673 #define BPF_FS_MAGIC 0xcafe4a11 +#define AAFS_MAGIC 0x5a3c69f0 + /* Since UDF 2.01 is ISO 13346 based... */ #define UDF_SUPER_MAGIC 0x15013346 #define BALLOON_KVM_MAGIC 0x13661366 diff --git a/include/linux/sctp.h b/include/linux/sctp.h index 4a169feb..fec24c41 100644 --- a/include/linux/sctp.h +++ b/include/linux/sctp.h @@ -121,6 +121,7 @@ typedef __s32 sctp_assoc_t; #define SCTP_RESET_STREAMS 119 #define SCTP_RESET_ASSOC 120 #define SCTP_ADD_STREAMS 121 +#define SCTP_SOCKOPT_PEELOFF_FLAGS 122 /* PR-SCTP policies */ #define SCTP_PR_SCTP_NONE 0x0000 @@ -972,6 +973,11 @@ typedef struct { int sd; } sctp_peeloff_arg_t; +typedef struct { + sctp_peeloff_arg_t p_arg; + unsigned flags; +} sctp_peeloff_flags_arg_t; + /* * Peer Address Thresholds socket option */ From 44e0f6f3cd93b45270d6c45c5f5d60baf311a38f Mon Sep 17 00:00:00 2001 From: Nikhil Gajendrakumar Date: Fri, 7 Jul 2017 15:24:16 -0700 Subject: [PATCH 02/53] bridge: this patch adds json support for bridge mdb show This patch adds json output to bridge mdb show Normal Output: $ bridge -d -s mdb show dev br0 port swp3 grp 239.0.0.1 temp vid 128 172.26 dev br0 port swp3 grp 239.0.0.1 temp vid 64 172.26 dev br0 port swp2 grp 239.0.0.2 temp vid 1024 172.26 dev br0 port swp2 grp 239.0.0.2 temp vid 256 172.26 dev br0 port swp2 grp 239.0.0.2 temp vid 1 172.26 dev br0 port swp3 grp 239.0.0.1 temp vid 1 172.26 router ports on br0: swp4 0.00 permanent router ports on br0: swp5 0.00 permanent Json Output: $ bridge -d -s -j mdb show { "mdb": [{ "dev": "br0", "port": "swp3", "grp": "239.0.0.1", "state": "temp", "vid": 128, "timer": " 166.74" },{ "dev": "br0", "port": "swp3", "grp": "239.0.0.1", "state": "temp", "vid": 64, "timer": " 166.74" },{ "dev": "br0", "port": "swp2", "grp": "239.0.0.2", "state": "temp", "vid": 1024, "timer": " 166.74" },{ "dev": "br0", "port": "swp2", "grp": "239.0.0.2", "state": "temp", "vid": 256, "timer": " 166.74" },{ "dev": "br0", "port": "swp2", "grp": "239.0.0.2", "state": "temp", "vid": 1, "timer": " 166.74" },{ "dev": "br0", "port": "swp3", "grp": "239.0.0.1", "state": "temp", "vid": 1, "timer": " 166.74" } ], "router": { "br0": [{ "port": "swp4", "timer": " 0.00", "type": "permanent" },{ "port": "swp5", "timer": " 0.00", "type": "permanent" } ] } } Signed-off-by: Nikhil Gajendrakumar Signed-off-by: Roopa Prabhu --- bridge/mdb.c | 218 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 180 insertions(+), 38 deletions(-) diff --git a/bridge/mdb.c b/bridge/mdb.c index e60ff3ef..748091b8 100644 --- a/bridge/mdb.c +++ b/bridge/mdb.c @@ -13,6 +13,7 @@ #include #include #include +#include #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; } From 72e4ea5eb63cb66cd7dee669ab2a2376eb84b34e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 3 Aug 2017 16:12:19 -0700 Subject: [PATCH 03/53] update headers from 4.13 net-next Signed-off-by: Stephen Hemminger --- include/linux/netlink.h | 17 +++++++++++++++++ include/linux/rtnetlink.h | 23 +++++++++++++++++++++-- include/linux/tcp.h | 8 ++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 3a53b9aa..654f08ad 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -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/rtnetlink.h b/include/linux/rtnetlink.h index 1d62dad0..813e9e07 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -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/tcp.h b/include/linux/tcp.h index 79b2d6fc..8d0545e6 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -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 */ From 4b3409d8631490a3cedc336239c700add78042ec Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 3 Aug 2017 09:13:55 +0300 Subject: [PATCH 04/53] iproute: Display offload indication per-nexthop Since kernel commit 475abbf1ef67 ("ipv4: fib: Set offload indication according to nexthop flags") offload indication is reported on a per-nexthop basis. Adjust iproute2 to display it. Signed-off-by: Ido Schimmel Reviewed-by: Jiri Pirko Acked-by: David Ahern --- ip/iproute.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ip/iproute.c b/ip/iproute.c index cb695ad4..39af38cf 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -696,6 +696,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); From 9e71352581954065ea4a6c0766f55fcb04ca0499 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Wed, 2 Aug 2017 07:46:26 -0400 Subject: [PATCH 05/53] tc actions: Improved batching and time filtered dumping dump more than TCA_ACT_MAX_PRIO actions per batch when the kernel supports it. Introduced keyword "since" for time based filtering of actions. Some example (we have 400 actions bound to 400 filters); at installation time. Using updated when tc setting the time of interest to 120 seconds earlier (we see 400 actions): prompt$ hackedtc actions ls action gact since 120000| grep index | wc -l 400 go get some coffee and wait for > 120 seconds and try again: prompt$ hackedtc actions ls action gact since 120000 | grep index | wc -l 0 Lets see a filter bound to one of these actions: .... filter pref 10 u32 filter pref 10 u32 fh 800: ht divisor 1 filter pref 10 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:10 (rule hit 2 success 1) match 7f000002/ffffffff at 12 (success 1 ) action order 1: gact action pass random type none pass val 0 index 23 ref 2 bind 1 installed 1145 sec used 802 sec Action statistics: Sent 84 bytes 1 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 ... that coffee took long, no? It was good. Now lets ping -c 1 127.0.0.2, then run the actions again: prompt$ hackedtc actions ls action gact since 120 | grep index | wc -l 1 More details please: prompt$ hackedtc -s actions ls action gact since 120000 action order 0: gact action pass random type none pass val 0 index 23 ref 2 bind 1 installed 1270 sec used 30 sec Action statistics: Sent 168 bytes 2 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 And the filter? filter pref 10 u32 filter pref 10 u32 fh 800: ht divisor 1 filter pref 10 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:10 (rule hit 4 success 2) match 7f000002/ffffffff at 12 (success 2 ) action order 1: gact action pass random type none pass val 0 index 23 ref 2 bind 1 installed 1324 sec used 84 sec Action statistics: Sent 168 bytes 2 pkt (dropped 0, overlimits 0 requeues 0) backlog 0b 0p requeues 0 Signed-off-by: Jamal Hadi Salim --- tc/f_basic.c | 2 +- tc/f_bpf.c | 2 +- tc/f_cgroup.c | 2 +- tc/f_flow.c | 2 +- tc/f_flower.c | 2 +- tc/f_fw.c | 2 +- tc/f_matchall.c | 2 +- tc/f_route.c | 2 +- tc/f_rsvp.c | 2 +- tc/f_tcindex.c | 2 +- tc/f_u32.c | 2 +- tc/m_action.c | 74 +++++++++++++++++++++++++++++++++++++++---------- tc/tc_util.h | 2 +- 13 files changed, 72 insertions(+), 26 deletions(-) diff --git a/tc/f_basic.c b/tc/f_basic.c index d663668a..8370ea60 100644 --- a/tc/f_basic.c +++ b/tc/f_basic.c @@ -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; diff --git a/tc/f_bpf.c b/tc/f_bpf.c index 2f8d12a6..c1154094 100644 --- a/tc/f_bpf.c +++ b/tc/f_bpf.c @@ -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; } diff --git a/tc/f_cgroup.c b/tc/f_cgroup.c index ecf99099..633700e6 100644 --- a/tc/f_cgroup.c +++ b/tc/f_cgroup.c @@ -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; } diff --git a/tc/f_flow.c b/tc/f_flow.c index 09ddcaa6..b1571049 100644 --- a/tc/f_flow.c +++ b/tc/f_flow.c @@ -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; } diff --git a/tc/f_flower.c b/tc/f_flower.c index 5be693ab..934832e2 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -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; } diff --git a/tc/f_fw.c b/tc/f_fw.c index 790bef96..c39789b3 100644 --- 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; } diff --git a/tc/f_matchall.c b/tc/f_matchall.c index 5a51e755..d78660e7 100644 --- a/tc/f_matchall.c +++ b/tc/f_matchall.c @@ -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; } diff --git a/tc/f_route.c b/tc/f_route.c index 30514c4f..e88313f6 100644 --- a/tc/f_route.c +++ b/tc/f_route.c @@ -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; } diff --git a/tc/f_rsvp.c b/tc/f_rsvp.c index 94bfbefe..65caeb42 100644 --- a/tc/f_rsvp.c +++ b/tc/f_rsvp.c @@ -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]); diff --git a/tc/f_tcindex.c b/tc/f_tcindex.c index 784c8905..dd1cb475 100644 --- a/tc/f_tcindex.c +++ b/tc/f_tcindex.c @@ -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; } diff --git a/tc/f_u32.c b/tc/f_u32.c index b272c2cb..5815be9c 100644 --- a/tc/f_u32.c +++ b/tc/f_u32.c @@ -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; } diff --git a/tc/m_action.c b/tc/m_action.c index 6ebe85e1..50d16b41 100644 --- a/tc/m_action.c +++ b/tc/m_action.c @@ -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; diff --git a/tc/tc_util.h b/tc/tc_util.h index 5c54ad38..583a21a8 100644 --- a/tc/tc_util.h +++ b/tc/tc_util.h @@ -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); From 5c8176ddbcda4ffe2648d3479fd0fe9f783c5ef9 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Wed, 2 Aug 2017 07:46:27 -0400 Subject: [PATCH 06/53] actions: update the man page to describe the "since" time filter Signed-off-by: Jamal Hadi Salim --- man/man8/tc-actions.8 | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/man/man8/tc-actions.8 b/man/man8/tc-actions.8 index 51f43afe..f46166e3 100644 --- a/man/man8/tc-actions.8 +++ b/man/man8/tc-actions.8 @@ -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 From 96421f92ef6233f07a04caa7532fa24abe406c45 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 9 Aug 2017 08:35:26 -0700 Subject: [PATCH 07/53] include: update headers from net-next Signed-off-by: Stephen Hemminger --- include/linux/bpf.h | 16 +++++++++++----- include/linux/lwtunnel.h | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 49e1def7..8b3d7d3f 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -345,14 +345,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 - * int bpf_redirect_map(key, map, flags) + * @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 - * @map: fd of map to do lookup in * @flags: -- + * Return: XDP_REDIRECT on success or XDP_ABORT on error * * u32 bpf_get_route_realm(skb) * retrieve a dst's tclassid diff --git a/include/linux/lwtunnel.h b/include/linux/lwtunnel.h index faa6eabe..32984262 100644 --- a/include/linux/lwtunnel.h +++ b/include/linux/lwtunnel.h @@ -11,6 +11,7 @@ enum lwtunnel_encap_types { LWTUNNEL_ENCAP_IP6, LWTUNNEL_ENCAP_SEG6, LWTUNNEL_ENCAP_BPF, + LWTUNNEL_ENCAP_SEG6_LOCAL, __LWTUNNEL_ENCAP_MAX, }; From 3af3d358a3a991f8276e96a06777fc43c28b8e71 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 10 Aug 2017 16:42:35 -0700 Subject: [PATCH 08/53] more BPF headers update Signed-off-by: Stephen Hemminger --- include/linux/bpf.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 8b3d7d3f..9c7c78bc 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -30,9 +30,14 @@ #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 */ From e0495b84ab71c7f9b0aac6b3b8bee1803344f9bf Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 15 Aug 2017 16:35:30 -0700 Subject: [PATCH 09/53] seg6: add include/linux/seg6_local.h Signed-off-by: Stephen Hemminger --- include/linux/seg6_local.h | 68 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 include/linux/seg6_local.h diff --git a/include/linux/seg6_local.h b/include/linux/seg6_local.h new file mode 100644 index 00000000..76b90d60 --- /dev/null +++ b/include/linux/seg6_local.h @@ -0,0 +1,68 @@ +/* + * SR-IPv6 implementation + * + * Author: + * David Lebrun + * + * + * 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 + +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 From b7f7c1b8173d3dc180b8f76a8a47087029bb3148 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 15 Aug 2017 16:42:24 -0700 Subject: [PATCH 10/53] include: add pfkeyv2.h drop ipv6.h pfkeyv2.h is include by ipsec. linux/ipv6.h is not included by any code in current tree. Signed-off-by: Stephen Hemminger --- include/linux/ipv6.h | 192 -------------------- include/linux/pfkeyv2.h | 383 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 383 insertions(+), 192 deletions(-) delete mode 100644 include/linux/ipv6.h create mode 100644 include/linux/pfkeyv2.h diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h deleted file mode 100644 index 5c08b222..00000000 --- a/include/linux/ipv6.h +++ /dev/null @@ -1,192 +0,0 @@ -#ifndef _IPV6_H -#define _IPV6_H - -#include -#include -#include -#include - -/* 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 " -#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 */ diff --git a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h new file mode 100644 index 00000000..ada7f017 --- /dev/null +++ b/include/linux/pfkeyv2.h @@ -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 + +#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) */ From 00e76d4da37fef37a96843b87dac34f9d4bd2133 Mon Sep 17 00:00:00 2001 From: David Lebrun Date: Wed, 9 Aug 2017 17:33:24 +0200 Subject: [PATCH 11/53] iproute: add helper functions for SRH processing This patch adds two helper functions to print and parse Segment Routing Headers. Signed-off-by: David Lebrun --- ip/iproute_lwtunnel.c | 124 ++++++++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 52 deletions(-) diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index 5c0c7d11..16d2584e 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -83,24 +83,10 @@ static int read_encap_type(const char *name) return LWTUNNEL_ENCAP_NONE; } -static void print_encap_seg6(FILE *fp, struct rtattr *encap) +static void print_srh(FILE *fp, struct ipv6_sr_hdr *srh) { - 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); - - if (!tb[SEG6_IPTUNNEL_SRH]) - return; - - tuninfo = RTA_DATA(tb[SEG6_IPTUNNEL_SRH]); - fprintf(fp, "mode %s ", - (tuninfo->mode == SEG6_IPTUN_MODE_ENCAP) ? "encap" : "inline"); - - srh = tuninfo->srh; - fprintf(fp, "segs %d [ ", srh->first_segment + 1); for (i = srh->first_segment; i >= 0; i--) @@ -118,6 +104,23 @@ static void print_encap_seg6(FILE *fp, struct rtattr *encap) } } +static void print_encap_seg6(FILE *fp, struct rtattr *encap) +{ + struct rtattr *tb[SEG6_IPTUNNEL_MAX+1]; + struct seg6_iptunnel_encap *tuninfo; + + parse_rtattr_nested(tb, SEG6_IPTUNNEL_MAX, encap); + + if (!tb[SEG6_IPTUNNEL_SRH]) + return; + + tuninfo = RTA_DATA(tb[SEG6_IPTUNNEL_SRH]); + fprintf(fp, "mode %s ", + (tuninfo->mode == SEG6_IPTUN_MODE_ENCAP) ? "encap" : "inline"); + + print_srh(fp, tuninfo->srh); +} + static void print_encap_mpls(FILE *fp, struct rtattr *encap) { struct rtattr *tb[MPLS_IPTUNNEL_MAX+1]; @@ -290,6 +293,55 @@ void lwt_print_encap(FILE *fp, struct rtattr *encap_type, } } +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 +353,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 +387,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 +398,13 @@ 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; - - 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); - } + memcpy(tuninfo->srh, srh, srhlen); rta_addattr_l(rta, len, SEG6_IPTUNNEL_SRH, tuninfo, sizeof(*tuninfo) + srhlen); + free(tuninfo); + free(srh); *argcp = argc + 1; *argvp = argv - 1; From 8db158b9caacede19bfdaabd9fea341b24bade39 Mon Sep 17 00:00:00 2001 From: David Lebrun Date: Wed, 9 Aug 2017 17:33:25 +0200 Subject: [PATCH 12/53] iproute: add support for SRv6 local segment processing This patch adds support for the seg6local lightweight tunnel ("ip route add ... encap seg6local ..."). Signed-off-by: David Lebrun --- ip/iproute.c | 2 +- ip/iproute_lwtunnel.c | 208 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 209 insertions(+), 1 deletion(-) diff --git a/ip/iproute.c b/ip/iproute.c index 39af38cf..be9181a6 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -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"); diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index 16d2584e..7dde4b27 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include 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,6 +81,8 @@ 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(); @@ -121,6 +127,94 @@ static void print_encap_seg6(FILE *fp, struct rtattr *encap) 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", +}; + +static const char *format_action_type(int action) +{ + if (action < 0 || action > SEG6_LOCAL_ACTION_MAX) + return ""; + + return seg6_action_names[action] ?: ""; +} + +static int read_action_type(const char *name) +{ + int i; + + for (i = 0; i < SEG6_LOCAL_ACTION_MAX + 1; i++) { + if (!seg6_action_names[i]) + continue; + + 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) ?: ""); + } + + if (tb[SEG6_LOCAL_OIF]) { + int oif = rta_getattr_u32(tb[SEG6_LOCAL_OIF]); + + fprintf(fp, "oif %s ", + if_indextoname(oif, ifbuf) ?: ""); + } +} + static void print_encap_mpls(FILE *fp, struct rtattr *encap) { struct rtattr *tb[MPLS_IPTUNNEL_MAX+1]; @@ -290,6 +384,9 @@ 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; } } @@ -412,6 +509,114 @@ static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp, 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++; + } + + 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; + + return 0; +} + static int parse_encap_mpls(struct rtattr *rta, size_t len, int *argcp, char ***argvp) { @@ -771,6 +976,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; From 043999023852b234c6062075660a8d39ec1410ac Mon Sep 17 00:00:00 2001 From: David Lebrun Date: Wed, 9 Aug 2017 17:33:26 +0200 Subject: [PATCH 13/53] man: add documentation for seg6local lwt This patch adds documentation in the ip-route man page about the seg6local lightweight tunnel. Signed-off-by: David Lebrun --- man/man8/ip-route.8.in | 62 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/man/man8/ip-route.8.in b/man/man8/ip-route.8.in index fc284921..11dd9d0f 100644 --- a/man/man8/ip-route.8.in +++ b/man/man8/ip-route.8.in @@ -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 From 959f142863954ad58db641a45b991e6f645dabaf Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:35:48 -0700 Subject: [PATCH 14/53] color: add new COLOR_NONE and disable_color function Signed-off-by: Julien Fortin --- include/color.h | 2 ++ lib/color.c | 12 ++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/color.h b/include/color.h index ba0b237e..1cd6f7d2 100644 --- a/include/color.h +++ b/include/color.h @@ -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); diff --git a/lib/color.c b/lib/color.c index 4e947500..79d5e289 100644 --- a/lib/color.c +++ b/lib/color.c @@ -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]); From 5df607725928d532a3b7e5095c04e943b2c3ce7f Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:35:49 -0700 Subject: [PATCH 15/53] ip: add new command line argument -json (mutually exclusive with -color) Signed-off-by: Julien Fortin --- include/utils.h | 1 + ip/ip.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/include/utils.h b/include/utils.h index 6080b962..565bda60 100644 --- a/include/utils.h +++ b/include/utils.h @@ -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_; diff --git a/ip/ip.c b/ip/ip.c index 7c14a8ec..e66f6970 100644 --- 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); From 7252f16b2d1919b31f0a2ec094dd3516b1e33a55 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:35:50 -0700 Subject: [PATCH 16/53] json_writer: add new json handlers (null, float with format, lluint, hu) Signed-off-by: Julien Fortin --- include/json_writer.h | 9 +++++++++ lib/json_writer.c | 44 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/include/json_writer.h b/include/json_writer.h index ab9a008a..1516aafb 100644 --- a/include/json_writer.h +++ b/include/json_writer.h @@ -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); diff --git a/lib/json_writer.c b/lib/json_writer.c index 9fc05e96..6b77d288 100644 --- a/lib/json_writer.c +++ b/lib/json_writer.c @@ -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) From 6377572f0aa83cf3a40c8de6248cc122e7350751 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:35:51 -0700 Subject: [PATCH 17/53] ip: ip_print: add new API to print JSON or regular format output To avoid code duplication and have a ligther impact on most of the files, these functions were made to handle both stdout (FP context) or JSON output. Using this api, the changes are easier to read and the code stays as compact as possible. includes json_writer.h in ip_common.h to make the lib/json_writer.c functions available to the new "ip_print" api. Signed-off-by: Julien Fortin --- ip/Makefile | 2 +- ip/ip_common.h | 56 ++++++++++++ ip/ip_print.c | 233 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 290 insertions(+), 1 deletion(-) create mode 100644 ip/ip_print.c diff --git a/ip/Makefile b/ip/Makefile index a754c04d..8ed2686c 100644 --- a/ip/Makefile +++ b/ip/Makefile @@ -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_common.h b/ip/ip_common.h index 77e9dd06..efc789cb 100644 --- a/ip/ip_common.h +++ b/ip/ip_common.h @@ -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 index 00000000..4cd6a0bc --- /dev/null +++ b/ip/ip_print.c @@ -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, + * + */ + +#include +#include + +#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); + } +} From d0e720111aad2527fa350723779144c56c8a5607 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:35:52 -0700 Subject: [PATCH 18/53] ip: ipaddress.c: add support for json output This patch converts all output (mostly fprintfs) to the new ip_print api which handle both regular and json output. Initialize a json_writer and open an array object if -json was specified. Note that the JSON attribute naming follows the NETLINK_ATTRIBUTE naming. In many places throughout the code, IP, matches integer values with hardcoded strings tables, such as link mode, link operstate or link family. In JSON context, this will result in a named string field. In the very unlikely event that the requested index is out of bound, IP displays the raw integer value. For JSON context this result in having a different integer field example bellow: if (mode >= ARRAY_SIZE(link_modes)) print_int(PRINT_ANY, "linkmode_index", "mode %d ", mode); else print_string(PRINT_ANY, "linkmode", "mode %s ", link_modes[mode]); The "_index" suffix is open to discussion and it is something that I came up with. The bottom line is that you can't have a string field that may become an int field in specific cases. Programs written in strongly type languages (like C) might break if they are expecting a string value and got an integer instead. We don't want to confuse anybody or make the code even more complicated handling these specifics cases. Hence the extra "_index" field that is easy to check for and deal with. JSON schema, followed by live example: Live config used: $ ip link add dev vxlan42 type vxlan id 42 $ ip link add dev bond0 type bond $ ip link add name swp1.50 link swp1 type vlan id 50 $ ip link add dev br0 type bridge $ ip link set dev vxlan42 master br0 $ ip link set dev bond0 master br0 $ ip link set dev swp1.50 master br0 $ ip link set dev br0 up $ ip -d link show 1: lo: mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0 addrgenmode eui64 2: eth0: mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000 link/ether 08:00:27:db:31:88 brd ff:ff:ff:ff:ff:ff promiscuity 0 addrgenmode eui64 3: swp1: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 08:00:27:5b:b1:75 brd ff:ff:ff:ff:ff:ff promiscuity 0 addrgenmode eui64 10: vxlan42: mtu 1500 qdisc noop master br0 state DOWN mode DEFAULT group default link/ether 4a:d9:91:42:a2:d2 brd ff:ff:ff:ff:ff:ff promiscuity 1 vxlan id 42 srcport 0 0 dstport 8472 ageing 300 bridge_slave state disabled priority 8 cost 100 hairpin off guard off root_block off fastleave off learning on flood on port_id 0x8001 port_no 0x1 designated_port 32769 designated_cost 0 designated_bridge 8000.8:0:27:5b:b1:75 designated_root 8000.8:0:27:5b:b1:75 hold_timer 0.00 message_age_timer 0.00 forward_delay_timer 0.00 topology_change_ack 0 config_pending 0 proxy_arp off proxy_arp_wifi off mcast_router 1 mcast_fast_leave off mcast_flood on neigh_suppress off addrgenmode eui64 11: bond0: mtu 1500 qdisc noop master br0 state DOWN mode DEFAULT group default link/ether e2:aa:7b:17:c5:14 brd ff:ff:ff:ff:ff:ff promiscuity 1 bond mode 802.3ad miimon 100 updelay 0 downdelay 0 use_carrier 1 arp_interval 0 arp_validate none arp_all_targets any primary_reselect always fail_over_mac none xmit_hash_policy layer3+4 resend_igmp 1 num_grat_arp 1 all_slaves_active 0 min_links 1 lp_interval 1 packets_per_slave 1 lacp_rate fast ad_select stable ad_actor_sys_prio 65535 ad_user_port_key 0 ad_actor_system 00:00:00:00:00:00 bridge_slave state disabled priority 8 cost 100 hairpin off guard off root_block off fastleave off learning on flood on port_id 0x8002 port_no 0x2 designated_port 32770 designated_cost 0 designated_bridge 8000.8:0:27:5b:b1:75 designated_root 8000.8:0:27:5b:b1:75 hold_timer 0.00 message_age_timer 0.00 forward_delay_timer 0.00 topology_change_ack 0 config_pending 0 proxy_arp off proxy_arp_wifi off mcast_router 1 mcast_fast_leave off mcast_flood on neigh_suppress off addrgenmode eui64 12: swp1.50@swp1: mtu 1500 qdisc noop master br0 state DOWN mode DEFAULT group default link/ether 08:00:27:5b:b1:75 brd ff:ff:ff:ff:ff:ff promiscuity 1 vlan protocol 802.1Q id 50 bridge_slave state disabled priority 8 cost 100 hairpin off guard off root_block off fastleave off learning on flood on port_id 0x8003 port_no 0x3 designated_port 32771 designated_cost 0 designated_bridge 8000.8:0:27:5b:b1:75 designated_root 8000.8:0:27:5b:b1:75 hold_timer 0.00 message_age_timer 0.00 forward_delay_timer 0.00 topology_change_ack 0 config_pending 0 proxy_arp off proxy_arp_wifi off mcast_router 1 mcast_fast_leave off mcast_flood on neigh_suppress off addrgenmode eui64 13: br0: mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default link/ether 08:00:27:5b:b1:75 brd ff:ff:ff:ff:ff:ff promiscuity 0 bridge forward_delay 1500 hello_time 200 max_age 2000 ageing_time 30000 stp_state 0 priority 32768 vlan_filtering 0 vlan_protocol 802.1Q bridge_id 8000.8:0:27:5b:b1:75 designated_root 8000.8:0:27:5b:b1:75 root_port 0 root_path_cost 0 topology_change 0 topology_change_detected 0 hello_timer 0.00 tcn_timer 0.00 topology_change_timer 0.00 gc_timer 244.44 vlan_default_pvid 1 vlan_stats_enabled 0 group_fwd_mask 0 group_address 01:80:c2:00:00:00 mcast_snooping 1 mcast_router 1 mcast_query_use_ifaddr 0 mcast_querier 0 mcast_hash_elasticity 4096 mcast_hash_max 4096 mcast_last_member_count 2 mcast_startup_query_count 2 mcast_last_member_interval 100 mcast_membership_interval 26000 mcast_querier_interval 25500 mcast_query_interval 12500 mcast_query_response_interval 1000 mcast_startup_query_interval 3125 mcast_stats_enabled 0 mcast_igmp_version 2 mcast_mld_version 1 nf_call_iptables 0 nf_call_ip6tables 0 nf_call_arptables 0 addrgenmode eui64 // Schema for: ip -brief link show [ { "deleted": { "type": "bool", "attr": "RTM_DELLINK" }, "link": { "type": "string", "attr": "IFLA_LINK" }, "ifname": { "type": "string", "attr": "IFNAME" }, "operstate": { "type": "string", "attr": "IFLA_OPERSTATE", "mutually_exclusive": { "operstate_index": { "type": "uint", "comment": "if state >= ARRAY_SIZE(oper_states)" } } }, "address": { "type": "string", "attr": "IFLA_ADDRESS" }, "flags": { "type": "array", "attr": "IFF_LOOPBACK, IFF_BROADCAST...IFF_*" }, "addr_info": { "type": "array", "array": [ { "deleted": { "type": "bool", "attr": "RTM_DELADDR" }, "family": { "type": "string", "attr": "ifa->ifa_family", "mutually_exclusive": { "family_index": { "type": "uint", "comment": "if family is not known" } } }, "local": { "type": "string", "attr": "IFA_LOCAL" }, "address": { "type": "string", "attr": "IFLA_LOCAL && IFA_ADDRESS" }, "prefixlen": { "type": "int", "attr": "IFLA_LOCAL" } } ] } } ] $ ip -json -brief link show [{ "ifname": "lo", "operstate": "UNKNOWN", "address": "00:00:00:00:00:00", "flags": ["LOOPBACK","UP","LOWER_UP"] },{ "ifname": "eth0", "operstate": "UP", "address": "08:00:27:db:31:88", "flags": ["BROADCAST","MULTICAST","UP","LOWER_UP"] },{ "ifname": "swp1", "operstate": "DOWN", "address": "08:00:27:5b:b1:75", "flags": ["BROADCAST","MULTICAST"] },{ "ifname": "vxlan42", "operstate": "DOWN", "address": "4a:d9:91:42:a2:d2", "flags": ["BROADCAST","MULTICAST"] },{ "ifname": "bond0", "operstate": "DOWN", "address": "e2:aa:7b:17:c5:14", "flags": ["BROADCAST","MULTICAST","MASTER"] },{ "link": "swp1", "ifname": "swp1.50", "operstate": "DOWN", "address": "08:00:27:5b:b1:75", "flags": ["BROADCAST","MULTICAST","M-DOWN"] },{ "ifname": "br0", "operstate": "DOWN", "address": "08:00:27:5b:b1:75", "flags": ["NO-CARRIER","BROADCAST","MULTICAST","UP"] } ] Schema for normal plus -details: ip -json -details link show [ { "deleted": { "type": "bool", "attr": "RTM_DELLINK" }, "ifindex": { "type": "int" }, "ifname": { "type": "string", "attr": "IFLA_IFNAME" }, "link": { "type": "string", "attr": "IFLA_LINK", "mutually_exclusive": { "link_index": { "type": "int", "comment": "if IFLA_LINK_NETNSID exists" } } }, "flags": { "type": "array", "attr": "IFF_LOOPBACK, IFF_BROADCAST...IFF_*" }, "mtu": { "type": "int", "attr": "IFLA_MTU" }, "xdp": { "type": "object", "attr": "IFLA_XDP", "object": { "mode": { "type": "utin", "attr": "IFLA_XDP_ATTACHED" }, "prog_id": { "type": "uint", "attr": "IFLA_XDP_PROG_ID" } } }, "qdisc": { "type": "string", "attr": "IFLA_QDISC" }, "master": { "type": "string", "attr": "IFLA_MASTER" }, "operstate": { "type": "string", "attr": "IFLA_OPERSTATE", "mutually_exclusive": { "operstate_index": { "type": "uint", "comment": "if state >= ARRAY_SIZE(oper_states)" } } }, "linkmode": { "type": "string", "attr": "IFLA_LINKMODE", "mutually_exclusive": { "linkmode_index": { "type": "uint", "comment": "if mode >= ARRAY_SIZE(link_modes)" } } }, "group": { "type": "string", "attr": "IFLA_GROUP" }, "txqlen": { "type": "int", "attr": "IFLA_TXQLEN" }, "event": { "type": "string", "attr": "IFLA_EVENT", "mutually_exclusive": { "event_index": { "type": "uint", "attr": "IFLA_OPERSTATE", "comment": "if event >= ARRAY_SIZE(link_events)" } } }, "link_type": { "type": "string", "attr": "ifi_type" }, "address": { "type": "string", "attr": "IFLA_ADDRESS" }, "link_pointtopoint": { "type": "bool", "attr": "IFF_POINTOPOINT" }, "broadcast": { "type": "string", "attr": "IFLA_BROADCAST" }, "link_netnsid": { "type": "int", "attr": "IFLA_LINK_NETNSID" }, "proto_down": { "type": "bool", "attr": "IFLA_PROTO_DOWN" }, // // if -details // "promiscuity": { "type": "uint", "attr": "IFLA_PROMISCUITY" }, "linkinfo": { "type": "dict", "attr": "IFLA_LINKINFO", "dict": { "info_kind": { "type": "string", "attr": "IFLA_INFO_KIND" }, "info_data": { "type": "dict", "attr": "IFLA_INFO_DATA", "dict": {} }, "info_xstats": { "type": "dict", "attr": "IFLA_INFO_XSTATS", "dict": {} }, "info_slave_data": { "type": "dict", "attr": "IFLA_INFO_SLAVE_DATA", "dict": {} } } }, "inet6_addr_gen_mode": { "type": "string", "attr": "IFLA_INET6_ADDR_GEN_MODE" }, "num_tx_queues": { "type": "uint", "attr": "IFLA_NUM_TX_QUEUES" }, "num_rx_queues": { "type": "uint", "attr": "IFLA_NUM_RX_QUEUES" }, "gso_max_size": { "type": "uint", "attr": "IFLA_GSO_MAX_SIZE" }, "gso_max_segs": { "type": "uint", "attr": "IFLA_GSO_MAX_SEGS" }, "phys_port_name": { "type": "string", "attr": "IFLA_PHYS_PORT_NAME" }, "phys_port_id": { "type": "string", "attr": "IFLA_PHYS_PORT_ID" }, "phys_switch_id": { "type": "string", "attr": "IFLA_PHYS_SWITCH_ID" }, "ifalias": { "type": "string", "attr": "IFLA_IFALIAS" }, "stats": { "type": "dict", "attr": "IFLA_STATS", "dict": { "rx": { "type": "dict", "dict": { "bytes": { "type": "uint" }, "packets": { "type": "uint" }, "errors": { "type": "uint" }, "dropped": { "type": "uint" }, "over_errors": { "type": "uint" }, "multicast": { "type": "uint" }, "compressed": { "type": "uint" }, "length_errors": { "type": "uint" }, "crc_errors": { "type": "uint" }, "frame_errors": { "type": "uint" }, "fifo_errors": { "type": "uint" }, "missed_errors": { "type": "uint" }, "nohandler": { "type": "uint" } } }, "tx": { "type": "dict", "dict": { "bytes": { "type": "uint" }, "packets": { "type": "uint" }, "errors": { "type": "uint" }, "dropped": { "type": "uint" }, "carrier_errors": { "type": "uint" }, "collisions": { "type": "uint" }, "compressed": { "type": "uint" }, "aborted_errors": { "type": "uint" }, "fifo_errors": { "type": "uint" }, "window_errors": { "type": "uint" }, "heartbeat_errors": { "type": "uint" }, "carrier_changes": { "type": "uint" } } } } }, "stats64": { "type": "dict", "attr": "IFLA_STATS64", "dict": { "rx": { "type": "dict", "dict": { "bytes": { "type": "uint" }, "packets": { "type": "uint" }, "errors": { "type": "uint" }, "dropped": { "type": "uint" }, "over_errors": { "type": "uint" }, "multicast": { "type": "uint" }, "compressed": { "type": "uint" }, "length_errors": { "type": "uint" }, "crc_errors": { "type": "uint" }, "frame_errors": { "type": "uint" }, "fifo_errors": { "type": "uint" }, "missed_errors": { "type": "uint" }, "nohandler": { "type": "uint" } } }, "tx": { "type": "dict", "dict": { "bytes": { "type": "uint" }, "packets": { "type": "uint" }, "errors": { "type": "uint" }, "dropped": { "type": "uint" }, "carrier_errors": { "type": "uint" }, "collisions": { "type": "uint" }, "compressed": { "type": "uint" }, "aborted_errors": { "type": "uint" }, "fifo_errors": { "type": "uint" }, "window_errors": { "type": "uint" }, "heartbeat_errors": { "type": "uint" }, "carrier_changes": { "type": "uint" } } } } }, "vfinfo_list": { "type": "array", "attr": "IFLA_VFINFO_LIST", "array": [ { "vf": { "type": "int" }, "mac": { "type": "string" }, "vlan_list": { "type": "array", "attr": "IFLA_VF_VLAN_LIST", "array": [ { "vlan": { "type": "int" }, "qos": { "type": "int" }, "protocol": { "type": "string" } } ] }, "vlan": { "type": "int", "attr": "!IFLA_VF_VLAN_LIST && IFLA_VF_VLAN" }, "qos": { "type": "int", "attr": "!IFLA_VF_VLAN_LIST && IFLA_VF_VLAN" }, "tx_rate": { "type": "int" }, "rate": { "type": "dict", "attr": "IFLA_VF_RATE", "dict": { "max_tx": { "type": "int" }, "min_tx": { "type": "int" } } }, "spoofchk": { "type": "bool", "attr": "IFLA_VF_SPOOFCHK" }, "link_state": { "type": "string", "attr": "IFLA_VF_LINK_STATE" }, "trust": { "type": "bool", "attr": "IFLA_VF_TRUST" }, "query_rss_en": { "type": "bool", "attr": "IFLA_VF_RSS_QUERY_EN" }, "stats": { "type": "dict", "attr": "IFLA_VF_STATS", "dict": { "rx": { "type": "dict", "dict": { "bytes": { "type": "uint", "attr": "IFLA_VF_STATS_RX_BYTES" }, "packets": { "type": "uint", "attr": "IFLA_VF_STATS_RX_PACKETS" }, "multicast": { "type": "uint", "attr": "IFLA_VF_STATS_MULTICAST" }, "broadcast": { "type": "uint", "attr": "IFLA_VF_STATS_BROADCAST" } } }, "tx": { "type": "dict", "dict": { "bytes": { "type": "uint", "attr": "IFLA_VF_STATS_TX_BYTES" }, "packets": { "type": "uint", "attr": "IFLA_VF_STATS_TX_PACKETS" } } } } } } ] } } ] Example with the config previously given: Note that here, linkinfo attributes are not populated. The schemas are provided in each link type patches. $ ip -details -json link show [{ "ifindex": 1, "ifname": "lo", "flags": ["LOOPBACK","UP","LOWER_UP"], "mtu": 65536, "qdisc": "noqueue", "operstate": "UNKNOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "loopback", "address": "00:00:00:00:00:00", "broadcast": "00:00:00:00:00:00", "promiscuity": 0, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 2, "ifname": "eth0", "flags": ["BROADCAST","MULTICAST","UP","LOWER_UP"], "mtu": 1500, "qdisc": "pfifo_fast", "operstate": "UP", "linkmode": "DEFAULT", "group": "default", "txqlen": 1000, "link_type": "ether", "address": "08:00:27:db:31:88", "broadcast": "ff:ff:ff:ff:ff:ff", "promiscuity": 0, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 3, "ifname": "swp1", "flags": ["BROADCAST","MULTICAST"], "mtu": 1500, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "txqlen": 1000, "link_type": "ether", "address": "08:00:27:5b:b1:75", "broadcast": "ff:ff:ff:ff:ff:ff", "promiscuity": 0, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 10, "ifname": "vxlan42", "flags": ["BROADCAST","MULTICAST"], "mtu": 1500, "qdisc": "noop", "master": "br0", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "ether", "address": "4a:d9:91:42:a2:d2", "broadcast": "ff:ff:ff:ff:ff:ff", "promiscuity": 1, "linkinfo": { "info_kind": "vxlan", "info_data": {}, "info_slave_kind": "bridge", "info_slave_data": {} }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 11, "ifname": "bond0", "flags": ["BROADCAST","MULTICAST","MASTER"], "mtu": 1500, "qdisc": "noop", "master": "br0", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "ether", "address": "e2:aa:7b:17:c5:14", "broadcast": "ff:ff:ff:ff:ff:ff", "promiscuity": 1, "linkinfo": { "info_kind": "bond", "info_data": {}, "info_slave_kind": "bridge", "info_slave_data": {}, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 16, "num_rx_queues": 16, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 12, "ifname": "swp1.50", "link": "swp1", "flags": ["BROADCAST","MULTICAST","M-DOWN"], "mtu": 1500, "qdisc": "noop", "master": "br0", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "ether", "address": "08:00:27:5b:b1:75", "broadcast": "ff:ff:ff:ff:ff:ff", "promiscuity": 1, "linkinfo": { "info_kind": "vlan", "info_data": {}, "info_slave_kind": "bridge", "info_slave_data": {}, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 13, "ifname": "br0", "flags": ["NO-CARRIER","BROADCAST","MULTICAST","UP"], "mtu": 1500, "qdisc": "noqueue", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "ether", "address": "08:00:27:5b:b1:75", "broadcast": "ff:ff:ff:ff:ff:ff", "promiscuity": 0, "linkinfo": { "info_kind": "bridge", "info_data": {}, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 } ] Signed-off-by: Julien Fortin --- ip/ipaddress.c | 1046 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 744 insertions(+), 302 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 4d37c5e0..81a5888f 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -30,6 +30,7 @@ #include #include +#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]); + int max_tx = vf_rate->max_tx_rate; + int min_tx = vf_rate->min_tx_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); + 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"); - 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])); + /* 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 */ - fprintf(fp, "%s", _SL_); - fprintf(fp, " TX: bytes packets %s", _SL_); - fprintf(fp, " "); + /* 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_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_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, " "); + + 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_); + if (is_json_context()) { + open_json_object("stats644"); - 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 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) { - fprintf(fp, "%s", _SL_); - fprintf(fp, " RX errors: length crc frame fifo missed%s%s", - s->rx_nohandler ? " nohandler" : "", _SL_); + /* 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(); - 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 */ + 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); - } - fprintf(fp, "%s", _SL_); + /* 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(); - /* TX stats */ - fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s", - s->tx_compressed ? "compressed" : "", _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->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); + 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); - /* 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"); + /* 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)); + } } } 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_); + if (is_json_context()) { + open_json_object("stats"); + + /* RX stats */ + open_json_object("rx"); + print_uint(PRINT_JSON, "bytes", NULL, s->rx_bytes); + print_uint(PRINT_JSON, "packets", NULL, s->rx_packets); + print_uint(PRINT_JSON, "errors", NULL, s->rx_errors); + print_uint(PRINT_JSON, "dropped", NULL, s->rx_dropped); + print_uint(PRINT_JSON, "over_errors", NULL, s->rx_over_errors); + print_uint(PRINT_JSON, "multicast", NULL, s->multicast); + if (s->rx_compressed) + print_int(PRINT_JSON, + "compressed", + NULL, s->rx_compressed); + + /* RX error stats */ + if (show_stats > 1) { + print_uint(PRINT_JSON, + "length_errors", + NULL, s->rx_length_errors); + print_uint(PRINT_JSON, + "crc_errors", + NULL, s->rx_crc_errors); + print_uint(PRINT_JSON, + "frame_errors", + NULL, s->rx_frame_errors); + print_uint(PRINT_JSON, + "fifo_errors", + NULL, s->rx_fifo_errors); + print_uint(PRINT_JSON, + "missed_errors", + NULL, s->rx_missed_errors); + if (s->rx_nohandler) + print_int(PRINT_JSON, + "nohandler", + NULL, s->rx_nohandler); + } + close_json_object(); + + /* TX stats */ + open_json_object("tx"); + print_uint(PRINT_JSON, "bytes", NULL, s->tx_bytes); + print_uint(PRINT_JSON, "packets", NULL, s->tx_packets); + print_uint(PRINT_JSON, "errors", NULL, s->tx_errors); + print_uint(PRINT_JSON, "dropped", NULL, s->tx_dropped); + print_uint(PRINT_JSON, + "carrier_errors", + NULL, s->tx_carrier_errors); + print_uint(PRINT_JSON, "collisions", NULL, s->collisions); + if (s->tx_compressed) + print_int(PRINT_JSON, + "compressed", + NULL, s->tx_compressed); + + /* TX error stats */ + if (show_stats > 1) { + print_uint(PRINT_JSON, + "aborted_errors", + NULL, s->tx_aborted_errors); + print_uint(PRINT_JSON, + "fifo_errors", + NULL, s->tx_fifo_errors); + print_uint(PRINT_JSON, + "window_errors", + NULL, s->tx_window_errors); + print_uint(PRINT_JSON, + "heartbeat_errors", + NULL, s->tx_heartbeat_errors); + if (carrier_changes) + print_uint(PRINT_JSON, + "carrier_changes", + NULL, + rta_getattr_u32(carrier_changes)); + } + + close_json_object(); + close_json_object(); + } 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); + fprintf(fp, " "); + print_num(fp, 10, s->rx_bytes); + print_num(fp, 8, s->rx_packets); + print_num(fp, 7, s->rx_errors); + print_num(fp, 7, s->rx_dropped); + print_num(fp, 7, s->rx_over_errors); + print_num(fp, 7, s->multicast); + if (s->rx_compressed) + print_num(fp, 7, s->rx_compressed); - /* RX error stats */ - if (show_stats > 1) { - fprintf(fp, "%s", _SL_); - fprintf(fp, " RX errors: length crc frame fifo missed%s%s", - s->rx_nohandler ? " nohandler" : "", _SL_); - fprintf(fp, " "); - print_num(fp, 8, s->rx_length_errors); - print_num(fp, 7, s->rx_crc_errors); - print_num(fp, 7, s->rx_frame_errors); - print_num(fp, 7, s->rx_fifo_errors); - print_num(fp, 7, s->rx_missed_errors); - if (s->rx_nohandler) - print_num(fp, 7, s->rx_nohandler); - } - fprintf(fp, "%s", _SL_); - - /* TX stats */ - fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s", - s->tx_compressed ? "compressed" : "", _SL_); - - fprintf(fp, " "); - print_num(fp, 10, s->tx_bytes); - print_num(fp, 8, s->tx_packets); - print_num(fp, 7, s->tx_errors); - print_num(fp, 7, s->tx_dropped); - print_num(fp, 7, s->tx_carrier_errors); - print_num(fp, 7, s->collisions); - if (s->tx_compressed) - print_num(fp, 7, s->tx_compressed); - - /* TX error stats */ - if (show_stats > 1) { - fprintf(fp, "%s", _SL_); - fprintf(fp, " TX errors: aborted fifo window heartbeat"); - if (carrier_changes) - fprintf(fp, " transns"); + /* 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 "); + print_bool(PRINT_ANY, "deleted", "Deleted ", true); - fprintf(fp, "%d: ", ifi->ifi_index); - color_fprintf(fp, COLOR_IFNAME, "%s", - tb[IFLA_IFNAME] ? rta_getattr_str(tb[IFLA_IFNAME]) : ""); + 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", ""); + } 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; } From e4a1216aeb2a46d3ab06359bf6820f0a98eb3f1e Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:35:53 -0700 Subject: [PATCH 19/53] ip: iplink.c: open/close json obj for ip -brief -json link show dev DEV Signed-off-by: Julien Fortin --- ip/iplink.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ip/iplink.c b/ip/iplink.c index 5aff2fde..19bda1b9 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -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; } From 7ff60b090f0a56ef5dee7e687b8799c56d3fa38a Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:35:54 -0700 Subject: [PATCH 20/53] ip: iplink_bond.c: add json output support Schema and live example: bond: IFLA_INFO_DATA { "mode": { "type": "string", "attr": "IFLA_BOND_MODE" }, "active_slave": { "type": "string", "attr": "IFLA_BOND_ACTIVE_SLAVE", "mutually_exclusive": { "active_slave_index": { "type": "int", "comment": "if active slave doesn't have a valid ifname" } } }, "miimon": { "type": "uint", "attr": "IFLA_BOND_MIIMON" }, "updelay": { "type": "uint", "attr": "IFLA_BOND_UPDELAY" }, "downdelay": { "type": "uint", "attr": "IFLA_BOND_DOWNDELAY" }, "use_carrier": { "type": "uint", "attr": "IFLA_BOND_USE_CARRIER" }, "arp_interval": { "type": "uint", "attr": "IFLA_BOND_ARP_INTERVAL" }, "arp_ip_target": { "type": "array", "attr": "IFLA_BOND_ARP_IP_TARGET", "array": [ { "type": "string" } ] }, "arp_validate": { "type": "string", "attr": "IFLA_BOND_ARP_VALIDATE" }, "arp_all_targets": { "type": "string", "attr": "IFLA_BOND_ARP_ALL_TARGETS" }, "primary": { "type": "string", "attr": "IFLA_BOND_PRIMARY", "mutually_exclusive": { "primary_index": { "type": "int", "comment": "if primary doesn't have a valid ifname" } } }, "primary_reselect": { "type": "string", "attr": "IFLA_BOND_PRIMARY_RESELECT" }, "fail_over_mac": { "type": "string", "attr": "IFLA_BOND_FAIL_OVER_MAC" }, "xmit_hash_policy": { "type": "string", "attr": "IFLA_BOND_XMIT_HASH_POLICY" }, "resend_igmp": { "type": "uint", "attr": "IFLA_BOND_RESEND_IGMP" }, "num_peer_notif": { "type": "uint", "attr": "IFLA_BOND_NUM_PEER_NOTIF" }, "all_slaves_active": { "type": "uint", "attr": "IFLA_BOND_ALL_SLAVES_ACTIVE" }, "min_links": { "type": "uint", "attr": "IFLA_BOND_MIN_LINKS" }, "lp_interval": { "type": "uint", "attr": "IFLA_BOND_LP_INTERVAL" }, "packets_per_slave": { "type": "uint", "attr": "IFLA_BOND_PACKETS_PER_SLAVE" }, "ad_lacp_rate": { "type": "string", "attr": "IFLA_BOND_AD_LACP_RATE" }, "ad_select": { "type": "string", "attr": "IFLA_BOND_AD_SELECT" }, "ad_info": { "type": "dict", "attr": "IFLA_BOND_AD_INFO", "dict": { "aggregator": { "type": "int", "attr": "IFLA_BOND_AD_INFO_AGGREGATOR" }, "num_ports": { "type": "int", "attr": "IFLA_BOND_AD_INFO_NUM_PORTS" }, "actor_key": { "type": "int", "attr": "IFLA_BOND_AD_INFO_ACTOR_KEY" }, "partner_key": { "type": "int", "attr": "IFLA_BOND_AD_INFO_PARTNER_KEY" }, "partner_mac": { "type": "string", "attr": "IFLA_BOND_AD_INFO_PARTNER_MAC" } } }, "ad_actor_sys_prio": { "type": "uint", "attr": "IFLA_BOND_AD_ACTOR_SYS_PRIO" }, "ad_user_port_key": { "type": "uint", "attr": "IFLA_BOND_AD_USER_PORT_KEY" }, "ad_actor_system": { "type": "string", "attr": "IFLA_BOND_AD_ACTOR_SYSTEM" }, "tlb_dynamic_lb": { "type": "uint", "attr": "IFLA_BOND_TLB_DYNAMIC_LB" } } $ ip link add dev bond42 type bond $ ip link set dev swp5 master bond42 $ ip link set dev bond42 up $ ip link set dev swp5 up $ ip -details -json link show [{ "ifindex": 7, "ifname": "swp5", "flags": ["BROADCAST","MULTICAST","SLAVE","UP","LOWER_UP"], "mtu": 1500, "qdisc": "pfifo_fast", "master": "bond42", "operstate": "UP", "linkmode": "DEFAULT", "group": "default", "txqlen": 1000, "link_type": "ether", "address": "08:00:27:5c:03:c6", "broadcast": "ff:ff:ff:ff:ff:ff", "promiscuity": 0, "linkinfo": { "info_slave_kind": "bond", "info_slave_data": { "state": "BACKUP", "mii_status": "UP", "link_failure_count": 0, "perm_hwaddr": "08:00:27:5c:03:c6", "queue_id": 0, "ad_aggregator_id": 1, "ad_actor_oper_port_state": 79, "ad_partner_oper_port_state": 1 } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 14, "ifname": "bond42", "flags": ["NO-CARRIER","BROADCAST","MULTICAST","MASTER","UP"], "mtu": 1500, "qdisc": "noqueue", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "ether", "address": "08:00:27:5c:03:c6", "broadcast": "ff:ff:ff:ff:ff:ff", "promiscuity": 0, "linkinfo": { "info_kind": "bond", "info_data": { "mode": "802.3ad", "miimon": 100, "updelay": 0, "downdelay": 0, "use_carrier": 1, "arp_interval": 0, "arp_validate": null, "arp_all_targets": "any", "primary_reselect": "always", "fail_over_mac": "none", "xmit_hash_policy": "layer3+4", "resend_igmp": 1, "num_peer_notif": 1, "all_slaves_active": 0, "min_links": 1, "lp_interval": 1, "packets_per_slave": 1, "ad_lacp_rate": "fast", "ad_select": "stable", "ad_info": { "aggregator": 1, "num_ports": 1, "actor_key": 0, "partner_key": 1, "partner_mac": "00:00:00:00:00:00" }, "ad_actor_sys_prio": 65535, "ad_user_port_key": 0, "ad_actor_system": "00:00:00:00:00:00" } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 16, "num_rx_queues": 16, "gso_max_size": 65536, "gso_max_segs": 65535 } ] Signed-off-by: Julien Fortin --- ip/iplink_bond.c | 231 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 160 insertions(+), 71 deletions(-) diff --git a/ip/iplink_bond.c b/ip/iplink_bond.c index 772b05fd..2b5cf4f6 100644 --- a/ip/iplink_bond.c +++ b/ip/iplink_bond.c @@ -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); } From 707cce5a630dd3ad11324e1dc1c34d80dea77bdd Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:35:55 -0700 Subject: [PATCH 21/53] ip: iplink_bond_slave.c: add json output support (info_slave_data) Schema and live example: bond_slave: IFLA_INFO_SLAVE_DATA { "state": { "type": "string", "attr": "IFLA_BOND_SLAVE_STATE", "mutually_exclusive": { "state_index": { "type": "int", "comment": "if (state >= ARRAY_SIZE(slave_states))" } } }, "mii_status": { "type": "string", "attr": "IFLA_BOND_SLAVE_MII_STATUS", "mutually_exclusive": { "mii_status_index": { "type": "int", "comment": "if (status >= ARRAY_SIZE(slave_mii_status))" } } }, "link_failure_count": { "type": "int", "attr": "IFLA_BOND_SLAVE_LINK_FAILURE_COUNT" }, "perm_hwaddr": { "type": "string", "attr": "IFLA_BOND_SLAVE_PERM_HWADDR" }, "queue_id": { "type": "int", "attr": "IFLA_BOND_SLAVE_QUEUE_ID" }, "ad_aggregator_id": { "type": "int", "attr": "IFLA_BOND_SLAVE_AD_AGGREGATOR_ID" }, "ad_actor_oper_port_state": { "type": "int", "attr": "IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE" }, "ad_partner_oper_port_state": { "type": "int", "attr": "IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE" } } $ ip link add dev bond42 type bond $ ip link set dev swp5 master bond42 $ ip link set dev bond42 up $ ip link set dev swp5 up $ ip -details -json link show [{ "ifindex": 7, "ifname": "swp5", "flags": ["BROADCAST","MULTICAST","SLAVE","UP","LOWER_UP"], "mtu": 1500, "qdisc": "pfifo_fast", "master": "bond42", "operstate": "UP", "linkmode": "DEFAULT", "group": "default", "txqlen": 1000, "link_type": "ether", "address": "08:00:27:5c:03:c6", "broadcast": "ff:ff:ff:ff:ff:ff", "promiscuity": 0, "linkinfo": { "info_slave_kind": "bond", "info_slave_data": { "state": "BACKUP", "mii_status": "UP", "link_failure_count": 0, "perm_hwaddr": "08:00:27:5c:03:c6", "queue_id": 0, "ad_aggregator_id": 1, "ad_actor_oper_port_state": 79, "ad_partner_oper_port_state": 1 } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 14, "ifname": "bond42", "flags": ["NO-CARRIER","BROADCAST","MULTICAST","MASTER","UP"], "mtu": 1500, "qdisc": "noqueue", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "ether", "address": "08:00:27:5c:03:c6", "broadcast": "ff:ff:ff:ff:ff:ff", "promiscuity": 0, "linkinfo": { "info_kind": "bond", "info_data": { "mode": "802.3ad", "miimon": 100, "updelay": 0, "downdelay": 0, "use_carrier": 1, "arp_interval": 0, "arp_validate": null, "arp_all_targets": "any", "primary_reselect": "always", "fail_over_mac": "none", "xmit_hash_policy": "layer3+4", "resend_igmp": 1, "num_peer_notif": 1, "all_slaves_active": 0, "min_links": 1, "lp_interval": 1, "packets_per_slave": 1, "ad_lacp_rate": "fast", "ad_select": "stable", "ad_info": { "aggregator": 1, "num_ports": 1, "actor_key": 0, "partner_key": 1, "partner_mac": "00:00:00:00:00:00" }, "ad_actor_sys_prio": 65535, "ad_user_port_key": 0, "ad_actor_system": "00:00:00:00:00:00" } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 16, "num_rx_queues": 16, "gso_max_size": 65536, "gso_max_segs": 65535 } ] Signed-off-by: Julien Fortin --- ip/iplink_bond_slave.c | 57 +++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/ip/iplink_bond_slave.c b/ip/iplink_bond_slave.c index 877e2d9e..67219c67 100644 --- a/ip/iplink_bond_slave.c +++ b/ip/iplink_bond_slave.c @@ -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, From 69ffd27325d719fe52b271551763ccdd1101a069 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:35:56 -0700 Subject: [PATCH 22/53] ip: iplink_hsr.c: add json output support Schema: hsr: IFLA_INFO_DATA { "slave1": { "type": "string", "attr": "IFLA_HSR_SLAVE1" }, "slave2": { "type": "string", "attr": "IFLA_HSR_SLAVE2" }, "seq_nr": { "type": "int", "attr": "IFLA_HSR_SEQ_NR" }, "supervision_addr": { "type": "int", "attr": "IFLA_HSR_SUPERVISION_ADDR" } } Signed-off-by: Julien Fortin --- ip/iplink_hsr.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/ip/iplink_hsr.c b/ip/iplink_hsr.c index 696b2c91..c673ccf7 100644 --- a/ip/iplink_hsr.c +++ b/ip/iplink_hsr.c @@ -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, " "); + print_null(PRINT_ANY, "slave1", "slave1 %s ", ""); - 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, " "); + print_null(PRINT_ANY, "slave2", "slave2 %s ", ""); 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, From 20aeecfbf5c1d1ebb09b8dd30746f2aadced96eb Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:35:57 -0700 Subject: [PATCH 23/53] ip: iplink_bridge.c: add json output support Schema and live example: bridge: IFLA_INFO_DATA { "forward_delay": { "type": "uint", "attr": "IFLA_BR_FORWARD_DELAY" }, "hello_time": { "type": "uint", "attr": "IFLA_BR_HELLO_TIME" }, "max_age": { "type": "uint", "attr": "IFLA_BR_MAX_AGE" }, "ageing_time": { "type": "uint", "attr": "IFLA_BR_AGEING_TIME" }, "stp_state": { "type": "uint", "attr": "IFLA_BR_STP_STATE" }, "priority": { "type": "uint", "attr": "IFLA_BR_PRIORITY" }, "vlan_filtering": { "type": "uint", "attr": "IFLA_BR_VLAN_FILTERING" }, "vlan_protocol": { "type": "string", "attr": "IFLA_BR_VLAN_PROTOCOL" }, "bridge_id": { "type": "string", "attr": "IFLA_BR_BRIDGE_ID" }, "root_id": { "type": "string", "attr": "IFLA_BR_ROOT_ID" }, "root_port": { "type": "uint", "attr": "IFLA_BR_ROOT_PORT" }, "root_path_cost": { "type": "uint", "attr": "IFLA_BR_ROOT_PATH_COST" }, "topology_change": { "type": "uint", "attr": "IFLA_BR_TOPOLOGY_CHANGE" }, "topology_change_detected": { "type": "uint", "attr": "IFLA_BR_TOPOLOGY_CHANGE_DETECTED" }, "hello_timer": { "type": "float", "attr": "IFLA_BR_HELLO_TIMER" }, "tcn_timer": { "type": "float", "attr": "IFLA_BR_TCN_TIMER" }, "topology_change_timer": { "type": "float", "attr": "IFLA_BR_TOPOLOGY_CHANGE_TIMER" }, "gc_timer": { "type": "float", "attr": "IFLA_BR_GC_TIMER" }, "vlan_default_pvid": { "type": "uint", "attr": "IFLA_BR_VLAN_DEFAULT_PVID" }, "vlan_stats_enabled": { "type": "uint", "attr": "IFLA_BR_VLAN_STATS_ENABLED" }, "group_fwd_mask": { "type": "string", "attr": "IFLA_BR_GROUP_FWD_MASK" }, "group_addr": { "type": "string", "attr": "IFLA_BR_GROUP_ADDR" }, "mcast_snooping": { "type": "uint", "attr": "IFLA_BR_MCAST_SNOOPING" }, "mcast_router": { "type": "uint", "attr": "IFLA_BR_MCAST_ROUTER" }, "mcast_query_use_ifaddr": { "type": "uint", "attr": "IFLA_BR_MCAST_QUERY_USE_IFADDR" }, "mcast_querier": { "type": "uint", "attr": "IFLA_BR_MCAST_QUERIER" }, "mcast_hash_elasticity": { "type": "uint", "attr": "IFLA_BR_MCAST_HASH_ELASTICITY" }, "mcast_hash_max": { "type": "uint", "attr": "IFLA_BR_MCAST_HASH_MAX" }, "mcast_last_member_cnt": { "type": "uint", "attr": "IFLA_BR_MCAST_LAST_MEMBER_CNT" }, "mcast_startup_query_cnt": { "type": "uint", "attr": "IFLA_BR_MCAST_STARTUP_QUERY_CNT" }, "mcast_last_member_intvl": { "type": "lluint", "attr": "IFLA_BR_MCAST_LAST_MEMBER_INTVL" }, "mcast_membership_intvl": { "type": "lluint", "attr": "IFLA_BR_MCAST_MEMBERSHIP_INTVL" }, "mcast_querier_intvl": { "type": "lluint", "attr": "IFLA_BR_MCAST_QUERIER_INTVL" }, "mcast_query_intvl": { "type": "lluint", "attr": "IFLA_BR_MCAST_QUERY_INTVL" }, "mcast_query_response_intvl": { "type": "lluint", "attr": "IFLA_BR_MCAST_QUERY_RESPONSE_INTVL" }, "mcast_startup_query_intvl": { "type": "lluint", "attr": "IFLA_BR_MCAST_STARTUP_QUERY_INTVL" }, "mcast_stats_enabled": { "type": "uint", "attr": "IFLA_BR_MCAST_STATS_ENABLED" }, "mcast_igmp_version": { "type": "uint", "attr": "IFLA_BR_MCAST_IGMP_VERSION" }, "mcast_mld_version": { "type": "uint", "attr": "IFLA_BR_MCAST_MLD_VERSION" }, "nf_call_iptables": { "type": "uint", "attr": "IFLA_BR_NF_CALL_IPTABLES" }, "nf_call_ip6tables": { "type": "uint", "attr": "IFLA_BR_NF_CALL_IP6TABLES" }, "nf_call_arptables": { "type": "uint", "attr": "IFLA_BR_NF_CALL_ARPTABLES" } } $ ip link add dev br42 type bridge $ ip link add dev bond42 type bond $ ip link set dev bond42 master br42 $ ip link set dev bond42 up $ ip link set dev br42 up $ ip -details link show 15: br42: mtu 1500 qdisc noqueue state UP mode DEFAULT group default link/ether 22:8f:91:bb:9f:09 brd ff:ff:ff:ff:ff:ff promiscuity 0 bridge forward_delay 1500 hello_time 200 max_age 2000 ageing_time 30000 stp_state 0 priority 32768 vlan_filtering 0 vlan_protocol 802.1Q bridge_id 8000.22:8f:91:bb:9f:9 designated_root 8000.22:8f:91:bb:9f:9 root_port 0 root_path_cost 0 topology_change 0 topology_change_detected 0 hello_timer 0.00 tcn_timer 0.00 topology_change_timer 0.00 gc_timer 199.11 vlan_default_pvid 1 vlan_stats_enabled 0 group_fwd_mask 0 group_address 01:80:c2:00:00:00 mcast_snooping 1 mcast_router 1 mcast_query_use_ifaddr 0 mcast_querier 0 mcast_hash_elasticity 4096 mcast_hash_max 4096 mcast_last_member_count 2 mcast_startup_query_count 2 mcast_last_member_interval 100 mcast_membership_interval 26000 mcast_querier_interval 25500 mcast_query_interval 12500 mcast_query_response_interval 1000 mcast_startup_query_interval 3125 mcast_stats_enabled 0 mcast_igmp_version 2 mcast_mld_version 1 nf_call_iptables 0 nf_call_ip6tables 0 nf_call_arptables 0 addrgenmode eui64 16: bond42: mtu 1500 qdisc noqueue master br42 state UNKNOWN mode DEFAULT group default link/ether 22:8f:91:bb:9f:09 brd ff:ff:ff:ff:ff:ff promiscuity 1 bond mode 802.3ad miimon 100 updelay 0 downdelay 0 use_carrier 1 arp_interval 0 arp_validate none arp_all_targets any primary_reselect always fail_over_mac none xmit_hash_policy layer3+4 resend_igmp 1 num_grat_arp 1 all_slaves_active 0 min_links 1 lp_interval 1 packets_per_slave 1 lacp_rate fast ad_select stable ad_actor_sys_prio 65535 ad_user_port_key 0 ad_actor_system 00:00:00:00:00:00 bridge_slave state forwarding priority 8 cost 100 hairpin off guard off root_block off fastleave off learning on flood on port_id 0x8001 port_no 0x1 designated_port 32769 designated_cost 0 designated_bridge 8000.22:8f:91:bb:9f:9 designated_root 8000.22:8f:91:bb:9f:9 hold_timer 0.00 message_age_timer 0.00 forward_delay_timer 0.00 topology_change_ack 0 config_pending 0 proxy_arp off proxy_arp_wifi off mcast_router 1 mcast_fast_leave off mcast_flood on neigh_suppress off addrgenmode eui64 $ ip -details -json link show [{ "ifindex": 15, "ifname": "br42", "flags": ["BROADCAST","MULTICAST","UP","LOWER_UP"], "mtu": 1500, "qdisc": "noqueue", "operstate": "UP", "linkmode": "DEFAULT", "group": "default", "link_type": "ether", "address": "22:8f:91:bb:9f:09", "broadcast": "ff:ff:ff:ff:ff:ff", "promiscuity": 0, "linkinfo": { "info_kind": "bridge", "info_data": { "forward_delay": 1500, "hello_time": 200, "max_age": 2000, "ageing_time": 30000, "stp_state": 0, "priority": 32768, "vlan_filtering": 0, "vlan_protocol": "802.1Q", "bridge_id": "8000.22:8f:91:bb:9f:9", "root_id": "8000.22:8f:91:bb:9f:9", "root_port": 0, "root_path_cost": 0, "topology_change": 0, "topology_change_detected": 0, "hello_timer": 0.00, "tcn_timer": 0.00, "topology_change_timer": 0.00, "gc_timer": 298.27, "vlan_default_pvid": 1, "vlan_stats_enabled": 0, "group_fwd_mask": "0", "group_addr": "01:80:c2:00:00:00", "mcast_snooping": 1, "mcast_router": 1, "mcast_query_use_ifaddr": 0, "mcast_querier": 0, "mcast_hash_elasticity": 4096, "mcast_hash_max": 4096, "mcast_last_member_cnt": 2, "mcast_startup_query_cnt": 2, "mcast_last_member_intvl": 100, "mcast_membership_intvl": 26000, "mcast_querier_intvl": 25500, "mcast_query_intvl": 12500, "mcast_query_response_intvl": 1000, "mcast_startup_query_intvl": 3125, "mcast_stats_enabled": 0, "mcast_igmp_version": 2, "mcast_mld_version": 1, "nf_call_iptables": 0, "nf_call_ip6tables": 0, "nf_call_arptables": 0 } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 16, "ifname": "bond42", "flags": ["BROADCAST","MULTICAST","MASTER","UP","LOWER_UP"], "mtu": 1500, "qdisc": "noqueue", "master": "br42", "operstate": "UNKNOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "ether", "address": "22:8f:91:bb:9f:09", "broadcast": "ff:ff:ff:ff:ff:ff", "promiscuity": 1, "linkinfo": { "info_kind": "bond", "info_data": { "mode": "802.3ad", "miimon": 100, "updelay": 0, "downdelay": 0, "use_carrier": 1, "arp_interval": 0, "arp_validate": null, "arp_all_targets": "any", "primary_reselect": "always", "fail_over_mac": "none", "xmit_hash_policy": "layer3+4", "resend_igmp": 1, "num_peer_notif": 1, "all_slaves_active": 0, "min_links": 1, "lp_interval": 1, "packets_per_slave": 1, "ad_lacp_rate": "fast", "ad_select": "stable", "ad_actor_sys_prio": 65535, "ad_user_port_key": 0, "ad_actor_system": "00:00:00:00:00:00" }, "info_slave_kind": "bridge", "info_slave_data": { "state": "forwarding", "priority": 8, "cost": 100, "hairpin": false, "guard": false, "root_block": false, "fastleave": false, "learning": true, "flood": true, "id": "0x8001", "no": "0x1", "designated_port": 32769, "designated_cost": 0, "bridge_id": "8000.22:8f:91:bb:9f:9", "root_id": "8000.22:8f:91:bb:9f:9", "hold_timer": 0.00, "message_age_timer": 0.00, "forward_delay_timer": 11.97, "topology_change_ack": 0, "config_pending": 0, "proxy_arp": false, "proxy_arp_wifi": false, "multicast_router": 1, "mcast_flood": true } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 16, "num_rx_queues": 16, "gso_max_size": 65536, "gso_max_segs": 65535 } ] Signed-off-by: Julien Fortin --- ip/iplink_bridge.c | 293 ++++++++++++++++++++++++++++----------------- 1 file changed, 185 insertions(+), 108 deletions(-) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index cccdec1c..d3250980 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -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])); + print_uint(PRINT_ANY, + "topology_change_detected", + "topology_change_detected %u ", + rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED])); - if (tb[IFLA_BR_HELLO_TIMER]) { - struct timeval tv; + if (tb[IFLA_BR_HELLO_TIMER]) + _bridge_print_timer(f, "hello_timer", tb[IFLA_BR_HELLO_TIMER]); - __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]) + _bridge_print_timer(f, "tcn_timer", tb[IFLA_BR_TCN_TIMER]); - if (tb[IFLA_BR_TCN_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_TCN_TIMER])); - fprintf(f, "tcn_timer %4i.%.2i ", (int)tv.tv_sec, - (int)tv.tv_usec/10000); - } - - if (tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]) { - unsigned long jiffies; - struct timeval tv; - - 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_GC_TIMER]) { - struct timeval tv; - - __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); } From 165a703909700139ba38660f64777edeabfb3565 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:35:58 -0700 Subject: [PATCH 24/53] ip: iplink_bridge_slave.c: add json output support Schema: bridge_slave: IFLA_INFO_SLAVE_DATA { "state": { "type": "string", "attr": "IFLA_BRPORT_STATE", "mutually_exclusive": { "state_index": { "type": "uint", "comment": "if (state > BR_STATE_BLOCKING)" } } }, "priority": { "type": "int", "attr": "IFLA_BRPORT_PRIORITY" }, "cost": { "type": "int", "attr": "IFLA_BRPORT_COST" }, "mode": { "type": "bool", "attr": "IFLA_BRPORT_MODE" }, "guard": { "type": "bool", "attr": "IFLA_BRPORT_GUARD" }, "protect": { "type": "bool", "attr": "IFLA_BRPORT_PROTECT" }, "fast_leave": { "type": "bool", "attr": "IFLA_BRPORT_FAST_LEAVE" }, "learning": { "type": "bool", "attr": "IFLA_BRPORT_LEARNING" }, "unicast_flood": { "type": "bool", "attr": "IFLA_BRPORT_UNICAST_FLOOD" }, "id": { "type": "string", "attr": "IFLA_BRPORT_ID" }, "no": { "type": "string", "attr": "IFLA_BRPORT_NO" }, "designated_port": { "type": "uint", "attr": "IFLA_BRPORT_DESIGNATED_PORT" }, "designated_cost": { "type": "uint", "attr": "IFLA_BRPORT_DESIGNATED_COST" }, "bridge_id": { "type": "string", "attr": "IFLA_BRPORT_BRIDGE_ID" }, "root_id": { "type": "string", "attr": "IFLA_BRPORT_ROOT_ID" }, "hold_timer": { "type": "float", "attr": "IFLA_BRPORT_HOLD_TIMER" }, "message_age_timer": { "type": "float", "attr": "IFLA_BRPORT_MESSAGE_AGE_TIMER" }, "forward_delay_timer": { "type": "float", "attr": "IFLA_BRPORT_FORWARD_DELAY_TIMER" }, "topology_change_ack": { "type": "uint", "attr": "IFLA_BRPORT_TOPOLOGY_CHANGE_ACK" }, "config_pending": { "type": "uint", "attr": "IFLA_BRPORT_CONFIG_PENDING" }, "proxyarp": { "type": "bool", "attr": "IFLA_BRPORT_PROXYARP" }, "proxyarp_wifi": { "type": "bool", "attr": "IFLA_BRPORT_PROXYARP_WIFI" }, "multicast_router": { "type": "uint", "attr": "IFLA_BRPORT_MULTICAST_ROUTER" }, "mcast_flood": { "type": "bool", "attr": "IFLA_BRPORT_MCAST_FLOOD" } } $ ip link add dev br42 type bridge $ ip link add dev bond42 type bond $ ip link set dev bond42 master br42 $ ip link set dev bond42 up $ ip link set dev br42 up $ ip -details link show $ ip -details link show 15: br42: mtu 1500 qdisc noqueue state UP mode DEFAULT group default link/ether 22:8f:91:bb:9f:09 brd ff:ff:ff:ff:ff:ff promiscuity 0 bridge forward_delay 1500 hello_time 200 max_age 2000 ageing_time 30000 stp_state 0 priority 32768 vlan_filtering 0 vlan_protocol 802.1Q bridge_id 8000.22:8f:91:bb:9f:9 designated_root 8000.22:8f:91:bb:9f:9 root_port 0 root_path_cost 0 topology_change 0 topology_change_detected 0 hello_timer 0.00 tcn_timer 0.00 topology_change_timer 0.00 gc_timer 199.11 vlan_default_pvid 1 vlan_stats_enabled 0 group_fwd_mask 0 group_address 01:80:c2:00:00:00 mcast_snooping 1 mcast_router 1 mcast_query_use_ifaddr 0 mcast_querier 0 mcast_hash_elasticity 4096 mcast_hash_max 4096 mcast_last_member_count 2 mcast_startup_query_count 2 mcast_last_member_interval 100 mcast_membership_interval 26000 mcast_querier_interval 25500 mcast_query_interval 12500 mcast_query_response_interval 1000 mcast_startup_query_interval 3125 mcast_stats_enabled 0 mcast_igmp_version 2 mcast_mld_version 1 nf_call_iptables 0 nf_call_ip6tables 0 nf_call_arptables 0 addrgenmode eui64 16: bond42: mtu 1500 qdisc noqueue master br42 state UNKNOWN mode DEFAULT group default link/ether 22:8f:91:bb:9f:09 brd ff:ff:ff:ff:ff:ff promiscuity 1 bond mode 802.3ad miimon 100 updelay 0 downdelay 0 use_carrier 1 arp_interval 0 arp_validate none arp_all_targets any primary_reselect always fail_over_mac none xmit_hash_policy layer3+4 resend_igmp 1 num_grat_arp 1 all_slaves_active 0 min_links 1 lp_interval 1 packets_per_slave 1 lacp_rate fast ad_select stable ad_actor_sys_prio 65535 ad_user_port_key 0 ad_actor_system 00:00:00:00:00:00 bridge_slave state forwarding priority 8 cost 100 hairpin off guard off root_block off fastleave off learning on flood on port_id 0x8001 port_no 0x1 designated_port 32769 designated_cost 0 designated_bridge 8000.22:8f:91:bb:9f:9 designated_root 8000.22:8f:91:bb:9f:9 hold_timer 0.00 message_age_timer 0.00 forward_delay_timer 0.00 topology_change_ack 0 config_pending 0 proxy_arp off proxy_arp_wifi off mcast_router 1 mcast_fast_leave off mcast_flood on neigh_suppress off addrgenmode eui64 $ ip -details -json link show [{ "ifindex": 15, "ifname": "br42", "flags": ["BROADCAST","MULTICAST","UP","LOWER_UP"], "mtu": 1500, "qdisc": "noqueue", "operstate": "UP", "linkmode": "DEFAULT", "group": "default", "link_type": "ether", "address": "22:8f:91:bb:9f:09", "broadcast": "ff:ff:ff:ff:ff:ff", "promiscuity": 0, "linkinfo": { "info_kind": "bridge", "info_data": { "forward_delay": 1500, "hello_time": 200, "max_age": 2000, "ageing_time": 30000, "stp_state": 0, "priority": 32768, "vlan_filtering": 0, "vlan_protocol": "802.1Q", "bridge_id": "8000.22:8f:91:bb:9f:9", "root_id": "8000.22:8f:91:bb:9f:9", "root_port": 0, "root_path_cost": 0, "topology_change": 0, "topology_change_detected": 0, "hello_timer": 0.00, "tcn_timer": 0.00, "topology_change_timer": 0.00, "gc_timer": 298.27, "vlan_default_pvid": 1, "vlan_stats_enabled": 0, "group_fwd_mask": "0", "group_addr": "01:80:c2:00:00:00", "mcast_snooping": 1, "mcast_router": 1, "mcast_query_use_ifaddr": 0, "mcast_querier": 0, "mcast_hash_elasticity": 4096, "mcast_hash_max": 4096, "mcast_last_member_cnt": 2, "mcast_startup_query_cnt": 2, "mcast_last_member_intvl": 100, "mcast_membership_intvl": 26000, "mcast_querier_intvl": 25500, "mcast_query_intvl": 12500, "mcast_query_response_intvl": 1000, "mcast_startup_query_intvl": 3125, "mcast_stats_enabled": 0, "mcast_igmp_version": 2, "mcast_mld_version": 1, "nf_call_iptables": 0, "nf_call_ip6tables": 0, "nf_call_arptables": 0 } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 16, "ifname": "bond42", "flags": ["BROADCAST","MULTICAST","MASTER","UP","LOWER_UP"], "mtu": 1500, "qdisc": "noqueue", "master": "br42", "operstate": "UNKNOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "ether", "address": "22:8f:91:bb:9f:09", "broadcast": "ff:ff:ff:ff:ff:ff", "promiscuity": 1, "linkinfo": { "info_kind": "bond", "info_data": { "mode": "802.3ad", "miimon": 100, "updelay": 0, "downdelay": 0, "use_carrier": 1, "arp_interval": 0, "arp_validate": null, "arp_all_targets": "any", "primary_reselect": "always", "fail_over_mac": "none", "xmit_hash_policy": "layer3+4", "resend_igmp": 1, "num_peer_notif": 1, "all_slaves_active": 0, "min_links": 1, "lp_interval": 1, "packets_per_slave": 1, "ad_lacp_rate": "fast", "ad_select": "stable", "ad_actor_sys_prio": 65535, "ad_user_port_key": 0, "ad_actor_system": "00:00:00:00:00:00" }, "info_slave_kind": "bridge", "info_slave_data": { "state": "forwarding", "priority": 8, "cost": 100, "hairpin": false, "guard": false, "root_block": false, "fastleave": false, "learning": true, "flood": true, "id": "0x8001", "no": "0x1", "designated_port": 32769, "designated_cost": 0, "bridge_id": "8000.22:8f:91:bb:9f:9", "root_id": "8000.22:8f:91:bb:9f:9", "hold_timer": 0.00, "message_age_timer": 0.00, "forward_delay_timer": 11.97, "topology_change_ack": 0, "config_pending": 0, "proxy_arp": false, "proxy_arp_wifi": false, "multicast_router": 1, "mcast_flood": true } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 16, "num_rx_queues": 16, "gso_max_size": 65536, "gso_max_segs": 65535 } ] Signed-off-by: Julien Fortin --- ip/iplink_bridge_slave.c | 185 ++++++++++++++++++++++++--------------- 1 file changed, 114 insertions(+), 71 deletions(-) diff --git a/ip/iplink_bridge_slave.c b/ip/iplink_bridge_slave.c index 3e883328..80272b09 100644 --- a/ip/iplink_bridge_slave.c +++ b/ip/iplink_bridge_slave.c @@ -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); + print_string(PRINT_ANY, + "root_id", + "designated_root %s ", root_id); } - if (tb[IFLA_BRPORT_HOLD_TIMER]) { - struct timeval tv; - __u64 htimer; + if (tb[IFLA_BRPORT_HOLD_TIMER]) + _print_timer(f, "hold_timer", tb[IFLA_BRPORT_HOLD_TIMER]); - 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); - } + if (tb[IFLA_BRPORT_MESSAGE_AGE_TIMER]) + _print_timer(f, "message_age_timer", + tb[IFLA_BRPORT_MESSAGE_AGE_TIMER]); - if (tb[IFLA_BRPORT_MESSAGE_AGE_TIMER]) { - struct timeval tv; - __u64 agetimer; - - 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; - - 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, From 529226009f24fec097f67c643d4524a61bc35700 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:35:59 -0700 Subject: [PATCH 25/53] ip: iplink_can.c: add json output support Schema: IFLA_INFO_DATA { "ctrlmode": { "type": "array", "attr": "IFLA_CAN_CTRLMODE", "array": [ { "type": "string" } ] }, "state": { "type": "string", "attr": "IFLA_CAN_STATE" }, "berr_counter": { "type": "dict", "attr": "IFLA_CAN_BERR_COUNTER", "dict": { "tx": { "type": "int" }, "rx": { "type": "int" } } }, "restart_ms": { "type": "int", "attr": "IFLA_CAN_RESTART_MS" }, "bittiming": { "type": "dict", "attr": "IFLA_CAN_BITTIMING", "dict": { "bitrate": { "type": "int" }, "sample_point": { "type": "float" }, "tq": { "type": "int" }, "prop_seg": { "type": "int" }, "phase_seg1": { "type": "int" }, "phase_seg2": { "type": "int" }, "sjw": { "type": "int" } } }, "bittiming_const": { "type": "dict", "attr": "IFLA_CAN_BITTIMING_CONST", "dict": { "name": { "type": "string" }, "tseg1": { "type": "dict", "dict": { "min": { "type": "int" }, "max": { "type": "int" } } }, "tseg2": { "type": "dict", "dict": { "min": { "type": "int" }, "max": { "type": "int" } } }, "sjw": { "type": "dict", "dict": { "min": { "type": "int" }, "max": { "type": "int" } } }, "brp": { "type": "dict", "dict": { "min": { "type": "int" }, "max": { "type": "int" } } }, "brp_inc": { "type": "int" } } }, "bittiming_bitrate": { "type": "uint", "attr": "IFLA_CAN_BITTIMING" }, "bitrate_const": { "type": "array", "attr": "IFLA_CAN_BITRATE_CONST", "array": [ { "type": "uint" } ] }, "data_bittiming": { "type": "dict", "attr": "IFLA_CAN_DATA_BITTIMING", "dict": { "bitrate": { "type": "int" }, "sample_point": { "type": "float" }, "tq": { "type": "int" }, "prop_seg": { "type": "int" }, "phase_seg1": { "type": "int" }, "phase_seg2": { "type": "int" }, "sjw": { "type": "int" } } }, "data_bittiming_const": { "type": "dict", "attr": "IFLA_CAN_DATA_BITTIMING_CONST", "dict": { "name": { "type": "string" }, "tseg1": { "type": "dict", "dict": { "min": { "type": "int" }, "max": { "type": "int" } } }, "tseg2": { "type": "dict", "dict": { "min": { "type": "int" }, "max": { "type": "int" } } }, "sjw": { "type": "dict", "dict": { "min": { "type": "int" }, "max": { "type": "int" } } }, "brp": { "type": "dict", "dict": { "min": { "type": "int" }, "max": { "type": "int" } } }, "brp_inc": { "type": "int" } } }, "data_bittiming_bitrate": { "type": "uint", "attr": "IFLA_CAN_DATA_BITTIMING" }, "data_bitrate_const": { "type": "array", "attr": "IFLA_CAN_DATA_BITRATE_CONST", "array": [ { "type": "uint" } ] }, "termination": { "type": "unsigned short", "attr": "IFLA_CAN_TERMINATION" }, "termination_const": { "type": "array", "attr": "IFLA_CAN_TERMINATION_CONST", "array": [ { "type": "unsigned short" } ] }, "clock": { "type": "int", "attr": "IFLA_CAN_CLOCK" } } IFLA_INFO_XSTATS { "restarts": { "type": "int" }, "bus_error": { "type": "int" }, "arbitration_lost": { "type": "int" }, "error_warning": { "type": "int" }, "error_passive": { "type": "int" }, "bus_off": { "type": "int" } } Signed-off-by: Julien Fortin --- ip/iplink_can.c | 282 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 211 insertions(+), 71 deletions(-) diff --git a/ip/iplink_can.c b/ip/iplink_can.c index 5df56b2b..f415558a 100644 --- a/ip/iplink_can.c +++ b/ip/iplink_can.c @@ -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); } From 119fae0aa5d1cfbc67d348ebf7307cd56f07a140 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:36:00 -0700 Subject: [PATCH 26/53] ip: iplink_geneve.c: add json output support Schema: { "id": { "type": "uint", "attr": "IFLA_GENEVE_ID" }, "remote": { "type": "string", "attr": "IFLA_GENEVE_REMOTE" }, "remote6": { "type": "string", "attr": "IFLA_GENEVE_REMOTE6" }, "ttl": { "type": "int", "attr": "IFLA_GENEVE_TTL" }, "tos": { "type": "string", "attr": "IFLA_GENEVE_TOS" }, "label": { "type": "string", "attr": "IFLA_GENEVE_LABEL" }, "port": { "type": "uint", "attr": "IFLA_GENEVE_PORT" }, "collect_metadata": { "type": "bool", "attr": "IFLA_GENEVE_COLLECT_METADATA" }, "udp_csum": { "type": "bool", "attr": "IFLA_GENEVE_UDP_CSUM" }, "udp_zero_csum6_tx": { "type": "bool", "attr": "IFLA_GENEVE_UDP_ZERO_CSUM6_TX" }, "udp_zero_csum6_rx": { "type": "bool", "attr": "IFLA_GENEVE_UDP_ZERO_CSUM6_RX" } } Signed-off-by: Julien Fortin --- ip/iplink_geneve.c | 86 +++++++++++++++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 23 deletions(-) diff --git a/ip/iplink_geneve.c b/ip/iplink_geneve.c index 594a3e59..f0f1d1c7 100644 --- a/ip/iplink_geneve.c +++ b/ip/iplink_geneve.c @@ -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); + } } } From 3bec1cf84efeafe51b32cc93b00dfc5bfb24f277 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:36:01 -0700 Subject: [PATCH 27/53] ip: iplink_ipoib.c: add json output support Schema: { "key": { "type": "string", "attr": "IFLA_IPOIB_PKEY" }, "mode": { "type": "string", "attr": "IFLA_IPOIB_PKEY" }, "umcast": { "type": "string", "attr": "IFLA_IPOIB_UMCAST" } } Signed-off-by: Julien Fortin --- ip/iplink_ipoib.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/ip/iplink_ipoib.c b/ip/iplink_ipoib.c index 86dc65ca..e69bda0e 100644 --- a/ip/iplink_ipoib.c +++ b/ip/iplink_ipoib.c @@ -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, From 8f24afc9d4339159ecff7765df682e3f8eb18d9a Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:36:02 -0700 Subject: [PATCH 28/53] ip: iplink_ipvlan.c: add json output support Schema: { "mode": { "type": "string", "attr": "IFLA_IPVLAN_MODE" } } Signed-off-by: Julien Fortin --- ip/iplink_ipvlan.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ip/iplink_ipvlan.c b/ip/iplink_ipvlan.c index f7735f3a..9f48309e 100644 --- a/ip/iplink_ipvlan.c +++ b/ip/iplink_ipvlan.c @@ -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); } } } From d9e84ec27ca34ea7e0dd2b88068a94720e22829e Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:36:03 -0700 Subject: [PATCH 29/53] ip: iplink_vrf.c: add json output support Schema: { "table": { "type": "uint", "attr": "IFLA_VRF_TABLE" } } Signed-off-by: Julien Fortin --- ip/iplink_vrf.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ip/iplink_vrf.c b/ip/iplink_vrf.c index 917630e8..f13b1d24 100644 --- a/ip/iplink_vrf.c +++ b/ip/iplink_vrf.c @@ -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); } From 3b98d9b804e010b3c890672ad6fefe2c7400145c Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:36:04 -0700 Subject: [PATCH 30/53] ip: iplink_vxlan.c: add json output support Schema: { "id": { "type": "uint", "attr": "IFLA_VXLAN_ID" }, "group": { "type": "string", "attr": "IFLA_VXLAN_GROUP" }, "remote": { "type": "string", "attr": "IFLA_VXLAN_GROUP" }, "group6": { "type": "string", "attr": "IFLA_VXLAN_GROUP6" }, "remote6": { "type": "string", "attr": "IFLA_VXLAN_GROUP6" }, "local": { "type": "string", "attr": "IFLA_VXLAN_LOCAL" }, "local6": { "type": "string", "attr": "IFLA_VXLAN_LOCAL6" }, "link": { "type": "string", "attr": "IFLA_VXLAN_LINK", "mutually_exclusive": { "link_index": { "type": "uint", "comment": "if not ifname for ifindex" } } }, "port_range": { "type": "dict", "attr": "IFLA_VXLAN_PORT_RANGE", "dict": { "low": { "type": "uint" }, "high": { "type": "uint" } } }, "port": { "type": "uint", "attr": "IFLA_VXLAN_PORT" }, "learning": { "type": "bool", "attr": "IFLA_VXLAN_LEARNING" }, "proxy": { "type": "bool", "attr": "IFLA_VXLAN_PROXY" }, "rsc": { "type": "bool", "attr": "IFLA_VXLAN_RSC" }, "l2miss": { "type": "bool", "attr": "IFLA_VXLAN_L2MISS" }, "l3miss": { "type": "bool", "attr": "IFLA_VXLAN_L3MISS" }, "tos": { "type": "string", "attr": "IFLA_VXLAN_TOS" }, "ttl": { "type": "int", "attr": "IFLA_VXLAN_TTL" }, "label": { "type": "string", "attr": "IFLA_VXLAN_LABEL" }, "ageing": { "type": "uint", "attr": "IFLA_VXLAN_AGEING" }, "limit": { "type": "uint", "attr": "IFLA_VXLAN_LIMIT" }, "udp_csum": { "type": "bool", "attr": "IFLA_VXLAN_UDP_CSUM" }, "udp_zero_csum6_tx": { "type": "bool", "attr": "IFLA_VXLAN_UDP_ZERO_CSUM6_TX" }, "udp_zero_csum6_rx": { "type": "bool", "attr": "IFLA_VXLAN_UDP_ZERO_CSUM6_RX" }, "remcsum_tx": { "type": "bool", "attr": "IFLA_VXLAN_REMCSUM_TX" }, "remcsum_rx": { "type": "bool", "attr": "IFLA_VXLAN_REMCSUM_RX" }, "collect_metadata": { "type": "bool", "attr": "IFLA_VXLAN_COLLECT_METADATA" }, "gbp": { "type": "bool", "attr": "IFLA_VXLAN_GBP" }, "gpe": { "type": "bool", "attr": "IFLA_VXLAN_GPE" } } $ ip link add name vxlan42 type vxlan id 42 dev eth0 remote 203.0.113.6 local 192.0.2.1 dstport 4789 $ ip link add name vxlan43 type vxlan id 43 dev eth0 group 239.0.0.1 dstport 4789 $ ip -details -json link show [{ "ifindex": 17, "ifname": "vxlan42", "flags": ["BROADCAST","MULTICAST"], "mtu": 1450, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "ether", "address": "b2:92:0e:1a:c6:42", "broadcast": "ff:ff:ff:ff:ff:ff", "promiscuity": 0, "linkinfo": { "info_kind": "vxlan", "info_data": { "id": 42, "remote": "203.0.113.6", "local": "192.0.2.1", "link": "eth0", "port_range": { "low": 0, "high": 0 }, "port": 4789, "learning": true, "ttl": 0, "ageing": 300, "udp_csum": false, "udp_zero_csum6_tx": false, "udp_zero_csum6_rx": false } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 18, "ifname": "vxlan43", "flags": ["BROADCAST","MULTICAST"], "mtu": 1450, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "ether", "address": "c6:51:4d:7f:f9:2f", "broadcast": "ff:ff:ff:ff:ff:ff", "promiscuity": 0, "linkinfo": { "info_kind": "vxlan", "info_data": { "id": 43, "group": "239.0.0.1", "link": "eth0", "port_range": { "low": 0, "high": 0 }, "port": 4789, "learning": true, "ttl": 0, "ageing": 300, "udp_csum": false, "udp_zero_csum6_tx": false, "udp_zero_csum6_rx": false } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 } ] Signed-off-by: Julien Fortin --- ip/iplink_vxlan.c | 161 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 112 insertions(+), 49 deletions(-) diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c index 2bd619d4..a0530dda 100644 --- a/ip/iplink_vxlan.c +++ b/ip/iplink_vxlan.c @@ -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); } From 2f26065e254352ec95d92e58ffd478de58fb98d6 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:36:05 -0700 Subject: [PATCH 31/53] ip: iplink_xdp.c: add json output support Schema { "attached": { "type": "uint", "attr": "IFLA_XDP_ATTACHED" }, "prog_id": { "type": "uint", "attr": "IFLA_XDP_PROG_ID" } } Signed-off-by: Julien Fortin --- ip/iplink_xdp.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/ip/iplink_xdp.c b/ip/iplink_xdp.c index 9ae9ee5d..3a61076e 100644 --- a/ip/iplink_xdp.c +++ b/ip/iplink_xdp.c @@ -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", " "); } From c33983468204216c96d7448ec1efd2af96ffc888 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:36:06 -0700 Subject: [PATCH 32/53] ip: ipmacsec.c: add json output support Schema { "sci": { "type": "string", "attr": "IFLA_MACSEC_SCI" }, "protect": { "type": "string", "attr": "IFLA_MACSEC_PROTECT" }, "cipher_suite": { "type": "string", "attr": "IFLA_MACSEC_CIPHER_SUITE" }, "icv_len": { "type": "uint", "attr": "IFLA_MACSEC_ICV_LEN" }, "encoding_sa": { "type": "uint", "attr": "IFLA_MACSEC_ENCODING_SA" }, "validation": { "type": "string", "attr": "IFLA_MACSEC_VALIDATION" }, "encrypt": { "type": "string", "attr": "IFLA_MACSEC_ENCRYPT" }, "inc_sci": { "type": "string", "attr": "IFLA_MACSEC_INC_SCI" }, "es": { "type": "string", "attr": "IFLA_MACSEC_ES" }, "scb": { "type": "string", "attr": "IFLA_MACSEC_SCB" }, "replay_protect": { "type": "string", "attr": "IFLA_MACSEC_REPLAY_PROTECT" }, "window": { "type": "int", "attr": "" } } Signed-off-by: Julien Fortin --- ip/ipmacsec.c | 84 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/ip/ipmacsec.c b/ip/ipmacsec.c index aa89a00f..ecc371a5 100644 --- a/ip/ipmacsec.c +++ b/ip/ipmacsec.c @@ -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) From e2d4588331fce62e6e47bcfa45cd763efa027f2b Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:36:07 -0700 Subject: [PATCH 33/53] ip: link_gre.c: add json output support Schema { "external": { "type": "bool", "comment": "!tb[IFLA_GRE_COLLECT_METADATA]" }, "remote": { "type": "string", "attr": "IFLA_GRE_REMOTE" }, "local": { "type": "string", "attr": "IFLA_GRE_LOCAL" }, "link": { "type": "string", "attr": "IFLA_GRE_LINK", "mutually_exclusive": { "link_index": { "type": "uint", } } }, "ttl": { "type": "int", "attr": "IFLA_GRE_TTL" }, "tos": { "type": "string", "attr": "IFLA_GRE_TOS" }, "pmtudisc": { "type": "bool", "attr": "IFLA_GRE_PMTUDISC" }, "ikey": { "type": "string", "attr": "IFLA_GRE_IKEY" }, "okey": { "type": "string", "attr": "IFLA_GRE_OKEY" }, "iseq": { "type": "bool", "attr": "IFLA_GRE_IFLAGS & GRE_SEQ" }, "oseq": { "type": "bool", "attr": "IFLA_GRE_OFLAGS & GRE_SEQ" }, "icsum": { "type": "bool", "attr": "IFLA_GRE_IFLAGS & GRE_CSUM" }, "ocsum": { "type": "bool", "attr": "IFLA_GRE_OFLAGS & GRE_CSUM" }, "ignore_df": { "type": "bool", "attr": "IFLA_GRE_IGNORE_DF" }, "encap": { "type": "dict", "attr": "IFLA_GRE_ENCAP_TYPE != TUNNEL_ENCAP_NONE", "dict": { "type": { "type": "string", "attr": "IFLA_GRE_ENCAP_TYPE" }, "sport": { "type": "uint", "attr": "IFLA_GRE_ENCAP_SPORT" }, "dport": { "type": "uint", "attr": "IFLA_GRE_ENCAP_DPORT" }, "csum": { "type": "bool", "attr": "TUNNEL_ENCAP_FLAG_CSUM" }, "csum6": { "type": "bool", "attr": "TUNNEL_ENCAP_FLAG_CSUM6" }, "remcsum": { "type": "bool", "attr": "TUNNEL_ENCAP_FLAG_REMCSUM" } } } } $ ip link show $ ip tunnel add tun42 mode gre local 192.0.2.42 remote 203.0.113.42 key 42 $ ip link show 10: gre0@NONE: mtu 1476 qdisc noop state DOWN mode DEFAULT group default link/gre 0.0.0.0 brd 0.0.0.0 11: gretap0@NONE: mtu 1462 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff 12: tun42@NONE: mtu 1472 qdisc noop state DOWN mode DEFAULT group default link/gre 192.0.2.42 peer 203.0.113.42 $ ip -details -json link show [{ "ifindex": 10, "ifname": "gre0", "link": null, "flags": ["NOARP"], "mtu": 1476, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "gre", "address": "0.0.0.0", "broadcast": "0.0.0.0", "promiscuity": 0, "linkinfo": { "info_kind": "gre", "info_data": { "remote": "any", "local": "any", "ttl": 0, "pmtudisc": false } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 11, "ifname": "gretap0", "link": null, "flags": ["BROADCAST","MULTICAST"], "mtu": 1462, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "txqlen": 1000, "link_type": "ether", "address": "00:00:00:00:00:00", "broadcast": "ff:ff:ff:ff:ff:ff", "promiscuity": 0, "linkinfo": { "info_kind": "gretap", "info_data": { "remote": "any", "local": "any", "ttl": 0, "pmtudisc": false } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 12, "ifname": "tun42", "link": null, "flags": ["POINTOPOINT","NOARP"], "mtu": 1472, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "gre", "address": "192.0.2.42", "link_pointtopoint": true, "broadcast": "203.0.113.42", "promiscuity": 0, "linkinfo": { "info_kind": "gre", "info_data": { "remote": "203.0.113.42", "local": "192.0.2.42", "ttl": 0, "pmtudisc": true, "ikey": "0.0.0.42", "okey": "0.0.0.42" } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 } ] Signed-off-by: Julien Fortin --- ip/link_gre.c | 147 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 98 insertions(+), 49 deletions(-) diff --git a/ip/link_gre.c b/ip/link_gre.c index c2ec5f26..3c9f8194 100644 --- a/ip/link_gre.c +++ b/ip/link_gre.c @@ -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] && rta_getattr_u32(tb[IFLA_GRE_FWMARK])) { - fprintf(f, "fwmark 0x%x ", - rta_getattr_u32(tb[IFLA_GRE_FWMARK])); + 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); + } } } @@ -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)); - fprintf(f, "encap-dport %u ", ntohs(dport)); + print_bool(PRINT_JSON, + "csum", + NULL, + flags & TUNNEL_ENCAP_FLAG_CSUM); - if (flags & TUNNEL_ENCAP_FLAG_CSUM) - fputs("encap-csum ", f); - else - fputs("noencap-csum ", f); + print_bool(PRINT_JSON, + "csum6", + NULL, + flags & TUNNEL_ENCAP_FLAG_CSUM6); - if (flags & TUNNEL_ENCAP_FLAG_CSUM6) - fputs("encap-csum6 ", f); - else - fputs("noencap-csum6 ", f); + print_bool(PRINT_JSON, + "remcsum", + NULL, + flags & TUNNEL_ENCAP_FLAG_REMCSUM); - if (flags & TUNNEL_ENCAP_FLAG_REMCSUM) - fputs("encap-remcsum ", f); - else - fputs("noencap-remcsum ", f); + 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)); + + 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_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); } From 6856fb65484ba0975dda2b6eeda581d53f03b3a7 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:36:08 -0700 Subject: [PATCH 34/53] ip: link_gre6.c: add json output support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Schema { "remote": { "type": "string", "attr": "IFLA_GRE_REMOTE" }, "local": { "type": "string", "attr": "IFLA_GRE_LOCAL" }, "link": { "type": "string", "attr": "IFLA_GRE_LINK", "mutually_exclusive": { "link_index": { "type": "uint", } } }, "ttl": { "type": "int", "attr": "IFLA_GRE_TTL" }, "ip6_tnl_f_ign_encap_limit": { "type": "bool", "attr": "IP6_TNL_F_IGN_ENCAP_LIMIT" }, "encap_limit": { "type": "int", "attr": "IFLA_GRE_ENCAP_LIMIT" }, "ip6_tnl_f_use_orig_flowlabel": { "type": "bool", "attr": "IP6_TNL_F_USE_ORIG_FLOWLABEL" }, "flowlabel": { "type": "string", "attr": "IP6_FLOWINFO_FLOWLABEL" }, "ip6_tnl_f_rcv_dscp_copy": { "type": "bool", "attr": "IP6_TNL_F_RCV_DSCP_COPY" }, "ikey": { "type": "string", "attr": "IFLA_GRE_IKEY" }, "okey": { "type": "string", "attr": "IFLA_GRE_OKEY" }, "iseq": { "type": "bool", "attr": "IFLA_GRE_IFLAGS & GRE_SEQ" }, "oseq": { "type": "bool", "attr": "IFLA_GRE_OFLAGS & GRE_SEQ" }, "icsum": { "type": "bool", "attr": "IFLA_GRE_IFLAGS & GRE_CSUM" }, "ocsum": { "type": "bool", "attr": "IFLA_GRE_OFLAGS & GRE_CSUM" }, "encap": { "type": "dict", "attr": "IFLA_GRE_ENCAP_TYPE != TUNNEL_ENCAP_NONE", "dict": { "type": { "type": "string", "attr": "IFLA_GRE_ENCAP_TYPE" }, "sport": { "type": "uint", "attr": "IFLA_GRE_ENCAP_SPORT" }, "dport": { "type": "uint", "attr": "IFLA_GRE_ENCAP_DPORT" }, "csum": { "type": "bool", "attr": "TUNNEL_ENCAP_FLAG_CSUM" }, "csum6": { "type": "bool", "attr": "TUNNEL_ENCAP_FLAG_CSUM6" }, "remcsum": { "type": "bool", "attr": "TUNNEL_ENCAP_FLAG_REMCSUM" } } } } $ ip link show $ ip -6 tunnel add name tun6 mode ip6gre local 2001:db8:1::1/64 remote 2001:0db8:85a3:0000:0000:8a2e:0370:7334 $ ip link show 10: ip6tnl0@NONE: mtu 1452 qdisc noop state DOWN mode DEFAULT group default link/tunnel6 :: brd :: 11: ip6gre0@NONE: mtu 1448 qdisc noop state DOWN mode DEFAULT group default link/gre6 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 brd 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 12: tun6@NONE: mtu 1448 qdisc noop state DOWN mode DEFAULT group default link/gre6 20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:01 peer 20:01:0d:b8:85:a3:00:00:00:00:8a:2e:03:70:73:34 ➜ ~ ./ip -details -json link show [{ "ifindex": 10, "ifname": "ip6tnl0", "link": null, "flags": ["NOARP"], "mtu": 1452, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "tunnel6", "address": "::", "broadcast": "::", "promiscuity": 0, "linkinfo": { "info_kind": "ip6tnl", "info_data": { "proto": "ip6ip6", "remote": "::", "local": "::", "encap_limit": 0, "ttl": 0, "flowinfo_tclass": "0x00", "flowlabel": "0x00000", "flowinfo": "0x00000000" } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 11, "ifname": "ip6gre0", "link": null, "flags": ["NOARP"], "mtu": 1448, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "gre6", "address": "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00", "broadcast": "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00", "promiscuity": 0, "linkinfo": { "info_kind": "ip6gre", "info_data": { "remote": "any", "local": "any", "ttl": 0, "encap_limit": 0, "flowlabel": "0x00000" } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 12, "ifname": "tun6", "link": null, "flags": ["POINTOPOINT","NOARP"], "mtu": 1448, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "gre6", "address": "20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:01", "link_pointtopoint": true, "broadcast": "20:01:0d:b8:85:a3:00:00:00:00:8a:2e:03:70:73:34", "promiscuity": 0, "linkinfo": { "info_kind": "ip6gre", "info_data": { "remote": "2001:db8:85a3::8a2e:370:7334", "local": "2001:db8:1::1", "ttl": 64, "encap_limit": 4, "flowlabel": "0x00000" } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 } ] Signed-off-by: Julien Fortin --- ip/link_gre6.c | 142 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 99 insertions(+), 43 deletions(-) diff --git a/ip/link_gre6.c b/ip/link_gre6.c index 4d3d4b54..957853d6 100644 --- a/ip/link_gre6.c +++ b/ip/link_gre6.c @@ -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); + } } } From 1facc1c61c07197e72b07e7ba53de6e8190adede Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:36:09 -0700 Subject: [PATCH 35/53] ip: link_ip6tnl.c: add json output support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Schema { "proto": { "type": "string", "attr": "IFLA_IPTUN_PROTO" }, "remote": { "type": "string", "attr": "IFLA_IPTUN_REMOTE" }, "local": { "type": "string", "attr": "IFLA_IPTUN_LOCAL" }, "link": { "type": "string", "attr": "IFLA_IPTUN_LINK", "mutually_exclusive": { "link_index": { "type": "uint", } } }, "ip6_tnl_f_ign_encap_limit": { "type": "bool", "attr": "IP6_TNL_F_IGN_ENCAP_LIMIT" }, "encap_limit": { "type": "uint", "attr": "IFLA_IPTUN_ENCAP_LIMIT" }, "ttl": { "type": "uint", "attr": "IFLA_IPTUN_TTL" }, "ip6_tnl_f_use_orig_tclass": { "type": "", "attr": "IP6_TNL_F_USE_ORIG_TCLASS" }, "flowinfo_tclass": { "type": "string", "attr": "IP6_FLOWINFO_TCLASS" }, "ip6_tnl_f_use_orig_flowlabel": { "type": "bool", "attr": "IP6_TNL_F_USE_ORIG_FLOWLABEL" }, "flowlabel": { "type": "string", "attr": "IP6_FLOWINFO_FLOWLABEL" }, "flowinfo": { "type": "string" }, "ip6_tnl_f_rcv_dscp_copy": { "type": "bool", "attr": "IP6_TNL_F_RCV_DSCP_COPY" }, "ip6_tnl_f_mip6_dev": { "type": "bool", "attr": "IP6_TNL_F_MIP6_DEV" }, "ip6_tnl_f_use_orig_fwmark": { "type": "bool", "attr": "IP6_TNL_F_USE_ORIG_FWMARK" }, "encap": { "type": "dict", "attr": "IFLA_IPTUN_ENCAP_TYPE", "dict": { "type": { "type": "string", "attr": "IFLA_IPTUN_ENCAP_TYPE" }, "sport": { "type": "uint", "attr": "IFLA_IPTUN_ENCAP_SPORT" }, "dport": { "type": "uint", "attr": "IFLA_IPTUN_ENCAP_DPORT" }, "csum": { "type": "bool", "attr": "TUNNEL_ENCAP_FLAG_CSUM" }, "csum6": { "type": "bool", "attr": "TUNNEL_ENCAP_FLAG_CSUM6" }, "remcsum": { "type": "bool", "attr": "TUNNEL_ENCAP_FLAG_REMCSUM" } } } } $ ip link show $ ip -6 tunnel add name tun6 mode ip6gre local 2001:db8:1::1/64 remote 2001:0db8:85a3:0000:0000:8a2e:0370:7334 $ ip link show 10: ip6tnl0@NONE: mtu 1452 qdisc noop state DOWN mode DEFAULT group default link/tunnel6 :: brd :: 11: ip6gre0@NONE: mtu 1448 qdisc noop state DOWN mode DEFAULT group default link/gre6 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 brd 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 12: tun6@NONE: mtu 1448 qdisc noop state DOWN mode DEFAULT group default link/gre6 20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:01 peer 20:01:0d:b8:85:a3:00:00:00:00:8a:2e:03:70:73:34 ➜ ~ ./ip -details -json link show [{ "ifindex": 10, "ifname": "ip6tnl0", "link": null, "flags": ["NOARP"], "mtu": 1452, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "tunnel6", "address": "::", "broadcast": "::", "promiscuity": 0, "linkinfo": { "info_kind": "ip6tnl", "info_data": { "proto": "ip6ip6", "remote": "::", "local": "::", "encap_limit": 0, "ttl": 0, "flowinfo_tclass": "0x00", "flowlabel": "0x00000", "flowinfo": "0x00000000" } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 11, "ifname": "ip6gre0", "link": null, "flags": ["NOARP"], "mtu": 1448, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "gre6", "address": "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00", "broadcast": "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00", "promiscuity": 0, "linkinfo": { "info_kind": "ip6gre", "info_data": { "remote": "any", "local": "any", "ttl": 0, "encap_limit": 0, "flowlabel": "0x00000" } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 12, "ifname": "tun6", "link": null, "flags": ["POINTOPOINT","NOARP"], "mtu": 1448, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "gre6", "address": "20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:01", "link_pointtopoint": true, "broadcast": "20:01:0d:b8:85:a3:00:00:00:00:8a:2e:03:70:73:34", "promiscuity": 0, "linkinfo": { "info_kind": "ip6gre", "info_data": { "remote": "2001:db8:85a3::8a2e:370:7334", "local": "2001:db8:1::1", "ttl": 64, "encap_limit": 4, "flowlabel": "0x00000" } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 } ] Signed-off-by: Julien Fortin --- ip/link_ip6tnl.c | 172 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 122 insertions(+), 50 deletions(-) diff --git a/ip/link_ip6tnl.c b/ip/link_ip6tnl.c index 505fb476..a4199006 100644 --- a/ip/link_ip6tnl.c +++ b/ip/link_ip6tnl.c @@ -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) - printf("flowlabel inherit "); - else - printf("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); - printf("(flowinfo 0x%08x) ", ntohl(flowinfo)); + 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 (is_json_context()) { + SPRINT_BUF(flwinfo); + + 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) - 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 (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 (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); } From 2539a407bb613484436f60bc1b14879694907cc9 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:36:10 -0700 Subject: [PATCH 36/53] ip: link_iptnl.c: add json output support Schema { "remote": { "type": "string", "attr": "IFLA_IPTUN_REMOTE" }, "local": { "type": "string", "attr": "IFLA_IPTUN_LOCAL" }, "link": { "type": "string", "attr": "IFLA_IPTUN_LINK", "mutually_exclusive": { "link_index": { "type": "uint", } } }, "ttl": { "type": "int", "attr": "IFLA_IPTUN_TTL" }, "tos": { "type": "string", "attr": "IFLA_IPTUN_TOS" }, "pmtudisc": { "type": "bool", "attr": "IFLA_IPTUN_PMTUDISC" }, "isatap": { "type": "bool", "attr": "SIT_ISATAP & IFLA_IPTUN_FLAGS" }, "6rd": { "type": "dict", "attr": "IFLA_IPTUN_6RD_PREFIXLEN", "dict": { "prefix": { "type": "string" }, "prefixlen": { "type": "uint", "attr": "IFLA_IPTUN_6RD_PREFIXLEN" }, "relay_prefix": { "type": "string" }, "relay_prefixlen": { "type": "uint", "attr": "IFLA_IPTUN_6RD_PREFIXLEN" } } }, "encap": { "type": "dict", "attr": "IFLA_IPTUN_ENCAP_TYPE", "dict": { "type": { "type": "string", "attr": "IFLA_IPTUN_ENCAP_TYPE" }, "sport": { "type": "uint", "attr": "IFLA_IPTUN_ENCAP_SPORT" }, "dport": { "type": "uint", "attr": "IFLA_IPTUN_ENCAP_DPORT" }, "csum": { "type": "bool", "attr": "TUNNEL_ENCAP_FLAG_CSUM" }, "csum6": { "type": "bool", "attr": "TUNNEL_ENCAP_FLAG_CSUM6" }, "remcsum": { "type": "bool", "attr": "TUNNEL_ENCAP_FLAG_REMCSUM" } } } } $ ip tunnel add tun0 mode ipip local 192.0.2.1 remote 198.51.100.3 $ ip link show 10: tunl0@NONE: mtu 1480 qdisc noop state DOWN mode DEFAULT group default link/ipip 0.0.0.0 brd 0.0.0.0 11: tun0@NONE: mtu 1480 qdisc noop state DOWN mode DEFAULT group default link/ipip 192.0.2.1 peer 198.51.100.3 $ ip -details -json link show [{ "ifindex": 10, "ifname": "tunl0", "link": null, "flags": ["NOARP"], "mtu": 1480, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "ipip", "address": "0.0.0.0", "broadcast": "0.0.0.0", "promiscuity": 0, "linkinfo": { "info_kind": "ipip", "info_data": { "remote": "any", "local": "any", "ttl": 0, "pmtudisc": false } }, "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 11, "ifname": "tun0", "link": null, "flags": ["POINTOPOINT","NOARP"], "mtu": 1480, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "ipip", "address": "192.0.2.1", "link_pointtopoint": true, "broadcast": "198.51.100.3", "promiscuity": 0, "linkinfo": { "info_kind": "ipip", "info_data": { "remote": "198.51.100.3", "local": "192.0.2.1", "ttl": 0, "pmtudisc": true } }, "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 } ] Signed-off-by: Julien Fortin --- ip/link_iptnl.c | 155 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 106 insertions(+), 49 deletions(-) diff --git a/ip/link_iptnl.c b/ip/link_iptnl.c index d24e7376..6a725e91 100644 --- a/ip/link_iptnl.c +++ b/ip/link_iptnl.c @@ -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 (tb[IFLA_IPTUN_TOS] && rta_getattr_u8(tb[IFLA_IPTUN_TOS])) { + 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]) { 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, From 4c42a1c103e8fb8730e1205a13d9b4fe1538b550 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:36:11 -0700 Subject: [PATCH 37/53] ip: link_vti.c: add json output support Schema: { "remote": { "type": "string", "attr": "IFLA_VTI_REMOTE" }, "local": { "type": "string", "attr": "IFLA_VTI_LOCAL" }, "link": { "type": "string", "attr": "IFLA_VTI_LINK", "mutually_exclusive": { "link_index": { "type": "uint", } } }, "ikey": { "type": "string", "attr": "IFLA_VTI_IKEY" }, "okey": { "type": "string", "attr": "IFLA_VTI_OKEY" } } $ ip tunnel add vti0 mode vti local 192.0.2.1 remote 198.51.100.3 $ ip link show 10: ip_vti0@NONE: mtu 1428 qdisc noop state DOWN mode DEFAULT group default link/ipip 0.0.0.0 brd 0.0.0.0 11: vti0@NONE: mtu 1428 qdisc noop state DOWN mode DEFAULT group default link/ipip 192.0.2.1 peer 198.51.100.3 $ ./ip -details -json link show [{ "ifindex": 10, "ifname": "ip_vti0", "link": null, "flags": ["NOARP"], "mtu": 1428, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "ipip", "address": "0.0.0.0", "broadcast": "0.0.0.0", "promiscuity": 0, "linkinfo": { "info_kind": "vti", "info_data": { "remote": "any", "local": "any", "ikey": "0.0.0.0", "okey": "0.0.0.0" } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 11, "ifname": "vti0", "link": null, "flags": ["POINTOPOINT","NOARP"], "mtu": 1428, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "ipip", "address": "192.0.2.1", "link_pointtopoint": true, "broadcast": "198.51.100.3", "promiscuity": 0, "linkinfo": { "info_kind": "vti", "info_data": { "remote": "198.51.100.3", "local": "192.0.2.1", "ikey": "0.0.0.0", "okey": "0.0.0.0" } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 } ] Signed-off-by: Julien Fortin --- ip/link_vti.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/ip/link_vti.c b/ip/link_vti.c index 3ffecfac..8bd4d900 100644 --- a/ip/link_vti.c +++ b/ip/link_vti.c @@ -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); + } } } From 063dd06cc1f272f6ab5342d29341cfa745bd75ff Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:36:12 -0700 Subject: [PATCH 38/53] ip: link_vti6.c: add json output support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Schema: { "remote": { "type": "string", "attr": "IFLA_VTI_REMOTE" }, "local": { "type": "string", "attr": "IFLA_VTI_LOCAL" }, "link": { "type": "string", "attr": "IFLA_VTI_LINK", "mutually_exclusive": { "link_index": { "type": "uint", } } }, "ikey": { "type": "string", "attr": "IFLA_VTI_IKEY" }, "okey": { "type": "string", "attr": "IFLA_VTI_OKEY" } } ➜ ~ ip -6 tunnel add name vti6 mode vti6 local 2001:db8:1::1/64 remote 2001:0db8:85a3:0000:0000:8a2e:0370:7334 ➜ ~ ip link show 10: ip6tnl0@NONE: mtu 1452 qdisc noop state DOWN mode DEFAULT group default link/tunnel6 :: brd :: 11: ip6_vti0@NONE: mtu 1500 qdisc noop state DOWN mode DEFAULT group default link/tunnel6 :: brd :: 12: vti6@NONE: mtu 1500 qdisc noop state DOWN mode DEFAULT group default link/tunnel6 2001:db8:1::1 peer 2001:db8:85a3::8a2e:370:7334 ➜ ~ ./ip -details -json link show [{ "ifindex": 10, "ifname": "ip6tnl0", "link": null, "flags": ["NOARP"], "mtu": 1452, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "tunnel6", "address": "::", "broadcast": "::", "promiscuity": 0, "linkinfo": { "info_kind": "ip6tnl", "info_data": { "proto": "ip6ip6", "remote": "::", "local": "::", "encap_limit": 0, "ttl": 0, "flowinfo_tclass": "0x00", "flowlabel": "0x00000", "flowinfo": "0x00000000" } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 11, "ifname": "ip6_vti0", "link": null, "flags": ["NOARP"], "mtu": 1500, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "tunnel6", "address": "::", "broadcast": "::", "promiscuity": 0, "linkinfo": { "info_kind": "vti6", "info_data": { "remote": "::", "local": "::", "ikey": "0.0.0.0", "okey": "0.0.0.0" } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 },{ "ifindex": 12, "ifname": "vti6", "link": null, "flags": ["POINTOPOINT","NOARP"], "mtu": 1500, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "tunnel6", "address": "2001:db8:1::1", "link_pointtopoint": true, "broadcast": "2001:db8:85a3::8a2e:370:7334", "promiscuity": 0, "linkinfo": { "info_kind": "vti6", "info_data": { "remote": "2001:db8:85a3::8a2e:370:7334", "local": "2001:db8:1::1", "ikey": "0.0.0.0", "okey": "0.0.0.0" } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 } ] Signed-off-by: Julien Fortin --- ip/link_vti6.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/ip/link_vti6.c b/ip/link_vti6.c index 6ea1fc23..8198d468 100644 --- a/ip/link_vti6.c +++ b/ip/link_vti6.c @@ -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); + } } } From 92b7454c3187314e72bddb3454affc513e0e755c Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:36:13 -0700 Subject: [PATCH 39/53] ip: link_macvlan.c: add json output support Schema: { "mode": { "type": "string", "attr": "IFLA_MACVLAN_MODE" }, "nopromisc": { "type": "bool", "attr": "MACVLAN_FLAG_NOPROMISC" }, "macaddr_count": { "type": "int", "attr": "IFLA_MACVLAN_MACADDR_COUNT" }, "macaddr_data": { "type": "array", "attr": "IFLA_MACVLAN_MACADDR_DATA", "array": [ { "type": "string" } ] }, } $ ip link add name peth0 link eth0 type macvlan $ ip -details -json link show peth0 [{ "ifindex": 26, "ifname": "peth0", "link": "eth0", "flags": ["BROADCAST","MULTICAST"], "mtu": 1500, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "ether", "address": "7a:84:48:3e:7b:1c", "broadcast": "ff:ff:ff:ff:ff:ff", "promiscuity": 0, "linkinfo": { "info_kind": "macvlan", "info_data": { "mode": "vepa" } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 } ] Signed-off-by: Julien Fortin --- ip/iplink_macvlan.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/ip/iplink_macvlan.c b/ip/iplink_macvlan.c index 662eb6ff..b966a615 100644 --- a/ip/iplink_macvlan.c +++ b/ip/iplink_macvlan.c @@ -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); } From 43bc20ae736c943a7202fef07104eb1b5800b7f8 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Thu, 17 Aug 2017 10:36:14 -0700 Subject: [PATCH 40/53] ip: iplink_vlan.c: add json output support Schema: { "protocol": { "type": "string", "attr": "IFLA_VLAN_PROTOCOL" }, "id": { "type": "uint", "attr": "IFLA_VLAN_ID" }, "flags": { "type": "array", "attr": "IFLA_VLAN_FLAGS", "array": [ { "type": "string" } ] }, "ingress_qos": { "type": "array", "attr": "IFLA_VLAN_INGRESS_QOS", "array": [ { "type": "dict", "dict": { "from": { "type": "uint" }, "to": { "type": "uint" } } } ] }, "egress_qos": { "type": "array", "attr": "IFLA_VLAN_EGRESS_QOS", "array": [ { "type": "dict", "dict": { "from": { "type": "uint" }, "to": { "type": "uint" } } } ] } } $ ip link add name eth0.42 link eth0 type vlan id 42 $ ip -details -json link show [{ "ifindex": 30, "ifname": "eth0.42", "link": "eth0", "flags": ["BROADCAST","MULTICAST"], "mtu": 1500, "qdisc": "noop", "operstate": "DOWN", "linkmode": "DEFAULT", "group": "default", "link_type": "ether", "address": "08:00:27:db:31:88", "broadcast": "ff:ff:ff:ff:ff:ff", "promiscuity": 0, "linkinfo": { "info_kind": "vlan", "info_data": { "protocol": "802.1Q", "id": 42, "flags": ["REORDER_HDR"] } }, "inet6_addr_gen_mode": "eui64", "num_tx_queues": 1, "num_rx_queues": 1, "gso_max_size": 65536, "gso_max_segs": 65535 } ] Signed-off-by: Julien Fortin --- ip/iplink_vlan.c | 62 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/ip/iplink_vlan.c b/ip/iplink_vlan.c index b47236d8..4d78cf9e 100644 --- a/ip/iplink_vlan.c +++ b/ip/iplink_vlan.c @@ -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); } From 18d7817c60773eafa6de51253de8763775db2a45 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 21 Aug 2017 16:54:39 -0700 Subject: [PATCH 41/53] update kernel headers from net-next Signed-off-by: Stephen Hemminger --- include/linux/bpf.h | 53 +++++++++++++++++++++++++++++++++++++-- include/linux/inet_diag.h | 1 + include/linux/xfrm.h | 1 + 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 9c7c78bc..cb840691 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -110,6 +110,7 @@ enum bpf_map_type { BPF_MAP_TYPE_ARRAY_OF_MAPS, BPF_MAP_TYPE_HASH_OF_MAPS, BPF_MAP_TYPE_DEVMAP, + BPF_MAP_TYPE_SOCKMAP, }; enum bpf_prog_type { @@ -127,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 { @@ -134,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 @@ -159,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 @@ -167,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 */ @@ -174,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 */ @@ -210,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 */ @@ -556,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), \ @@ -609,7 +641,9 @@ union bpf_attr { FN(set_hash), \ FN(setsockopt), \ FN(skb_adjust_room), \ - FN(redirect_map), + 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 @@ -686,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 { @@ -746,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 { diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h index f7bf7819..c51a7051 100644 --- a/include/linux/inet_diag.h +++ b/include/linux/inet_diag.h @@ -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/xfrm.h b/include/linux/xfrm.h index 3af99e02..5790293b 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -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) From 5f1df307b47f7f0b28a29d85418a3934cc3a83b2 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 10 Aug 2017 17:05:03 -0700 Subject: [PATCH 42/53] config: put CFLAGS/LDLIBS in config.mk This renames Config to config.mk and includes more Make input. Now configure generates all the required CFLAGS and LDLIBS for the optional libraries. Also, use pkg-config to test for libelf, rather than using a test program. This makes it consistent with other libraries. Signed-off-by: Stephen Hemminger --- .gitignore | 1 - Makefile | 8 ++--- README | 5 +-- bridge/Makefile | 11 +------ configure | 81 ++++++++++++++++++++++++------------------------ devlink/Makefile | 3 +- genl/Makefile | 7 +---- ip/Makefile | 15 +-------- lib/Makefile | 14 +-------- misc/Makefile | 16 +--------- netem/Makefile | 7 +---- rdma/Makefile | 5 +-- tc/Makefile | 15 +-------- tipc/Makefile | 5 ++- 14 files changed, 60 insertions(+), 133 deletions(-) diff --git a/.gitignore b/.gitignore index c3b8d386..308aec6b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ static-syms.h config.* -Config *.o *.a *.so diff --git a/Makefile b/Makefile index dbb4a4af..7a691dea 100644 --- a/Makefile +++ b/Makefile @@ -54,12 +54,12 @@ SUBDIRS=lib ip tc bridge misc netem genl tipc devlink rdma man LIBNETLINK=../lib/libnetlink.a ../lib/libutil.a LDLIBS += $(LIBNETLINK) -all: Config +all: config.mk @set -e; \ for i in $(SUBDIRS); \ do echo; echo $$i; $(MAKE) $(MFLAGS) -C $$i; done -Config: +config.mk: sh configure $(KERNEL_INCLUDE) install: all @@ -88,9 +88,9 @@ clean: do $(MAKE) $(MFLAGS) -C $$i clean; done clobber: - touch Config + touch config.mk $(MAKE) $(MFLAGS) clean - rm -f Config cscope.* + rm -f config.mk cscope.* distclean: clobber diff --git a/README b/README index c7a5118d..386fbaf6 100644 --- a/README +++ b/README @@ -21,8 +21,9 @@ database routines. Often this is in the db-devel package. 2. make -The makefile will automatically build a Config file which -contains whether or not ATM is available, etc. +The makefile will automatically build a config.mk file which +contains definitions of libraries that may or may not be available +on the system such as: ATM, ELF, MNL, and SELINUX. 3. To make documentation, cd to doc/ directory , then look at start of Makefile and set correct values for diff --git a/bridge/Makefile b/bridge/Makefile index fa448ea2..b2ae0a4e 100644 --- a/bridge/Makefile +++ b/bridge/Makefile @@ -1,15 +1,6 @@ BROBJ = bridge.o fdb.o monitor.o link.o mdb.o vlan.o -include ../Config - -ifeq ($(IP_CONFIG_SETNS),y) - CFLAGS += -DHAVE_SETNS -endif - -ifeq ($(HAVE_MNL),y) - CFLAGS += -DHAVE_LIBMNL $(shell $(PKG_CONFIG) libmnl --cflags) - LDLIBS += $(shell $(PKG_CONFIG) libmnl --libs) -endif +include ../config.mk all: bridge diff --git a/configure b/configure index 88cbdb82..7be8fb11 100755 --- a/configure +++ b/configure @@ -3,6 +3,9 @@ # INCLUDE=${1:-"$PWD/include"} +# Output file which is input to Makefile +CONFIG=config.mk + # Make a temp directory in build tree. TMPDIR=$(mktemp -d config.XXXXXX) trap 'status=$?; rm -rf $TMPDIR; exit $status' EXIT HUP INT QUIT TERM @@ -10,7 +13,7 @@ trap 'status=$?; rm -rf $TMPDIR; exit $status' EXIT HUP INT QUIT TERM check_prog() { echo -n "$2" - command -v $1 >/dev/null 2>&1 && (echo "$3:=y" >> Config; echo "yes") || (echo "no"; return 1) + command -v $1 >/dev/null 2>&1 && (echo "$3:=y" >> $CONFIG; echo "yes") || (echo "no"; return 1) } check_docs() @@ -30,9 +33,9 @@ check_toolchain() : ${PKG_CONFIG:=pkg-config} : ${AR=ar} : ${CC=gcc} - echo "PKG_CONFIG:=${PKG_CONFIG}" >>Config - echo "AR:=${AR}" >>Config - echo "CC:=${CC}" >>Config + echo "PKG_CONFIG:=${PKG_CONFIG}" >>$CONFIG + echo "AR:=${AR}" >>$CONFIG + echo "CC:=${CC}" >>$CONFIG } check_atm() @@ -49,7 +52,7 @@ EOF $CC -I$INCLUDE -o $TMPDIR/atmtest $TMPDIR/atmtest.c -latm >/dev/null 2>&1 if [ $? -eq 0 ] then - echo "TC_CONFIG_ATM:=y" >>Config + echo "TC_CONFIG_ATM:=y" >>$CONFIG echo yes else echo no @@ -61,7 +64,7 @@ check_xtables() { if ! ${PKG_CONFIG} xtables --exists then - echo "TC_CONFIG_NO_XT:=y" >>Config + echo "TC_CONFIG_NO_XT:=y" >>$CONFIG fi } @@ -90,7 +93,7 @@ EOF if $CC -I$INCLUDE $IPTC -o $TMPDIR/ipttest $TMPDIR/ipttest.c $IPTL \ $(${PKG_CONFIG} xtables --cflags --libs) -ldl >/dev/null 2>&1 then - echo "TC_CONFIG_XT:=y" >>Config + echo "TC_CONFIG_XT:=y" >>$CONFIG echo "using xtables" fi rm -f $TMPDIR/ipttest.c $TMPDIR/ipttest @@ -99,7 +102,7 @@ EOF check_xt_old() { # bail if previous XT checks has already succeded. - if grep -q TC_CONFIG_XT Config + if grep -q TC_CONFIG_XT $CONFIG then return fi @@ -129,7 +132,7 @@ EOF $CC -I$INCLUDE $IPTC -o $TMPDIR/ipttest $TMPDIR/ipttest.c $IPTL -ldl >/dev/null 2>&1 if [ $? -eq 0 ] then - echo "TC_CONFIG_XT_OLD:=y" >>Config + echo "TC_CONFIG_XT_OLD:=y" >>$CONFIG echo "using old xtables (no need for xt-internal.h)" fi rm -f $TMPDIR/ipttest.c $TMPDIR/ipttest @@ -138,7 +141,7 @@ EOF check_xt_old_internal_h() { # bail if previous XT checks has already succeded. - if grep -q TC_CONFIG_XT Config + if grep -q TC_CONFIG_XT $CONFIG then return fi @@ -170,14 +173,14 @@ EOF if [ $? -eq 0 ] then echo "using old xtables with xt-internal.h" - echo "TC_CONFIG_XT_OLD_H:=y" >>Config + echo "TC_CONFIG_XT_OLD_H:=y" >>$CONFIG fi rm -f $TMPDIR/ipttest.c $TMPDIR/ipttest } check_ipt() { - if ! grep TC_CONFIG_XT Config > /dev/null + if ! grep TC_CONFIG_XT $CONFIG > /dev/null then echo "using iptables" fi @@ -188,7 +191,7 @@ check_ipt_lib_dir() IPT_LIB_DIR=$(${PKG_CONFIG} --variable=xtlibdir xtables) if [ -n "$IPT_LIB_DIR" ]; then echo $IPT_LIB_DIR - echo "IPT_LIB_DIR:=$IPT_LIB_DIR" >> Config + echo "IPT_LIB_DIR:=$IPT_LIB_DIR" >> $CONFIG return fi @@ -197,7 +200,7 @@ check_ipt_lib_dir() for file in $dir/{xtables,iptables}/lib*t_*so ; do if [ -f $file ]; then echo ${file%/*} - echo "IPT_LIB_DIR:=${file%/*}" >> Config + echo "IPT_LIB_DIR:=${file%/*}" >> $CONFIG return fi done @@ -218,8 +221,9 @@ EOF $CC -I$INCLUDE -o $TMPDIR/setnstest $TMPDIR/setnstest.c >/dev/null 2>&1 if [ $? -eq 0 ] then - echo "IP_CONFIG_SETNS:=y" >>Config + echo "IP_CONFIG_SETNS:=y" >>$CONFIG echo "yes" + echo "CFLAGS += -DHAVE_SETNS" >>$CONFIG else echo "no" fi @@ -249,7 +253,7 @@ EOF if $CC -I$INCLUDE -o $TMPDIR/ipsettest $TMPDIR/ipsettest.c >/dev/null 2>&1 then - echo "TC_CONFIG_IPSET:=y" >>Config + echo "TC_CONFIG_IPSET:=y" >>$CONFIG echo "yes" else echo "no" @@ -259,25 +263,16 @@ EOF check_elf() { - cat >$TMPDIR/elftest.c < -#include -int main(void) -{ - Elf_Scn *scn __attribute__((__unused__)); - GElf_Shdr shdr __attribute__((__unused__));; - return elf_version(EV_CURRENT); -} -EOF - - if $CC -I$INCLUDE -o $TMPDIR/elftest $TMPDIR/elftest.c -lelf >/dev/null 2>&1 + if ${PKG_CONFIG} libelf --exists then - echo "HAVE_ELF:=y" >>Config + echo "HAVE_ELF:=y" >>$CONFIG echo "yes" + + echo 'CFLAGS += -DHAVE_ELF' `${PKG_CONFIG} libelf --cflags` >> $CONFIG + echo 'LDLIBS += ' `${PKG_CONFIG} libelf --libs` >>$CONFIG else echo "no" fi - rm -f $TMPDIR/elftest.c $TMPDIR/elftest } check_selinux() @@ -285,8 +280,11 @@ check_selinux() { if ${PKG_CONFIG} libselinux --exists then - echo "HAVE_SELINUX:=y" >>Config + echo "HAVE_SELINUX:=y" >>$CONFIG echo "yes" + + echo 'LDLIBS +=' `${PKG_CONFIG} --libs libselinux` >>$CONFIG + echo 'CFLAGS += -DHAVE_SELINUX' `${PKG_CONFIG} --cflags libselinux` >>$CONFIG else echo "no" fi @@ -296,8 +294,11 @@ check_mnl() { if ${PKG_CONFIG} libmnl --exists then - echo "HAVE_MNL:=y" >>Config + echo "HAVE_MNL:=y" >>$CONFIG echo "yes" + + echo 'CFLAGS += -DHAVE_LIBMNL' `${PKG_CONFIG} libmnl --cflags` >>$CONFIG + echo 'LDLIBS +=' `${PKG_CONFIG} libmnl --libs` >> $CONFIG else echo "no" fi @@ -317,7 +318,7 @@ EOF $CC -I$INCLUDE -o $TMPDIR/dbtest $TMPDIR/dbtest.c -ldb >/dev/null 2>&1 if [ $? -eq 0 ] then - echo "HAVE_BERKELEY_DB:=y" >>Config + echo "HAVE_BERKELEY_DB:=y" >>$CONFIG echo "yes" else echo "no" @@ -351,8 +352,8 @@ endif EOF } -echo "# Generated config based on" $INCLUDE >Config -quiet_config >> Config +echo "# Generated config based on" $INCLUDE >$CONFIG +quiet_config >> $CONFIG check_toolchain @@ -362,7 +363,7 @@ echo -n " ATM " check_atm check_xtables -if ! grep -q TC_CONFIG_NO_XT Config +if ! grep -q TC_CONFIG_NO_XT $CONFIG then echo -n " IPT " check_xt @@ -375,7 +376,7 @@ then fi echo -if ! grep -q TC_CONFIG_NO_XT Config +if ! grep -q TC_CONFIG_NO_XT $CONFIG then echo -n "iptables modules directory: " check_ipt_lib_dir @@ -401,6 +402,6 @@ echo -n "docs:" check_docs echo -echo >> Config -echo "%.o: %.c" >> Config -echo ' $(QUIET_CC)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<' >> Config +echo >> $CONFIG +echo "%.o: %.c" >> $CONFIG +echo ' $(QUIET_CC)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<' >> $CONFIG diff --git a/devlink/Makefile b/devlink/Makefile index 7256c287..3b2067d6 100644 --- a/devlink/Makefile +++ b/devlink/Makefile @@ -1,4 +1,5 @@ -include ../Config +include ../config.mk + ifeq ($(HAVE_MNL),y) DEVLINKOBJ = devlink.o mnlg.o diff --git a/genl/Makefile b/genl/Makefile index f0efe1ac..de1635e4 100644 --- a/genl/Makefile +++ b/genl/Makefile @@ -1,6 +1,6 @@ GENLOBJ=genl.o -include ../Config +include ../config.mk SHARED_LIBS ?= y CFLAGS += -fno-strict-aliasing @@ -17,11 +17,6 @@ LDFLAGS += -Wl,-export-dynamic LDLIBS += -lm -ldl endif -ifeq ($(HAVE_MNL),y) - CFLAGS += -DHAVE_LIBMNL $(shell $(PKG_CONFIG) libmnl --cflags) - LDLIBS += $(shell $(PKG_CONFIG) libmnl --libs) -endif - all: genl genl: $(GENLOBJ) $(LIBNETLINK) $(LIBUTIL) $(GENLLIB) diff --git a/ip/Makefile b/ip/Makefile index 8ed2686c..52c9a2e5 100644 --- a/ip/Makefile +++ b/ip/Makefile @@ -13,20 +13,7 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \ RTMONOBJ=rtmon.o -include ../Config - -ifeq ($(IP_CONFIG_SETNS),y) - CFLAGS += -DHAVE_SETNS -endif - -ifeq ($(HAVE_ELF),y) - CFLAGS += -DHAVE_ELF - LDLIBS += -lelf -endif -ifeq ($(HAVE_MNL),y) - CFLAGS += -DHAVE_LIBMNL $(shell $(PKG_CONFIG) libmnl --cflags) - LDLIBS += $(shell $(PKG_CONFIG) libmnl --libs) -endif +include ../config.mk ALLOBJ=$(IPOBJ) $(RTMONOBJ) SCRIPTS=ifcfg rtpr routel routef diff --git a/lib/Makefile b/lib/Makefile index b7b1d568..5e9f72fa 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,16 +1,4 @@ -include ../Config - -ifeq ($(IP_CONFIG_SETNS),y) - CFLAGS += -DHAVE_SETNS -endif - -ifeq ($(HAVE_ELF),y) - CFLAGS += -DHAVE_ELF -endif - -ifeq ($(HAVE_MNL),y) - CFLAGS += -DHAVE_LIBMNL $(shell $(PKG_CONFIG) libmnl --cflags) -endif +include ../config.mk CFLAGS += -fPIC diff --git a/misc/Makefile b/misc/Makefile index fa90308e..d02616e3 100644 --- a/misc/Makefile +++ b/misc/Makefile @@ -3,26 +3,12 @@ LNSTATOBJ=lnstat.o lnstat_util.o TARGETS=ss nstat ifstat rtacct lnstat -include ../Config +include ../config.mk ifeq ($(HAVE_BERKELEY_DB),y) TARGETS += arpd endif -ifeq ($(HAVE_SELINUX),y) - LDLIBS += $(shell $(PKG_CONFIG) --libs libselinux) - CFLAGS += $(shell $(PKG_CONFIG) --cflags libselinux) -DHAVE_SELINUX -endif - -ifeq ($(IP_CONFIG_SETNS),y) - CFLAGS += -DHAVE_SETNS -endif - -ifeq ($(HAVE_MNL),y) - CFLAGS += -DHAVE_LIBMNL $(shell $(PKG_CONFIG) libmnl --cflags) - LDLIBS += $(shell $(PKG_CONFIG) libmnl --libs) -endif - all: $(TARGETS) ss: $(SSOBJ) diff --git a/netem/Makefile b/netem/Makefile index 2499f086..43418527 100644 --- a/netem/Makefile +++ b/netem/Makefile @@ -1,4 +1,4 @@ -include ../Config +include ../config.mk DISTGEN = maketable normal pareto paretonormal DISTDATA = normal.dist pareto.dist paretonormal.dist experimental.dist @@ -7,11 +7,6 @@ HOSTCC ?= $(CC) CCOPTS = $(CBUILD_CFLAGS) LDLIBS += -lm -ifeq ($(HAVE_MNL),y) - CFLAGS += -DHAVE_LIBMNL $(shell $(PKG_CONFIG) libmnl --cflags) - LDLIBS += $(shell $(PKG_CONFIG) libmnl --libs) -endif - all: $(DISTGEN) $(DISTDATA) $(DISTGEN): diff --git a/rdma/Makefile b/rdma/Makefile index 1a9e4b1a..1b5aa50b 100644 --- a/rdma/Makefile +++ b/rdma/Makefile @@ -1,13 +1,10 @@ -include ../Config +include ../config.mk ifeq ($(HAVE_MNL),y) RDMA_OBJ = rdma.o utils.o dev.o link.o TARGETS=rdma -CFLAGS += $(shell $(PKG_CONFIG) libmnl --cflags) -LDLIBS += $(shell $(PKG_CONFIG) libmnl --libs) - endif all: $(TARGETS) $(LIBS) diff --git a/tc/Makefile b/tc/Makefile index a9b4b8e6..777de5e6 100644 --- a/tc/Makefile +++ b/tc/Makefile @@ -2,11 +2,7 @@ TCOBJ= tc.o tc_qdisc.o tc_class.o tc_filter.o tc_util.o tc_monitor.o \ tc_exec.o m_police.o m_estimator.o m_action.o m_ematch.o \ emp_ematch.yacc.o emp_ematch.lex.o -include ../Config - -ifeq ($(IP_CONFIG_SETNS),y) - CFLAGS += -DHAVE_SETNS -endif +include ../config.mk SHARED_LIBS ?= y @@ -102,15 +98,6 @@ endif TCOBJ += $(TCMODULES) LDLIBS += -L. -lm -ifeq ($(HAVE_ELF),y) - CFLAGS += -DHAVE_ELF - LDLIBS += -lelf -endif -ifeq ($(HAVE_MNL),y) - CFLAGS += -DHAVE_LIBMNL $(shell $(PKG_CONFIG) libmnl --cflags) - LDLIBS += $(shell $(PKG_CONFIG) libmnl --libs) -endif - ifeq ($(SHARED_LIBS),y) LDLIBS += -ldl LDFLAGS += -Wl,-export-dynamic diff --git a/tipc/Makefile b/tipc/Makefile index 87e3cac3..2212beb0 100644 --- a/tipc/Makefile +++ b/tipc/Makefile @@ -1,4 +1,5 @@ -include ../Config +include ../config.mk + ifeq ($(HAVE_MNL),y) TIPCOBJ=bearer.o \ @@ -8,8 +9,6 @@ TIPCOBJ=bearer.o \ node.o socket.o \ peer.o tipc.o -include ../Config - TARGETS=tipc CFLAGS += $(shell $(PKG_CONFIG) libmnl --cflags) LDLIBS += $(shell $(PKG_CONFIG) libmnl --libs) From fb14560b76597480b570112077bf18d42f5fe87d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 23 Aug 2017 10:05:08 -0700 Subject: [PATCH 43/53] add ERSPAN headers Signed-off-by: Stephen Hemminger --- include/linux/if_ether.h | 1 + include/linux/if_tunnel.h | 1 + 2 files changed, 2 insertions(+) diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index b7d3beb5..aa2ba16e 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -66,6 +66,7 @@ #define ETH_P_ATALK 0x809B /* Appletalk DDP */ #define ETH_P_AARP 0x80F3 /* Appletalk AARP */ #define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */ +#define ETH_P_ERSPAN 0x88BE /* ERSPAN type II */ #define ETH_P_IPX 0x8137 /* IPX over DIX */ #define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */ #define ETH_P_PAUSE 0x8808 /* IEEE Pause frames. See 802.3 31B */ diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h index 7375335a..21834cac 100644 --- a/include/linux/if_tunnel.h +++ b/include/linux/if_tunnel.h @@ -134,6 +134,7 @@ enum { IFLA_GRE_COLLECT_METADATA, IFLA_GRE_IGNORE_DF, IFLA_GRE_FWMARK, + IFLA_GRE_ERSPAN_INDEX, __IFLA_GRE_MAX, }; From 9a1381d50913d59aa3ba1ccb12dc3a0bbd64573b Mon Sep 17 00:00:00 2001 From: William Tu Date: Wed, 23 Aug 2017 10:06:54 -0700 Subject: [PATCH 44/53] gre: add support for ERSPAN tunnel The patch adds ERSPAN type II tunnel support. The implementation is based on the draft at https://tools.ietf.org/html/draft-foschiano-erspan-01. One of the purposes is for Linux box to be able to receive ERSPAN monitoring traffic sent from the Cisco switch, by creating a ERSPAN tunnel device. In addition, the patch also adds ERSPAN TX, so traffic can also be encapsulated into ERSPAN and sent out. The implementation reuses the key as ERSPAN session ID, and field 'erspan' as ERSPAN Index fields: ./ip link add dev ers11 type erspan seq key 100 erspan 123 \ local 172.16.1.200 remote 172.16.1.100 Signed-off-by: William Tu Signed-off-by: Meenakshi Vohra --- ip/ipaddress.c | 2 +- ip/iplink.c | 5 +++-- ip/link_gre.c | 29 ++++++++++++++++++++++++++++- man/man8/ip-address.8.in | 1 + man/man8/ip-link.8.in | 19 ++++++++++++++++--- 5 files changed, 49 insertions(+), 7 deletions(-) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index db54b4e3..201225f7 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -77,7 +77,7 @@ static void usage(void) fprintf(stderr, "LFT := forever | SECONDS\n"); fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n"); fprintf(stderr, " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan | lowpan |\n"); - fprintf(stderr, " gre | gretap | ip6gre | ip6gretap | vti | nlmon | can |\n"); + fprintf(stderr, " gre | gretap | erspan | ip6gre | ip6gretap | vti | nlmon | can |\n"); fprintf(stderr, " bond_slave | ipvlan | geneve | bridge_slave | vrf | hsr | macsec }\n"); exit(-1); diff --git a/ip/iplink.c b/ip/iplink.c index 19bda1b9..a132707f 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -112,8 +112,9 @@ void iplink_usage(void) "\n" "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n" " bridge | bond | team | ipoib | ip6tnl | ipip | sit | vxlan |\n" - " gre | gretap | ip6gre | ip6gretap | vti | nlmon | team_slave |\n" - " bond_slave | ipvlan | geneve | bridge_slave | vrf | macsec }\n"); + " gre | gretap | erspan | ip6gre | ip6gretap | vti | nlmon |\n" + " team_slave | bond_slave | ipvlan | geneve | bridge_slave |\n" + " vrf | macsec }\n"); } exit(-1); } diff --git a/ip/link_gre.c b/ip/link_gre.c index 3c9f8194..9ea2970c 100644 --- a/ip/link_gre.c +++ b/ip/link_gre.c @@ -26,7 +26,7 @@ static void print_usage(FILE *f) { fprintf(f, - "Usage: ... { gre | gretap } [ remote ADDR ]\n" + "Usage: ... { gre | gretap | erspan } [ remote ADDR ]\n" " [ local ADDR ]\n" " [ [i|o]seq ]\n" " [ [i|o]key KEY ]\n" @@ -44,6 +44,7 @@ static void print_usage(FILE *f) " [ [no]encap-csum6 ]\n" " [ [no]encap-remcsum ]\n" " [ fwmark MARK ]\n" + " [ erspan IDX ]\n" "\n" "Where: ADDR := { IP_ADDRESS | any }\n" " TOS := { NUMBER | inherit }\n" @@ -96,6 +97,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, __u8 metadata = 0; __u8 ignore_df = 0; __u32 fwmark = 0; + __u32 erspan_idx = 0; if (!(n->nlmsg_flags & NLM_F_CREATE)) { if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) { @@ -172,6 +174,9 @@ get_failed: if (greinfo[IFLA_GRE_FWMARK]) fwmark = rta_getattr_u32(greinfo[IFLA_GRE_FWMARK]); + + if (greinfo[IFLA_GRE_ERSPAN_INDEX]) + erspan_idx = rta_getattr_u32(greinfo[IFLA_GRE_ERSPAN_INDEX]); } while (argc > 0) { @@ -328,6 +333,12 @@ get_failed: NEXT_ARG(); if (get_u32(&fwmark, *argv, 0)) invarg("invalid fwmark\n", *argv); + } else if (strcmp(*argv, "erspan") == 0) { + NEXT_ARG(); + if (get_u32(&erspan_idx, *argv, 0)) + invarg("invalid erspan index\n", *argv); + if (erspan_idx & ~((1<<20) - 1) || erspan_idx == 0) + invarg("erspan index must be > 0 and <= 20-bit\n", *argv); } else usage(); argc--; argv++; @@ -359,6 +370,8 @@ get_failed: addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1); addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1); addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark); + if (erspan_idx != 0) + addattr32(n, 1024, IFLA_GRE_ERSPAN_INDEX, erspan_idx); } else { addattr_l(n, 1024, IFLA_GRE_COLLECT_METADATA, NULL, 0); } @@ -494,6 +507,12 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) if (tb[IFLA_GRE_IGNORE_DF] && rta_getattr_u8(tb[IFLA_GRE_IGNORE_DF])) print_bool(PRINT_ANY, "ignore_df", "ignore-df ", true); + if (tb[IFLA_GRE_ERSPAN_INDEX]) { + __u32 erspan_idx = rta_getattr_u32(tb[IFLA_GRE_ERSPAN_INDEX]); + + fprintf(f, "erspan_index %u ", erspan_idx); + } + if (tb[IFLA_GRE_ENCAP_TYPE] && rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) { __u16 type = rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]); @@ -587,3 +606,11 @@ struct link_util gretap_link_util = { .print_opt = gre_print_opt, .print_help = gre_print_help, }; + +struct link_util erspan_link_util = { + .id = "erspan", + .maxattr = IFLA_GRE_MAX, + .parse_opt = gre_parse_opt, + .print_opt = gre_print_opt, + .print_help = gre_print_help, +}; diff --git a/man/man8/ip-address.8.in b/man/man8/ip-address.8.in index 43385813..988a7965 100644 --- a/man/man8/ip-address.8.in +++ b/man/man8/ip-address.8.in @@ -120,6 +120,7 @@ ip-address \- protocol address management .BR sit " |" .BR gre " |" .BR gretap " |" +.BR erspan " |" .BR ip6gre " |" .BR ip6gretap " |" .BR vti " |" diff --git a/man/man8/ip-link.8.in b/man/man8/ip-link.8.in index c0207281..851b308c 100644 --- a/man/man8/ip-link.8.in +++ b/man/man8/ip-link.8.in @@ -202,6 +202,7 @@ ip-link \- network device configuration .BR sit " |" .BR gre " |" .BR gretap " |" +.BR erspan " |" .BR ip6gre " |" .BR ip6gretap " |" .BR vti " |" @@ -297,6 +298,9 @@ Link types: .BR gretap - Virtual L2 tunnel interface GRE over IPv4 .sp +.BR erspan +- Encapsulated Remote SPAN over GRE and IPv4 +.sp .BR ip6gre - Virtual tunnel interface GRE over IPv6 .sp @@ -643,13 +647,13 @@ keyword. .in -8 .TP -GRE, IPIP, SIT Type Support +GRE, IPIP, SIT, ERSPAN Type Support For a link of types -.I GRE/IPIP/SIT +.I GRE/IPIP/SIT/ERSPAN the following additional arguments are supported: .BI "ip link add " DEVICE -.BR type " { " gre " | " ipip " | " sit " }" +.BR type " { " gre " | " ipip " | " sit " | " erspan " }" .BI " remote " ADDR " local " ADDR [ .BR encap " { " fou " | " gue " | " none " }" @@ -663,6 +667,8 @@ the following additional arguments are supported: .I " [no]encap-remcsum " ] [ .I " mode " { ip6ip | ipip | mplsip | any } " +] [ +.BR erspan " \fIIDX " ] .in +8 @@ -707,6 +713,13 @@ MPLS-Over-IPv4, "any" indicates IPv6, IPv4 or MPLS Over IPv4. Supported for SIT where the default is "ip6ip" and IPIP where the default is "ipip". IPv6-Over-IPv4 is not supported for IPIP. +.sp +.BR erspan " \fIIDX " +- specifies the ERSPAN index field. +.IR IDX +indicates a 20 bit index/port number associated with the ERSPAN +traffic's source port and direction. + .in -8 .TP From b43b5b9acc00c47fe9204fe0aa3de6441fdebd59 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 24 Aug 2017 15:31:57 -0700 Subject: [PATCH 45/53] devlink: header update Signed-off-by: Stephen Hemminger --- include/linux/devlink.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/linux/devlink.h b/include/linux/devlink.h index 76440050..83a125cf 100644 --- a/include/linux/devlink.h +++ b/include/linux/devlink.h @@ -226,4 +226,17 @@ enum devlink_dpipe_action_type { DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY, }; +enum devlink_dpipe_field_ethernet_id { + DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC, +}; + +enum devlink_dpipe_field_ipv4_id { + DEVLINK_DPIPE_FIELD_IPV4_DST_IP, +}; + +enum devlink_dpipe_header_id { + DEVLINK_DPIPE_HEADER_ETHERNET, + DEVLINK_DPIPE_HEADER_IPV4, +}; + #endif /* _LINUX_DEVLINK_H_ */ From 8707fd8c9317f1ffe98113e79ac5ff03e00339c6 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 30 Aug 2017 08:26:43 -0700 Subject: [PATCH 46/53] update headers from net-next Signed-off-by: Stephen Hemminger --- include/linux/bpf.h | 12 +++--------- include/linux/if_ether.h | 2 ++ include/linux/seg6_iptunnel.h | 1 + 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index cb840691..32b7221d 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -136,15 +136,13 @@ enum bpf_attach_type { BPF_CGROUP_INET_EGRESS, BPF_CGROUP_INET_SOCK_CREATE, BPF_CGROUP_SOCK_OPS, - BPF_CGROUP_SMAP_INGRESS, + BPF_SK_SKB_STREAM_PARSER, + BPF_SK_SKB_STREAM_VERDICT, __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 @@ -224,7 +222,6 @@ 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 */ @@ -580,14 +577,11 @@ union bpf_attr { * @flags: reserved for future use * Return: SK_REDIRECT * - * int bpf_sock_map_update(skops, map, key, flags, map_flags) + * int bpf_sock_map_update(skops, map, key, 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), \ diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index aa2ba16e..a39acec5 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -99,11 +99,13 @@ #define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */ #define ETH_P_80221 0x8917 /* IEEE 802.21 Media Independent Handover Protocol */ #define ETH_P_HSR 0x892F /* IEC 62439-3 HSRv1 */ +#define ETH_P_NSH 0x894F /* Network Service Header */ #define ETH_P_LOOPBACK 0x9000 /* Ethernet loopback packet, per IEEE 802.3 */ #define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ #define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ #define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ #define ETH_P_EDSA 0xDADA /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */ +#define ETH_P_IFE 0xED3E /* ForCES inter-FE LFB type */ #define ETH_P_AF_IUCV 0xFBFB /* IBM af_iucv [ NOT AN OFFICIALLY REGISTERED ID ] */ #define ETH_P_802_3_MIN 0x0600 /* If the value in the ethernet type is less than this value diff --git a/include/linux/seg6_iptunnel.h b/include/linux/seg6_iptunnel.h index c9bba0e7..a5dc05a1 100644 --- a/include/linux/seg6_iptunnel.h +++ b/include/linux/seg6_iptunnel.h @@ -33,6 +33,7 @@ struct seg6_iptunnel_encap { enum { SEG6_IPTUN_MODE_INLINE, SEG6_IPTUN_MODE_ENCAP, + SEG6_IPTUN_MODE_L2ENCAP, }; From bf338b60d46235f314bd293121be4035c57c8bce Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 28 Aug 2017 15:07:35 -0400 Subject: [PATCH 47/53] tc: m_ife: allow ife type to zero This patch allows to set an ethertype for IFE which is zero. There is no kernel side validation which forbids a type to zero. Signed-off-by: Alexander Aring Acked-by: Jamal Hadi Salim --- tc/m_ife.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tc/m_ife.c b/tc/m_ife.c index e3521e62..e05e2276 100644 --- a/tc/m_ife.c +++ b/tc/m_ife.c @@ -63,6 +63,7 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p, char dbuf[ETH_ALEN]; char sbuf[ETH_ALEN]; __u16 ife_type = 0; + int user_type = 0; __u32 ife_prio = 0; __u32 ife_prio_v = 0; __u32 ife_mark = 0; @@ -125,6 +126,7 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p, if (get_u16(&ife_type, *argv, 0)) invarg("ife type is invalid", *argv); fprintf(stderr, "IFE type 0x%x\n", ife_type); + user_type = 1; } else if (matches(*argv, "dst") == 0) { NEXT_ARG(); daddr = *argv; @@ -185,7 +187,7 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p, if (daddr) addattr_l(n, MAX_MSG, TCA_IFE_DMAC, dbuf, ETH_ALEN); - if (ife_type) + if (user_type) addattr_l(n, MAX_MSG, TCA_IFE_TYPE, &ife_type, 2); if (saddr) addattr_l(n, MAX_MSG, TCA_IFE_SMAC, sbuf, ETH_ALEN); From 664f35aa7cd53153c224fa142c7502cf53a99b05 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 28 Aug 2017 15:07:36 -0400 Subject: [PATCH 48/53] tc: m_ife: print IEEE ethertype format This patch uses the usually IEEE format to display an ethertype which is 4-digits and every digit in upper case. Signed-off-by: Alexander Aring --- tc/m_ife.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tc/m_ife.c b/tc/m_ife.c index e05e2276..7b57130e 100644 --- a/tc/m_ife.c +++ b/tc/m_ife.c @@ -125,7 +125,7 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p, NEXT_ARG(); if (get_u16(&ife_type, *argv, 0)) invarg("ife type is invalid", *argv); - fprintf(stderr, "IFE type 0x%x\n", ife_type); + fprintf(stderr, "IFE type 0x%04X\n", ife_type); user_type = 1; } else if (matches(*argv, "dst") == 0) { NEXT_ARG(); From 38060de1eb53fb3b677e43eb13b2e27bf6eb985f Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 28 Aug 2017 15:07:37 -0400 Subject: [PATCH 49/53] tc: m_ife: report about kernels default type This patch will report about if the ethertype for IFE is not specified that the default IFE type is used. Signed-off-by: Alexander Aring --- tc/m_ife.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tc/m_ife.c b/tc/m_ife.c index 7b57130e..5633ab90 100644 --- a/tc/m_ife.c +++ b/tc/m_ife.c @@ -189,6 +189,8 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p, addattr_l(n, MAX_MSG, TCA_IFE_DMAC, dbuf, ETH_ALEN); if (user_type) addattr_l(n, MAX_MSG, TCA_IFE_TYPE, &ife_type, 2); + else + fprintf(stderr, "IFE type 0x%04X\n", ETH_P_IFE); if (saddr) addattr_l(n, MAX_MSG, TCA_IFE_SMAC, sbuf, ETH_ALEN); From 3ee52855a0769b1db15a2363d368703f05bd5178 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 28 Aug 2017 15:07:38 -0400 Subject: [PATCH 50/53] man: tc-ife: add default type note This patch updates the tc-ife man page that the default IFE ethertype will be used if it's not specified. Signed-off-by: Alexander Aring Acked-by: Jamal Hadi Salim --- man/man8/tc-ife.8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man8/tc-ife.8 b/man/man8/tc-ife.8 index 3a42d51b..fd2df6c3 100644 --- a/man/man8/tc-ife.8 +++ b/man/man8/tc-ife.8 @@ -82,7 +82,7 @@ is required only when Optional six byte destination or source MAC address to encode. .TP .BI type " TYPE" -Optional 16-bit ethertype to encode. +Optional 16-bit ethertype to encode. If not specified value of 0xED3E will be used. .TP .BI CONTROL Action to take following an encode/decode. From cf87da417bb427d09d6ed8a12f3f1ad32e397207 Mon Sep 17 00:00:00 2001 From: David Lebrun Date: Mon, 28 Aug 2017 20:26:39 +0100 Subject: [PATCH 51/53] iproute: add support for seg6 l2encap mode This patch adds support for the L2ENCAP seg6 mode, enabling to encapsulate L2 frames within SRv6 packets. Signed-off-by: David Lebrun --- ip/iproute_lwtunnel.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index 14294c60..02f36ef7 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -110,6 +110,32 @@ static void print_srh(FILE *fp, struct ipv6_sr_hdr *srh) } } +static const char *seg6_mode_types[] = { + [SEG6_IPTUN_MODE_INLINE] = "inline", + [SEG6_IPTUN_MODE_ENCAP] = "encap", + [SEG6_IPTUN_MODE_L2ENCAP] = "l2encap", +}; + +static const char *format_seg6mode_type(int mode) +{ + if (mode < 0 || mode > ARRAY_SIZE(seg6_mode_types)) + return ""; + + return seg6_mode_types[mode]; +} + +static int read_seg6mode_type(const char *mode) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(seg6_mode_types); i++) { + if (strcmp(mode, seg6_mode_types[i]) == 0) + return i; + } + + return -1; +} + static void print_encap_seg6(FILE *fp, struct rtattr *encap) { struct rtattr *tb[SEG6_IPTUNNEL_MAX+1]; @@ -121,8 +147,7 @@ static void print_encap_seg6(FILE *fp, struct rtattr *encap) return; tuninfo = RTA_DATA(tb[SEG6_IPTUNNEL_SRH]); - fprintf(fp, "mode %s ", - (tuninfo->mode == SEG6_IPTUN_MODE_ENCAP) ? "encap" : "inline"); + fprintf(fp, "mode %s ", format_seg6mode_type(tuninfo->mode)); print_srh(fp, tuninfo->srh); } @@ -457,11 +482,8 @@ static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp, NEXT_ARG(); if (mode_ok++) duparg2("mode", *argv); - if (strcmp(*argv, "encap") == 0) - encap = 1; - else if (strcmp(*argv, "inline") == 0) - encap = 0; - else + encap = read_seg6mode_type(*argv); + if (encap < 0) invarg("\"mode\" value is invalid\n", *argv); } else if (strcmp(*argv, "segs") == 0) { NEXT_ARG(); @@ -490,10 +512,7 @@ static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp, tuninfo = malloc(sizeof(*tuninfo) + srhlen); memset(tuninfo, 0, sizeof(*tuninfo) + srhlen); - if (encap) - tuninfo->mode = SEG6_IPTUN_MODE_ENCAP; - else - tuninfo->mode = SEG6_IPTUN_MODE_INLINE; + tuninfo->mode = encap; memcpy(tuninfo->srh, srh, srhlen); From 9d563d52f6fc506e51bde6bed9af2a69da01397a Mon Sep 17 00:00:00 2001 From: David Lebrun Date: Mon, 28 Aug 2017 20:26:40 +0100 Subject: [PATCH 52/53] man: add documentation for seg6 l2encap mode This patch adds documentation for the seg6 L2ENCAP encapsulation mode. Signed-off-by: David Lebrun --- man/man8/ip-route.8.in | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/man/man8/ip-route.8.in b/man/man8/ip-route.8.in index 11dd9d0f..803de3b9 100644 --- a/man/man8/ip-route.8.in +++ b/man/man8/ip-route.8.in @@ -214,7 +214,7 @@ throw " | " unreachable " | " prohibit " | " blackhole " | " nat " ]" .IR ENCAP_SEG6 " := " .B seg6 .BR mode " [ " -.BR encap " | " inline " ] " +.BR encap " | " inline " | " l2encap " ] " .B segs .IR SEGMENTS " [ " .B hmac @@ -750,6 +750,10 @@ is a set of encapsulation attributes specific to the - Encapsulate packet in an outer IPv6 header with SRH .sp +.B mode l2encap +- Encapsulate ingress L2 frame within an outer IPv6 header and SRH +.sp + .I SEGMENTS - List of comma-separated IPv6 addresses .sp From 4a5b3035dea9336d7a005d881d88424895971fd7 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 5 Sep 2017 09:36:54 -0700 Subject: [PATCH 53/53] update headers from 4.14 merge Signed-off-by: Stephen Hemminger --- include/linux/bpf.h | 2 ++ include/linux/devlink.h | 5 +++++ include/linux/if_arp.h | 1 + include/linux/if_ether.h | 3 +++ include/linux/inet_diag.h | 1 + include/linux/netlink.h | 3 +++ include/linux/tcp.h | 9 +++++++++ 7 files changed, 24 insertions(+) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 32b7221d..b94acdc0 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -758,6 +758,8 @@ struct bpf_sock { __u32 family; __u32 type; __u32 protocol; + __u32 mark; + __u32 priority; }; #define XDP_PACKET_HEADROOM 256 diff --git a/include/linux/devlink.h b/include/linux/devlink.h index 83a125cf..a62695e2 100644 --- a/include/linux/devlink.h +++ b/include/linux/devlink.h @@ -234,9 +234,14 @@ enum devlink_dpipe_field_ipv4_id { DEVLINK_DPIPE_FIELD_IPV4_DST_IP, }; +enum devlink_dpipe_field_ipv6_id { + DEVLINK_DPIPE_FIELD_IPV6_DST_IP, +}; + enum devlink_dpipe_header_id { DEVLINK_DPIPE_HEADER_ETHERNET, DEVLINK_DPIPE_HEADER_IPV4, + DEVLINK_DPIPE_HEADER_IPV6, }; #endif /* _LINUX_DEVLINK_H_ */ diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index 8ce598b9..199f253b 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -59,6 +59,7 @@ #define ARPHRD_LAPB 516 /* LAPB */ #define ARPHRD_DDCMP 517 /* Digital's DDCMP protocol */ #define ARPHRD_RAWHDLC 518 /* Raw HDLC */ +#define ARPHRD_RAWIP 519 /* Raw IP */ #define ARPHRD_TUNNEL 768 /* IPIP tunnel */ #define ARPHRD_TUNNEL6 769 /* IP6IP6 tunnel */ diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index a39acec5..7dde037a 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -140,6 +140,9 @@ #define ETH_P_IEEE802154 0x00F6 /* IEEE802.15.4 frame */ #define ETH_P_CAIF 0x00F7 /* ST-Ericsson CAIF protocol */ #define ETH_P_XDSA 0x00F8 /* Multiplexed DSA protocol */ +#define ETH_P_MAP 0x00F9 /* Qualcomm multiplexing and + * aggregation protocol + */ /* * This is an Ethernet frame header. diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h index c51a7051..bada4d7b 100644 --- a/include/linux/inet_diag.h +++ b/include/linux/inet_diag.h @@ -143,6 +143,7 @@ enum { INET_DIAG_MARK, INET_DIAG_BBRINFO, INET_DIAG_CLASS_ID, + INET_DIAG_MD5SIG, __INET_DIAG_MAX, }; diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 654f08ad..ec0690b5 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -69,6 +69,9 @@ struct nlmsghdr { #define NLM_F_CREATE 0x400 /* Create, if it does not exist */ #define NLM_F_APPEND 0x800 /* Add to end of list */ +/* Modifiers to DELETE request */ +#define NLM_F_NONREC 0x100 /* Do not delete recursively */ + /* Flags for ACK message */ #define NLM_F_CAPPED 0x100 /* request was capped */ #define NLM_F_ACK_TLVS 0x200 /* extended ACK TVLs were included */ diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 8d0545e6..8edad3f9 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -256,4 +256,13 @@ struct tcp_md5sig { __u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */ }; +/* INET_DIAG_MD5SIG */ +struct tcp_diag_md5sig { + __u8 tcpm_family; + __u8 tcpm_prefixlen; + __u16 tcpm_keylen; + __be32 tcpm_addr[4]; + __u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; +}; + #endif /* _LINUX_TCP_H */