From d857a7fd4bb6f07ce7a7f12ce83cbd7427e1b8d9 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 5 Feb 2018 17:18:53 -0800 Subject: [PATCH 01/20] include: update uapi with BPF from 4.15-rc1 Signed-off-by: Stephen Hemminger --- include/uapi/linux/bpf.h | 89 +++++++++++++++++++++++++++++++-- include/uapi/linux/bpf_common.h | 7 +-- 2 files changed, 89 insertions(+), 7 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index a902a490..40b08520 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -17,7 +17,7 @@ #define BPF_ALU64 0x07 /* alu mode in double word width */ /* ld/ldx fields */ -#define BPF_DW 0x18 /* double word */ +#define BPF_DW 0x18 /* double word (64-bit) */ #define BPF_XADD 0xc0 /* exclusive add */ /* alu/jmp fields */ @@ -642,6 +642,14 @@ union bpf_attr { * @optlen: length of optval in bytes * Return: 0 or negative error * + * int bpf_sock_ops_cb_flags_set(bpf_sock_ops, flags) + * Set callback flags for sock_ops + * @bpf_sock_ops: pointer to bpf_sock_ops_kern struct + * @flags: flags value + * Return: 0 for no error + * -EINVAL if there is no full tcp socket + * bits in flags that are not supported by current kernel + * * int bpf_skb_adjust_room(skb, len_diff, mode, flags) * Grow or shrink room in sk_buff. * @skb: pointer to skb @@ -748,7 +756,8 @@ union bpf_attr { FN(perf_event_read_value), \ FN(perf_prog_read_value), \ FN(getsockopt), \ - FN(override_return), + FN(override_return), \ + FN(sock_ops_cb_flags_set), /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call @@ -938,6 +947,9 @@ struct bpf_map_info { __u32 max_entries; __u32 map_flags; char name[BPF_OBJ_NAME_LEN]; + __u32 ifindex; + __u64 netns_dev; + __u64 netns_ino; } __attribute__((aligned(8))); /* User bpf_sock_ops struct to access socket values and specify request ops @@ -949,8 +961,9 @@ struct bpf_map_info { struct bpf_sock_ops { __u32 op; union { - __u32 reply; - __u32 replylong[4]; + __u32 args[4]; /* Optionally passed to bpf program */ + __u32 reply; /* Returned by bpf program */ + __u32 replylong[4]; /* Optionally returned by bpf prog */ }; __u32 family; __u32 remote_ip4; /* Stored in network byte order */ @@ -965,8 +978,39 @@ struct bpf_sock_ops { */ __u32 snd_cwnd; __u32 srtt_us; /* Averaged RTT << 3 in usecs */ + __u32 bpf_sock_ops_cb_flags; /* flags defined in uapi/linux/tcp.h */ + __u32 state; + __u32 rtt_min; + __u32 snd_ssthresh; + __u32 rcv_nxt; + __u32 snd_nxt; + __u32 snd_una; + __u32 mss_cache; + __u32 ecn_flags; + __u32 rate_delivered; + __u32 rate_interval_us; + __u32 packets_out; + __u32 retrans_out; + __u32 total_retrans; + __u32 segs_in; + __u32 data_segs_in; + __u32 segs_out; + __u32 data_segs_out; + __u32 lost_out; + __u32 sacked_out; + __u32 sk_txhash; + __u64 bytes_received; + __u64 bytes_acked; }; +/* Definitions for bpf_sock_ops_cb_flags */ +#define BPF_SOCK_OPS_RTO_CB_FLAG (1<<0) +#define BPF_SOCK_OPS_RETRANS_CB_FLAG (1<<1) +#define BPF_SOCK_OPS_STATE_CB_FLAG (1<<2) +#define BPF_SOCK_OPS_ALL_CB_FLAGS 0x7 /* Mask of all currently + * supported cb flags + */ + /* List of known BPF sock_ops operators. * New entries can only be added at the end */ @@ -1000,6 +1044,43 @@ enum { * a congestion threshold. RTTs above * this indicate congestion */ + BPF_SOCK_OPS_RTO_CB, /* Called when an RTO has triggered. + * Arg1: value of icsk_retransmits + * Arg2: value of icsk_rto + * Arg3: whether RTO has expired + */ + BPF_SOCK_OPS_RETRANS_CB, /* Called when skb is retransmitted. + * Arg1: sequence number of 1st byte + * Arg2: # segments + * Arg3: return value of + * tcp_transmit_skb (0 => success) + */ + BPF_SOCK_OPS_STATE_CB, /* Called when TCP changes state. + * Arg1: old_state + * Arg2: new_state + */ +}; + +/* List of TCP states. There is a build check in net/ipv4/tcp.c to detect + * changes between the TCP and BPF versions. Ideally this should never happen. + * If it does, we need to add code to convert them before calling + * the BPF sock_ops function. + */ +enum { + BPF_TCP_ESTABLISHED = 1, + BPF_TCP_SYN_SENT, + BPF_TCP_SYN_RECV, + BPF_TCP_FIN_WAIT1, + BPF_TCP_FIN_WAIT2, + BPF_TCP_TIME_WAIT, + BPF_TCP_CLOSE, + BPF_TCP_CLOSE_WAIT, + BPF_TCP_LAST_ACK, + BPF_TCP_LISTEN, + BPF_TCP_CLOSING, /* Now a valid state */ + BPF_TCP_NEW_SYN_RECV, + + BPF_TCP_MAX_STATES /* Leave at the end! */ }; #define TCP_BPF_IW 1001 /* Set TCP initial congestion window */ diff --git a/include/uapi/linux/bpf_common.h b/include/uapi/linux/bpf_common.h index 9f0201be..f0fe1394 100644 --- a/include/uapi/linux/bpf_common.h +++ b/include/uapi/linux/bpf_common.h @@ -15,9 +15,10 @@ /* ld/ldx fields */ #define BPF_SIZE(code) ((code) & 0x18) -#define BPF_W 0x00 -#define BPF_H 0x08 -#define BPF_B 0x10 +#define BPF_W 0x00 /* 32-bit */ +#define BPF_H 0x08 /* 16-bit */ +#define BPF_B 0x10 /* 8-bit */ +/* eBPF BPF_DW 0x18 64-bit */ #define BPF_MODE(code) ((code) & 0xe0) #define BPF_IMM 0x00 #define BPF_ABS 0x20 From d707207f4d46a2e7a3940890e1556fa0d0e4de57 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 5 Feb 2018 17:19:32 -0800 Subject: [PATCH 02/20] include: update netfilter headers from 4.15-rc1 Signed-off-by: Stephen Hemminger --- include/uapi/linux/netfilter_ipv4.h | 1 + include/uapi/linux/netfilter_ipv6.h | 1 + 2 files changed, 2 insertions(+) diff --git a/include/uapi/linux/netfilter_ipv4.h b/include/uapi/linux/netfilter_ipv4.h index 27ca143b..074e2c8b 100644 --- a/include/uapi/linux/netfilter_ipv4.h +++ b/include/uapi/linux/netfilter_ipv4.h @@ -55,6 +55,7 @@ enum nf_ip_hook_priorities { NF_IP_PRI_FIRST = INT_MIN, + NF_IP_PRI_RAW_BEFORE_DEFRAG = -450, NF_IP_PRI_CONNTRACK_DEFRAG = -400, NF_IP_PRI_RAW = -300, NF_IP_PRI_SELINUX_FIRST = -225, diff --git a/include/uapi/linux/netfilter_ipv6.h b/include/uapi/linux/netfilter_ipv6.h index 35f33d1a..92701fe8 100644 --- a/include/uapi/linux/netfilter_ipv6.h +++ b/include/uapi/linux/netfilter_ipv6.h @@ -60,6 +60,7 @@ enum nf_ip6_hook_priorities { NF_IP6_PRI_FIRST = INT_MIN, + NF_IP6_PRI_RAW_BEFORE_DEFRAG = -450, NF_IP6_PRI_CONNTRACK_DEFRAG = -400, NF_IP6_PRI_RAW = -300, NF_IP6_PRI_SELINUX_FIRST = -225, From a0fc63ed6837ae10cc60fcd3a89f717c18285b42 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 5 Feb 2018 17:20:14 -0800 Subject: [PATCH 03/20] include: update rdma uapi from 4.15-rc1 Signed-off-by: Stephen Hemminger --- include/uapi/rdma/rdma_netlink.h | 49 ++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/include/uapi/rdma/rdma_netlink.h b/include/uapi/rdma/rdma_netlink.h index 48fbf3c3..b36d43a3 100644 --- a/include/uapi/rdma/rdma_netlink.h +++ b/include/uapi/rdma/rdma_netlink.h @@ -236,6 +236,10 @@ enum rdma_nldev_command { RDMA_NLDEV_CMD_PORT_NEW, RDMA_NLDEV_CMD_PORT_DEL, + RDMA_NLDEV_CMD_RES_GET, /* can dump */ + + RDMA_NLDEV_CMD_RES_QP_GET, /* can dump */ + RDMA_NLDEV_NUM_OPS }; @@ -303,6 +307,51 @@ enum rdma_nldev_attr { RDMA_NLDEV_ATTR_DEV_NODE_TYPE, /* u8 */ + RDMA_NLDEV_ATTR_RES_SUMMARY, /* nested table */ + RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY, /* nested table */ + RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME, /* string */ + RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR, /* u64 */ + + RDMA_NLDEV_ATTR_RES_QP, /* nested table */ + RDMA_NLDEV_ATTR_RES_QP_ENTRY, /* nested table */ + /* + * Local QPN + */ + RDMA_NLDEV_ATTR_RES_LQPN, /* u32 */ + /* + * Remote QPN, + * Applicable for RC and UC only IBTA 11.2.5.3 QUERY QUEUE PAIR + */ + RDMA_NLDEV_ATTR_RES_RQPN, /* u32 */ + /* + * Receive Queue PSN, + * Applicable for RC and UC only 11.2.5.3 QUERY QUEUE PAIR + */ + RDMA_NLDEV_ATTR_RES_RQ_PSN, /* u32 */ + /* + * Send Queue PSN + */ + RDMA_NLDEV_ATTR_RES_SQ_PSN, /* u32 */ + RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE, /* u8 */ + /* + * QP types as visible to RDMA/core, the reserved QPT + * are not exported through this interface. + */ + RDMA_NLDEV_ATTR_RES_TYPE, /* u8 */ + RDMA_NLDEV_ATTR_RES_STATE, /* u8 */ + /* + * Process ID which created object, + * in case of kernel origin, PID won't exist. + */ + RDMA_NLDEV_ATTR_RES_PID, /* u32 */ + /* + * The name of process created following resource. + * It will exist only for kernel objects. + * For user created objects, the user is supposed + * to read /proc/PID/comm file. + */ + RDMA_NLDEV_ATTR_RES_KERN_NAME, /* string */ + RDMA_NLDEV_ATTR_MAX }; #endif /* _RDMA_NETLINK_H */ From 25226777b80c1a9cbc32441d572300a00dbe980a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 5 Feb 2018 17:21:01 -0800 Subject: [PATCH 04/20] include: update interface UAPI from 4.15-rc1 Signed-off-by: Stephen Hemminger --- include/uapi/linux/if_link.h | 3 +++ include/uapi/linux/if_macsec.h | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 1726e49f..7ac1042c 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -161,6 +161,9 @@ enum { IFLA_EVENT, IFLA_NEW_NETNSID, IFLA_IF_NETNSID, + IFLA_CARRIER_UP_COUNT, + IFLA_CARRIER_DOWN_COUNT, + IFLA_NEW_IFINDEX, __IFLA_MAX }; diff --git a/include/uapi/linux/if_macsec.h b/include/uapi/linux/if_macsec.h index 0cfb902a..77439932 100644 --- a/include/uapi/linux/if_macsec.h +++ b/include/uapi/linux/if_macsec.h @@ -18,7 +18,7 @@ #define MACSEC_GENL_NAME "macsec" #define MACSEC_GENL_VERSION 1 -#define MACSEC_MAX_KEY_LEN 256 +#define MACSEC_MAX_KEY_LEN 128 #define MACSEC_KEYID_LEN 16 @@ -26,9 +26,9 @@ #define MACSEC_CIPHER_ID_GCM_AES_128 0x0080C20001000001ULL #define MACSEC_CIPHER_ID_GCM_AES_256 0x0080C20001000002ULL -#define MACSEC_DEFAULT_CIPHER_ID MACSEC_CIPHER_ID_GCM_AES_128 /* deprecated cipher ID for GCM-AES-128 */ -#define MACSEC_DEFAULT_CIPHER_ALT 0x0080020001000001ULL +#define MACSEC_DEFAULT_CIPHER_ID 0x0080020001000001ULL +#define MACSEC_DEFAULT_CIPHER_ALT MACSEC_CIPHER_ID_GCM_AES_128 #define MACSEC_MIN_ICV_LEN 8 #define MACSEC_MAX_ICV_LEN 32 From c30c7b6e351edabf6e64487125393df0d857f99b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 5 Feb 2018 17:21:27 -0800 Subject: [PATCH 05/20] include: update UAPI types.h Signed-off-by: Stephen Hemminger --- include/uapi/linux/types.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/uapi/linux/types.h b/include/uapi/linux/types.h index b1c10874..5ea4daa7 100644 --- a/include/uapi/linux/types.h +++ b/include/uapi/linux/types.h @@ -44,5 +44,11 @@ typedef __u32 __bitwise __wsum; #define __aligned_be64 __be64 __attribute__((aligned(8))) #define __aligned_le64 __le64 __attribute__((aligned(8))) +#ifdef __CHECK_POLL +typedef unsigned __bitwise __poll_t; +#else +typedef unsigned __poll_t; +#endif + #endif /* __ASSEMBLY__ */ #endif /* _LINUX_TYPES_H */ From 6416d1a01f5b3ac4a7ba62e22b6ec9534736594e Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 31 Jan 2018 10:11:47 +0200 Subject: [PATCH 06/20] rdma: Add option to provide "-" sign for the port number According to the IBTA spec [1], the physical connected port is provided for the QP in RTR-to-INIT stage performed by modify_qp(). It causes to do not have port number for newly created QPs. The following patch adds "-" sign to present absence of port, because QPs are going to be associated with rdmatool link object, which needs port number as an index. [1] InfiniBand Architecture Release 1.3 - "Table 96 QP State Transition Properties" Signed-off-by: Leon Romanovsky Signed-off-by: Stephen Hemminger --- rdma/link.c | 2 +- rdma/rdma.h | 3 +-- rdma/utils.c | 50 ++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/rdma/link.c b/rdma/link.c index 676cb21d..66bcd50e 100644 --- a/rdma/link.c +++ b/rdma/link.c @@ -285,7 +285,7 @@ static int link_one_show(struct rd *rd) static int link_show(struct rd *rd) { - return rd_exec_link(rd, link_one_show); + return rd_exec_link(rd, link_one_show, true); } int cmd_link(struct rd *rd) diff --git a/rdma/rdma.h b/rdma/rdma.h index 8d53d3a0..cbd9aa89 100644 --- a/rdma/rdma.h +++ b/rdma/rdma.h @@ -64,7 +64,6 @@ bool rd_no_arg(struct rd *rd); void rd_arg_inc(struct rd *rd); char *rd_argv(struct rd *rd); -uint32_t get_port_from_argv(struct rd *rd); /* * Commands interface @@ -73,7 +72,7 @@ int cmd_dev(struct rd *rd); int cmd_link(struct rd *rd); int rd_exec_cmd(struct rd *rd, const struct rd_cmd *c, const char *str); int rd_exec_dev(struct rd *rd, int (*cb)(struct rd *rd)); -int rd_exec_link(struct rd *rd, int (*cb)(struct rd *rd)); +int rd_exec_link(struct rd *rd, int (*cb)(struct rd *rd), bool strict_port); void rd_free(struct rd *rd); /* diff --git a/rdma/utils.c b/rdma/utils.c index 7b2001e2..b9c668a3 100644 --- a/rdma/utils.c +++ b/rdma/utils.c @@ -10,6 +10,7 @@ */ #include "rdma.h" +#include static int rd_argc(struct rd *rd) { @@ -50,13 +51,43 @@ bool rd_no_arg(struct rd *rd) return rd_argc(rd) == 0; } -uint32_t get_port_from_argv(struct rd *rd) +/* + * Possible input:output + * dev/port | first port | is_dump_all + * mlx5_1 | 0 | true + * mlx5_1/ | 0 | true + * mlx5_1/0 | 0 | false + * mlx5_1/1 | 1 | false + * mlx5_1/- | 0 | false + * + * In strict mode, /- will return error. + */ +static int get_port_from_argv(struct rd *rd, uint32_t *port, + bool *is_dump_all, bool strict_port) { char *slash; + *port = 0; + *is_dump_all = true; + slash = strchr(rd_argv(rd), '/'); /* if no port found, return 0 */ - return slash ? atoi(slash + 1) : 0; + if (slash++) { + if (*slash == '-') { + if (strict_port) + return -EINVAL; + *is_dump_all = false; + return 0; + } + + if (isdigit(*slash)) { + *is_dump_all = false; + *port = atoi(slash); + } + if (!*port && strlen(slash)) + return -EINVAL; + } + return 0; } static struct dev_map *dev_map_alloc(const char *dev_name) @@ -152,7 +183,7 @@ void rd_free(struct rd *rd) dev_map_cleanup(rd); } -int rd_exec_link(struct rd *rd, int (*cb)(struct rd *rd)) +int rd_exec_link(struct rd *rd, int (*cb)(struct rd *rd), bool strict_port) { struct dev_map *dev_map; uint32_t port; @@ -163,7 +194,8 @@ int rd_exec_link(struct rd *rd, int (*cb)(struct rd *rd)) if (rd_no_arg(rd)) { list_for_each_entry(dev_map, &rd->dev_map_list, list) { rd->dev_idx = dev_map->idx; - for (port = 1; port < dev_map->num_ports + 1; port++) { + port = (strict_port) ? 1 : 0; + for (; port < dev_map->num_ports + 1; port++) { rd->port_idx = port; ret = cb(rd); if (ret) @@ -172,21 +204,23 @@ int rd_exec_link(struct rd *rd, int (*cb)(struct rd *rd)) } } else { + bool is_dump_all; + dev_map = dev_map_lookup(rd, true); - port = get_port_from_argv(rd); - if (!dev_map || port > dev_map->num_ports) { + ret = get_port_from_argv(rd, &port, &is_dump_all, strict_port); + if (!dev_map || port > dev_map->num_ports || (!port && ret)) { pr_err("Wrong device name\n"); ret = -ENOENT; goto out; } rd_arg_inc(rd); rd->dev_idx = dev_map->idx; - rd->port_idx = port ? : 1; + rd->port_idx = port; for (; rd->port_idx < dev_map->num_ports + 1; rd->port_idx++) { ret = cb(rd); if (ret) goto out; - if (port) + if (!is_dump_all) /* * We got request to show link for devname * with port index. From 5f4892e2c8d4fb22118713e0c83290b352fe0e34 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 31 Jan 2018 10:11:48 +0200 Subject: [PATCH 07/20] rdma: Make visible the number of arguments Signed-off-by: Leon Romanovsky Signed-off-by: Stephen Hemminger --- rdma/rdma.h | 1 + rdma/utils.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rdma/rdma.h b/rdma/rdma.h index cbd9aa89..1b66ae04 100644 --- a/rdma/rdma.h +++ b/rdma/rdma.h @@ -74,6 +74,7 @@ int rd_exec_cmd(struct rd *rd, const struct rd_cmd *c, const char *str); int rd_exec_dev(struct rd *rd, int (*cb)(struct rd *rd)); int rd_exec_link(struct rd *rd, int (*cb)(struct rd *rd), bool strict_port); void rd_free(struct rd *rd); +int rd_argc(struct rd *rd); /* * Device manipulation diff --git a/rdma/utils.c b/rdma/utils.c index b9c668a3..af2b374d 100644 --- a/rdma/utils.c +++ b/rdma/utils.c @@ -12,7 +12,7 @@ #include "rdma.h" #include -static int rd_argc(struct rd *rd) +int rd_argc(struct rd *rd) { return rd->argc; } From 1174be72d1b4ccb1b078c569bd785445416e85af Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 31 Jan 2018 10:11:49 +0200 Subject: [PATCH 08/20] rdma: Add filtering infrastructure This patch adds general infrastructure to RDMAtool to handle various filtering options needed for the downstream resource tracking patches. The infrastructure is generic and stores filters in list of key<->value entries. There are three types of filters: 1. Numeric - the values are intended to be digits combined with '-' to mark range and ',' to mark multiple entries, e.g. pid 1-100,234,400-401 is perfectly legit filter to limit process ids. 2. String - the values are consist from strings and "," as a denominator. 3. Link - special case to allow '/' in string to provide link name, e.g. link mlx4_1/2. Signed-off-by: Leon Romanovsky Signed-off-by: Stephen Hemminger --- rdma/rdma.c | 1 + rdma/rdma.h | 20 +++++ rdma/utils.c | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 250 insertions(+) diff --git a/rdma/rdma.c b/rdma/rdma.c index 0e8fd688..a21ba440 100644 --- a/rdma/rdma.c +++ b/rdma/rdma.c @@ -47,6 +47,7 @@ static int rd_init(struct rd *rd, int argc, char **argv, char *filename) rd->argc = argc; rd->argv = argv; INIT_LIST_HEAD(&rd->dev_map_list); + INIT_LIST_HEAD(&rd->filter_list); if (rd->json_output) { rd->jw = jsonw_new(stdout); diff --git a/rdma/rdma.h b/rdma/rdma.h index 1b66ae04..8e60ce26 100644 --- a/rdma/rdma.h +++ b/rdma/rdma.h @@ -29,6 +29,18 @@ #define RDMA_BITMAP_ENUM(name, bit_no) RDMA_BITMAP_##name = BIT(bit_no), #define RDMA_BITMAP_NAMES(name, bit_no) [bit_no] = #name, +#define MAX_NUMBER_OF_FILTERS 64 +struct filters { + char name[32]; + bool is_number; +}; + +struct filter_entry { + struct list_head list; + char *key; + char *value; +}; + struct dev_map { struct list_head list; char *dev_name; @@ -50,6 +62,7 @@ struct rd { json_writer_t *jw; bool json_output; bool pretty_output; + struct list_head filter_list; }; struct rd_cmd { @@ -81,6 +94,13 @@ int rd_argc(struct rd *rd); */ struct dev_map *dev_map_lookup(struct rd *rd, bool allow_port_index); +/* + * Filter manipulation + */ +int rd_build_filter(struct rd *rd, const struct filters valid_filters[]); +bool rd_check_is_filtered(struct rd *rd, const char *key, uint32_t val); +bool rd_check_is_string_filtered(struct rd *rd, const char *key, const char *val); +bool rd_check_is_key_exist(struct rd *rd, const char *key); /* * Netlink */ diff --git a/rdma/utils.c b/rdma/utils.c index af2b374d..157699c0 100644 --- a/rdma/utils.c +++ b/rdma/utils.c @@ -114,6 +114,234 @@ static void dev_map_cleanup(struct rd *rd) } } +static int add_filter(struct rd *rd, char *key, char *value, + const struct filters valid_filters[]) +{ + char cset[] = "1234567890,-"; + struct filter_entry *fe; + bool key_found = false; + int idx = 0; + int ret; + + fe = calloc(1, sizeof(*fe)); + if (!fe) + return -ENOMEM; + + while (idx < MAX_NUMBER_OF_FILTERS && valid_filters[idx].name) { + if (!strcmpx(key, valid_filters[idx].name)) { + key_found = true; + break; + } + idx++; + } + if (!key_found) { + pr_err("Unsupported filter option: %s\n", key); + ret = -EINVAL; + goto err; + } + + /* + * Check the filter validity, not optimal, but works + * + * Actually, there are three types of filters + * numeric - for example PID or QPN + * string - for example states + * link - user requested to filter on specific link + * e.g. mlx5_1/1, mlx5_1/-, mlx5_1 ... + */ + if (valid_filters[idx].is_number && + strspn(value, cset) != strlen(value)) { + pr_err("%s filter accepts \"%s\" characters only\n", key, cset); + ret = -EINVAL; + goto err; + } + + fe->key = strdup(key); + fe->value = strdup(value); + if (!fe->key || !fe->value) { + ret = -ENOMEM; + goto err_alloc; + } + + for (idx = 0; idx < strlen(fe->value); idx++) + fe->value[idx] = tolower(fe->value[idx]); + + list_add_tail(&fe->list, &rd->filter_list); + return 0; + +err_alloc: + free(fe->value); + free(fe->key); +err: + free(fe); + return ret; +} + +int rd_build_filter(struct rd *rd, const struct filters valid_filters[]) +{ + int ret = 0; + int idx = 0; + + if (!valid_filters || !rd_argc(rd)) + goto out; + + if (rd_argc(rd) == 1) { + pr_err("No filter data was supplied to filter option %s\n", rd_argv(rd)); + ret = -EINVAL; + goto out; + } + + if (rd_argc(rd) % 2) { + pr_err("There is filter option without data\n"); + ret = -EINVAL; + goto out; + } + + while (idx != rd_argc(rd)) { + /* + * We can do micro-optimization and skip "dev" + * and "link" filters, but it is not worth of it. + */ + ret = add_filter(rd, *(rd->argv + idx), + *(rd->argv + idx + 1), valid_filters); + if (ret) + goto out; + idx += 2; + } + +out: + return ret; +} + +bool rd_check_is_key_exist(struct rd *rd, const char *key) +{ + struct filter_entry *fe; + + list_for_each_entry(fe, &rd->filter_list, list) { + if (!strcmpx(fe->key, key)) + return true; + } + + return false; +} + +/* + * Check if string entry is filtered: + * * key doesn't exist -> user didn't request -> not filtered + */ +bool rd_check_is_string_filtered(struct rd *rd, + const char *key, const char *val) +{ + bool key_is_filtered = false; + struct filter_entry *fe; + char *p = NULL; + char *str; + + list_for_each_entry(fe, &rd->filter_list, list) { + if (!strcmpx(fe->key, key)) { + /* We found the key */ + p = strdup(fe->value); + key_is_filtered = true; + if (!p) { + /* + * Something extremely wrong if we fail + * to allocate small amount of bytes. + */ + pr_err("Found key, but failed to allocate memory to store value\n"); + return key_is_filtered; + } + + /* + * Need to check if value in range + * It can come in the following formats + * and their permutations: + * str + * str1,str2 + */ + str = strtok(p, ","); + while (str) { + if (strlen(str) == strlen(val) && + !strcasecmp(str, val)) { + key_is_filtered = false; + goto out; + } + str = strtok(NULL, ","); + } + goto out; + } + } + +out: + free(p); + return key_is_filtered; +} + +/* + * Check if key is filtered: + * key doesn't exist -> user didn't request -> not filtered + */ +bool rd_check_is_filtered(struct rd *rd, const char *key, uint32_t val) +{ + bool key_is_filtered = false; + struct filter_entry *fe; + + list_for_each_entry(fe, &rd->filter_list, list) { + uint32_t left_val = 0, fe_value = 0; + bool range_check = false; + char *p = fe->value; + + if (!strcmpx(fe->key, key)) { + /* We found the key */ + key_is_filtered = true; + /* + * Need to check if value in range + * It can come in the following formats + * (and their permutations): + * numb + * numb1,numb2 + * ,numb1,numb2 + * numb1-numb2 + * numb1,numb2-numb3,numb4-numb5 + */ + while (*p) { + if (isdigit(*p)) { + fe_value = strtol(p, &p, 10); + if (fe_value == val || + (range_check && left_val < val && + val < fe_value)) { + key_is_filtered = false; + goto out; + } + range_check = false; + } else { + if (*p == '-') { + left_val = fe_value; + range_check = true; + } + p++; + } + } + goto out; + } + } + +out: + return key_is_filtered; +} + +static void filters_cleanup(struct rd *rd) +{ + struct filter_entry *fe, *tmp; + + list_for_each_entry_safe(fe, tmp, + &rd->filter_list, list) { + list_del(&fe->list); + free(fe->key); + free(fe->value); + free(fe); + } +} + static const enum mnl_attr_data_type nldev_policy[RDMA_NLDEV_ATTR_MAX] = { [RDMA_NLDEV_ATTR_DEV_INDEX] = MNL_TYPE_U32, [RDMA_NLDEV_ATTR_DEV_NAME] = MNL_TYPE_NUL_STRING, @@ -181,6 +409,7 @@ void rd_free(struct rd *rd) return; free(rd->buff); dev_map_cleanup(rd); + filters_cleanup(rd); } int rd_exec_link(struct rd *rd, int (*cb)(struct rd *rd), bool strict_port) From 6e0de6e886571cab7787f9b809b6db5e05b2444c Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 31 Jan 2018 10:11:50 +0200 Subject: [PATCH 09/20] rdma: Set pointer to device name position The dev and link execution callbacks expects that next command line argument is device or port name. Set pointer to device or port name position prior calls to rd_exec_dev()/rd_exec_link(). Signed-off-by: Leon Romanovsky Signed-off-by: Stephen Hemminger --- rdma/rdma.h | 1 + rdma/utils.c | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/rdma/rdma.h b/rdma/rdma.h index 8e60ce26..35506a96 100644 --- a/rdma/rdma.h +++ b/rdma/rdma.h @@ -87,6 +87,7 @@ int rd_exec_cmd(struct rd *rd, const struct rd_cmd *c, const char *str); int rd_exec_dev(struct rd *rd, int (*cb)(struct rd *rd)); int rd_exec_link(struct rd *rd, int (*cb)(struct rd *rd), bool strict_port); void rd_free(struct rd *rd); +int rd_set_arg_to_devname(struct rd *rd); int rd_argc(struct rd *rd); /* diff --git a/rdma/utils.c b/rdma/utils.c index 157699c0..f93f05e1 100644 --- a/rdma/utils.c +++ b/rdma/utils.c @@ -412,6 +412,25 @@ void rd_free(struct rd *rd) filters_cleanup(rd); } +int rd_set_arg_to_devname(struct rd *rd) +{ + int ret = 0; + + while (!rd_no_arg(rd)) { + if (rd_argv_match(rd, "dev") || rd_argv_match(rd, "link")) { + rd_arg_inc(rd); + if (rd_no_arg(rd)) { + pr_err("No device name was supplied\n"); + ret = -EINVAL; + } + goto out; + } + rd_arg_inc(rd); + } +out: + return ret; +} + int rd_exec_link(struct rd *rd, int (*cb)(struct rd *rd), bool strict_port) { struct dev_map *dev_map; From 684d82094b0e0788c5e7f0eee07d8d51375d6878 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 31 Jan 2018 10:11:51 +0200 Subject: [PATCH 10/20] rdma: Allow external usage of compare string routine Signed-off-by: Leon Romanovsky Signed-off-by: Stephen Hemminger --- rdma/rdma.h | 2 ++ rdma/utils.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rdma/rdma.h b/rdma/rdma.h index 35506a96..d2cde895 100644 --- a/rdma/rdma.h +++ b/rdma/rdma.h @@ -90,6 +90,8 @@ void rd_free(struct rd *rd); int rd_set_arg_to_devname(struct rd *rd); int rd_argc(struct rd *rd); +int strcmpx(const char *str1, const char *str2); + /* * Device manipulation */ diff --git a/rdma/utils.c b/rdma/utils.c index f93f05e1..9e15b7cf 100644 --- a/rdma/utils.c +++ b/rdma/utils.c @@ -24,7 +24,7 @@ char *rd_argv(struct rd *rd) return *rd->argv; } -static int strcmpx(const char *str1, const char *str2) +int strcmpx(const char *str1, const char *str2) { if (strlen(str1) > strlen(str2)) return -1; From 923aa825ffc02cbfb8f557fdc75a9889af883b3d Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 31 Jan 2018 10:11:53 +0200 Subject: [PATCH 11/20] rdma: Add resource tracking summary The global resource summary information. The object names, current utilization and maximum numbers are received as is from the kernel. $ rdma res 1: mlx5_0: pd 3 cq 5 qp 4 2: mlx5_1: pd 3 cq 5 qp 4 3: mlx5_2: pd 3 cq 5 qp 4 4: mlx5_3: pd 2 cq 3 qp 2 5: mlx5_4: pd 3 cq 5 qp 4 $ rdma res show mlx5_4 5: mlx5_4: pd 3 cq 5 qp 44 Signed-off-by: Leon Romanovsky Signed-off-by: Stephen Hemminger --- rdma/Makefile | 2 +- rdma/rdma.c | 3 +- rdma/rdma.h | 1 + rdma/res.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++ rdma/utils.c | 4 ++ 5 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 rdma/res.c diff --git a/rdma/Makefile b/rdma/Makefile index 454f25f8..360f09b2 100644 --- a/rdma/Makefile +++ b/rdma/Makefile @@ -5,7 +5,7 @@ TARGETS := ifeq ($(HAVE_MNL),y) -RDMA_OBJ = rdma.o utils.o dev.o link.o +RDMA_OBJ = rdma.o utils.o dev.o link.o res.o TARGETS += rdma endif diff --git a/rdma/rdma.c b/rdma/rdma.c index a21ba440..19608f41 100644 --- a/rdma/rdma.c +++ b/rdma/rdma.c @@ -15,7 +15,7 @@ static void help(char *name) { pr_out("Usage: %s [ OPTIONS ] OBJECT { COMMAND | help }\n" - "where OBJECT := { dev | link | help }\n" + "where OBJECT := { dev | link | resource | help }\n" " OPTIONS := { -V[ersion] | -d[etails] | -j[son] | -p[retty]}\n", name); } @@ -32,6 +32,7 @@ static int rd_cmd(struct rd *rd) { "help", cmd_help }, { "dev", cmd_dev }, { "link", cmd_link }, + { "resource", cmd_res }, { 0 } }; diff --git a/rdma/rdma.h b/rdma/rdma.h index d2cde895..5809f706 100644 --- a/rdma/rdma.h +++ b/rdma/rdma.h @@ -83,6 +83,7 @@ char *rd_argv(struct rd *rd); */ int cmd_dev(struct rd *rd); int cmd_link(struct rd *rd); +int cmd_res(struct rd *rd); int rd_exec_cmd(struct rd *rd, const struct rd_cmd *c, const char *str); int rd_exec_dev(struct rd *rd, int (*cb)(struct rd *rd)); int rd_exec_link(struct rd *rd, int (*cb)(struct rd *rd), bool strict_port); diff --git a/rdma/res.c b/rdma/res.c new file mode 100644 index 00000000..bd97c58e --- /dev/null +++ b/rdma/res.c @@ -0,0 +1,161 @@ +/* + * res.c RDMA tool + * + * 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: Leon Romanovsky + */ + +#include "rdma.h" +#include + +static int res_help(struct rd *rd) +{ + pr_out("Usage: %s resource\n", rd->filename); + pr_out(" resource show [DEV]\n"); + return 0; +} + +static int res_print_summary(struct rd *rd, struct nlattr **tb) +{ + struct nlattr *nla_table = tb[RDMA_NLDEV_ATTR_RES_SUMMARY]; + struct nlattr *nla_entry; + const char *name; + uint64_t curr; + int err; + + mnl_attr_for_each_nested(nla_entry, nla_table) { + struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {}; + char json_name[32]; + + err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line); + if (err != MNL_CB_OK) + return -EINVAL; + + if (!nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME] || + !nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR]) { + return -EINVAL; + } + + name = mnl_attr_get_str(nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME]); + curr = mnl_attr_get_u64(nla_line[RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR]); + if (rd->json_output) { + snprintf(json_name, 32, "%s", name); + jsonw_lluint_field(rd->jw, json_name, curr); + } else { + pr_out("%s %"PRId64 " ", name, curr); + } + } + return 0; +} + +static int res_no_args_parse_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {}; + struct rd *rd = data; + const char *name; + uint32_t idx; + + mnl_attr_parse(nlh, 0, rd_attr_cb, tb); + if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || + !tb[RDMA_NLDEV_ATTR_DEV_NAME] || + !tb[RDMA_NLDEV_ATTR_RES_SUMMARY]) + return MNL_CB_ERROR; + + idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); + name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]); + if (rd->json_output) { + jsonw_uint_field(rd->jw, "ifindex", idx); + jsonw_string_field(rd->jw, "ifname", name); + } else { + pr_out("%u: %s: ", idx, name); + } + + res_print_summary(rd, tb); + + if (!rd->json_output) + pr_out("\n"); + return MNL_CB_OK; +} + +static int _res_send_msg(struct rd *rd, uint32_t command, mnl_cb_t callback) +{ + uint32_t flags = NLM_F_REQUEST | NLM_F_ACK; + uint32_t seq; + int ret; + + if (command != RDMA_NLDEV_CMD_RES_GET) + flags |= NLM_F_DUMP; + + rd_prepare_msg(rd, command, &seq, flags); + mnl_attr_put_u32(rd->nlh, RDMA_NLDEV_ATTR_DEV_INDEX, rd->dev_idx); + if (rd->port_idx) + mnl_attr_put_u32(rd->nlh, + RDMA_NLDEV_ATTR_PORT_INDEX, rd->port_idx); + + ret = rd_send_msg(rd); + if (ret) + return ret; + + if (rd->json_output) + jsonw_start_object(rd->jw); + ret = rd_recv_msg(rd, callback, rd, seq); + if (rd->json_output) + jsonw_end_object(rd->jw); + return ret; +} + +#define RES_FUNC(name, command, valid_filters, strict_port) \ + static int _##name(struct rd *rd)\ + { \ + return _res_send_msg(rd, command, name##_parse_cb); \ + } \ + static int name(struct rd *rd) \ + {\ + int ret = rd_build_filter(rd, valid_filters); \ + if (ret) \ + return ret; \ + if ((uintptr_t)valid_filters != (uintptr_t)NULL) { \ + ret = rd_set_arg_to_devname(rd); \ + if (ret) \ + return ret;\ + } \ + if (strict_port) \ + return rd_exec_dev(rd, _##name); \ + else \ + return rd_exec_link(rd, _##name, strict_port); \ + } + +RES_FUNC(res_no_args, RDMA_NLDEV_CMD_RES_GET, NULL, true); + +static int res_show(struct rd *rd) +{ + const struct rd_cmd cmds[] = { + { NULL, res_no_args }, + { 0 } + }; + + /* + * Special case to support "rdma res show DEV_NAME" + */ + if (rd_argc(rd) == 1 && dev_map_lookup(rd, false)) + return rd_exec_dev(rd, _res_no_args); + + return rd_exec_cmd(rd, cmds, "parameter"); +} + +int cmd_res(struct rd *rd) +{ + const struct rd_cmd cmds[] = { + { NULL, res_show }, + { "show", res_show }, + { "list", res_show }, + { "help", res_help }, + { 0 } + }; + + return rd_exec_cmd(rd, cmds, "resource command"); +} diff --git a/rdma/utils.c b/rdma/utils.c index 9e15b7cf..344f0a93 100644 --- a/rdma/utils.c +++ b/rdma/utils.c @@ -356,6 +356,10 @@ static const enum mnl_attr_data_type nldev_policy[RDMA_NLDEV_ATTR_MAX] = { [RDMA_NLDEV_ATTR_PORT_STATE] = MNL_TYPE_U8, [RDMA_NLDEV_ATTR_PORT_PHYS_STATE] = MNL_TYPE_U8, [RDMA_NLDEV_ATTR_DEV_NODE_TYPE] = MNL_TYPE_U8, + [RDMA_NLDEV_ATTR_RES_SUMMARY] = MNL_TYPE_NESTED, + [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY] = MNL_TYPE_NESTED, + [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME] = MNL_TYPE_NUL_STRING, + [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR] = MNL_TYPE_U64, }; int rd_attr_cb(const struct nlattr *attr, void *data) From 8ecac46a60ff79c23b8f7fc19dfab7858739246a Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 31 Jan 2018 10:11:54 +0200 Subject: [PATCH 12/20] rdma: Add QP resource tracking information This patch adds ss-similar interface to view various resource tracked objects. At this stage, only QP is presented. 1. Get all QPs for the specific device: $ rdma res show qp link mlx5_4 link mlx5_4/- lqpn 8 type UD state RESET sq-psn 0 pid 0 comm [ib_ipoib] link mlx5_4/1 lqpn 7 type UD state RTS sq-psn 0 pid 0 comm [ib_core] link mlx5_4/1 lqpn 1 type GSI state RTS sq-psn 0 pid 0 comm [ib_core] link mlx5_4/1 lqpn 0 type SMI state RTS sq-psn 0 pid 0 comm [ib_core] $ rdma res show qp link mlx5_4/ link mlx5_4/- lqpn 8 type UD state RESET sq-psn 0 pid 0 comm [ib_ipoib] link mlx5_4/1 lqpn 7 type UD state RTS sq-psn 0 pid 0 comm [ib_core] link mlx5_4/1 lqpn 1 type GSI state RTS sq-psn 0 pid 0 comm [ib_core] link mlx5_4/1 lqpn 0 type SMI state RTS sq-psn 0 pid 0 comm [ib_core] 2. Provide illegal port number (0 is illegal): $ rdma res show qp link mlx5_4/0 Wrong device name 3. Get QPs of specific port: $ rdma res show qp link mlx5_4/1 link mlx5_4/1 lqpn 7 type UD state RTS sq-psn 0 pid 0 comm [ib_core] link mlx5_4/1 lqpn 1 type GSI state RTS sq-psn 0 pid 0 comm [ib_core] link mlx5_4/1 lqpn 0 type SMI state RTS sq-psn 0 pid 0 comm [ib_core] 4. Get QPs which have not assigned port yet: link mlx5_4/- lqpn 8 type UD state RESET sq-psn 0 pid 0 comm [ib_ipoib] 5. Limit to specific Local QPNs: $ rdma res show qp link mlx5_4/1 lqpn 1-3,7 link mlx5_4/1 lqpn 7 type UD state RTS sq-psn 0 pid 0 comm [ib_core] link mlx5_4/1 lqpn 1 type GSI state RTS sq-psn 0 pid 0 comm [ib_core] link mlx5_4/1 lqpn 0 type SMI state RTS sq-psn 0 pid 0 comm [ib_core] . Filter types (strings): $ rdma res show qp link mlx5_4/1 type UD,gSi link mlx5_4/1 lqpn 7 type UD state RTS sq-psn 0 pid 0 comm [ib_core] link mlx5_4/1 lqpn 1 type GSI state RTS sq-psn 0 pid 0 comm [ib_core] Signed-off-by: Leon Romanovsky Signed-off-by: Stephen Hemminger --- rdma/res.c | 325 +++++++++++++++++++++++++++++++++++++++++++++++++++ rdma/utils.c | 11 ++ 2 files changed, 336 insertions(+) diff --git a/rdma/res.c b/rdma/res.c index bd97c58e..2a63e712 100644 --- a/rdma/res.c +++ b/rdma/res.c @@ -16,6 +16,9 @@ static int res_help(struct rd *rd) { pr_out("Usage: %s resource\n", rd->filename); pr_out(" resource show [DEV]\n"); + pr_out(" resource show [qp]\n"); + pr_out(" resource show qp link [DEV/PORT]\n"); + pr_out(" resource show qp link [DEV/PORT] [FILTER-NAME FILTER-VALUE]\n"); return 0; } @@ -129,12 +132,334 @@ static int _res_send_msg(struct rd *rd, uint32_t command, mnl_cb_t callback) return rd_exec_link(rd, _##name, strict_port); \ } +static const char *path_mig_to_str(uint8_t idx) +{ + static const char * const path_mig_str[] = { "MIGRATED", + "REARM", "ARMED" }; + + if (idx < ARRAY_SIZE(path_mig_str)) + return path_mig_str[idx]; + return "UNKNOWN"; +} + +static const char *qp_states_to_str(uint8_t idx) +{ + static const char * const qp_states_str[] = { "RESET", "INIT", + "RTR", "RTS", "SQD", + "SQE", "ERR" }; + + if (idx < ARRAY_SIZE(qp_states_str)) + return qp_states_str[idx]; + return "UNKNOWN"; +} + +static const char *qp_types_to_str(uint8_t idx) +{ + static const char * const qp_types_str[] = { "SMI", "GSI", "RC", + "UC", "UD", "RAW_IPV6", + "RAW_ETHERTYPE", + "UNKNOWN", "RAW_PACKET", + "XRC_INI", "XRC_TGT" }; + + if (idx < ARRAY_SIZE(qp_types_str)) + return qp_types_str[idx]; + return "UNKNOWN"; +} + +static void print_lqpn(struct rd *rd, uint32_t val) +{ + if (rd->json_output) + jsonw_uint_field(rd->jw, "lqpn", val); + else + pr_out("lqpn %u ", val); +} + +static void print_rqpn(struct rd *rd, uint32_t val, struct nlattr **nla_line) +{ + if (!nla_line[RDMA_NLDEV_ATTR_RES_RQPN]) + return; + + if (rd->json_output) + jsonw_uint_field(rd->jw, "rqpn", val); + else + pr_out("rqpn %u ", val); +} + +static void print_type(struct rd *rd, uint32_t val) +{ + if (rd->json_output) + jsonw_string_field(rd->jw, "type", + qp_types_to_str(val)); + else + pr_out("type %s ", qp_types_to_str(val)); +} + +static void print_state(struct rd *rd, uint32_t val) +{ + if (rd->json_output) + jsonw_string_field(rd->jw, "state", + qp_states_to_str(val)); + else + pr_out("state %s ", qp_states_to_str(val)); +} + +static void print_rqpsn(struct rd *rd, uint32_t val, struct nlattr **nla_line) +{ + if (!nla_line[RDMA_NLDEV_ATTR_RES_RQ_PSN]) + return; + + if (rd->json_output) + jsonw_uint_field(rd->jw, "rq-psn", val); + else + pr_out("rq-psn %u ", val); +} + +static void print_sqpsn(struct rd *rd, uint32_t val) +{ + if (rd->json_output) + jsonw_uint_field(rd->jw, "sq-psn", val); + else + pr_out("sq-psn %u ", val); +} + +static void print_pathmig(struct rd *rd, uint32_t val, + struct nlattr **nla_line) +{ + if (!nla_line[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE]) + return; + + if (rd->json_output) + jsonw_string_field(rd->jw, + "path-mig-state", + path_mig_to_str(val)); + else + pr_out("path-mig-state %s ", path_mig_to_str(val)); +} + +static void print_pid(struct rd *rd, uint32_t val) +{ + if (rd->json_output) + jsonw_uint_field(rd->jw, "pid", val); + else + pr_out("pid %u ", val); +} + +static void print_comm(struct rd *rd, const char *str, + struct nlattr **nla_line) +{ + char tmp[18]; + + if (rd->json_output) { + /* Don't beatify output in JSON format */ + jsonw_string_field(rd->jw, "comm", str); + return; + } + + if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) + snprintf(tmp, sizeof(tmp), "%s", str); + else + snprintf(tmp, sizeof(tmp), "[%s]", str); + + pr_out("comm %s ", tmp); +} + +static void print_link(struct rd *rd, uint32_t idx, const char *name, + uint32_t port, struct nlattr **nla_line) +{ + if (rd->json_output) { + jsonw_uint_field(rd->jw, "ifindex", idx); + + if (nla_line[RDMA_NLDEV_ATTR_PORT_INDEX]) + jsonw_uint_field(rd->jw, "port", port); + + jsonw_string_field(rd->jw, "ifname", name); + } else { + if (nla_line[RDMA_NLDEV_ATTR_PORT_INDEX]) + pr_out("link %s/%u ", name, port); + else + pr_out("link %s/- ", name); + } +} + +static char *get_task_name(uint32_t pid) +{ + char *comm; + FILE *f; + + if (asprintf(&comm, "/proc/%d/comm", pid) < 0) + return NULL; + + f = fopen(comm, "r"); + free(comm); + if (!f) + return NULL; + + if (fscanf(f, "%ms\n", &comm) != 1) + comm = NULL; + + fclose(f); + + return comm; +} + +static int res_qp_parse_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[RDMA_NLDEV_ATTR_MAX] = {}; + struct nlattr *nla_table, *nla_entry; + struct rd *rd = data; + const char *name; + uint32_t idx; + + mnl_attr_parse(nlh, 0, rd_attr_cb, tb); + if (!tb[RDMA_NLDEV_ATTR_DEV_INDEX] || + !tb[RDMA_NLDEV_ATTR_DEV_NAME] || + !tb[RDMA_NLDEV_ATTR_RES_QP]) + return MNL_CB_ERROR; + + name = mnl_attr_get_str(tb[RDMA_NLDEV_ATTR_DEV_NAME]); + idx = mnl_attr_get_u32(tb[RDMA_NLDEV_ATTR_DEV_INDEX]); + nla_table = tb[RDMA_NLDEV_ATTR_RES_QP]; + + mnl_attr_for_each_nested(nla_entry, nla_table) { + struct nlattr *nla_line[RDMA_NLDEV_ATTR_MAX] = {}; + uint32_t lqpn, rqpn = 0, rq_psn = 0, sq_psn; + uint8_t type, state, path_mig_state = 0; + uint32_t port = 0, pid = 0; + char *comm = NULL; + int err; + + err = mnl_attr_parse_nested(nla_entry, rd_attr_cb, nla_line); + if (err != MNL_CB_OK) + return MNL_CB_ERROR; + + if (!nla_line[RDMA_NLDEV_ATTR_RES_LQPN] || + !nla_line[RDMA_NLDEV_ATTR_RES_SQ_PSN] || + !nla_line[RDMA_NLDEV_ATTR_RES_TYPE] || + !nla_line[RDMA_NLDEV_ATTR_RES_STATE] || + (!nla_line[RDMA_NLDEV_ATTR_RES_PID] && + !nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME])) { + return MNL_CB_ERROR; + } + + if (nla_line[RDMA_NLDEV_ATTR_PORT_INDEX]) + port = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_PORT_INDEX]); + + if (port != rd->port_idx) + continue; + + lqpn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_LQPN]); + if (rd_check_is_filtered(rd, "lqpn", lqpn)) + continue; + + if (nla_line[RDMA_NLDEV_ATTR_RES_RQPN]) { + rqpn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_RQPN]); + if (rd_check_is_filtered(rd, "rqpn", rqpn)) + continue; + } else { + if (rd_check_is_key_exist(rd, "rqpn")) + continue; + } + + if (nla_line[RDMA_NLDEV_ATTR_RES_RQ_PSN]) { + rq_psn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_RQ_PSN]); + if (rd_check_is_filtered(rd, "rq-psn", rq_psn)) + continue; + } else { + if (rd_check_is_key_exist(rd, "rq-psn")) + continue; + } + + sq_psn = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_SQ_PSN]); + if (rd_check_is_filtered(rd, "sq-psn", sq_psn)) + continue; + + if (nla_line[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE]) { + path_mig_state = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE]); + if (rd_check_is_string_filtered(rd, "path-mig-state", path_mig_to_str(path_mig_state))) + continue; + } else { + if (rd_check_is_key_exist(rd, "path-mig-state")) + continue; + } + + type = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_TYPE]); + if (rd_check_is_string_filtered(rd, "type", qp_types_to_str(type))) + continue; + + state = mnl_attr_get_u8(nla_line[RDMA_NLDEV_ATTR_RES_STATE]); + if (rd_check_is_string_filtered(rd, "state", qp_states_to_str(state))) + continue; + + if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) { + pid = mnl_attr_get_u32(nla_line[RDMA_NLDEV_ATTR_RES_PID]); + comm = get_task_name(pid); + } + + if (rd_check_is_filtered(rd, "pid", pid)) + continue; + + if (nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]) + /* discard const from mnl_attr_get_str */ + comm = (char *)mnl_attr_get_str(nla_line[RDMA_NLDEV_ATTR_RES_KERN_NAME]); + + if (rd->json_output) + jsonw_start_array(rd->jw); + + print_link(rd, idx, name, port, nla_line); + + print_lqpn(rd, lqpn); + print_rqpn(rd, rqpn, nla_line); + + print_type(rd, type); + print_state(rd, state); + + print_rqpsn(rd, rq_psn, nla_line); + print_sqpsn(rd, sq_psn); + + print_pathmig(rd, path_mig_state, nla_line); + print_pid(rd, pid); + print_comm(rd, comm, nla_line); + + if (nla_line[RDMA_NLDEV_ATTR_RES_PID]) + free(comm); + + if (rd->json_output) + jsonw_end_array(rd->jw); + else + pr_out("\n"); + } + return MNL_CB_OK; +} + RES_FUNC(res_no_args, RDMA_NLDEV_CMD_RES_GET, NULL, true); +static const struct +filters qp_valid_filters[MAX_NUMBER_OF_FILTERS] = {{ .name = "link", + .is_number = false }, + { .name = "lqpn", + .is_number = true }, + { .name = "rqpn", + .is_number = true }, + { .name = "pid", + .is_number = true }, + { .name = "sq-psn", + .is_number = true }, + { .name = "rq-psn", + .is_number = true }, + { .name = "type", + .is_number = false }, + { .name = "path-mig-state", + .is_number = false }, + { .name = "state", + .is_number = false } }; + +RES_FUNC(res_qp, RDMA_NLDEV_CMD_RES_QP_GET, qp_valid_filters, false); + static int res_show(struct rd *rd) { const struct rd_cmd cmds[] = { { NULL, res_no_args }, + { "qp", res_qp }, { 0 } }; diff --git a/rdma/utils.c b/rdma/utils.c index 344f0a93..059aa788 100644 --- a/rdma/utils.c +++ b/rdma/utils.c @@ -360,6 +360,17 @@ static const enum mnl_attr_data_type nldev_policy[RDMA_NLDEV_ATTR_MAX] = { [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY] = MNL_TYPE_NESTED, [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_NAME] = MNL_TYPE_NUL_STRING, [RDMA_NLDEV_ATTR_RES_SUMMARY_ENTRY_CURR] = MNL_TYPE_U64, + [RDMA_NLDEV_ATTR_RES_QP] = MNL_TYPE_NESTED, + [RDMA_NLDEV_ATTR_RES_QP_ENTRY] = MNL_TYPE_NESTED, + [RDMA_NLDEV_ATTR_RES_LQPN] = MNL_TYPE_U32, + [RDMA_NLDEV_ATTR_RES_RQPN] = MNL_TYPE_U32, + [RDMA_NLDEV_ATTR_RES_RQ_PSN] = MNL_TYPE_U32, + [RDMA_NLDEV_ATTR_RES_SQ_PSN] = MNL_TYPE_U32, + [RDMA_NLDEV_ATTR_RES_PATH_MIG_STATE] = MNL_TYPE_U8, + [RDMA_NLDEV_ATTR_RES_TYPE] = MNL_TYPE_U8, + [RDMA_NLDEV_ATTR_RES_STATE] = MNL_TYPE_U8, + [RDMA_NLDEV_ATTR_RES_PID] = MNL_TYPE_U32, + [RDMA_NLDEV_ATTR_RES_KERN_NAME] = MNL_TYPE_NUL_STRING, }; int rd_attr_cb(const struct nlattr *attr, void *data) From 860676b4244540fd2a652fc5b76f10c73078c163 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 31 Jan 2018 10:11:55 +0200 Subject: [PATCH 13/20] rdma: Document resource tracking Spartan version of resource tracking documentation. Signed-off-by: Leon Romanovsky Signed-off-by: Stephen Hemminger --- man/man8/rdma-resource.8 | 86 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 man/man8/rdma-resource.8 diff --git a/man/man8/rdma-resource.8 b/man/man8/rdma-resource.8 new file mode 100644 index 00000000..ff5d25d7 --- /dev/null +++ b/man/man8/rdma-resource.8 @@ -0,0 +1,86 @@ +.TH RDMA\-RESOURCE 8 "26 Dec 2017" "iproute2" "Linux" +.SH NAME +rdma-resource \- rdma resource configuration +.SH SYNOPSIS +.sp +.ad l +.in +8 +.ti -8 +.B rdma +.RI "[ " OPTIONS " ]" +.B resource +.RI " { " COMMAND " | " +.BR help " }" +.sp + +.ti -8 +.IR OPTIONS " := { " +\fB\-j\fR[\fIson\fR] | +\fB\-d\fR[\fIetails\fR] } + +.ti -8 +.B rdma resource show +.RI "[ " DEV/PORT_INDEX " ]" + +.ti -8 +.B rdma resource help + +.SH "DESCRIPTION" +.SS rdma resource show - display rdma resource tracking information + +.PP +.I "DEV/PORT_INDEX" +- specifies the RDMA link to show. +If this argument is omitted all links are listed. + +.SH "EXAMPLES" +.PP +rdma resource show +.RS 4 +Shows summary for all devices on the system. +.RE +.PP +rdma resource show mlx5_2 +.RS 4 +Shows the state of specified rdma device. +.RE +.PP +rdma res show qp link mlx5_4 +.RS 4 +Get all QPs for the specific device. +.RE +.PP +rdma res show qp link mlx5_4/1 +.RS 4 +Get QPs of specific port. +.RE +.PP +rdma res show qp link mlx5_4/0 +.RS 4 +Provide illegal port number (0 is illegal). +.RE +.PP +rdma res show qp link mlx5_4/- +.RS 4 +Get QPs which have not assigned port yet. +.RE +.PP +rdma res show qp link mlx5_4/- -d +.RS 4 +Detailed view. +.RE +.PP +rdma res show qp link mlx5_4/1 lqpn 0-6 +.RS 4 +Limit to specific Local QPNs. +.RE +.PP + +.SH SEE ALSO +.BR rdma (8), +.BR rdma-dev (8), +.BR rdma-link (8), +.br + +.SH AUTHOR +Leon Romanovsky From 5f8265536f6f511ec62d3a0ee7e1324a8720f7e3 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 31 Jan 2018 10:11:56 +0200 Subject: [PATCH 14/20] rdma: Check return value of strdup call Fixes: 74bd75c2b68d ("rdma: Add basic infrastructure for RDMA tool") Signed-off-by: Leon Romanovsky Signed-off-by: Stephen Hemminger --- rdma/utils.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rdma/utils.c b/rdma/utils.c index 059aa788..f9460162 100644 --- a/rdma/utils.c +++ b/rdma/utils.c @@ -98,6 +98,10 @@ static struct dev_map *dev_map_alloc(const char *dev_name) if (!dev_map) return NULL; dev_map->dev_name = strdup(dev_name); + if (!dev_map->dev_name) { + free(dev_map); + return NULL; + } return dev_map; } From 375d51caaaa7a381dbeab8fb622d3c6ff9597be7 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Tue, 6 Feb 2018 19:39:31 +0100 Subject: [PATCH 15/20] netns: allow negative nsid If the kernel receives a negative nsid it will automatically assign the next available nsid. In this case alloc_netid() will set min and max to 0 for ird_alloc(). And when max == 0 idr_alloc() will interpret this as the maximum range, i.e. specific to nsids it will try to find an id in the range [0,INT_MAX). This is intentionally supported in the kernel for nsids. Commit acbe9118ce80 ("ip netns: use strtol() instead of atoi()") regressed ip netns in that respect although previously the use-case was either accidentally supported or opaquely supported such that it triggered the original commit. From what I can gather it went as follows before: atoi() was called with a string indicating a negative value which caused it to return -1 which was passed to the kernel. Let's make it less opaque by introducing the keyword "auto": ip netns set auto will cause nsid to be set to -1 and the kernel will select an available nsid. Signed-off-by: Christian Brauner Signed-off-by: Stephen Hemminger --- ip/ipnetns.c | 5 ++++- man/man8/ip-netns.8 | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ip/ipnetns.c b/ip/ipnetns.c index 059a4220..631794b8 100644 --- a/ip/ipnetns.c +++ b/ip/ipnetns.c @@ -718,7 +718,10 @@ static int netns_set(int argc, char **argv) return -1; } name = argv[0]; - if (get_unsigned(&nsid, argv[1], 0)) + /* If a negative nsid is specified the kernel will select the nsid. */ + if (strcmp(argv[1], "auto") == 0) + nsid = -1; + else if (get_unsigned(&nsid, argv[1], 0)) invarg("Invalid \"netnsid\" value\n", argv[1]); snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name); diff --git a/man/man8/ip-netns.8 b/man/man8/ip-netns.8 index c5310e24..d539f18b 100644 --- a/man/man8/ip-netns.8 +++ b/man/man8/ip-netns.8 @@ -137,6 +137,7 @@ $ ip netns del net0 .sp This command assigns a id to a peer network namespace. This id is valid only in the current network namespace. +If the keyword "auto" is specified an available nsid will be chosen. This id will be used by the kernel in some netlink messages. If no id is assigned when the kernel needs it, it will be automatically assigned by the kernel. From 766fa4ac332540238908dffca627584ccfd495d2 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 13 Feb 2018 16:42:00 -0800 Subject: [PATCH 16/20] include: update rdma header from 4.16-rc1 Signed-off-by: Stephen Hemminger --- include/uapi/rdma/rdma_netlink.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/include/uapi/rdma/rdma_netlink.h b/include/uapi/rdma/rdma_netlink.h index b36d43a3..dbac3b82 100644 --- a/include/uapi/rdma/rdma_netlink.h +++ b/include/uapi/rdma/rdma_netlink.h @@ -227,16 +227,14 @@ enum rdma_nldev_command { RDMA_NLDEV_CMD_UNSPEC, RDMA_NLDEV_CMD_GET, /* can dump */ - RDMA_NLDEV_CMD_SET, - RDMA_NLDEV_CMD_NEW, - RDMA_NLDEV_CMD_DEL, - RDMA_NLDEV_CMD_PORT_GET, /* can dump */ - RDMA_NLDEV_CMD_PORT_SET, - RDMA_NLDEV_CMD_PORT_NEW, - RDMA_NLDEV_CMD_PORT_DEL, + /* 2 - 4 are free to use */ - RDMA_NLDEV_CMD_RES_GET, /* can dump */ + RDMA_NLDEV_CMD_PORT_GET = 5, /* can dump */ + + /* 6 - 8 are free to use */ + + RDMA_NLDEV_CMD_RES_GET = 9, /* can dump */ RDMA_NLDEV_CMD_RES_QP_GET, /* can dump */ From d7843207e6fda4ba22b88efbacd131b3c6d9c59f Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Fri, 9 Feb 2018 09:11:09 -0800 Subject: [PATCH 17/20] README: update location of git repositories, remove broken info link Reflect the recent change of location for the git repositories, and the creation of the -next development repo, in README and README.devel. Also remove the link to the Linux Foundation wiki that contained information about iproute2. The link is now broken, I did not find any alternative page to point to. Signed-off-by: Quentin Monnet Acked-by: David Ahern --- README | 10 +++++----- README.devel | 17 ++++++++++------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/README b/README index 386fbaf6..1b7f4427 100644 --- a/README +++ b/README @@ -1,13 +1,13 @@ This is a set of utilities for Linux networking. -Information: - http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2 - Download: http://www.kernel.org/pub/linux/utils/net/iproute2/ -Repository: - git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git +Stable version repository: + git://git.kernel.org/pub/scm/network/iproute2/iproute2.git + +Development repository: + git://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git How to compile this. -------------------- diff --git a/README.devel b/README.devel index 9b7d11e3..60c95468 100644 --- a/README.devel +++ b/README.devel @@ -4,12 +4,15 @@ development. Most new features require a kernel and a utility component. Please submit both to the Linux networking mailing list -The current source is in the git repository: - git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git +The current source for the stable version is in the git repository: + git://git.kernel.org/pub/scm/network/iproute2/iproute2.git -The master branch contains the source corresponding to the current -code in the mainline Linux kernel (ie follows Linus). The net-next -branch is a temporary branch that tracks the code intended for the -next release; it corresponds with networking development branch in -the kernel. +The development git repository is available at the following address: + git://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git +The stable repository contains the source corresponding to the +current code in the Linux networking tree (net), which in turn is +aligned on the mainline Linux kernel (ie follows Linus). +The iproute2-next repository tracks the code intended for the next +release; it corresponds with networking development tree (net-next) +in the kernel. From 8a237420f2051d6282262d33dbb3b10052fcfa61 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 9 Feb 2018 18:49:38 +0100 Subject: [PATCH 18/20] Remove leftovers from removed Latex documentation Since there is no documentation in Latex format left, there is no need to check for commands to build it. Also there is no need to ignore any of the temporary files which were created by them. Signed-off-by: Phil Sutter --- .gitignore | 10 ---------- configure | 17 ----------------- 2 files changed, 27 deletions(-) diff --git a/.gitignore b/.gitignore index f8c3dfca..e5234a3d 100644 --- a/.gitignore +++ b/.gitignore @@ -39,13 +39,3 @@ testsuite/results testsuite/iproute2/iproute2-this testsuite/tools/generate_nlmsg testsuite/tests/ip/link/dev_wo_vf_rate.nl - -# doc files generated at runtime -doc/*.aux -doc/*.log -doc/*.toc -doc/*.ps -doc/*.dvi -doc/*.html -doc/*.pdf -doc/*.out diff --git a/configure b/configure index d6832464..f7c2d7a7 100755 --- a/configure +++ b/configure @@ -17,18 +17,6 @@ check_prog() command -v $1 >/dev/null 2>&1 && (echo "$3:=y" >> $CONFIG; echo "yes") || (echo "no"; return 1) } -check_docs() -{ - if check_prog latex " latex: " HAVE_LATEX; then - check_prog pdflatex " pdflatex: " HAVE_PDFLATEX || echo " WARNING: no PDF docs can be built from LaTeX files" - check_prog sgml2latex " sgml2latex: " HAVE_SGML2LATEX || echo " WARNING: no LaTeX files can be build from SGML files" - else - echo " WARNING: no docs can be built from LaTeX files" - fi - - check_prog sgml2html " sgml2html: " HAVE_SGML2HTML || echo " WARNING: no HTML docs can be built from SGML" -} - check_toolchain() { : ${PKG_CONFIG:=pkg-config} @@ -422,11 +410,6 @@ check_berkeley_db echo -n "need for strlcpy: " check_strlcpy -echo -echo -n "docs:" -check_docs -echo - echo >> $CONFIG echo "%.o: %.c" >> $CONFIG echo ' $(QUIET_CC)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<' >> $CONFIG From a8beadb5f61d6efa9994c5bcff28a0f4e9d07c5a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 20 Feb 2018 10:48:32 -0800 Subject: [PATCH 19/20] uapi: update if_ether compat headers Signed-off-by: Stephen Hemminger --- include/uapi/linux/if_ether.h | 6 +++++- include/uapi/linux/libc-compat.h | 6 ------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h index 5f1d4af3..a34b152e 100644 --- a/include/uapi/linux/if_ether.h +++ b/include/uapi/linux/if_ether.h @@ -23,7 +23,6 @@ #define _LINUX_IF_ETHER_H #include -#include /* * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble @@ -151,6 +150,11 @@ * This is an Ethernet frame header. */ +/* allow libcs like musl to deactivate this, glibc does not implement this. */ +#ifndef __UAPI_DEF_ETHHDR +#define __UAPI_DEF_ETHHDR 1 +#endif + #if __UAPI_DEF_ETHHDR struct ethhdr { unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ diff --git a/include/uapi/linux/libc-compat.h b/include/uapi/linux/libc-compat.h index 5668ec3d..a1599911 100644 --- a/include/uapi/linux/libc-compat.h +++ b/include/uapi/linux/libc-compat.h @@ -264,10 +264,4 @@ #endif /* __GLIBC__ */ -/* Definitions for if_ether.h */ -/* allow libcs like musl to deactivate this, glibc does not implement this. */ -#ifndef __UAPI_DEF_ETHHDR -#define __UAPI_DEF_ETHHDR 1 -#endif - #endif /* _LIBC_COMPAT_H */ From 6bfa7a6b0ec28b75274dc270e0f5a6eaf147e557 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 20 Feb 2018 16:01:46 -0800 Subject: [PATCH 20/20] ip: remove dead code Remove long dead code (in #if 0) from original iproute2 for numeric names. Signed-off-by: Stephen Hemminger --- ip/ip.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ip/ip.c b/ip/ip.c index b15e6b66..ee0d6346 100644 --- a/ip/ip.c +++ b/ip/ip.c @@ -240,10 +240,6 @@ int main(int argc, char **argv) } else if (matches(opt, "-tshort") == 0) { ++timestamp; ++timestamp_short; -#if 0 - } else if (matches(opt, "-numeric") == 0) { - rtnl_names_numeric++; -#endif } else if (matches(opt, "-Version") == 0) { printf("ip utility, iproute2-ss%s\n", SNAPSHOT); exit(0);