mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2025-08-15 09:33:17 +00:00
ip: ipaddress.c: add support for json output
This patch converts all output (mostly fprintfs) to the new ip_print api which handle both regular and json output. Initialize a json_writer and open an array object if -json was specified. Note that the JSON attribute naming follows the NETLINK_ATTRIBUTE naming. In many places throughout the code, IP, matches integer values with hardcoded strings tables, such as link mode, link operstate or link family. In JSON context, this will result in a named string field. In the very unlikely event that the requested index is out of bound, IP displays the raw integer value. For JSON context this result in having a different integer field example bellow: if (mode >= ARRAY_SIZE(link_modes)) print_int(PRINT_ANY, "linkmode_index", "mode %d ", mode); else print_string(PRINT_ANY, "linkmode", "mode %s ", link_modes[mode]); The "_index" suffix is open to discussion and it is something that I came up with. The bottom line is that you can't have a string field that may become an int field in specific cases. Programs written in strongly type languages (like C) might break if they are expecting a string value and got an integer instead. We don't want to confuse anybody or make the code even more complicated handling these specifics cases. Hence the extra "_index" field that is easy to check for and deal with. JSON schema, followed by live example: Live config used: $ ip link add dev vxlan42 type vxlan id 42 $ ip link add dev bond0 type bond $ ip link add name swp1.50 link swp1 type vlan id 50 $ ip link add dev br0 type bridge $ ip link set dev vxlan42 master br0 $ ip link set dev bond0 master br0 $ ip link set dev swp1.50 master br0 $ ip link set dev br0 up $ ip -d link show 1: lo: <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>
This commit is contained in:
parent
6377572f0a
commit
d0e720111a
722
ip/ipaddress.c
722
ip/ipaddress.c
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user