* [PATCH iproute2 json v2 06/27] ip: iplink.c: open/close json obj for ip -brief -json link show dev DEV
From: Julien Fortin @ 2017-08-17 17:35 UTC (permalink / raw)
To: netdev; +Cc: roopa, nikolay, dsa, Julien Fortin
In-Reply-To: <20170817173614.54987-1-julien@cumulusnetworks.com>
From: Julien Fortin <julien@cumulusnetworks.com>
Signed-off-by: Julien Fortin <julien@cumulusnetworks.com>
---
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;
}
--
2.14.1
^ permalink raw reply related
* [PATCH iproute2 json v2 05/27] ip: ipaddress.c: add support for json output
From: Julien Fortin @ 2017-08-17 17:35 UTC (permalink / raw)
To: netdev; +Cc: roopa, nikolay, dsa, Julien Fortin
In-Reply-To: <20170817173614.54987-1-julien@cumulusnetworks.com>
From: Julien Fortin <julien@cumulusnetworks.com>
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: <LOOPBACK,UP,LOWER_UP> 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: <BROADCAST,MULTICAST,UP,LOWER_UP> 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: <BROADCAST,MULTICAST> 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: <BROADCAST,MULTICAST> 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: <BROADCAST,MULTICAST,MASTER> 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: <BROADCAST,MULTICAST,M-DOWN> 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 <REORDER_HDR>
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: <NO-CARRIER,BROADCAST,MULTICAST,UP> 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 <julien@cumulusnetworks.com>
---
ip/ipaddress.c | 1064 +++++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 753 insertions(+), 311 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 <linux/sockios.h>
#include <linux/net_namespace.h>
+#include "utils.h"
#include "rt_names.h"
#include "utils.h"
#include "ll_map.h"
@@ -84,13 +85,14 @@ static void usage(void)
static void print_link_flags(FILE *fp, unsigned int flags, unsigned int mdown)
{
- fprintf(fp, "<");
+ open_json_array(PRINT_ANY, is_json_context() ? "flags" : "<");
if (flags & IFF_UP && !(flags & IFF_RUNNING))
- fprintf(fp, "NO-CARRIER%s", flags ? "," : "");
+ print_string(PRINT_ANY, NULL,
+ flags ? "%s," : "%s", "NO-CARRIER");
flags &= ~IFF_RUNNING;
-#define _PF(f) if (flags&IFF_##f) { \
- flags &= ~IFF_##f ; \
- fprintf(fp, #f "%s", flags ? "," : ""); }
+#define _PF(f) if (flags&IFF_##f) { \
+ flags &= ~IFF_##f ; \
+ print_string(PRINT_ANY, NULL, flags ? "%s," : "%s", #f); }
_PF(LOOPBACK);
_PF(BROADCAST);
_PF(POINTOPOINT);
@@ -111,10 +113,10 @@ static void print_link_flags(FILE *fp, unsigned int flags, unsigned int mdown)
_PF(ECHO);
#undef _PF
if (flags)
- fprintf(fp, "%x", flags);
+ print_hex(PRINT_ANY, NULL, "%x", flags);
if (mdown)
- fprintf(fp, ",M-DOWN");
- fprintf(fp, "> ");
+ print_string(PRINT_ANY, NULL, ",%s", "M-DOWN");
+ close_json_array(PRINT_ANY, "> ");
}
static const char *oper_states[] = {
@@ -125,14 +127,26 @@ static const char *oper_states[] = {
static void print_operstate(FILE *f, __u8 state)
{
if (state >= ARRAY_SIZE(oper_states)) {
- fprintf(f, "state %#x ", state);
+ if (is_json_context())
+ print_uint(PRINT_JSON, "operstate_index", NULL, state);
+ else
+ print_0xhex(PRINT_FP, NULL, "state %#x", state);
} else if (brief) {
- color_fprintf(f, oper_state_color(state),
- "%-14s ", oper_states[state]);
+ print_color_string(PRINT_ANY,
+ oper_state_color(state),
+ "operstate",
+ "%-14s ",
+ oper_states[state]);
} else {
- fprintf(f, "state ");
- color_fprintf(f, oper_state_color(state),
- "%s ", oper_states[state]);
+ if (is_json_context())
+ print_string(PRINT_JSON,
+ "operstate",
+ NULL, oper_states[state]);
+ else {
+ fprintf(f, "state ");
+ color_fprintf(f, oper_state_color(state),
+ "%s ", oper_states[state]);
+ }
}
}
@@ -169,7 +183,7 @@ static void print_queuelen(FILE *f, struct rtattr *tb[IFLA_MAX + 1])
qlen = ifr.ifr_qlen;
}
if (qlen)
- fprintf(f, "qlen %d", qlen);
+ print_int(PRINT_ANY, "txqlen", "qlen %d", qlen);
}
static const char *link_modes[] = {
@@ -181,9 +195,15 @@ static void print_linkmode(FILE *f, struct rtattr *tb)
unsigned int mode = rta_getattr_u8(tb);
if (mode >= ARRAY_SIZE(link_modes))
- fprintf(f, "mode %d ", mode);
+ print_int(PRINT_ANY,
+ "linkmode_index",
+ "mode %d ",
+ mode);
else
- fprintf(f, "mode %s ", link_modes[mode]);
+ print_string(PRINT_ANY,
+ "linkmode",
+ "mode %s "
+ , link_modes[mode]);
}
static char *parse_link_kind(struct rtattr *tb, bool slave)
@@ -215,13 +235,14 @@ static void print_linktype(FILE *fp, struct rtattr *tb)
char slave[32];
parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb);
+ open_json_object("linkinfo");
if (linkinfo[IFLA_INFO_KIND]) {
const char *kind
= rta_getattr_str(linkinfo[IFLA_INFO_KIND]);
- fprintf(fp, "%s", _SL_);
- fprintf(fp, " %s ", kind);
+ print_string(PRINT_FP, NULL, "%s", _SL_);
+ print_string(PRINT_ANY, "info_kind", " %s ", kind);
lu = get_link_kind(kind);
if (lu && lu->print_opt) {
@@ -232,11 +253,16 @@ static void print_linktype(FILE *fp, struct rtattr *tb)
linkinfo[IFLA_INFO_DATA]);
data = attr;
}
+ open_json_object("info_data");
lu->print_opt(lu, fp, data);
+ close_json_object();
if (linkinfo[IFLA_INFO_XSTATS] && show_stats &&
- lu->print_xstats)
+ lu->print_xstats) {
+ open_json_object("info_xstats");
lu->print_xstats(lu, fp, linkinfo[IFLA_INFO_XSTATS]);
+ close_json_object();
+ }
}
}
@@ -244,8 +270,12 @@ static void print_linktype(FILE *fp, struct rtattr *tb)
const char *slave_kind
= rta_getattr_str(linkinfo[IFLA_INFO_SLAVE_KIND]);
- fprintf(fp, "%s", _SL_);
- fprintf(fp, " %s_slave ", slave_kind);
+ print_string(PRINT_FP, NULL, "%s", _SL_);
+ print_string(PRINT_ANY,
+ "info_slave_kind",
+ " %s_slave ",
+ slave_kind);
+
snprintf(slave, sizeof(slave), "%s_slave", slave_kind);
slave_lu = get_link_kind(slave);
@@ -257,9 +287,12 @@ static void print_linktype(FILE *fp, struct rtattr *tb)
linkinfo[IFLA_INFO_SLAVE_DATA]);
data = attr;
}
+ open_json_object("info_slave_data");
slave_lu->print_opt(slave_lu, fp, data);
+ close_json_object();
}
}
+ close_json_object();
}
static void print_af_spec(FILE *fp, struct rtattr *af_spec_attr)
@@ -275,22 +308,39 @@ static void print_af_spec(FILE *fp, struct rtattr *af_spec_attr)
if (tb[IFLA_INET6_ADDR_GEN_MODE]) {
__u8 mode = rta_getattr_u8(tb[IFLA_INET6_ADDR_GEN_MODE]);
+ SPRINT_BUF(b1);
switch (mode) {
case IN6_ADDR_GEN_MODE_EUI64:
- fprintf(fp, "addrgenmode eui64 ");
+ print_string(PRINT_ANY,
+ "inet6_addr_gen_mode",
+ "addrgenmode %s ",
+ "eui64");
break;
case IN6_ADDR_GEN_MODE_NONE:
- fprintf(fp, "addrgenmode none ");
+ print_string(PRINT_ANY,
+ "inet6_addr_gen_mode",
+ "addrgenmode %s ",
+ "none");
break;
case IN6_ADDR_GEN_MODE_STABLE_PRIVACY:
- fprintf(fp, "addrgenmode stable_secret ");
+ print_string(PRINT_ANY,
+ "inet6_addr_gen_mode",
+ "addrgenmode %s ",
+ "stable_secret");
break;
case IN6_ADDR_GEN_MODE_RANDOM:
- fprintf(fp, "addrgenmode random ");
+ print_string(PRINT_ANY,
+ "inet6_addr_gen_mode",
+ "addrgenmode %s ",
+ "random");
break;
default:
- fprintf(fp, "addrgenmode %#.2hhx ", mode);
+ snprintf(b1, sizeof(b1), "%#.2hhx", mode);
+ print_string(PRINT_ANY,
+ "inet6_addr_gen_mode",
+ "addrgenmode %s ",
+ b1);
break;
}
}
@@ -316,83 +366,135 @@ static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
vf_mac = RTA_DATA(vf[IFLA_VF_MAC]);
vf_tx_rate = RTA_DATA(vf[IFLA_VF_TX_RATE]);
- fprintf(fp, "%s vf %d MAC %s", _SL_, vf_mac->vf,
- ll_addr_n2a((unsigned char *)&vf_mac->mac,
- ETH_ALEN, 0, b1, sizeof(b1)));
+ print_string(PRINT_FP, NULL, "%s ", _SL_);
+ print_int(PRINT_ANY, "vf", "vf %d ", vf_mac->vf);
+ print_string(PRINT_ANY, "mac", "MAC %s",
+ ll_addr_n2a((unsigned char *) &vf_mac->mac,
+ ETH_ALEN, 0, b1, sizeof(b1)));
+
if (vf[IFLA_VF_VLAN_LIST]) {
struct rtattr *i, *vfvlanlist = vf[IFLA_VF_VLAN_LIST];
int rem = RTA_PAYLOAD(vfvlanlist);
+ open_json_array(PRINT_JSON, "vlan_list");
for (i = RTA_DATA(vfvlanlist);
- RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
- struct ifla_vf_vlan_info *vf_vlan_info =
- RTA_DATA(i);
+ RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+ struct ifla_vf_vlan_info *vf_vlan_info = RTA_DATA(i);
SPRINT_BUF(b2);
+ open_json_object(NULL);
if (vf_vlan_info->vlan)
- fprintf(fp, ", vlan %d", vf_vlan_info->vlan);
+ print_int(PRINT_ANY,
+ "vlan",
+ ", vlan %d",
+ vf_vlan_info->vlan);
if (vf_vlan_info->qos)
- fprintf(fp, ", qos %d", vf_vlan_info->qos);
+ print_int(PRINT_ANY,
+ "qos",
+ ", qos %d",
+ vf_vlan_info->qos);
if (vf_vlan_info->vlan_proto &&
vf_vlan_info->vlan_proto != htons(ETH_P_8021Q))
- fprintf(fp, ", vlan protocol %s",
- ll_proto_n2a(vf_vlan_info->vlan_proto,
+ print_string(PRINT_ANY,
+ "protocol",
+ ", vlan protocol %s",
+ ll_proto_n2a(
+ vf_vlan_info->vlan_proto,
b2, sizeof(b2)));
-
+ close_json_object();
}
+ close_json_array(PRINT_JSON, NULL);
} else {
struct ifla_vf_vlan *vf_vlan = RTA_DATA(vf[IFLA_VF_VLAN]);
if (vf_vlan->vlan)
- fprintf(fp, ", vlan %d", vf_vlan->vlan);
+ print_int(PRINT_ANY,
+ "vlan",
+ ", vlan %d",
+ vf_vlan->vlan);
if (vf_vlan->qos)
- fprintf(fp, ", qos %d", vf_vlan->qos);
+ print_int(PRINT_ANY, "qos", ", qos %d", vf_vlan->qos);
}
+
if (vf_tx_rate->rate)
- fprintf(fp, ", tx rate %d (Mbps)", vf_tx_rate->rate);
+ print_int(PRINT_ANY,
+ "tx_rate",
+ ", tx rate %d (Mbps)",
+ vf_tx_rate->rate);
if (vf[IFLA_VF_RATE]) {
struct ifla_vf_rate *vf_rate = RTA_DATA(vf[IFLA_VF_RATE]);
-
- if (vf_rate->max_tx_rate)
- fprintf(fp, ", max_tx_rate %dMbps", vf_rate->max_tx_rate);
- if (vf_rate->min_tx_rate)
- fprintf(fp, ", min_tx_rate %dMbps", vf_rate->min_tx_rate);
+ int max_tx = vf_rate->max_tx_rate;
+ int min_tx = vf_rate->min_tx_rate;
+
+ if (is_json_context()) {
+ open_json_object("rate");
+ print_int(PRINT_JSON, "max_tx", NULL, max_tx);
+ print_int(PRINT_ANY, "min_tx", NULL, min_tx);
+ close_json_object();
+ } else {
+ if (max_tx)
+ fprintf(fp, ", max_tx_rate %dMbps", max_tx);
+ if (min_tx)
+ fprintf(fp, ", min_tx_rate %dMbps", min_tx);
+ }
}
+
if (vf[IFLA_VF_SPOOFCHK]) {
struct ifla_vf_spoofchk *vf_spoofchk =
RTA_DATA(vf[IFLA_VF_SPOOFCHK]);
if (vf_spoofchk->setting != -1)
- fprintf(fp, ", spoof checking %s",
- vf_spoofchk->setting ? "on" : "off");
+ print_bool(PRINT_ANY,
+ "spoofchk",
+ vf_spoofchk->setting ?
+ ", spoof checking on" : ", spoof checking off",
+ vf_spoofchk->setting);
}
+
if (vf[IFLA_VF_LINK_STATE]) {
struct ifla_vf_link_state *vf_linkstate =
RTA_DATA(vf[IFLA_VF_LINK_STATE]);
if (vf_linkstate->link_state == IFLA_VF_LINK_STATE_AUTO)
- fprintf(fp, ", link-state auto");
+ print_string(PRINT_ANY,
+ "link_state",
+ ", link-state %s",
+ "auto");
else if (vf_linkstate->link_state == IFLA_VF_LINK_STATE_ENABLE)
- fprintf(fp, ", link-state enable");
+ print_string(PRINT_ANY,
+ "link_state",
+ ", link-state %s",
+ "enable");
else
- fprintf(fp, ", link-state disable");
+ print_string(PRINT_ANY,
+ "link_state",
+ ", link-state %s",
+ "disable");
}
+
if (vf[IFLA_VF_TRUST]) {
struct ifla_vf_trust *vf_trust = RTA_DATA(vf[IFLA_VF_TRUST]);
if (vf_trust->setting != -1)
- fprintf(fp, ", trust %s",
- vf_trust->setting ? "on" : "off");
+ print_bool(PRINT_ANY,
+ "trust",
+ vf_trust->setting ? ", trust on" : ", trust off",
+ vf_trust->setting);
}
+
if (vf[IFLA_VF_RSS_QUERY_EN]) {
struct ifla_vf_rss_query_en *rss_query =
RTA_DATA(vf[IFLA_VF_RSS_QUERY_EN]);
if (rss_query->setting != -1)
- fprintf(fp, ", query_rss %s",
- rss_query->setting ? "on" : "off");
+ print_bool(PRINT_ANY,
+ "query_rss_en",
+ rss_query->setting ? ", query_rss on"
+ : ", query_rss off",
+ rss_query->setting);
}
+
if (vf[IFLA_VF_STATS] && show_stats)
print_vf_stats64(fp, vf[IFLA_VF_STATS]);
}
@@ -432,7 +534,7 @@ void print_num(FILE *fp, unsigned int width, uint64_t count)
}
snprintf(buf, sizeof(buf), "%.*f%c%s", precision,
- (double) count / powi, *prefix, use_iec ? "i" : "");
+ (double) count / powi, *prefix, use_iec ? "i" : "");
fprintf(fp, "%-*s ", width, buf);
}
@@ -448,155 +550,339 @@ static void print_vf_stats64(FILE *fp, struct rtattr *vfstats)
parse_rtattr_nested(vf, IFLA_VF_MAX, vfstats);
- /* RX stats */
- fprintf(fp, "%s", _SL_);
- fprintf(fp, " RX: bytes packets mcast bcast %s", _SL_);
- fprintf(fp, " ");
+ if (is_json_context()) {
+ open_json_object("stats");
+
+ /* RX stats */
+ open_json_object("rx");
+ print_uint(PRINT_JSON, "bytes", NULL,
+ rta_getattr_u64(vf[IFLA_VF_STATS_RX_BYTES]));
+ print_uint(PRINT_JSON, "packets", NULL,
+ rta_getattr_u64(vf[IFLA_VF_STATS_RX_PACKETS]));
+ print_uint(PRINT_JSON, "multicast", NULL,
+ rta_getattr_u64(vf[IFLA_VF_STATS_MULTICAST]));
+ print_uint(PRINT_JSON, "broadcast", NULL,
+ rta_getattr_u64(vf[IFLA_VF_STATS_BROADCAST]));
+ close_json_object();
+
+ /* TX stats */
+ open_json_object("tx");
+ print_uint(PRINT_JSON, "tx_bytes", NULL,
+ rta_getattr_u64(vf[IFLA_VF_STATS_TX_BYTES]));
+ print_uint(PRINT_JSON, "tx_packets", NULL,
+ rta_getattr_u64(vf[IFLA_VF_STATS_TX_PACKETS]));
+ close_json_object();
+ close_json_object();
+ } else {
+ /* RX stats */
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " RX: bytes packets mcast bcast %s", _SL_);
+ fprintf(fp, " ");
- print_num(fp, 10, rta_getattr_u64(vf[IFLA_VF_STATS_RX_BYTES]));
- print_num(fp, 8, rta_getattr_u64(vf[IFLA_VF_STATS_RX_PACKETS]));
- print_num(fp, 7, rta_getattr_u64(vf[IFLA_VF_STATS_MULTICAST]));
- print_num(fp, 7, rta_getattr_u64(vf[IFLA_VF_STATS_BROADCAST]));
+ print_num(fp, 10, rta_getattr_u64(vf[IFLA_VF_STATS_RX_BYTES]));
+ print_num(fp, 8, rta_getattr_u64(vf[IFLA_VF_STATS_RX_PACKETS]));
+ print_num(fp, 7, rta_getattr_u64(vf[IFLA_VF_STATS_MULTICAST]));
+ print_num(fp, 7, rta_getattr_u64(vf[IFLA_VF_STATS_BROADCAST]));
- /* TX stats */
- fprintf(fp, "%s", _SL_);
- fprintf(fp, " TX: bytes packets %s", _SL_);
- fprintf(fp, " ");
+ /* TX stats */
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " TX: bytes packets %s", _SL_);
+ fprintf(fp, " ");
- print_num(fp, 10, rta_getattr_u64(vf[IFLA_VF_STATS_TX_BYTES]));
- print_num(fp, 8, rta_getattr_u64(vf[IFLA_VF_STATS_TX_PACKETS]));
+ print_num(fp, 10, rta_getattr_u64(vf[IFLA_VF_STATS_TX_BYTES]));
+ print_num(fp, 8, rta_getattr_u64(vf[IFLA_VF_STATS_TX_PACKETS]));
+ }
}
static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s,
const struct rtattr *carrier_changes)
{
- /* RX stats */
- fprintf(fp, " RX: bytes packets errors dropped overrun mcast %s%s",
- s->rx_compressed ? "compressed" : "", _SL_);
-
- fprintf(fp, " ");
- print_num(fp, 10, s->rx_bytes);
- print_num(fp, 8, s->rx_packets);
- print_num(fp, 7, s->rx_errors);
- print_num(fp, 7, s->rx_dropped);
- print_num(fp, 7, s->rx_over_errors);
- print_num(fp, 7, s->multicast);
- if (s->rx_compressed)
- print_num(fp, 7, s->rx_compressed);
-
- /* RX error stats */
- if (show_stats > 1) {
- fprintf(fp, "%s", _SL_);
- fprintf(fp, " RX errors: length crc frame fifo missed%s%s",
- s->rx_nohandler ? " nohandler" : "", _SL_);
-
- fprintf(fp, " ");
- print_num(fp, 8, s->rx_length_errors);
- print_num(fp, 7, s->rx_crc_errors);
- print_num(fp, 7, s->rx_frame_errors);
- print_num(fp, 7, s->rx_fifo_errors);
- print_num(fp, 7, s->rx_missed_errors);
- if (s->rx_nohandler)
- print_num(fp, 7, s->rx_nohandler);
+ if (is_json_context()) {
+ open_json_object("stats644");
+
+ /* RX stats */
+ open_json_object("rx");
+ print_uint(PRINT_JSON, "bytes", NULL, s->rx_bytes);
+ print_uint(PRINT_JSON, "packets", NULL, s->rx_packets);
+ print_uint(PRINT_JSON, "errors", NULL, s->rx_errors);
+ print_uint(PRINT_JSON, "dropped", NULL, s->rx_dropped);
+ print_uint(PRINT_JSON, "over_errors", NULL, s->rx_over_errors);
+ print_uint(PRINT_JSON, "multicast", NULL, s->multicast);
+ if (s->rx_compressed)
+ print_uint(PRINT_JSON,
+ "compressed",
+ NULL, s->rx_compressed);
+
+ /* RX error stats */
+ if (show_stats > 1) {
+ print_uint(PRINT_JSON,
+ "length_errors",
+ NULL, s->rx_length_errors);
+ print_uint(PRINT_JSON,
+ "crc_errors",
+ NULL, s->rx_crc_errors);
+ print_uint(PRINT_JSON,
+ "frame_errors",
+ NULL, s->rx_frame_errors);
+ print_uint(PRINT_JSON,
+ "fifo_errors",
+ NULL, s->rx_fifo_errors);
+ print_uint(PRINT_JSON,
+ "missed_errors",
+ NULL, s->rx_missed_errors);
+ if (s->rx_nohandler)
+ print_uint(PRINT_JSON,
+ "nohandler", NULL, s->rx_nohandler);
+ }
+ close_json_object();
+
+ /* TX stats */
+ open_json_object("tx");
+ print_uint(PRINT_JSON, "bytes", NULL, s->tx_bytes);
+ print_uint(PRINT_JSON, "packets", NULL, s->tx_packets);
+ print_uint(PRINT_JSON, "errors", NULL, s->tx_errors);
+ print_uint(PRINT_JSON, "dropped", NULL, s->tx_dropped);
+ print_uint(PRINT_JSON,
+ "carrier_errors",
+ NULL, s->tx_carrier_errors);
+ print_uint(PRINT_JSON, "collisions", NULL, s->collisions);
+ if (s->tx_compressed)
+ print_uint(PRINT_JSON,
+ "compressed",
+ NULL, s->tx_compressed);
+
+ /* TX error stats */
+ if (show_stats > 1) {
+ print_uint(PRINT_JSON,
+ "aborted_errors",
+ NULL, s->tx_aborted_errors);
+ print_uint(PRINT_JSON,
+ "fifo_errors",
+ NULL, s->tx_fifo_errors);
+ print_uint(PRINT_JSON,
+ "window_errors",
+ NULL, s->tx_window_errors);
+ print_uint(PRINT_JSON,
+ "heartbeat_errors",
+ NULL, s->tx_heartbeat_errors);
+ if (carrier_changes)
+ print_uint(PRINT_JSON, "carrier_changes", NULL,
+ rta_getattr_u32(carrier_changes));
+ }
+ close_json_object();
+ close_json_object();
- }
- fprintf(fp, "%s", _SL_);
+ } else {
+ /* RX stats */
+ fprintf(fp, " RX: bytes packets errors dropped overrun mcast %s%s",
+ s->rx_compressed ? "compressed" : "", _SL_);
+
+ fprintf(fp, " ");
+ print_num(fp, 10, s->rx_bytes);
+ print_num(fp, 8, s->rx_packets);
+ print_num(fp, 7, s->rx_errors);
+ print_num(fp, 7, s->rx_dropped);
+ print_num(fp, 7, s->rx_over_errors);
+ print_num(fp, 7, s->multicast);
+ if (s->rx_compressed)
+ print_num(fp, 7, s->rx_compressed);
+
+ /* RX error stats */
+ if (show_stats > 1) {
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " RX errors: length crc frame fifo missed%s%s",
+ s->rx_nohandler ? " nohandler" : "", _SL_);
+
+ fprintf(fp, " ");
+ print_num(fp, 8, s->rx_length_errors);
+ print_num(fp, 7, s->rx_crc_errors);
+ print_num(fp, 7, s->rx_frame_errors);
+ print_num(fp, 7, s->rx_fifo_errors);
+ print_num(fp, 7, s->rx_missed_errors);
+ if (s->rx_nohandler)
+ print_num(fp, 7, s->rx_nohandler);
- /* TX stats */
- fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s",
- s->tx_compressed ? "compressed" : "", _SL_);
-
- fprintf(fp, " ");
- print_num(fp, 10, s->tx_bytes);
- print_num(fp, 8, s->tx_packets);
- print_num(fp, 7, s->tx_errors);
- print_num(fp, 7, s->tx_dropped);
- print_num(fp, 7, s->tx_carrier_errors);
- print_num(fp, 7, s->collisions);
- if (s->tx_compressed)
- print_num(fp, 7, s->tx_compressed);
-
- /* TX error stats */
- if (show_stats > 1) {
- fprintf(fp, "%s", _SL_);
- fprintf(fp, " TX errors: aborted fifo window heartbeat");
- if (carrier_changes)
- fprintf(fp, " transns");
+ }
fprintf(fp, "%s", _SL_);
- fprintf(fp, " ");
- print_num(fp, 8, s->tx_aborted_errors);
- print_num(fp, 7, s->tx_fifo_errors);
- print_num(fp, 7, s->tx_window_errors);
- print_num(fp, 7, s->tx_heartbeat_errors);
- if (carrier_changes)
- print_num(fp, 7, rta_getattr_u32(carrier_changes));
+ /* TX stats */
+ fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s",
+ s->tx_compressed ? "compressed" : "", _SL_);
+
+ fprintf(fp, " ");
+ print_num(fp, 10, s->tx_bytes);
+ print_num(fp, 8, s->tx_packets);
+ print_num(fp, 7, s->tx_errors);
+ print_num(fp, 7, s->tx_dropped);
+ print_num(fp, 7, s->tx_carrier_errors);
+ print_num(fp, 7, s->collisions);
+ if (s->tx_compressed)
+ print_num(fp, 7, s->tx_compressed);
+
+ /* TX error stats */
+ if (show_stats > 1) {
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " TX errors: aborted fifo window heartbeat");
+ if (carrier_changes)
+ fprintf(fp, " transns");
+ fprintf(fp, "%s", _SL_);
+
+ fprintf(fp, " ");
+ print_num(fp, 8, s->tx_aborted_errors);
+ print_num(fp, 7, s->tx_fifo_errors);
+ print_num(fp, 7, s->tx_window_errors);
+ print_num(fp, 7, s->tx_heartbeat_errors);
+ if (carrier_changes)
+ print_num(fp, 7,
+ rta_getattr_u32(carrier_changes));
+ }
}
}
static void print_link_stats32(FILE *fp, const struct rtnl_link_stats *s,
const struct rtattr *carrier_changes)
{
- /* RX stats */
- fprintf(fp, " RX: bytes packets errors dropped overrun mcast %s%s",
- s->rx_compressed ? "compressed" : "", _SL_);
-
-
- fprintf(fp, " ");
- print_num(fp, 10, s->rx_bytes);
- print_num(fp, 8, s->rx_packets);
- print_num(fp, 7, s->rx_errors);
- print_num(fp, 7, s->rx_dropped);
- print_num(fp, 7, s->rx_over_errors);
- print_num(fp, 7, s->multicast);
- if (s->rx_compressed)
- print_num(fp, 7, s->rx_compressed);
-
- /* RX error stats */
- if (show_stats > 1) {
- fprintf(fp, "%s", _SL_);
- fprintf(fp, " RX errors: length crc frame fifo missed%s%s",
- s->rx_nohandler ? " nohandler" : "", _SL_);
- fprintf(fp, " ");
- print_num(fp, 8, s->rx_length_errors);
- print_num(fp, 7, s->rx_crc_errors);
- print_num(fp, 7, s->rx_frame_errors);
- print_num(fp, 7, s->rx_fifo_errors);
- print_num(fp, 7, s->rx_missed_errors);
- if (s->rx_nohandler)
- print_num(fp, 7, s->rx_nohandler);
- }
- fprintf(fp, "%s", _SL_);
+ if (is_json_context()) {
+ open_json_object("stats");
+
+ /* RX stats */
+ open_json_object("rx");
+ print_uint(PRINT_JSON, "bytes", NULL, s->rx_bytes);
+ print_uint(PRINT_JSON, "packets", NULL, s->rx_packets);
+ print_uint(PRINT_JSON, "errors", NULL, s->rx_errors);
+ print_uint(PRINT_JSON, "dropped", NULL, s->rx_dropped);
+ print_uint(PRINT_JSON, "over_errors", NULL, s->rx_over_errors);
+ print_uint(PRINT_JSON, "multicast", NULL, s->multicast);
+ if (s->rx_compressed)
+ print_int(PRINT_JSON,
+ "compressed",
+ NULL, s->rx_compressed);
+
+ /* RX error stats */
+ if (show_stats > 1) {
+ print_uint(PRINT_JSON,
+ "length_errors",
+ NULL, s->rx_length_errors);
+ print_uint(PRINT_JSON,
+ "crc_errors",
+ NULL, s->rx_crc_errors);
+ print_uint(PRINT_JSON,
+ "frame_errors",
+ NULL, s->rx_frame_errors);
+ print_uint(PRINT_JSON,
+ "fifo_errors",
+ NULL, s->rx_fifo_errors);
+ print_uint(PRINT_JSON,
+ "missed_errors",
+ NULL, s->rx_missed_errors);
+ if (s->rx_nohandler)
+ print_int(PRINT_JSON,
+ "nohandler",
+ NULL, s->rx_nohandler);
+ }
+ close_json_object();
+
+ /* TX stats */
+ open_json_object("tx");
+ print_uint(PRINT_JSON, "bytes", NULL, s->tx_bytes);
+ print_uint(PRINT_JSON, "packets", NULL, s->tx_packets);
+ print_uint(PRINT_JSON, "errors", NULL, s->tx_errors);
+ print_uint(PRINT_JSON, "dropped", NULL, s->tx_dropped);
+ print_uint(PRINT_JSON,
+ "carrier_errors",
+ NULL, s->tx_carrier_errors);
+ print_uint(PRINT_JSON, "collisions", NULL, s->collisions);
+ if (s->tx_compressed)
+ print_int(PRINT_JSON,
+ "compressed",
+ NULL, s->tx_compressed);
+
+ /* TX error stats */
+ if (show_stats > 1) {
+ print_uint(PRINT_JSON,
+ "aborted_errors",
+ NULL, s->tx_aborted_errors);
+ print_uint(PRINT_JSON,
+ "fifo_errors",
+ NULL, s->tx_fifo_errors);
+ print_uint(PRINT_JSON,
+ "window_errors",
+ NULL, s->tx_window_errors);
+ print_uint(PRINT_JSON,
+ "heartbeat_errors",
+ NULL, s->tx_heartbeat_errors);
+ if (carrier_changes)
+ print_uint(PRINT_JSON,
+ "carrier_changes",
+ NULL,
+ rta_getattr_u32(carrier_changes));
+ }
- /* TX stats */
- fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s",
- s->tx_compressed ? "compressed" : "", _SL_);
-
- fprintf(fp, " ");
- print_num(fp, 10, s->tx_bytes);
- print_num(fp, 8, s->tx_packets);
- print_num(fp, 7, s->tx_errors);
- print_num(fp, 7, s->tx_dropped);
- print_num(fp, 7, s->tx_carrier_errors);
- print_num(fp, 7, s->collisions);
- if (s->tx_compressed)
- print_num(fp, 7, s->tx_compressed);
-
- /* TX error stats */
- if (show_stats > 1) {
- fprintf(fp, "%s", _SL_);
- fprintf(fp, " TX errors: aborted fifo window heartbeat");
- if (carrier_changes)
- fprintf(fp, " transns");
+ close_json_object();
+ close_json_object();
+ } else {
+ /* RX stats */
+ fprintf(fp, " RX: bytes packets errors dropped overrun mcast %s%s",
+ s->rx_compressed ? "compressed" : "", _SL_);
+
+
+ fprintf(fp, " ");
+ print_num(fp, 10, s->rx_bytes);
+ print_num(fp, 8, s->rx_packets);
+ print_num(fp, 7, s->rx_errors);
+ print_num(fp, 7, s->rx_dropped);
+ print_num(fp, 7, s->rx_over_errors);
+ print_num(fp, 7, s->multicast);
+ if (s->rx_compressed)
+ print_num(fp, 7, s->rx_compressed);
+
+ /* RX error stats */
+ if (show_stats > 1) {
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " RX errors: length crc frame fifo missed%s%s",
+ s->rx_nohandler ? " nohandler" : "", _SL_);
+ fprintf(fp, " ");
+ print_num(fp, 8, s->rx_length_errors);
+ print_num(fp, 7, s->rx_crc_errors);
+ print_num(fp, 7, s->rx_frame_errors);
+ print_num(fp, 7, s->rx_fifo_errors);
+ print_num(fp, 7, s->rx_missed_errors);
+ if (s->rx_nohandler)
+ print_num(fp, 7, s->rx_nohandler);
+ }
fprintf(fp, "%s", _SL_);
- fprintf(fp, " ");
- print_num(fp, 8, s->tx_aborted_errors);
- print_num(fp, 7, s->tx_fifo_errors);
- print_num(fp, 7, s->tx_window_errors);
- print_num(fp, 7, s->tx_heartbeat_errors);
- if (carrier_changes)
- print_num(fp, 7, rta_getattr_u32(carrier_changes));
+ /* TX stats */
+ fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s",
+ s->tx_compressed ? "compressed" : "", _SL_);
+
+ fprintf(fp, " ");
+ print_num(fp, 10, s->tx_bytes);
+ print_num(fp, 8, s->tx_packets);
+ print_num(fp, 7, s->tx_errors);
+ print_num(fp, 7, s->tx_dropped);
+ print_num(fp, 7, s->tx_carrier_errors);
+ print_num(fp, 7, s->collisions);
+ if (s->tx_compressed)
+ print_num(fp, 7, s->tx_compressed);
+
+ /* TX error stats */
+ if (show_stats > 1) {
+ fprintf(fp, "%s", _SL_);
+ fprintf(fp, " TX errors: aborted fifo window heartbeat");
+ if (carrier_changes)
+ fprintf(fp, " transns");
+ fprintf(fp, "%s", _SL_);
+
+ fprintf(fp, " ");
+ print_num(fp, 8, s->tx_aborted_errors);
+ print_num(fp, 7, s->tx_fifo_errors);
+ print_num(fp, 7, s->tx_window_errors);
+ print_num(fp, 7, s->tx_heartbeat_errors);
+ if (carrier_changes)
+ print_num(fp, 7,
+ rta_getattr_u32(carrier_changes));
+ }
}
}
@@ -694,44 +980,50 @@ int print_linkinfo_brief(const struct sockaddr_nl *who,
return -1;
if (n->nlmsg_type == RTM_DELLINK)
- fprintf(fp, "Deleted ");
+ print_bool(PRINT_ANY, "deleted", "Deleted ", true);
if (tb[IFLA_LINK]) {
SPRINT_BUF(b1);
int iflink = rta_getattr_u32(tb[IFLA_LINK]);
- if (iflink == 0)
+ if (iflink == 0) {
snprintf(buf, sizeof(buf), "%s@NONE", name);
- else {
- snprintf(buf, sizeof(buf),
- "%s@%s", name, ll_idx_n2a(iflink, b1));
+ print_null(PRINT_JSON, "link", NULL, NULL);
+ } else {
+ const char *link = ll_idx_n2a(iflink, b1);
+
+ print_string(PRINT_JSON, "link", NULL, link);
+ snprintf(buf, sizeof(buf), "%s@%s", name, link);
m_flag = ll_index_to_flags(iflink);
m_flag = !(m_flag & IFF_UP);
}
} else
snprintf(buf, sizeof(buf), "%s", name);
- fprintf(fp, "%-16s ", buf);
+ print_string(PRINT_FP, NULL, "%-16s ", buf);
+ print_string(PRINT_JSON, "ifname", NULL, name);
if (tb[IFLA_OPERSTATE])
print_operstate(fp, rta_getattr_u8(tb[IFLA_OPERSTATE]));
if (pfilter->family == AF_PACKET) {
SPRINT_BUF(b1);
+
if (tb[IFLA_ADDRESS]) {
- color_fprintf(fp, COLOR_MAC, "%s ",
- ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]),
- RTA_PAYLOAD(tb[IFLA_ADDRESS]),
- ifi->ifi_type,
- b1, sizeof(b1)));
+ print_color_string(PRINT_ANY, COLOR_MAC,
+ "address", "%s ",
+ ll_addr_n2a(
+ RTA_DATA(tb[IFLA_ADDRESS]),
+ RTA_PAYLOAD(tb[IFLA_ADDRESS]),
+ ifi->ifi_type,
+ b1, sizeof(b1)));
}
}
- if (pfilter->family == AF_PACKET)
+ if (pfilter->family == AF_PACKET) {
print_link_flags(fp, ifi->ifi_flags, m_flag);
-
- if (pfilter->family == AF_PACKET)
- fprintf(fp, "\n");
+ print_string(PRINT_FP, NULL, "%s", "\n");
+ }
fflush(fp);
return 0;
}
@@ -749,10 +1041,12 @@ static const char *link_events[] = {
static void print_link_event(FILE *f, __u32 event)
{
if (event >= ARRAY_SIZE(link_events))
- fprintf(f, "event %d ", event);
+ print_int(PRINT_ANY, "event", "event %d ", event);
else {
if (event)
- fprintf(f, "event %s ", link_events[event]);
+ print_string(PRINT_ANY,
+ "event", "event %s ",
+ link_events[event]);
}
}
@@ -808,41 +1102,63 @@ int print_linkinfo(const struct sockaddr_nl *who,
return -1;
if (n->nlmsg_type == RTM_DELLINK)
- fprintf(fp, "Deleted ");
-
- fprintf(fp, "%d: ", ifi->ifi_index);
- color_fprintf(fp, COLOR_IFNAME, "%s",
- tb[IFLA_IFNAME] ? rta_getattr_str(tb[IFLA_IFNAME]) : "<nil>");
+ print_bool(PRINT_ANY, "deleted", "Deleted ", true);
+
+ print_int(PRINT_ANY, "ifindex", "%d: ", ifi->ifi_index);
+ if (tb[IFLA_IFNAME]) {
+ print_color_string(PRINT_ANY,
+ COLOR_IFNAME,
+ "ifname", "%s",
+ rta_getattr_str(tb[IFLA_IFNAME]));
+ } else {
+ print_null(PRINT_JSON, "ifname", NULL, NULL);
+ print_color_null(PRINT_FP, COLOR_IFNAME,
+ "ifname", "%s", "<nil>");
+ }
if (tb[IFLA_LINK]) {
- SPRINT_BUF(b1);
int iflink = rta_getattr_u32(tb[IFLA_LINK]);
if (iflink == 0)
- fprintf(fp, "@NONE: ");
+ print_null(PRINT_ANY, "link", "@%s: ", "NONE");
else {
if (tb[IFLA_LINK_NETNSID])
- fprintf(fp, "@if%d: ", iflink);
+ print_int(PRINT_ANY,
+ "link_index", "@if%d: ", iflink);
else {
- fprintf(fp, "@%s: ", ll_idx_n2a(iflink, b1));
+ SPRINT_BUF(b1);
+
+ print_string(PRINT_ANY,
+ "link",
+ "@%s: ",
+ ll_idx_n2a(iflink, b1));
m_flag = ll_index_to_flags(iflink);
m_flag = !(m_flag & IFF_UP);
}
}
} else {
- fprintf(fp, ": ");
+ print_string(PRINT_FP, NULL, ": ", NULL);
}
print_link_flags(fp, ifi->ifi_flags, m_flag);
if (tb[IFLA_MTU])
- fprintf(fp, "mtu %u ", rta_getattr_u32(tb[IFLA_MTU]));
+ print_int(PRINT_ANY,
+ "mtu", "mtu %u ",
+ rta_getattr_u32(tb[IFLA_MTU]));
if (tb[IFLA_XDP])
xdp_dump(fp, tb[IFLA_XDP]);
if (tb[IFLA_QDISC])
- fprintf(fp, "qdisc %s ", rta_getattr_str(tb[IFLA_QDISC]));
+ print_string(PRINT_ANY,
+ "qdisc",
+ "qdisc %s ",
+ rta_getattr_str(tb[IFLA_QDISC]));
if (tb[IFLA_MASTER]) {
SPRINT_BUF(b1);
- fprintf(fp, "master %s ", ll_idx_n2a(rta_getattr_u32(tb[IFLA_MASTER]), b1));
+
+ print_string(PRINT_ANY,
+ "master",
+ "master %s ",
+ ll_idx_n2a(rta_getattr_u32(tb[IFLA_MASTER]), b1));
}
if (tb[IFLA_OPERSTATE])
@@ -855,7 +1171,10 @@ int print_linkinfo(const struct sockaddr_nl *who,
SPRINT_BUF(b1);
int group = rta_getattr_u32(tb[IFLA_GROUP]);
- fprintf(fp, "group %s ", rtnl_group_n2a(group, b1, sizeof(b1)));
+ print_string(PRINT_ANY,
+ "group",
+ "group %s ",
+ rtnl_group_n2a(group, b1, sizeof(b1)));
}
if (filter.showqueue)
@@ -866,47 +1185,68 @@ int print_linkinfo(const struct sockaddr_nl *who,
if (!filter.family || filter.family == AF_PACKET || show_details) {
SPRINT_BUF(b1);
- fprintf(fp, "%s", _SL_);
- fprintf(fp, " link/%s ", ll_type_n2a(ifi->ifi_type, b1, sizeof(b1)));
+ print_string(PRINT_FP, NULL, "%s", _SL_);
+ print_string(PRINT_ANY,
+ "link_type",
+ " link/%s ",
+ ll_type_n2a(ifi->ifi_type, b1, sizeof(b1)));
if (tb[IFLA_ADDRESS]) {
- color_fprintf(fp, COLOR_MAC, "%s",
- ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]),
- RTA_PAYLOAD(tb[IFLA_ADDRESS]),
- ifi->ifi_type,
- b1, sizeof(b1)));
+ print_color_string(PRINT_ANY,
+ COLOR_MAC,
+ "address",
+ "%s",
+ ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]),
+ RTA_PAYLOAD(tb[IFLA_ADDRESS]),
+ ifi->ifi_type,
+ b1, sizeof(b1)));
}
if (tb[IFLA_BROADCAST]) {
- if (ifi->ifi_flags&IFF_POINTOPOINT)
- fprintf(fp, " peer ");
- else
- fprintf(fp, " brd ");
- color_fprintf(fp, COLOR_MAC, "%s",
- ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]),
- RTA_PAYLOAD(tb[IFLA_BROADCAST]),
- ifi->ifi_type,
- b1, sizeof(b1)));
+ if (ifi->ifi_flags&IFF_POINTOPOINT) {
+ print_string(PRINT_FP, NULL, " peer ", NULL);
+ print_bool(PRINT_JSON,
+ "link_pointtopoint", NULL, true);
+ } else {
+ print_string(PRINT_FP, NULL, " brd ", NULL);
+ }
+ print_color_string(PRINT_ANY,
+ COLOR_MAC,
+ "broadcast",
+ "%s",
+ ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]),
+ RTA_PAYLOAD(tb[IFLA_BROADCAST]),
+ ifi->ifi_type,
+ b1, sizeof(b1)));
}
}
if (tb[IFLA_LINK_NETNSID]) {
int id = rta_getattr_u32(tb[IFLA_LINK_NETNSID]);
- if (id >= 0)
- fprintf(fp, " link-netnsid %d", id);
- else
- fprintf(fp, " link-netnsid unknown");
+ if (is_json_context()) {
+ print_int(PRINT_JSON, "link_netnsid", NULL, id);
+ } else {
+ if (id >= 0)
+ print_int(PRINT_FP, NULL,
+ " link-netnsid %d", id);
+ else
+ print_string(PRINT_FP, NULL,
+ " link-netnsid %s", "unknown");
+ }
}
if (tb[IFLA_PROTO_DOWN]) {
if (rta_getattr_u8(tb[IFLA_PROTO_DOWN]))
- fprintf(fp, " protodown on ");
+ print_bool(PRINT_ANY,
+ "proto_down", " protodown on ", true);
}
if (show_details) {
if (tb[IFLA_PROMISCUITY])
- fprintf(fp, " promiscuity %u ",
- rta_getattr_u32(tb[IFLA_PROMISCUITY]));
+ print_uint(PRINT_ANY,
+ "promiscuity",
+ " promiscuity %u ",
+ rta_getattr_u32(tb[IFLA_PROMISCUITY]));
if (tb[IFLA_LINKINFO])
print_linktype(fp, tb[IFLA_LINKINFO]);
@@ -915,50 +1255,68 @@ int print_linkinfo(const struct sockaddr_nl *who,
print_af_spec(fp, tb[IFLA_AF_SPEC]);
if (tb[IFLA_NUM_TX_QUEUES])
- fprintf(fp, "numtxqueues %u ",
- rta_getattr_u32(tb[IFLA_NUM_TX_QUEUES]));
+ print_uint(PRINT_ANY,
+ "num_tx_queues",
+ "numtxqueues %u ",
+ rta_getattr_u32(tb[IFLA_NUM_TX_QUEUES]));
if (tb[IFLA_NUM_RX_QUEUES])
- fprintf(fp, "numrxqueues %u ",
- rta_getattr_u32(tb[IFLA_NUM_RX_QUEUES]));
+ print_uint(PRINT_ANY,
+ "num_rx_queues",
+ "numrxqueues %u ",
+ rta_getattr_u32(tb[IFLA_NUM_RX_QUEUES]));
if (tb[IFLA_GSO_MAX_SIZE])
- fprintf(fp, "gso_max_size %u ",
- rta_getattr_u32(tb[IFLA_GSO_MAX_SIZE]));
+ print_uint(PRINT_ANY,
+ "gso_max_size",
+ "gso_max_size %u ",
+ rta_getattr_u32(tb[IFLA_GSO_MAX_SIZE]));
if (tb[IFLA_GSO_MAX_SEGS])
- fprintf(fp, "gso_max_segs %u ",
- rta_getattr_u32(tb[IFLA_GSO_MAX_SEGS]));
+ print_uint(PRINT_ANY,
+ "gso_max_segs",
+ "gso_max_segs %u ",
+ rta_getattr_u32(tb[IFLA_GSO_MAX_SEGS]));
if (tb[IFLA_PHYS_PORT_NAME])
- fprintf(fp, "portname %s ",
- rta_getattr_str(tb[IFLA_PHYS_PORT_NAME]));
+ print_string(PRINT_ANY,
+ "phys_port_name",
+ "portname %s ",
+ rta_getattr_str(tb[IFLA_PHYS_PORT_NAME]));
if (tb[IFLA_PHYS_PORT_ID]) {
SPRINT_BUF(b1);
- fprintf(fp, "portid %s ",
- hexstring_n2a(RTA_DATA(tb[IFLA_PHYS_PORT_ID]),
- RTA_PAYLOAD(tb[IFLA_PHYS_PORT_ID]),
- b1, sizeof(b1)));
+ print_string(PRINT_ANY,
+ "phys_port_id",
+ "portid %s ",
+ hexstring_n2a(
+ RTA_DATA(tb[IFLA_PHYS_PORT_ID]),
+ RTA_PAYLOAD(tb[IFLA_PHYS_PORT_ID]),
+ b1, sizeof(b1)));
}
if (tb[IFLA_PHYS_SWITCH_ID]) {
SPRINT_BUF(b1);
- fprintf(fp, "switchid %s ",
- hexstring_n2a(RTA_DATA(tb[IFLA_PHYS_SWITCH_ID]),
- RTA_PAYLOAD(tb[IFLA_PHYS_SWITCH_ID]),
- b1, sizeof(b1)));
+ print_string(PRINT_ANY,
+ "phys_switch_id",
+ "switchid %s ",
+ hexstring_n2a(RTA_DATA(tb[IFLA_PHYS_SWITCH_ID]),
+ RTA_PAYLOAD(tb[IFLA_PHYS_SWITCH_ID]),
+ b1, sizeof(b1)));
}
}
if ((do_link || show_details) && tb[IFLA_IFALIAS]) {
- fprintf(fp, "%s alias %s", _SL_,
- rta_getattr_str(tb[IFLA_IFALIAS]));
+ print_string(PRINT_FP, NULL, "%s ", _SL_);
+ print_string(PRINT_ANY,
+ "ifalias",
+ "alias %s",
+ rta_getattr_str(tb[IFLA_IFALIAS]));
}
if (do_link && show_stats) {
- fprintf(fp, "%s", _SL_);
+ print_string(PRINT_FP, NULL, "%s", _SL_);
__print_link_stats(fp, tb);
}
@@ -966,11 +1324,16 @@ int print_linkinfo(const struct sockaddr_nl *who,
struct rtattr *i, *vflist = tb[IFLA_VFINFO_LIST];
int rem = RTA_PAYLOAD(vflist);
- for (i = RTA_DATA(vflist); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
+ open_json_array(PRINT_JSON, "vfinfo_list");
+ for (i = RTA_DATA(vflist); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+ open_json_object(NULL);
print_vfinfo(fp, i);
+ close_json_object();
+ }
+ close_json_array(PRINT_JSON, NULL);
}
- fprintf(fp, "\n");
+ print_string(PRINT_FP, NULL, "\n", NULL);
fflush(fp);
return 1;
}
@@ -1009,7 +1372,7 @@ static unsigned int get_ifa_flags(struct ifaddrmsg *ifa,
struct rtattr *ifa_flags_attr)
{
return ifa_flags_attr ? rta_getattr_u32(ifa_flags_attr) :
- ifa->ifa_flags;
+ ifa->ifa_flags;
}
/* Mapping from argument to address flag mask */
@@ -1042,20 +1405,34 @@ static void print_ifa_flags(FILE *fp, const struct ifaddrmsg *ifa,
if (mask == IFA_F_PERMANENT) {
if (!(flags & mask))
- fprintf(fp, "dynamic ");
+ print_bool(PRINT_ANY,
+ "dynamic", "dynamic ", true);
} else if (flags & mask) {
if (mask == IFA_F_SECONDARY &&
- ifa->ifa_family == AF_INET6)
- fprintf(fp, "temporary ");
- else
- fprintf(fp, "%s ", ifa_flag_names[i].name);
+ ifa->ifa_family == AF_INET6) {
+ print_bool(PRINT_ANY,
+ "temporary", "temporary ", true);
+ } else {
+ print_string(PRINT_FP, NULL,
+ "%s ", ifa_flag_names[i].name);
+ print_bool(PRINT_JSON,
+ ifa_flag_names[i].name, NULL, true);
+ }
}
flags &= ~mask;
}
- if (flags)
- fprintf(fp, "flags %02x ", flags);
+ if (flags) {
+ if (is_json_context()) {
+ SPRINT_BUF(b1);
+
+ snprintf(b1, sizeof(b1), "%02x", flags);
+ print_string(PRINT_JSON, "ifa_flags", NULL, b1);
+ } else {
+ fprintf(fp, "flags %02x ", flags);
+ }
+ }
}
@@ -1176,80 +1553,130 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
}
if (n->nlmsg_type == RTM_DELADDR)
- fprintf(fp, "Deleted ");
+ print_bool(PRINT_ANY, "deleted", "Deleted ", true);
if (!brief) {
- if (filter.oneline || filter.flushb)
- fprintf(fp, "%u: %s", ifa->ifa_index, ll_index_to_name(ifa->ifa_index));
+ if (filter.oneline || filter.flushb) {
+ const char *dev = ll_index_to_name(ifa->ifa_index);
+
+ if (is_json_context()) {
+ print_int(PRINT_JSON,
+ "index", NULL, ifa->ifa_index);
+ print_string(PRINT_JSON, "dev", NULL, dev);
+ } else {
+ fprintf(fp, "%u: %s", ifa->ifa_index, dev);
+ }
+ }
+
+ int family = ifa->ifa_family;
+
if (ifa->ifa_family == AF_INET)
- fprintf(fp, " inet ");
+ print_string(PRINT_ANY, "family", " %s ", "inet");
else if (ifa->ifa_family == AF_INET6)
- fprintf(fp, " inet6 ");
+ print_string(PRINT_ANY, "family", " %s ", "inet6");
else if (ifa->ifa_family == AF_DECnet)
- fprintf(fp, " dnet ");
+ print_string(PRINT_ANY, "family", " %s ", "dnet");
else if (ifa->ifa_family == AF_IPX)
- fprintf(fp, " ipx ");
+ print_string(PRINT_ANY, "family", " %s ", "ipx");
else
- fprintf(fp, " family %d ", ifa->ifa_family);
+ print_int(PRINT_ANY,
+ "family_index",
+ " family %d ", family);
}
if (rta_tb[IFA_LOCAL]) {
- color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s",
- format_host_rta(ifa->ifa_family,
- rta_tb[IFA_LOCAL]));
+ print_color_string(PRINT_ANY,
+ ifa_family_color(ifa->ifa_family),
+ "local", "%s",
+ format_host_rta(ifa->ifa_family,
+ rta_tb[IFA_LOCAL]));
if (rta_tb[IFA_ADDRESS] &&
memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]),
RTA_DATA(rta_tb[IFA_LOCAL]),
ifa->ifa_family == AF_INET ? 4 : 16)) {
- fprintf(fp, " peer ");
- color_fprintf(fp, ifa_family_color(ifa->ifa_family),
- "%s", format_host_rta(ifa->ifa_family,
- rta_tb[IFA_ADDRESS]));
+ print_string(PRINT_FP, NULL, " %s ", "peer");
+ print_color_string(PRINT_ANY,
+ ifa_family_color(ifa->ifa_family),
+ "address",
+ "%s",
+ format_host_rta(ifa->ifa_family,
+ rta_tb[IFA_ADDRESS]));
}
- fprintf(fp, "/%d ", ifa->ifa_prefixlen);
+ print_int(PRINT_ANY, "prefixlen", "/%d", ifa->ifa_prefixlen);
}
if (brief)
goto brief_exit;
if (rta_tb[IFA_BROADCAST]) {
- fprintf(fp, "brd ");
- color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s ",
- format_host_rta(ifa->ifa_family,
- rta_tb[IFA_BROADCAST]));
+ print_string(PRINT_FP, NULL, "%s ", "brd");
+ print_color_string(PRINT_ANY,
+ ifa_family_color(ifa->ifa_family),
+ "broadcast",
+ "%s ",
+ format_host_rta(ifa->ifa_family,
+ rta_tb[IFA_BROADCAST]));
}
+
if (rta_tb[IFA_ANYCAST]) {
- fprintf(fp, "any ");
- color_fprintf(fp, ifa_family_color(ifa->ifa_family), "%s ",
- format_host_rta(ifa->ifa_family,
- rta_tb[IFA_ANYCAST]));
+ print_string(PRINT_FP, NULL, "%s ", "any");
+ print_color_string(PRINT_ANY,
+ ifa_family_color(ifa->ifa_family),
+ "anycast",
+ "%s ",
+ format_host_rta(ifa->ifa_family,
+ rta_tb[IFA_ANYCAST]));
}
- fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1)));
+
+ print_string(PRINT_ANY,
+ "scope",
+ "scope %s ",
+ rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1)));
print_ifa_flags(fp, ifa, ifa_flags);
if (rta_tb[IFA_LABEL])
- fprintf(fp, "%s", rta_getattr_str(rta_tb[IFA_LABEL]));
+ print_string(PRINT_ANY,
+ "label",
+ "%s",
+ rta_getattr_str(rta_tb[IFA_LABEL]));
+
if (rta_tb[IFA_CACHEINFO]) {
struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]);
- fprintf(fp, "%s", _SL_);
- fprintf(fp, " valid_lft ");
- if (ci->ifa_valid == INFINITY_LIFE_TIME)
- fprintf(fp, "forever");
- else
- fprintf(fp, "%usec", ci->ifa_valid);
- fprintf(fp, " preferred_lft ");
- if (ci->ifa_prefered == INFINITY_LIFE_TIME)
- fprintf(fp, "forever");
- else {
+ print_string(PRINT_FP, NULL, "%s", _SL_);
+ print_string(PRINT_FP, NULL, " valid_lft ", NULL);
+
+ if (ci->ifa_valid == INFINITY_LIFE_TIME) {
+ print_uint(PRINT_JSON,
+ "valid_life_time",
+ NULL, INFINITY_LIFE_TIME);
+ print_string(PRINT_FP, NULL, "%s", "forever");
+ } else {
+ print_uint(PRINT_ANY,
+ "valid_life_time", "%usec", ci->ifa_valid);
+ }
+
+ print_string(PRINT_FP, NULL, " preferred_lft ", NULL);
+ if (ci->ifa_prefered == INFINITY_LIFE_TIME) {
+ print_uint(PRINT_JSON,
+ "preferred_life_time",
+ NULL, INFINITY_LIFE_TIME);
+ print_string(PRINT_FP, NULL, "%s", "forever");
+ } else {
if (ifa_flags & IFA_F_DEPRECATED)
- fprintf(fp, "%dsec", ci->ifa_prefered);
+ print_int(PRINT_ANY,
+ "preferred_life_time",
+ "%dsec",
+ ci->ifa_prefered);
else
- fprintf(fp, "%usec", ci->ifa_prefered);
+ print_uint(PRINT_ANY,
+ "preferred_life_time",
+ "%usec",
+ ci->ifa_prefered);
}
}
- fprintf(fp, "\n");
+ print_string(PRINT_FP, NULL, "%s", "\n");
brief_exit:
fflush(fp);
return 0;
@@ -1258,6 +1685,7 @@ brief_exit:
static int print_selected_addrinfo(struct ifinfomsg *ifi,
struct nlmsg_list *ainfo, FILE *fp)
{
+ open_json_array(PRINT_JSON, "addr_info");
for ( ; ainfo ; ainfo = ainfo->next) {
struct nlmsghdr *n = &ainfo->h;
struct ifaddrmsg *ifa = NLMSG_DATA(n);
@@ -1275,10 +1703,14 @@ static int print_selected_addrinfo(struct ifinfomsg *ifi,
if (filter.up && !(ifi->ifi_flags&IFF_UP))
continue;
+ open_json_object(NULL);
print_addrinfo(NULL, n, fp);
+ close_json_object();
}
+ close_json_array(PRINT_JSON, NULL);
+
if (brief) {
- fprintf(fp, "\n");
+ print_string(PRINT_FP, NULL, "%s", "\n");
fflush(fp);
}
return 0;
@@ -1724,6 +2156,12 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
exit(0);
}
+ /*
+ * Initialize a json_writer and open an array object
+ * if -json was specified.
+ */
+ new_json_obj(json, stdout);
+
/*
* If only filter_dev present and none of the other
* link filters are present, use RTM_GETLINK to get
@@ -1732,8 +2170,10 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
if (filter_dev && filter.group == -1 && do_link == 1) {
if (iplink_get(0, filter_dev, RTEXT_FILTER_VF) < 0) {
perror("Cannot send link get request");
+ delete_json_obj();
exit(1);
}
+ delete_json_obj();
exit(0);
}
@@ -1755,6 +2195,7 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
int res = 0;
struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
+ open_json_object(NULL);
if (brief) {
if (print_linkinfo_brief(NULL, &l->h,
stdout, NULL) == 0)
@@ -1763,13 +2204,14 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
ainfo->head,
stdout);
} else if (no_link ||
- (res = print_linkinfo(NULL, &l->h, stdout)) >= 0) {
+ (res = print_linkinfo(NULL, &l->h, stdout)) >= 0) {
if (filter.family != AF_PACKET)
print_selected_addrinfo(ifi,
ainfo->head, stdout);
if (res > 0 && !do_link && show_stats)
print_link_stats(stdout, &l->h);
}
+ close_json_object();
}
fflush(stdout);
@@ -1777,7 +2219,7 @@ out:
if (ainfo)
free_nlmsg_chain(ainfo);
free_nlmsg_chain(&linfo);
-
+ delete_json_obj();
return 0;
}
--
2.14.1
^ permalink raw reply related
* [PATCH iproute2 json v2 04/27] ip: ip_print: add new API to print JSON or regular format output
From: Julien Fortin @ 2017-08-17 17:35 UTC (permalink / raw)
To: netdev; +Cc: roopa, nikolay, dsa, Julien Fortin
In-Reply-To: <20170817173614.54987-1-julien@cumulusnetworks.com>
From: Julien Fortin <julien@cumulusnetworks.com>
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 <julien@cumulusnetworks.com>
---
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, <julien@cumulusnetworks.com>
+ *
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "utils.h"
+#include "ip_common.h"
+#include "json_writer.h"
+
+static json_writer_t *_jw;
+static FILE *_fp;
+
+#define _IS_JSON_CONTEXT(type) ((type & PRINT_JSON || type & PRINT_ANY) && _jw)
+#define _IS_FP_CONTEXT(type) (!_jw && (type & PRINT_FP || type & PRINT_ANY))
+
+void new_json_obj(int json, FILE *fp)
+{
+ if (json) {
+ _jw = jsonw_new(fp);
+ if (!_jw) {
+ perror("json object");
+ exit(1);
+ }
+ jsonw_pretty(_jw, true);
+ jsonw_start_array(_jw);
+ }
+ set_current_fp(fp);
+}
+
+void delete_json_obj(void)
+{
+ if (_jw) {
+ jsonw_end_array(_jw);
+ jsonw_destroy(&_jw);
+ }
+}
+
+bool is_json_context(void)
+{
+ return _jw != NULL;
+}
+
+void set_current_fp(FILE *fp)
+{
+ if (!fp) {
+ fprintf(stderr, "Error: invalid file pointer.\n");
+ exit(1);
+ }
+ _fp = fp;
+}
+
+json_writer_t *get_json_writer(void)
+{
+ return _jw;
+}
+
+void open_json_object(const char *str)
+{
+ if (_IS_JSON_CONTEXT(PRINT_JSON)) {
+ if (str)
+ jsonw_name(_jw, str);
+ jsonw_start_object(_jw);
+ }
+}
+
+void close_json_object(void)
+{
+ if (_IS_JSON_CONTEXT(PRINT_JSON))
+ jsonw_end_object(_jw);
+}
+
+/*
+ * Start json array or string array using
+ * the provided string as json key (if not null)
+ * or as array delimiter in non-json context.
+ */
+void open_json_array(enum output_type type, const char *str)
+{
+ if (_IS_JSON_CONTEXT(type)) {
+ if (str)
+ jsonw_name(_jw, str);
+ jsonw_start_array(_jw);
+ } else if (_IS_FP_CONTEXT(type)) {
+ fprintf(_fp, "%s", str);
+ }
+}
+
+/*
+ * End json array or string array
+ */
+void close_json_array(enum output_type type, const char *str)
+{
+ if (_IS_JSON_CONTEXT(type)) {
+ jsonw_pretty(_jw, false);
+ jsonw_end_array(_jw);
+ jsonw_pretty(_jw, true);
+ } else if (_IS_FP_CONTEXT(type)) {
+ fprintf(_fp, "%s", str);
+ }
+}
+
+/*
+ * pre-processor directive to generate similar
+ * functions handling different types
+ */
+#define _PRINT_FUNC(type_name, type) \
+ void print_color_##type_name(enum output_type t, \
+ enum color_attr color, \
+ const char *key, \
+ const char *fmt, \
+ type value) \
+ { \
+ if (_IS_JSON_CONTEXT(t)) { \
+ if (!key) \
+ jsonw_##type_name(_jw, value); \
+ else \
+ jsonw_##type_name##_field(_jw, key, value); \
+ } else if (_IS_FP_CONTEXT(t)) { \
+ color_fprintf(_fp, color, fmt, value); \
+ } \
+ }
+_PRINT_FUNC(int, int);
+_PRINT_FUNC(hu, unsigned short);
+_PRINT_FUNC(uint, uint64_t);
+_PRINT_FUNC(lluint, unsigned long long int);
+#undef _PRINT_FUNC
+
+void print_color_string(enum output_type type,
+ enum color_attr color,
+ const char *key,
+ const char *fmt,
+ const char *value)
+{
+ if (_IS_JSON_CONTEXT(type)) {
+ if (key && !value)
+ jsonw_name(_jw, key);
+ else if (!key && value)
+ jsonw_string(_jw, value);
+ else
+ jsonw_string_field(_jw, key, value);
+ } else if (_IS_FP_CONTEXT(type)) {
+ color_fprintf(_fp, color, fmt, value);
+ }
+}
+
+/*
+ * value's type is bool. When using this function in FP context you can't pass
+ * a value to it, you will need to use "is_json_context()" to have different
+ * branch for json and regular output. grep -r "print_bool" for example
+ */
+void print_color_bool(enum output_type type,
+ enum color_attr color,
+ const char *key,
+ const char *fmt,
+ bool value)
+{
+ if (_IS_JSON_CONTEXT(type)) {
+ if (key)
+ jsonw_bool_field(_jw, key, value);
+ else
+ jsonw_bool(_jw, value);
+ } else if (_IS_FP_CONTEXT(type)) {
+ color_fprintf(_fp, color, fmt, value ? "true" : "false");
+ }
+}
+
+/*
+ * In JSON context uses hardcode %#x format: 42 -> 0x2a
+ */
+void print_color_0xhex(enum output_type type,
+ enum color_attr color,
+ const char *key,
+ const char *fmt,
+ unsigned int hex)
+{
+ if (_IS_JSON_CONTEXT(type)) {
+ SPRINT_BUF(b1);
+
+ snprintf(b1, sizeof(b1), "%#x", hex);
+ print_string(PRINT_JSON, key, NULL, b1);
+ } else if (_IS_FP_CONTEXT(type)) {
+ color_fprintf(_fp, color, fmt, hex);
+ }
+}
+
+void print_color_hex(enum output_type type,
+ enum color_attr color,
+ const char *key,
+ const char *fmt,
+ unsigned int hex)
+{
+ if (_IS_JSON_CONTEXT(type)) {
+ SPRINT_BUF(b1);
+
+ snprintf(b1, sizeof(b1), "%x", hex);
+ if (key)
+ jsonw_string_field(_jw, key, b1);
+ else
+ jsonw_string(_jw, b1);
+ } else if (_IS_FP_CONTEXT(type)) {
+ color_fprintf(_fp, color, fmt, hex);
+ }
+}
+
+/*
+ * In JSON context we don't use the argument "value" we simply call jsonw_null
+ * whereas FP context can use "value" to output anything
+ */
+void print_color_null(enum output_type type,
+ enum color_attr color,
+ const char *key,
+ const char *fmt,
+ const char *value)
+{
+ if (_IS_JSON_CONTEXT(type)) {
+ if (key)
+ jsonw_null_field(_jw, key);
+ else
+ jsonw_null(_jw);
+ } else if (_IS_FP_CONTEXT(type)) {
+ color_fprintf(_fp, color, fmt, value);
+ }
+}
--
2.14.1
^ permalink raw reply related
* [PATCH iproute2 json v2 03/27] json_writer: add new json handlers (null, float with format, lluint, hu)
From: Julien Fortin @ 2017-08-17 17:35 UTC (permalink / raw)
To: netdev; +Cc: roopa, nikolay, dsa, Julien Fortin
In-Reply-To: <20170817173614.54987-1-julien@cumulusnetworks.com>
From: Julien Fortin <julien@cumulusnetworks.com>
Signed-off-by: Julien Fortin <julien@cumulusnetworks.com>
---
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)
--
2.14.1
^ permalink raw reply related
* [PATCH iproute2 json v2 02/27] ip: add new command line argument -json (mutually exclusive with -color)
From: Julien Fortin @ 2017-08-17 17:35 UTC (permalink / raw)
To: netdev; +Cc: roopa, nikolay, dsa, Julien Fortin
In-Reply-To: <20170817173614.54987-1-julien@cumulusnetworks.com>
From: Julien Fortin <julien@cumulusnetworks.com>
Signed-off-by: Julien Fortin <julien@cumulusnetworks.com>
---
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);
--
2.14.1
^ permalink raw reply related
* [PATCH iproute2 json v2 01/27] color: add new COLOR_NONE and disable_color function
From: Julien Fortin @ 2017-08-17 17:35 UTC (permalink / raw)
To: netdev; +Cc: roopa, nikolay, dsa, Julien Fortin
In-Reply-To: <20170817173614.54987-1-julien@cumulusnetworks.com>
From: Julien Fortin <julien@cumulusnetworks.com>
Signed-off-by: Julien Fortin <julien@cumulusnetworks.com>
---
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]);
--
2.14.1
^ permalink raw reply related
* [PATCH iproute2 json v2 00/27] ip: add -json support to 'ip link show'
From: Julien Fortin @ 2017-08-17 17:35 UTC (permalink / raw)
To: netdev; +Cc: roopa, nikolay, dsa, Julien Fortin
From: Julien Fortin <julien@cumulusnetworks.com>
This patch series adds json support to 'ip [-details] link show [dev DEV]'
Each patch describes the json schema it adds and provides some examples.
Julien Fortin (27):
color: add new COLOR_NONE and disable_color function
ip: add new command line argument -json (mutually exclusive with
-color)
json_writer: add new json handlers (null, float with format, lluint,
hu)
ip: ip_print: add new API to print JSON or regular format output
ip: ipaddress.c: add support for json output
ip: iplink.c: open/close json obj for ip -brief -json link show dev
DEV
ip: iplink_bond.c: add json output support
ip: iplink_bond_slave.c: add json output support (info_slave_data)
ip: iplink_hsr.c: add json output support
ip: iplink_bridge.c: add json output support
ip: iplink_bridge_slave.c: add json output support
ip: iplink_can.c: add json output support
ip: iplink_geneve.c: add json output support
ip: iplink_ipoib.c: add json output support
ip: iplink_ipvlan.c: add json output support
ip: iplink_vrf.c: add json output support
ip: iplink_vxlan.c: add json output support
ip: iplink_xdp.c: add json output support
ip: ipmacsec.c: add json output support
ip: link_gre.c: add json output support
ip: link_gre6.c: add json output support
ip: link_ip6tnl.c: add json output support
ip: link_iptnl.c: add json output support
ip: link_vti.c: add json output support
ip: link_vti6.c: add json output support
ip: link_macvlan.c: add json output support
ip: iplink_vlan.c: add json output support
include/color.h | 2 +
include/json_writer.h | 9 +
include/utils.h | 1 +
ip/Makefile | 2 +-
ip/ip.c | 6 +
ip/ip_common.h | 56 +++
ip/ip_print.c | 233 ++++++++++
ip/ipaddress.c | 1064 ++++++++++++++++++++++++++++++++--------------
ip/iplink.c | 2 +
ip/iplink_bond.c | 231 ++++++----
ip/iplink_bond_slave.c | 57 ++-
ip/iplink_bridge.c | 293 ++++++++-----
ip/iplink_bridge_slave.c | 185 ++++----
ip/iplink_can.c | 282 ++++++++----
ip/iplink_geneve.c | 86 +++-
ip/iplink_hsr.c | 36 +-
ip/iplink_ipoib.c | 30 +-
ip/iplink_ipvlan.c | 8 +-
ip/iplink_macvlan.c | 37 +-
ip/iplink_vlan.c | 62 ++-
ip/iplink_vrf.c | 13 +-
ip/iplink_vxlan.c | 161 ++++---
ip/iplink_xdp.c | 31 +-
ip/ipmacsec.c | 84 +++-
ip/link_gre.c | 147 ++++---
ip/link_gre6.c | 142 +++++--
ip/link_ip6tnl.c | 172 +++++---
ip/link_iptnl.c | 155 ++++---
ip/link_vti.c | 24 +-
ip/link_vti6.c | 22 +-
lib/color.c | 12 +-
lib/json_writer.c | 44 +-
32 files changed, 2663 insertions(+), 1026 deletions(-)
create mode 100644 ip/ip_print.c
--
2.14.1
^ permalink raw reply
* Re: [PATCH net-next] net: ipv6: put host and anycast routes on device with address
From: David Miller @ 2017-08-17 17:31 UTC (permalink / raw)
To: dsahern; +Cc: netdev, yoshfuji, hannes
In-Reply-To: <3b4eb556-a25b-75a8-9d29-1974607044cf@gmail.com>
From: David Ahern <dsahern@gmail.com>
Date: Thu, 17 Aug 2017 10:56:54 -0600
> DaveM: please drop this one. I found a use case that is failing: UDP
> packets to a local linklocal address with no server are not getting the
> ICMP unreachable. Will send a v2 when tests complete.
Ok.
^ permalink raw reply
* Re: [PATCH V4 net 0/2] ipv6: fix flowlabel issue for reset packet
From: Shaohua Li @ 2017-08-17 17:26 UTC (permalink / raw)
To: Tom Herbert
Cc: Linux Kernel Network Developers, David S. Miller,
Martin KaFai Lau
In-Reply-To: <CALx6S34C5aT+UX-Rz39iu5FX-U-EAw23ZiBEcGP90HZRj4xf+g@mail.gmail.com>
On Tue, Aug 15, 2017 at 05:15:46PM -0700, Tom Herbert wrote:
> On Tue, Aug 15, 2017 at 3:42 PM, Shaohua Li <shli@kernel.org> wrote:
> > On Tue, Aug 15, 2017 at 07:08:31AM -0700, Tom Herbert wrote:
> >> On Mon, Aug 14, 2017 at 7:52 PM, Shaohua Li <shli@kernel.org> wrote:
> >> > On Fri, Aug 11, 2017 at 06:00:20PM -0700, Tom Herbert wrote:
> >> >> On Thu, Aug 10, 2017 at 12:13 PM, Shaohua Li <shli@kernel.org> wrote:
> >> >> > On Thu, Aug 10, 2017 at 11:30:51AM -0700, Tom Herbert wrote:
> >> >> >> On Thu, Aug 10, 2017 at 9:30 AM, Shaohua Li <shli@kernel.org> wrote:
> >> >> >> > On Wed, Aug 09, 2017 at 09:40:08AM -0700, Tom Herbert wrote:
> >> >> >> >> On Mon, Jul 31, 2017 at 3:19 PM, Shaohua Li <shli@kernel.org> wrote:
> >> >> >> >> > From: Shaohua Li <shli@fb.com>
> >> >> >> >> >
> >> >> >> >> > Please see below tcpdump output:
> >> >> >> >> > 21:00:48.109122 IP6 (flowlabel 0x43304, hlim 64, next-header TCP (6) payload length: 40) fec0::5054:ff:fe12:3456.55804 > fec0::5054:ff:fe12:3456.5555: Flags [S], cksum 0x0529 (incorrect -> 0xf56c), seq 3282214508, win 43690, options [mss 65476,sackOK,TS val 2500903437 ecr 0,nop,wscale 7], length 0
> >> >> >> >> > 21:00:48.109381 IP6 (flowlabel 0xd827f, hlim 64, next-header TCP (6) payload length: 40) fec0::5054:ff:fe12:3456.5555 > fec0::5054:ff:fe12:3456.55804: Flags [S.], cksum 0x0529 (incorrect -> 0x49ad), seq 1923801573, ack 3282214509, win 43690, options [mss 65476,sackOK,TS val 2500903437 ecr 2500903437,nop,wscale 7], length 0
> >> >> >> >> > 21:00:48.109548 IP6 (flowlabel 0x43304, hlim 64, next-header TCP (6) payload length: 32) fec0::5054:ff:fe12:3456.55804 > fec0::5054:ff:fe12:3456.5555: Flags [.], cksum 0x0521 (incorrect -> 0x1bdf), seq 1, ack 1, win 342, options [nop,nop,TS val 2500903437 ecr 2500903437], length 0
> >> >> >> >> > 21:00:48.109823 IP6 (flowlabel 0x43304, hlim 64, next-header TCP (6) payload length: 62) fec0::5054:ff:fe12:3456.55804 > fec0::5054:ff:fe12:3456.5555: Flags [P.], cksum 0x053f (incorrect -> 0xb8b1), seq 1:31, ack 1, win 342, options [nop,nop,TS val 2500903437 ecr 2500903437], length 30
> >> >> >> >> > 21:00:48.109910 IP6 (flowlabel 0xd827f, hlim 64, next-header TCP (6) payload length: 32) fec0::5054:ff:fe12:3456.5555 > fec0::5054:ff:fe12:3456.55804: Flags [.], cksum 0x0521 (incorrect -> 0x1bc1), seq 1, ack 31, win 342, options [nop,nop,TS val 2500903437 ecr 2500903437], length 0
> >> >> >> >> > 21:00:48.110043 IP6 (flowlabel 0xd827f, hlim 64, next-header TCP (6) payload length: 56) fec0::5054:ff:fe12:3456.5555 > fec0::5054:ff:fe12:3456.55804: Flags [P.], cksum 0x0539 (incorrect -> 0xb726), seq 1:25, ack 31, win 342, options [nop,nop,TS val 2500903438 ecr 2500903437], length 24
> >> >> >> >> > 21:00:48.110173 IP6 (flowlabel 0x43304, hlim 64, next-header TCP (6) payload length: 32) fec0::5054:ff:fe12:3456.55804 > fec0::5054:ff:fe12:3456.5555: Flags [.], cksum 0x0521 (incorrect -> 0x1ba7), seq 31, ack 25, win 342, options [nop,nop,TS val 2500903438 ecr 2500903438], length 0
> >> >> >> >> > 21:00:48.110211 IP6 (flowlabel 0xd827f, hlim 64, next-header TCP (6) payload length: 32) fec0::5054:ff:fe12:3456.5555 > fec0::5054:ff:fe12:3456.55804: Flags [F.], cksum 0x0521 (incorrect -> 0x1ba7), seq 25, ack 31, win 342, options [nop,nop,TS val 2500903438 ecr 2500903437], length 0
> >> >> >> >> > 21:00:48.151099 IP6 (flowlabel 0x43304, hlim 64, next-header TCP (6) payload length: 32) fec0::5054:ff:fe12:3456.55804 > fec0::5054:ff:fe12:3456.5555: Flags [.], cksum 0x0521 (incorrect -> 0x1ba6), seq 31, ack 26, win 342, options [nop,nop,TS val 2500903438 ecr 2500903438], length 0
> >> >> >> >> > 21:00:49.110524 IP6 (flowlabel 0x43304, hlim 64, next-header TCP (6) payload length: 56) fec0::5054:ff:fe12:3456.55804 > fec0::5054:ff:fe12:3456.5555: Flags [P.], cksum 0x0539 (incorrect -> 0xb324), seq 31:55, ack 26, win 342, options [nop,nop,TS val 2500904438 ecr 2500903438], length 24
> >> >> >> >> > 21:00:49.110637 IP6 (flowlabel 0xb34d5, hlim 64, next-header TCP (6) payload length: 20) fec0::5054:ff:fe12:3456.5555 > fec0::5054:ff:fe12:3456.55804: Flags [R], cksum 0x0515 (incorrect -> 0x668c), seq 1923801599, win 0, length 0
> >> >> >> >> >
> >> >> >> >> > The flowlabel of reset packet (0xb34d5) and flowlabel of normal packet
> >> >> >> >> > (0xd827f) are different. This causes our router doesn't correctly close tcp
> >> >> >> >> > connection. The patches try to fix the issue.
> >> >> >> >> >
> >> >> >> >> Shaohua,
> >> >> >> >>
> >> >> >> >> Can you give some more detail about what the router doesn't close the
> >> >> >> >> TCP connection means? I'm guessing the problem is either: 1) the
> >> >> >> >> router is maintaining connection state that includes the flow label in
> >> >> >> >> a connection tuple. 2) some router in the path is maintaining
> >> >> >> >> connection state, but when the flow label changes the flow's packet
> >> >> >> >> are routed through a different router that doesn't have a state for
> >> >> >> >> the flow it drops the packet. #1 should be easily fix in the router,
> >> >> >> >> flow labels cannot be used as state. #2 is the known problem that
> >> >> >> >> stateful firewalls have killed our ability to use multihoming.
> >> >> >> >
> >> >> >> > The #2 is exactly the problem we saw.
> >> >> >> >
> >> >> >> >> Another consideration is that sk_txhash is also used in routing
> >> >> >> >> decisions by the local host (flow label is normally derived from
> >> >> >> >> txhash). If you want to ensure that connections are routed
> >> >> >> >> consistently for timewait state you might need sk_txhash saved also.
> >> >> >> >
> >> >> >> > As far as I understood, we don't use sk_txhash for routing selection. The code
> >> >> >> > does routing selection with flowlabel user configured, at that time we don't
> >> >> >> > derive fl6.flowlabel from skb->hash (which is from sk_txhash). The code always
> >> >> >> > does routing selection first and then uses ip6_make_flowlabel to build packet
> >> >> >> > data where we derive flowlabel from skb->hash.
> >> >> >> >
> >> >> >> That is assuming one particular use case. Generally, if you want to
> >> >> >> ensure all packets for a flow take the same path you'll need tx_hash
> >> >> >> and make it persistent (disable flow bender). For instance, if you
> >> >> >> were doing UDP encapsulation like in VXLAN the UDP source port
> >> >> >> selection is unaffected by saved flow label for the lifetime of the
> >> >> >> flow. So we would still hit #2 in that case and the stateful device
> >> >> >> doesn't see whole flow. It might be just as easy to move tx_hash in
> >> >> >> skc_common so that it's available in TW state for this purpose. Then
> >> >> >> when moving to TW state just copy the tx_hash.
> >> >> >
> >> >> > Hi Tom,
> >> >> >
> >> >> > My original implementation is to add a tx_hash in tw sock, we then copy sock's
> >> >> > tx_hash to the tw tx_hash. This does makes things simplier. One concern from
> >> >> > Eric is this will increase the size of tw sock. If we move tx_hash to
> >> >> > skc_common, all sock size will increase, is this acceptable?
> >> >>
> >> >> I think that can only be measured by how critical it is to
> >> >> persistently route all packets the same exact way for every
> >> >> connection. Page one of the IP book clearly states that IP packets can
> >> >> be dropped, duplicated, or received out of order. Received OOO implies
> >> >> that packet for the same flow are allowed to take different paths. The
> >> >> requirement that packets for the same flow must always take the same
> >> >> path through the network was created by stateful middleboxes-- it's
> >> >> not inherent in the architecture of IP networking. Unfortunately,
> >> >> we're seeing this become more and more of a problem as more devices
> >> >> are multi-homed (like smart phones) and these network requirement
> >> >> cripple our ability to take advantage of features like that.
> >> >>
> >> >> Personally, I wish the middleboxes fix the problem they created, but I
> >> >> suppose we need to be pragmatic at least in the short term.
> >> >
> >> > Hmm, I still hesitate to add a new field in skc_common. Fixing current problem
> >> > looks propriate in current stage. I'd defer fixing the generic issue till it's
> >> > necessary.
> >> >
> >> Shaohua,
> >>
> >> An alternative would be to not initialize sk_txhash, but instead defer
> >> hash computation to use flow dissector in the TX path when the hash is
> >> needed (to get flow label, src port for UDP encap, route for
> >> multipath, etc.). At the first hash computation in TX path the result
> >> in sk_txhash. TW state there is no socket so flow dissector is
> >> always used but that should yield the same hash. No extra fields would
> >> be needed and additional cost is negligible.
> >
> > Hi Tom,
> >
> > Did you mean revert 877d1f6291f8(net: Set sk_txhash from a random number)? This
> > could fix the issue. So in normal case we calculate the sk_txhash using flow
> > dissector but in negative routing case we use the random hash, is this what you
> > want?
> >
> No. What you'd want is something like a sysctl that sets an alternate
> mode for sk_txhash processing. sk_txhash is derived from flow
> dissector for the first TX packet and then it's never allowed to
> change. Maybe this should be called persistent-hash mode.
persistent-hash will almostly mean disabling auto flowlabel. We'd prefer
disabling auto flowlabel rather than the persistent-hash. But I think we do
want to use the auto flowlabel for load balancing, so the persistent-hash isn't
a go for us.
Let's take the other way. Your main concern is the multipath selection. I think
this can be fixed. We can still use the tw->tw_flowlabel to store the auto
created flowlabel like what my patch does, but we use an extra bit in tw_pad of
inet_timewait_sock to indicate this flowlabel is auto created. In the reset
packet send path, we don't use the auto created flowlabel for route slection,
but just for packet data. This will keep current multipath selection behavior
and fix the reset packet flowlabel issue.
> > There seems to have other bug in this side. From my understanding, commit
> > 265f94ff54d6(net: Recompute sk_txhash on negative routing advice) tries to
> > select a different route. But the multipath selection code
> > (rt6_multipath_select) doesn't use sk_txhash or skb->hash, it does use
> > fl6.flowlabel, but that is the flowlabel user sets. So looks like the commit
> > doesn't change anything.
> >
> The routing functions typically don't use sock of skbuff, but use flow
> structs instead. It may be reasonable to add a hash to those.
I'll look at this issue later. It's not related to current flowlabel problem.
Thanks,
Shaohua
^ permalink raw reply
* Re: [PATCH net-next 0/2] Two BPF smap related followups
From: David Miller @ 2017-08-17 17:25 UTC (permalink / raw)
To: daniel; +Cc: john.fastabend, ast, netdev
In-Reply-To: <cover.1502983087.git.daniel@iogearbox.net>
From: Daniel Borkmann <daniel@iogearbox.net>
Date: Thu, 17 Aug 2017 17:22:35 +0200
> Fixing preemption imbalance and consolidating prologue
> generation. Thanks!
Series applied, thanks.
^ permalink raw reply
* Re: [net-next 11/15] net/mlx5e: Properly indent within conditional statements
From: David Miller @ 2017-08-17 17:21 UTC (permalink / raw)
To: David.Laight; +Cc: saeedm, netdev, leonro, ogerlitz
In-Reply-To: <063D6719AE5E284EB5DD2968C1650D6DD0059721@AcuExch.aculab.com>
From: David Laight <David.Laight@ACULAB.COM>
Date: Thu, 17 Aug 2017 14:18:29 +0000
> From: Saeed Mahameed
>> Sent: 17 August 2017 14:30
>> To: David S. Miller
>> Cc: netdev@vger.kernel.org; Leon Romanovsky; Or Gerlitz; Saeed Mahameed
>> Subject: [net-next 11/15] net/mlx5e: Properly indent within conditional statements
>>
>> From: Or Gerlitz <ogerlitz@mellanox.com>
>>
>> To fix these checkpatch complaints:
>>
>> WARNING: suspect code indent for conditional statements (8, 24)
>> + if (eth_proto & (MLX5E_PROT_MASK(MLX5E_10GBASE_SR)
>> [...]
>> + return PORT_FIBRE;
>>
>> Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
>> Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
>> ---
>> .../net/ethernet/mellanox/mlx5/core/en_ethtool.c | 22 +++++++++++-----------
>> 1 file changed, 11 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
>> b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
>> index a75ac4d11c5b..ed161312a773 100644
>> --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
>> +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
>> @@ -988,23 +988,23 @@ static u8 get_connector_port(u32 eth_proto, u8 connector_type)
>> return ptys2connector_type[connector_type];
>>
>> if (eth_proto & (MLX5E_PROT_MASK(MLX5E_10GBASE_SR)
>> - | MLX5E_PROT_MASK(MLX5E_40GBASE_SR4)
>> - | MLX5E_PROT_MASK(MLX5E_100GBASE_SR4)
>> - | MLX5E_PROT_MASK(MLX5E_1000BASE_CX_SGMII))) {
>> - return PORT_FIBRE;
>> + | MLX5E_PROT_MASK(MLX5E_40GBASE_SR4)
>> + | MLX5E_PROT_MASK(MLX5E_100GBASE_SR4)
>> + | MLX5E_PROT_MASK(MLX5E_1000BASE_CX_SGMII))) {
>> + return PORT_FIBRE;
>
> Gah, that is why the rules are stupid.
> If anything the continuation lines want indenting a few more bytes.
And in fact, operators should be at the end rather the beginning of lines.
This statement therefore must be formatted like this:
if (x & (A |
B |
C |
C))
The indentation shows the grouping, therefore each line after the first must
start exactly at the column after the inner openning parenthesis.
Please fix this properly.
^ permalink raw reply
* Re: [PATCH] net: ibm: ibmvnic: constify vio_device_id
From: David Miller @ 2017-08-17 17:18 UTC (permalink / raw)
To: arvind.yadav.cs
Cc: tlfalcon, benh, jallen, mpe, linux-kernel, linuxppc-dev, netdev
In-Reply-To: <74d0d08fe98bf52e122d027efdcd7f9811309325.1502975929.git.arvind.yadav.cs@gmail.com>
From: Arvind Yadav <arvind.yadav.cs@gmail.com>
Date: Thu, 17 Aug 2017 18:52:54 +0530
> vio_device_id are not supposed to change at runtime. All functions
> working with vio_device_id provided by <asm/vio.h> work with
> const vio_device_id. So mark the non-const structs as const.
>
> Signed-off-by: Arvind Yadav <arvind.yadav.cs@gmail.com>
Applied.
^ permalink raw reply
* Re: [PATCH] net: ibm: ibmveth: constify vio_device_id
From: David Miller @ 2017-08-17 17:18 UTC (permalink / raw)
To: arvind.yadav.cs
Cc: tlfalcon, benh, jallen, mpe, linux-kernel, linuxppc-dev, netdev
In-Reply-To: <b8393cdf646fae5ccbb64aab482c133fd54a7339.1502975929.git.arvind.yadav.cs@gmail.com>
From: Arvind Yadav <arvind.yadav.cs@gmail.com>
Date: Thu, 17 Aug 2017 18:52:53 +0530
> vio_device_id are not supposed to change at runtime. All functions
> working with vio_device_id provided by <asm/vio.h> work with
> const vio_device_id. So mark the non-const structs as const.
>
> Signed-off-by: Arvind Yadav <arvind.yadav.cs@gmail.com>
Applied.
^ permalink raw reply
* Re: [PATCH net-next] bpf: no need to nullify ri->map in xdp_do_redirect
From: David Miller @ 2017-08-17 17:16 UTC (permalink / raw)
To: daniel; +Cc: john.fastabend, ast, netdev
In-Reply-To: <782d0b6850cb1a63230c0fd634f1e61d67a01e60.1502975082.git.daniel@iogearbox.net>
From: Daniel Borkmann <daniel@iogearbox.net>
Date: Thu, 17 Aug 2017 15:07:22 +0200
> We are guaranteed to have a NULL ri->map in this branch since
> we test for it earlier, so we don't need to reset it here.
>
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Applied.
^ permalink raw reply
* Re: [PATCH net-next] bpf: fix liveness propagation to parent in spilled stack slots
From: David Miller @ 2017-08-17 17:16 UTC (permalink / raw)
To: daniel; +Cc: ecree, ast, netdev
In-Reply-To: <058693b94f456324fd1a3d5946fa486e3a09ca06.1502974643.git.daniel@iogearbox.net>
From: Daniel Borkmann <daniel@iogearbox.net>
Date: Thu, 17 Aug 2017 14:59:40 +0200
> Using parent->regs[] when propagating REG_LIVE_READ for spilled regs
> doesn't work since parent->regs[] denote the set of normal registers
> but not spilled ones. Propagate to the correct regs.
>
> Fixes: dc503a8ad984 ("bpf/verifier: track liveness for pruning")
> Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
> Acked-by: Edward Cree <ecree@solarflare.com>
Applied.
^ permalink raw reply
* [iproute PATCH v2 1/3] iproute_lwtunnel: csum_mode value checking was ineffective
From: Phil Sutter @ 2017-08-17 17:09 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
In-Reply-To: <20170817170932.24812-1-phil@nwl.cc>
ila_csum_name2mode() returning -1 on error but being declared as
returning __u8 doesn't make much sense. Change the code to correctly
detect this issue. Checking for __u8 overruns shouldn't be necessary
though since ila_csum_name2mode() return values are well-defined.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
ip/iproute_lwtunnel.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c
index 5c0c7d110d23e..398ab5e077ed8 100644
--- a/ip/iproute_lwtunnel.c
+++ b/ip/iproute_lwtunnel.c
@@ -171,7 +171,7 @@ static char *ila_csum_mode2name(__u8 csum_mode)
}
}
-static __u8 ila_csum_name2mode(char *name)
+static int ila_csum_name2mode(char *name)
{
if (strcmp(name, "adj-transport") == 0)
return ILA_CSUM_ADJUST_TRANSPORT;
@@ -517,7 +517,7 @@ static int parse_encap_ila(struct rtattr *rta, size_t len,
while (argc > 0) {
if (strcmp(*argv, "csum-mode") == 0) {
- __u8 csum_mode;
+ int csum_mode;
NEXT_ARG();
@@ -526,7 +526,8 @@ static int parse_encap_ila(struct rtattr *rta, size_t len,
invarg("\"csum-mode\" value is invalid\n",
*argv);
- rta_addattr8(rta, 1024, ILA_ATTR_CSUM_MODE, csum_mode);
+ rta_addattr8(rta, 1024, ILA_ATTR_CSUM_MODE,
+ (__u8)csum_mode);
argc--; argv++;
} else {
--
2.13.1
^ permalink raw reply related
* [iproute PATCH v2 0/5] Covscan: Fix potential NULL pointer dereferences
From: Phil Sutter @ 2017-08-17 17:09 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
This series collects patches from v1 which eliminate possible cases of
NULL pointer dereferences.
No changes to the actual patches, just splitting into smaller series.
Phil Sutter (5):
ifstat, nstat: Check fdopen() return value
nstat: Fix for potential NULL pointer dereference
tc/q_netem: Don't dereference possibly NULL pointer
tc/tc_filter: Make sure filter name is not empty
tipc/bearer: Prevent NULL pointer dereference
misc/ifstat.c | 16 +++++++++++-----
misc/nstat.c | 18 ++++++++++++------
tc/q_netem.c | 4 +++-
tc/tc_filter.c | 3 +++
tipc/bearer.c | 4 ++--
5 files changed, 31 insertions(+), 14 deletions(-)
--
2.13.1
^ permalink raw reply
* [iproute PATCH v2 2/7] xfrm_state: Make sure alg_name is NULL-terminated
From: Phil Sutter @ 2017-08-17 17:09 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
In-Reply-To: <20170817170932.24659-1-phil@nwl.cc>
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
ip/xfrm_state.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c
index e11c93bf1c3b5..7c0389038986e 100644
--- a/ip/xfrm_state.c
+++ b/ip/xfrm_state.c
@@ -125,7 +125,8 @@ static int xfrm_algo_parse(struct xfrm_algo *alg, enum xfrm_attr_type_t type,
fprintf(stderr, "warning: ALGO-NAME/ALGO-KEYMAT values will be sent to the kernel promiscuously! (verifying them isn't implemented yet)\n");
#endif
- strncpy(alg->alg_name, name, sizeof(alg->alg_name));
+ strncpy(alg->alg_name, name, sizeof(alg->alg_name) - 1);
+ alg->alg_name[sizeof(alg->alg_name) - 1] = '\0';
if (slen > 2 && strncmp(key, "0x", 2) == 0) {
/* split two chars "0x" from the top */
--
2.13.1
^ permalink raw reply related
* [iproute PATCH v2 2/2] ifcfg: Quote left-hand side of [ ] expression
From: Phil Sutter @ 2017-08-17 17:09 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
In-Reply-To: <20170817170932.24900-1-phil@nwl.cc>
This prevents word-splitting and therefore leads to more accurate error
message in case 'grep -c' prints something other than a number.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
ip/ifcfg | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ip/ifcfg b/ip/ifcfg
index 083d9df36742f..30a2dc49816cd 100644
--- a/ip/ifcfg
+++ b/ip/ifcfg
@@ -131,7 +131,7 @@ noarp=$?
ip route add unreachable 224.0.0.0/24 >& /dev/null
ip route add unreachable 255.255.255.255 >& /dev/null
-if [ `ip link ls $dev | grep -c MULTICAST` -ge 1 ]; then
+if [ "`ip link ls $dev | grep -c MULTICAST`" -ge 1 ]; then
ip route add 224.0.0.0/4 dev $dev scope global >& /dev/null
fi
--
2.13.1
^ permalink raw reply related
* [iproute PATCH v2 0/7] Covscan: Dead code elimination
From: Phil Sutter @ 2017-08-17 17:09 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
This series collects patches from v1 which deal with dead code, either
by removing it or changing context so it is accessed again if that makes
sense.
No changes to the actual patches, just splitting into smaller series.
Phil Sutter (7):
devlink: No need for this self-assignment
ipntable: No need to check and assign to parms_rta
iproute: Fix for missing 'Oifs:' display
lib/rt_names: Drop dead code in rtnl_rttable_n2a()
ss: Skip useless check in parse_hostcond()
ss: Drop useless assignment
tc/m_gact: Drop dead code
devlink/devlink.c | 2 +-
ip/ipntable.c | 2 --
ip/iproute.c | 8 +++++---
lib/rt_names.c | 4 ----
misc/ss.c | 3 +--
tc/m_gact.c | 14 +++-----------
6 files changed, 10 insertions(+), 23 deletions(-)
--
2.13.1
^ permalink raw reply
* [iproute PATCH v2 5/7] lnstat_util: Simplify alloc_and_open() a bit
From: Phil Sutter @ 2017-08-17 17:09 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
In-Reply-To: <20170817170932.24659-1-phil@nwl.cc>
Relying upon callers and using unsafe strcpy() is probably not the best
idea. Aside from that, using snprintf() allows to format the string for
lf->path in one go.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
misc/lnstat_util.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/misc/lnstat_util.c b/misc/lnstat_util.c
index cc54598fe1bef..ec19238c24b94 100644
--- a/misc/lnstat_util.c
+++ b/misc/lnstat_util.c
@@ -180,11 +180,8 @@ static struct lnstat_file *alloc_and_open(const char *path, const char *file)
}
/* initialize */
- /* de->d_name is guaranteed to be <= NAME_MAX */
- strcpy(lf->basename, file);
- strcpy(lf->path, path);
- strcat(lf->path, "/");
- strcat(lf->path, lf->basename);
+ snprintf(lf->basename, sizeof(lf->basename), "%s", file);
+ snprintf(lf->path, sizeof(lf->path), "%s/%s", path, file);
/* initialize to default */
lf->interval.tv_sec = 1;
--
2.13.1
^ permalink raw reply related
* [iproute PATCH v2 3/5] ifstat: Fix memleak in dump_kern_db() for json output
From: Phil Sutter @ 2017-08-17 17:09 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
In-Reply-To: <20170817170931.24435-1-phil@nwl.cc>
Looks like this was forgotten when converting to common json output
formatter.
Fixes: fcc16c2287bf8 ("provide common json output formatter")
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
misc/ifstat.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/misc/ifstat.c b/misc/ifstat.c
index 8fa354265a9a1..1be21703bf14c 100644
--- a/misc/ifstat.c
+++ b/misc/ifstat.c
@@ -535,8 +535,12 @@ static void dump_kern_db(FILE *fp)
else
print_one_if(fp, n, n->val);
}
- if (json_output)
- fprintf(fp, "\n} }\n");
+ if (jw) {
+ jsonw_end_object(jw);
+
+ jsonw_end_object(jw);
+ jsonw_destroy(&jw);
+ }
}
static void dump_incr_db(FILE *fp)
--
2.13.1
^ permalink raw reply related
* [iproute PATCH v2 3/7] iplink_can: Prevent overstepping array bounds
From: Phil Sutter @ 2017-08-17 17:09 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
In-Reply-To: <20170817170931.24302-1-phil@nwl.cc>
can_state_names array contains at most CAN_STATE_MAX fields, so allowing
an index to it to be equal to that number is wrong. While here, also
make sure the array is indeed that big so nothing bad happens if
CAN_STATE_MAX ever increases.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
ip/iplink_can.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/ip/iplink_can.c b/ip/iplink_can.c
index 5df56b2bbbb3b..2954010fefa22 100644
--- a/ip/iplink_can.c
+++ b/ip/iplink_can.c
@@ -251,7 +251,7 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
return 0;
}
-static const char *can_state_names[] = {
+static const char *can_state_names[CAN_STATE_MAX] = {
[CAN_STATE_ERROR_ACTIVE] = "ERROR-ACTIVE",
[CAN_STATE_ERROR_WARNING] = "ERROR-WARNING",
[CAN_STATE_ERROR_PASSIVE] = "ERROR-PASSIVE",
@@ -275,7 +275,7 @@ 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 ?
+ fprintf(f, "state %s ", state < CAN_STATE_MAX ?
can_state_names[state] : "UNKNOWN");
}
--
2.13.1
^ permalink raw reply related
* [iproute PATCH v2 4/7] lib/rt_names: Drop dead code in rtnl_rttable_n2a()
From: Phil Sutter @ 2017-08-17 17:09 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
In-Reply-To: <20170817170931.24089-1-phil@nwl.cc>
Since 'id' is 32bit unsigned, it can never exceed RT_TABLE_MAX (which is
defined to 0xFFFFFFFF). Therefore drop that never matching conditional.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
lib/rt_names.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/lib/rt_names.c b/lib/rt_names.c
index 04c15ff5b15f8..e5efd78e6f810 100644
--- a/lib/rt_names.c
+++ b/lib/rt_names.c
@@ -410,10 +410,6 @@ const char *rtnl_rttable_n2a(__u32 id, char *buf, int len)
{
struct rtnl_hash_entry *entry;
- if (id > RT_TABLE_MAX) {
- snprintf(buf, len, "%u", id);
- return buf;
- }
if (!rtnl_rttable_init)
rtnl_rttable_initialize();
entry = rtnl_rttable_hash[id & 255];
--
2.13.1
^ permalink raw reply related
* [iproute PATCH v2 0/5] Covscan: Fix potential memory leaks
From: Phil Sutter @ 2017-08-17 17:09 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
This series collects patches from v1 which deal with potential memory leaks.
No changes to the actual patches, just splitting into smaller series.
Phil Sutter (5):
ipvrf: Fix error path of vrf_switch()
ifstat: Fix memleak in error case
ifstat: Fix memleak in dump_kern_db() for json output
ss: Fix potential memleak in unix_stats_print()
tipc/bearer: Fix resource leak in error path
ip/ipvrf.c | 9 +++++----
misc/ifstat.c | 12 +++++++++---
misc/ss.c | 4 +++-
tipc/bearer.c | 3 +++
4 files changed, 20 insertions(+), 8 deletions(-)
--
2.13.1
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox