From 0b9467d28440bf137b8eac41f08721b5dd837534 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 25 Nov 2016 17:53:50 +0200 Subject: [PATCH 01/11] Add devlink shared buffer patches Signed-off-by: Phil Sutter --- ...link-implement-shared-buffer-support.patch | 779 ++++++++++++++++++ ...ment-shared-buffer-occupancy-control.patch | 441 ++++++++++ devlink-kernel-headers.patch | 88 ++ iproute.spec | 18 +- 4 files changed, 1325 insertions(+), 1 deletion(-) create mode 100644 0001-devlink-implement-shared-buffer-support.patch create mode 100644 0002-devlink-implement-shared-buffer-occupancy-control.patch create mode 100644 devlink-kernel-headers.patch diff --git a/0001-devlink-implement-shared-buffer-support.patch b/0001-devlink-implement-shared-buffer-support.patch new file mode 100644 index 0000000..608518a --- /dev/null +++ b/0001-devlink-implement-shared-buffer-support.patch @@ -0,0 +1,779 @@ +From e6d7367d795a41abeea4acc1af8f3885c8918ba7 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Sat, 14 May 2016 15:21:01 +0200 +Subject: [PATCH 1/2] devlink: implement shared buffer support + +Implement kernel devlink shared buffer interface. Introduce new object +"sb" and allow to browse the shared buffer parameters and also change +configuration. + +Signed-off-by: Jiri Pirko +--- + devlink/devlink.c | 653 +++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 652 insertions(+), 1 deletion(-) + +diff --git a/devlink/devlink.c b/devlink/devlink.c +index 89a3083..ca3f586 100644 +--- a/devlink/devlink.c ++++ b/devlink/devlink.c +@@ -114,6 +114,13 @@ static void ifname_map_free(struct ifname_map *ifname_map) + #define DL_OPT_HANDLEP BIT(1) + #define DL_OPT_PORT_TYPE BIT(2) + #define DL_OPT_PORT_COUNT BIT(3) ++#define DL_OPT_SB BIT(4) ++#define DL_OPT_SB_POOL BIT(5) ++#define DL_OPT_SB_SIZE BIT(6) ++#define DL_OPT_SB_TYPE BIT(7) ++#define DL_OPT_SB_THTYPE BIT(8) ++#define DL_OPT_SB_TH BIT(9) ++#define DL_OPT_SB_TC BIT(10) + + struct dl_opts { + uint32_t present; /* flags of present items */ +@@ -122,6 +129,13 @@ struct dl_opts { + uint32_t port_index; + enum devlink_port_type port_type; + uint32_t port_count; ++ uint32_t sb_index; ++ uint16_t sb_pool_index; ++ uint32_t sb_pool_size; ++ enum devlink_sb_pool_type sb_pool_type; ++ enum devlink_sb_threshold_type sb_pool_thtype; ++ uint32_t sb_threshold; ++ uint16_t sb_tc_index; + }; + + struct dl { +@@ -225,6 +239,42 @@ static int attr_cb(const struct nlattr *attr, void *data) + if (type == DEVLINK_ATTR_PORT_IBDEV_NAME && + mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) + return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_INDEX && ++ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_SIZE && ++ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_INGRESS_POOL_COUNT && ++ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_EGRESS_POOL_COUNT && ++ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_INGRESS_TC_COUNT && ++ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_EGRESS_TC_COUNT && ++ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_POOL_INDEX && ++ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_POOL_TYPE && ++ mnl_attr_validate(attr, MNL_TYPE_U8) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_POOL_SIZE && ++ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE && ++ mnl_attr_validate(attr, MNL_TYPE_U8) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_THRESHOLD && ++ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_TC_INDEX && ++ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) ++ return MNL_CB_ERROR; + tb[type] = attr; + return MNL_CB_OK; + } +@@ -307,6 +357,23 @@ static int ifname_map_lookup(struct dl *dl, const char *ifname, + return -ENOENT; + } + ++static int ifname_map_rev_lookup(struct dl *dl, const char *bus_name, ++ const char *dev_name, uint32_t port_index, ++ char **p_ifname) ++{ ++ struct ifname_map *ifname_map; ++ ++ list_for_each_entry(ifname_map, &dl->ifname_map_list, list) { ++ if (strcmp(bus_name, ifname_map->bus_name) == 0 && ++ strcmp(dev_name, ifname_map->dev_name) == 0 && ++ port_index == ifname_map->port_index) { ++ *p_ifname = ifname_map->ifname; ++ return 0; ++ } ++ } ++ return -ENOENT; ++} ++ + static unsigned int strslashcount(char *str) + { + unsigned int count = 0; +@@ -346,6 +413,20 @@ static int strtouint32_t(const char *str, uint32_t *p_val) + return 0; + } + ++static int strtouint16_t(const char *str, uint16_t *p_val) ++{ ++ char *endptr; ++ unsigned long int val; ++ ++ val = strtoul(str, &endptr, 10); ++ if (endptr == str || *endptr != '\0') ++ return -EINVAL; ++ if (val > USHRT_MAX) ++ return -ERANGE; ++ *p_val = val; ++ return 0; ++} ++ + static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name) + { + strslashrsplit(str, p_bus_name, p_dev_name); +@@ -486,6 +567,24 @@ static int dl_argv_uint32_t(struct dl *dl, uint32_t *p_val) + return 0; + } + ++static int dl_argv_uint16_t(struct dl *dl, uint16_t *p_val) ++{ ++ char *str = dl_argv_next(dl); ++ int err; ++ ++ if (!str) { ++ pr_err("Unsigned number argument expected\n"); ++ return -EINVAL; ++ } ++ ++ err = strtouint16_t(str, p_val); ++ if (err) { ++ pr_err("\"%s\" is not a number or not within range\n", str); ++ return err; ++ } ++ return 0; ++} ++ + static int dl_argv_str(struct dl *dl, const char **p_str) + { + const char *str = dl_argv_next(dl); +@@ -513,6 +612,33 @@ static int port_type_get(const char *typestr, enum devlink_port_type *p_type) + return 0; + } + ++static int pool_type_get(const char *typestr, enum devlink_sb_pool_type *p_type) ++{ ++ if (strcmp(typestr, "ingress") == 0) { ++ *p_type = DEVLINK_SB_POOL_TYPE_INGRESS; ++ } else if (strcmp(typestr, "egress") == 0) { ++ *p_type = DEVLINK_SB_POOL_TYPE_EGRESS; ++ } else { ++ pr_err("Unknown pool type \"%s\"\n", typestr); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int threshold_type_get(const char *typestr, ++ enum devlink_sb_threshold_type *p_type) ++{ ++ if (strcmp(typestr, "static") == 0) { ++ *p_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC; ++ } else if (strcmp(typestr, "dynamic") == 0) { ++ *p_type = DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC; ++ } else { ++ pr_err("Unknown threshold type \"%s\"\n", typestr); ++ return -EINVAL; ++ } ++ return 0; ++} ++ + static int dl_argv_parse(struct dl *dl, uint32_t o_required, + uint32_t o_optional) + { +@@ -562,6 +688,66 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, + if (err) + return err; + o_found |= DL_OPT_PORT_COUNT; ++ } else if (dl_argv_match(dl, "sb") && ++ (o_all & DL_OPT_SB)) { ++ dl_arg_inc(dl); ++ err = dl_argv_uint32_t(dl, &opts->sb_index); ++ if (err) ++ return err; ++ o_found |= DL_OPT_SB; ++ } else if (dl_argv_match(dl, "pool") && ++ (o_all & DL_OPT_SB_POOL)) { ++ dl_arg_inc(dl); ++ err = dl_argv_uint16_t(dl, &opts->sb_pool_index); ++ if (err) ++ return err; ++ o_found |= DL_OPT_SB_POOL; ++ } else if (dl_argv_match(dl, "size") && ++ (o_all & DL_OPT_SB_SIZE)) { ++ dl_arg_inc(dl); ++ err = dl_argv_uint32_t(dl, &opts->sb_pool_size); ++ if (err) ++ return err; ++ o_found |= DL_OPT_SB_SIZE; ++ } else if (dl_argv_match(dl, "type") && ++ (o_all & DL_OPT_SB_TYPE)) { ++ const char *typestr; ++ ++ dl_arg_inc(dl); ++ err = dl_argv_str(dl, &typestr); ++ if (err) ++ return err; ++ err = pool_type_get(typestr, &opts->sb_pool_type); ++ if (err) ++ return err; ++ o_found |= DL_OPT_SB_TYPE; ++ } else if (dl_argv_match(dl, "thtype") && ++ (o_all & DL_OPT_SB_THTYPE)) { ++ const char *typestr; ++ ++ dl_arg_inc(dl); ++ err = dl_argv_str(dl, &typestr); ++ if (err) ++ return err; ++ err = threshold_type_get(typestr, ++ &opts->sb_pool_thtype); ++ if (err) ++ return err; ++ o_found |= DL_OPT_SB_THTYPE; ++ } else if (dl_argv_match(dl, "th") && ++ (o_all & DL_OPT_SB_TH)) { ++ dl_arg_inc(dl); ++ err = dl_argv_uint32_t(dl, &opts->sb_threshold); ++ if (err) ++ return err; ++ o_found |= DL_OPT_SB_TH; ++ } else if (dl_argv_match(dl, "tc") && ++ (o_all & DL_OPT_SB_TC)) { ++ dl_arg_inc(dl); ++ err = dl_argv_uint16_t(dl, &opts->sb_tc_index); ++ if (err) ++ return err; ++ o_found |= DL_OPT_SB_TC; + } else { + pr_err("Unknown option \"%s\"\n", dl_argv(dl)); + return -EINVAL; +@@ -570,6 +756,11 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, + + opts->present = o_found; + ++ if ((o_optional & DL_OPT_SB) && !(o_found & DL_OPT_SB)) { ++ opts->sb_index = 0; ++ opts->present |= DL_OPT_SB; ++ } ++ + if ((o_required & DL_OPT_PORT_TYPE) && !(o_found & DL_OPT_PORT_TYPE)) { + pr_err("Port type option expected.\n"); + return -EINVAL; +@@ -581,6 +772,35 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, + return -EINVAL; + } + ++ if ((o_required & DL_OPT_SB_POOL) && !(o_found & DL_OPT_SB_POOL)) { ++ pr_err("Pool index option expected.\n"); ++ return -EINVAL; ++ } ++ ++ if ((o_required & DL_OPT_SB_SIZE) && !(o_found & DL_OPT_SB_SIZE)) { ++ pr_err("Pool size option expected.\n"); ++ return -EINVAL; ++ } ++ ++ if ((o_required & DL_OPT_SB_TYPE) && !(o_found & DL_OPT_SB_TYPE)) { ++ pr_err("Pool type option expected.\n"); ++ return -EINVAL; ++ } ++ ++ if ((o_required & DL_OPT_SB_THTYPE) && !(o_found & DL_OPT_SB_THTYPE)) { ++ pr_err("Pool threshold type option expected.\n"); ++ return -EINVAL; ++ } ++ ++ if ((o_required & DL_OPT_SB_TH) && !(o_found & DL_OPT_SB_TH)) { ++ pr_err("Threshold option expected.\n"); ++ return -EINVAL; ++ } ++ ++ if ((o_required & DL_OPT_SB_TC) && !(o_found & DL_OPT_SB_TC)) { ++ pr_err("TC index option expected.\n"); ++ return -EINVAL; ++ } + return 0; + } + +@@ -603,6 +823,27 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl) + if (opts->present & DL_OPT_PORT_COUNT) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT, + opts->port_count); ++ if (opts->present & DL_OPT_SB) ++ mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, ++ opts->sb_index); ++ if (opts->present & DL_OPT_SB_POOL) ++ mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, ++ opts->sb_pool_index); ++ if (opts->present & DL_OPT_SB_SIZE) ++ mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_POOL_SIZE, ++ opts->sb_pool_size); ++ if (opts->present & DL_OPT_SB_TYPE) ++ mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE, ++ opts->sb_pool_type); ++ if (opts->present & DL_OPT_SB_THTYPE) ++ mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, ++ opts->sb_pool_thtype); ++ if (opts->present & DL_OPT_SB_TH) ++ mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD, ++ opts->sb_threshold); ++ if (opts->present & DL_OPT_SB_TC) ++ mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX, ++ opts->sb_tc_index); + } + + static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, +@@ -648,6 +889,39 @@ static void pr_out_port_handle(struct nlattr **tb) + mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX])); + } + ++static void __pr_out_port_handle_nice(struct dl *dl, const char *bus_name, ++ const char *dev_name, uint32_t port_index) ++{ ++ char *ifname; ++ int err; ++ ++ if (dl->no_nice_names) ++ goto no_nice_names; ++ ++ err = ifname_map_rev_lookup(dl, bus_name, dev_name, ++ port_index, &ifname); ++ if (err) ++ goto no_nice_names; ++ pr_out("%s", ifname); ++ return; ++ ++no_nice_names: ++ __pr_out_port_handle(bus_name, dev_name, port_index); ++} ++ ++static void pr_out_port_handle_nice(struct dl *dl, struct nlattr **tb) ++{ ++ const char *bus_name; ++ const char *dev_name; ++ uint32_t port_index; ++ ++ bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); ++ dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); ++ port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); ++ ++ __pr_out_port_handle_nice(dl, bus_name, dev_name, port_index); ++} ++ + static void pr_out_dev(struct nlattr **tb) + { + pr_out_handle(tb); +@@ -850,6 +1124,380 @@ static int cmd_port(struct dl *dl) + return -ENOENT; + } + ++static void cmd_sb_help(void) ++{ ++ pr_out("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n"); ++ pr_out(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n"); ++ pr_out(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n"); ++ pr_out(" size POOL_SIZE thtype { static | dynamic }\n"); ++ pr_out(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n"); ++ pr_out(" pool POOL_INDEX ]\n"); ++ pr_out(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n"); ++ pr_out(" pool POOL_INDEX th THRESHOLD\n"); ++ pr_out(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); ++ pr_out(" type { ingress | egress } ]\n"); ++ pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); ++ pr_out(" type { ingress | egress } pool POOL_INDEX\n"); ++ pr_out(" th THRESHOLD\n"); ++} ++ ++static void pr_out_sb(struct nlattr **tb) ++{ ++ pr_out_handle(tb); ++ pr_out(": sb %u size %u ing_pools %u eg_pools %u ing_tcs %u eg_tcs %u\n", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]), ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]), ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]), ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]), ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])); ++} ++ ++static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data) ++{ ++ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; ++ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); ++ ++ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); ++ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || ++ !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_SIZE] || ++ !tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] || ++ !tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] || ++ !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] || ++ !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]) ++ return MNL_CB_ERROR; ++ pr_out_sb(tb); ++ return MNL_CB_OK; ++} ++ ++static int cmd_sb_show(struct dl *dl) ++{ ++ struct nlmsghdr *nlh; ++ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; ++ int err; ++ ++ if (dl_argc(dl) == 0) ++ flags |= NLM_F_DUMP; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_GET, flags); ++ ++ if (dl_argc(dl) > 0) { ++ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); ++ if (err) ++ return err; ++ } ++ ++ return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, NULL); ++} ++ ++static const char *pool_type_name(uint8_t type) ++{ ++ switch (type) { ++ case DEVLINK_SB_POOL_TYPE_INGRESS: return "ingress"; ++ case DEVLINK_SB_POOL_TYPE_EGRESS: return "egress"; ++ default: return ""; ++ } ++} ++ ++static const char *threshold_type_name(uint8_t type) ++{ ++ switch (type) { ++ case DEVLINK_SB_THRESHOLD_TYPE_STATIC: return "static"; ++ case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC: return "dynamic"; ++ default: return ""; ++ } ++} ++ ++static void pr_out_sb_pool(struct nlattr **tb) ++{ ++ pr_out_handle(tb); ++ pr_out(": sb %u pool %u type %s size %u thtype %s\n", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), ++ pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]), ++ threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]))); ++} ++ ++static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data) ++{ ++ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; ++ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); ++ ++ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); ++ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || ++ !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_INDEX] || ++ !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] || ++ !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]) ++ return MNL_CB_ERROR; ++ pr_out_sb_pool(tb); ++ return MNL_CB_OK; ++} ++ ++static int cmd_sb_pool_show(struct dl *dl) ++{ ++ struct nlmsghdr *nlh; ++ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; ++ int err; ++ ++ if (dl_argc(dl) == 0) ++ flags |= NLM_F_DUMP; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags); ++ ++ if (dl_argc(dl) > 0) { ++ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL, ++ DL_OPT_SB); ++ if (err) ++ return err; ++ } ++ ++ return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, NULL); ++} ++ ++static int cmd_sb_pool_set(struct dl *dl) ++{ ++ struct nlmsghdr *nlh; ++ int err; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_SET, ++ NLM_F_REQUEST | NLM_F_ACK); ++ ++ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL | ++ DL_OPT_SB_SIZE | DL_OPT_SB_THTYPE, DL_OPT_SB); ++ if (err) ++ return err; ++ ++ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); ++} ++ ++static int cmd_sb_pool(struct dl *dl) ++{ ++ if (dl_argv_match(dl, "help")) { ++ cmd_sb_help(); ++ return 0; ++ } else if (dl_argv_match(dl, "show") || ++ dl_argv_match(dl, "list") || dl_no_arg(dl)) { ++ dl_arg_inc(dl); ++ return cmd_sb_pool_show(dl); ++ } else if (dl_argv_match(dl, "set")) { ++ dl_arg_inc(dl); ++ return cmd_sb_pool_set(dl); ++ } ++ pr_err("Command \"%s\" not found\n", dl_argv(dl)); ++ return -ENOENT; ++} ++ ++static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb) ++{ ++ pr_out_port_handle_nice(dl, tb); ++ pr_out(": sb %u pool %u threshold %u\n", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); ++} ++ ++static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data) ++{ ++ struct dl *dl = data; ++ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; ++ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); ++ ++ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); ++ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || ++ !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || ++ !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD]) ++ return MNL_CB_ERROR; ++ pr_out_sb_port_pool(dl, tb); ++ return MNL_CB_OK; ++} ++ ++static int cmd_sb_port_pool_show(struct dl *dl) ++{ ++ struct nlmsghdr *nlh; ++ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; ++ int err; ++ ++ if (dl_argc(dl) == 0) ++ flags |= NLM_F_DUMP; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); ++ ++ if (dl_argc(dl) > 0) { ++ err = dl_argv_parse_put(nlh, dl, ++ DL_OPT_HANDLEP | DL_OPT_SB_POOL, ++ DL_OPT_SB); ++ if (err) ++ return err; ++ } ++ ++ return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl); ++} ++ ++static int cmd_sb_port_pool_set(struct dl *dl) ++{ ++ struct nlmsghdr *nlh; ++ int err; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET, ++ NLM_F_REQUEST | NLM_F_ACK); ++ ++ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL | ++ DL_OPT_SB_TH, DL_OPT_SB); ++ if (err) ++ return err; ++ ++ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); ++} ++ ++static int cmd_sb_port_pool(struct dl *dl) ++{ ++ if (dl_argv_match(dl, "help")) { ++ cmd_sb_help(); ++ return 0; ++ } else if (dl_argv_match(dl, "show") || ++ dl_argv_match(dl, "list") || dl_no_arg(dl)) { ++ dl_arg_inc(dl); ++ return cmd_sb_port_pool_show(dl); ++ } else if (dl_argv_match(dl, "set")) { ++ dl_arg_inc(dl); ++ return cmd_sb_port_pool_set(dl); ++ } ++ pr_err("Command \"%s\" not found\n", dl_argv(dl)); ++ return -ENOENT; ++} ++ ++static int cmd_sb_port(struct dl *dl) ++{ ++ if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { ++ cmd_sb_help(); ++ return 0; ++ } else if (dl_argv_match(dl, "pool")) { ++ dl_arg_inc(dl); ++ return cmd_sb_port_pool(dl); ++ } ++ pr_err("Command \"%s\" not found\n", dl_argv(dl)); ++ return -ENOENT; ++} ++ ++static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb) ++{ ++ pr_out_port_handle_nice(dl, tb); ++ pr_out(": sb %u tc %u type %s pool %u threshold %u\n", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]), ++ pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); ++} ++ ++static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data) ++{ ++ struct dl *dl = data; ++ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; ++ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); ++ ++ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); ++ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || ++ !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || ++ !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] || ++ !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD]) ++ return MNL_CB_ERROR; ++ pr_out_sb_tc_bind(dl, tb); ++ return MNL_CB_OK; ++} ++ ++static int cmd_sb_tc_bind_show(struct dl *dl) ++{ ++ struct nlmsghdr *nlh; ++ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; ++ int err; ++ ++ if (dl_argc(dl) == 0) ++ flags |= NLM_F_DUMP; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); ++ ++ if (dl_argc(dl) > 0) { ++ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC | ++ DL_OPT_SB_TYPE, DL_OPT_SB); ++ if (err) ++ return err; ++ } ++ ++ return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl); ++} ++ ++static int cmd_sb_tc_bind_set(struct dl *dl) ++{ ++ struct nlmsghdr *nlh; ++ int err; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET, ++ NLM_F_REQUEST | NLM_F_ACK); ++ ++ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC | ++ DL_OPT_SB_TYPE | DL_OPT_SB_POOL | DL_OPT_SB_TH, ++ DL_OPT_SB); ++ if (err) ++ return err; ++ ++ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); ++} ++ ++static int cmd_sb_tc_bind(struct dl *dl) ++{ ++ if (dl_argv_match(dl, "help")) { ++ cmd_sb_help(); ++ return 0; ++ } else if (dl_argv_match(dl, "show") || ++ dl_argv_match(dl, "list") || dl_no_arg(dl)) { ++ dl_arg_inc(dl); ++ return cmd_sb_tc_bind_show(dl); ++ } else if (dl_argv_match(dl, "set")) { ++ dl_arg_inc(dl); ++ return cmd_sb_tc_bind_set(dl); ++ } ++ pr_err("Command \"%s\" not found\n", dl_argv(dl)); ++ return -ENOENT; ++} ++ ++static int cmd_sb_tc(struct dl *dl) ++{ ++ if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { ++ cmd_sb_help(); ++ return 0; ++ } else if (dl_argv_match(dl, "bind")) { ++ dl_arg_inc(dl); ++ return cmd_sb_tc_bind(dl); ++ } ++ pr_err("Command \"%s\" not found\n", dl_argv(dl)); ++ return -ENOENT; ++} ++ ++static int cmd_sb(struct dl *dl) ++{ ++ if (dl_argv_match(dl, "help")) { ++ cmd_sb_help(); ++ return 0; ++ } else if (dl_argv_match(dl, "show") || ++ dl_argv_match(dl, "list") || dl_no_arg(dl)) { ++ dl_arg_inc(dl); ++ return cmd_sb_show(dl); ++ } else if (dl_argv_match(dl, "pool")) { ++ dl_arg_inc(dl); ++ return cmd_sb_pool(dl); ++ } else if (dl_argv_match(dl, "port")) { ++ dl_arg_inc(dl); ++ return cmd_sb_port(dl); ++ } else if (dl_argv_match(dl, "tc")) { ++ dl_arg_inc(dl); ++ return cmd_sb_tc(dl); ++ } ++ pr_err("Command \"%s\" not found\n", dl_argv(dl)); ++ return -ENOENT; ++} ++ + static const char *cmd_name(uint8_t cmd) + { + switch (cmd) { +@@ -985,7 +1633,7 @@ static int cmd_mon(struct dl *dl) + static void help(void) + { + pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" +- "where OBJECT := { dev | port | monitor }\n" ++ "where OBJECT := { dev | port | sb | monitor }\n" + " OPTIONS := { -V[ersion] | -n[no-nice-names] }\n"); + } + +@@ -1000,6 +1648,9 @@ static int dl_cmd(struct dl *dl) + } else if (dl_argv_match(dl, "port")) { + dl_arg_inc(dl); + return cmd_port(dl); ++ } else if (dl_argv_match(dl, "sb")) { ++ dl_arg_inc(dl); ++ return cmd_sb(dl); + } else if (dl_argv_match(dl, "monitor")) { + dl_arg_inc(dl); + return cmd_mon(dl); +-- +2.9.3 + diff --git a/0002-devlink-implement-shared-buffer-occupancy-control.patch b/0002-devlink-implement-shared-buffer-occupancy-control.patch new file mode 100644 index 0000000..1194bdf --- /dev/null +++ b/0002-devlink-implement-shared-buffer-occupancy-control.patch @@ -0,0 +1,441 @@ +From 25ec49be2cdfa571d5151f19a7395a7e462d2f49 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Sat, 14 May 2016 15:21:02 +0200 +Subject: [PATCH 2/2] devlink: implement shared buffer occupancy control + +Use kernel shared buffer occupancy control commands to make snapshot and +clear occupancy watermarks. Also, allow to show occupancy values in a +nice way. + +Signed-off-by: Jiri Pirko +--- + devlink/devlink.c | 378 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 378 insertions(+) + +diff --git a/devlink/devlink.c b/devlink/devlink.c +index ca3f586..ffefa86 100644 +--- a/devlink/devlink.c ++++ b/devlink/devlink.c +@@ -27,6 +27,12 @@ + + #define pr_err(args...) fprintf(stderr, ##args) + #define pr_out(args...) fprintf(stdout, ##args) ++#define pr_out_sp(num, args...) \ ++ do { \ ++ int ret = fprintf(stdout, ##args); \ ++ if (ret < num) \ ++ fprintf(stdout, "%*s", num - ret, ""); \ ++ } while (0) + + static int _mnlg_socket_recv_run(struct mnlg_socket *nlg, + mnl_cb_t data_cb, void *data) +@@ -275,6 +281,12 @@ static int attr_cb(const struct nlattr *attr, void *data) + if (type == DEVLINK_ATTR_SB_TC_INDEX && + mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_OCC_CUR && ++ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_OCC_MAX && ++ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) ++ return MNL_CB_ERROR; + tb[type] = attr; + return MNL_CB_OK; + } +@@ -858,6 +870,42 @@ static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, + return 0; + } + ++static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) ++{ ++ struct dl_opts *opts = &dl->opts; ++ struct nlattr *attr_bus_name = tb[DEVLINK_ATTR_BUS_NAME]; ++ struct nlattr *attr_dev_name = tb[DEVLINK_ATTR_DEV_NAME]; ++ struct nlattr *attr_port_index = tb[DEVLINK_ATTR_PORT_INDEX]; ++ struct nlattr *attr_sb_index = tb[DEVLINK_ATTR_SB_INDEX]; ++ ++ if (opts->present & DL_OPT_HANDLE && ++ attr_bus_name && attr_dev_name) { ++ const char *bus_name = mnl_attr_get_str(attr_bus_name); ++ const char *dev_name = mnl_attr_get_str(attr_dev_name); ++ ++ if (strcmp(bus_name, opts->bus_name) != 0 || ++ strcmp(dev_name, opts->dev_name) != 0) ++ return false; ++ } ++ if (opts->present & DL_OPT_HANDLEP && ++ attr_bus_name && attr_dev_name && attr_port_index) { ++ const char *bus_name = mnl_attr_get_str(attr_bus_name); ++ const char *dev_name = mnl_attr_get_str(attr_dev_name); ++ uint32_t port_index = mnl_attr_get_u32(attr_port_index); ++ ++ if (strcmp(bus_name, opts->bus_name) != 0 || ++ strcmp(dev_name, opts->dev_name) != 0 || ++ port_index != opts->port_index) ++ return false; ++ } ++ if (opts->present & DL_OPT_SB && attr_sb_index) { ++ uint32_t sb_index = mnl_attr_get_u32(attr_sb_index); ++ ++ if (sb_index != opts->sb_index) ++ return false; ++ } ++ return true; ++} + + static void cmd_dev_help(void) + { +@@ -1139,6 +1187,9 @@ static void cmd_sb_help(void) + pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); + pr_out(" type { ingress | egress } pool POOL_INDEX\n"); + pr_out(" th THRESHOLD\n"); ++ pr_out(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n"); ++ pr_out(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n"); ++ pr_out(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); + } + + static void pr_out_sb(struct nlattr **tb) +@@ -1475,6 +1526,330 @@ static int cmd_sb_tc(struct dl *dl) + return -ENOENT; + } + ++struct occ_item { ++ struct list_head list; ++ uint32_t index; ++ uint32_t cur; ++ uint32_t max; ++ uint32_t bound_pool_index; ++}; ++ ++struct occ_port { ++ struct list_head list; ++ char *bus_name; ++ char *dev_name; ++ uint32_t port_index; ++ uint32_t sb_index; ++ struct list_head pool_list; ++ struct list_head ing_tc_list; ++ struct list_head eg_tc_list; ++}; ++ ++struct occ_show { ++ struct dl *dl; ++ int err; ++ struct list_head port_list; ++}; ++ ++static struct occ_item *occ_item_alloc(void) ++{ ++ return calloc(1, sizeof(struct occ_item)); ++} ++ ++static void occ_item_free(struct occ_item *occ_item) ++{ ++ free(occ_item); ++} ++ ++static struct occ_port *occ_port_alloc(uint32_t port_index) ++{ ++ struct occ_port *occ_port; ++ ++ occ_port = calloc(1, sizeof(*occ_port)); ++ if (!occ_port) ++ return NULL; ++ occ_port->port_index = port_index; ++ INIT_LIST_HEAD(&occ_port->pool_list); ++ INIT_LIST_HEAD(&occ_port->ing_tc_list); ++ INIT_LIST_HEAD(&occ_port->eg_tc_list); ++ return occ_port; ++} ++ ++static void occ_port_free(struct occ_port *occ_port) ++{ ++ struct occ_item *occ_item, *tmp; ++ ++ list_for_each_entry_safe(occ_item, tmp, &occ_port->pool_list, list) ++ occ_item_free(occ_item); ++ list_for_each_entry_safe(occ_item, tmp, &occ_port->ing_tc_list, list) ++ occ_item_free(occ_item); ++ list_for_each_entry_safe(occ_item, tmp, &occ_port->eg_tc_list, list) ++ occ_item_free(occ_item); ++} ++ ++static struct occ_show *occ_show_alloc(struct dl *dl) ++{ ++ struct occ_show *occ_show; ++ ++ occ_show = calloc(1, sizeof(*occ_show)); ++ if (!occ_show) ++ return NULL; ++ occ_show->dl = dl; ++ INIT_LIST_HEAD(&occ_show->port_list); ++ return occ_show; ++} ++ ++static void occ_show_free(struct occ_show *occ_show) ++{ ++ struct occ_port *occ_port, *tmp; ++ ++ list_for_each_entry_safe(occ_port, tmp, &occ_show->port_list, list) ++ occ_port_free(occ_port); ++} ++ ++static struct occ_port *occ_port_get(struct occ_show *occ_show, ++ struct nlattr **tb) ++{ ++ struct occ_port *occ_port; ++ uint32_t port_index; ++ ++ port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); ++ ++ list_for_each_entry_reverse(occ_port, &occ_show->port_list, list) { ++ if (occ_port->port_index == port_index) ++ return occ_port; ++ } ++ occ_port = occ_port_alloc(port_index); ++ if (!occ_port) ++ return NULL; ++ list_add_tail(&occ_port->list, &occ_show->port_list); ++ return occ_port; ++} ++ ++static void pr_out_occ_show_item_list(const char *label, struct list_head *list, ++ bool bound_pool) ++{ ++ struct occ_item *occ_item; ++ int i = 1; ++ ++ pr_out_sp(7, " %s:", label); ++ list_for_each_entry(occ_item, list, list) { ++ if ((i - 1) % 4 == 0 && i != 1) ++ pr_out_sp(7, " "); ++ if (bound_pool) ++ pr_out_sp(7, "%2u(%u):", occ_item->index, ++ occ_item->bound_pool_index); ++ else ++ pr_out_sp(7, "%2u:", occ_item->index); ++ pr_out_sp(15, "%7u/%u", occ_item->cur, occ_item->max); ++ if (i++ % 4 == 0) ++ pr_out("\n"); ++ } ++ if ((i - 1) % 4 != 0) ++ pr_out("\n"); ++} ++ ++static void pr_out_occ_show_port(struct occ_port *occ_port) ++{ ++ pr_out_occ_show_item_list("pool", &occ_port->pool_list, false); ++ pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true); ++ pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true); ++} ++ ++static void pr_out_occ_show(struct occ_show *occ_show) ++{ ++ struct dl *dl = occ_show->dl; ++ struct dl_opts *opts = &dl->opts; ++ struct occ_port *occ_port; ++ ++ list_for_each_entry(occ_port, &occ_show->port_list, list) { ++ __pr_out_port_handle_nice(dl, opts->bus_name, opts->dev_name, ++ occ_port->port_index); ++ pr_out(":\n"); ++ pr_out_occ_show_port(occ_port); ++ } ++} ++ ++static void cmd_sb_occ_port_pool_process(struct occ_show *occ_show, ++ struct nlattr **tb) ++{ ++ struct occ_port *occ_port; ++ struct occ_item *occ_item; ++ ++ if (occ_show->err || !dl_dump_filter(occ_show->dl, tb)) ++ return; ++ ++ occ_port = occ_port_get(occ_show, tb); ++ if (!occ_port) { ++ occ_show->err = -ENOMEM; ++ return; ++ } ++ ++ occ_item = occ_item_alloc(); ++ if (!occ_item) { ++ occ_show->err = -ENOMEM; ++ return; ++ } ++ occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]); ++ occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]); ++ occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]); ++ list_add_tail(&occ_item->list, &occ_port->pool_list); ++} ++ ++static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr *nlh, void *data) ++{ ++ struct occ_show *occ_show = data; ++ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; ++ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); ++ ++ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); ++ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || ++ !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || ++ !tb[DEVLINK_ATTR_SB_POOL_INDEX] || ++ !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX]) ++ return MNL_CB_ERROR; ++ cmd_sb_occ_port_pool_process(occ_show, tb); ++ return MNL_CB_OK; ++} ++ ++static void cmd_sb_occ_tc_pool_process(struct occ_show *occ_show, ++ struct nlattr **tb) ++{ ++ struct occ_port *occ_port; ++ struct occ_item *occ_item; ++ uint8_t pool_type; ++ ++ if (occ_show->err || !dl_dump_filter(occ_show->dl, tb)) ++ return; ++ ++ occ_port = occ_port_get(occ_show, tb); ++ if (!occ_port) { ++ occ_show->err = -ENOMEM; ++ return; ++ } ++ ++ occ_item = occ_item_alloc(); ++ if (!occ_item) { ++ occ_show->err = -ENOMEM; ++ return; ++ } ++ occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]); ++ occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]); ++ occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]); ++ occ_item->bound_pool_index = ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]); ++ pool_type = mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]); ++ if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS) ++ list_add_tail(&occ_item->list, &occ_port->ing_tc_list); ++ else if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS) ++ list_add_tail(&occ_item->list, &occ_port->eg_tc_list); ++ else ++ occ_item_free(occ_item); ++} ++ ++static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr *nlh, void *data) ++{ ++ struct occ_show *occ_show = data; ++ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; ++ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); ++ ++ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); ++ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || ++ !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || ++ !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] || ++ !tb[DEVLINK_ATTR_SB_POOL_INDEX] || ++ !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX]) ++ return MNL_CB_ERROR; ++ cmd_sb_occ_tc_pool_process(occ_show, tb); ++ return MNL_CB_OK; ++} ++ ++static int cmd_sb_occ_show(struct dl *dl) ++{ ++ struct nlmsghdr *nlh; ++ struct occ_show *occ_show; ++ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP; ++ int err; ++ ++ err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP, DL_OPT_SB); ++ if (err) ++ return err; ++ ++ occ_show = occ_show_alloc(dl); ++ if (!occ_show) ++ return -ENOMEM; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); ++ ++ err = _mnlg_socket_sndrcv(dl->nlg, nlh, ++ cmd_sb_occ_port_pool_process_cb, occ_show); ++ if (err) ++ goto out; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); ++ ++ err = _mnlg_socket_sndrcv(dl->nlg, nlh, ++ cmd_sb_occ_tc_pool_process_cb, occ_show); ++ if (err) ++ goto out; ++ ++ pr_out_occ_show(occ_show); ++ ++out: ++ occ_show_free(occ_show); ++ return err; ++} ++ ++static int cmd_sb_occ_snapshot(struct dl *dl) ++{ ++ struct nlmsghdr *nlh; ++ int err; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_SNAPSHOT, ++ NLM_F_REQUEST | NLM_F_ACK); ++ ++ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); ++ if (err) ++ return err; ++ ++ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); ++} ++ ++static int cmd_sb_occ_clearmax(struct dl *dl) ++{ ++ struct nlmsghdr *nlh; ++ int err; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_MAX_CLEAR, ++ NLM_F_REQUEST | NLM_F_ACK); ++ ++ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); ++ if (err) ++ return err; ++ ++ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); ++} ++ ++static int cmd_sb_occ(struct dl *dl) ++{ ++ if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { ++ cmd_sb_help(); ++ return 0; ++ } else if (dl_argv_match(dl, "show") || ++ dl_argv_match(dl, "list")) { ++ dl_arg_inc(dl); ++ return cmd_sb_occ_show(dl); ++ } else if (dl_argv_match(dl, "snapshot")) { ++ dl_arg_inc(dl); ++ return cmd_sb_occ_snapshot(dl); ++ } else if (dl_argv_match(dl, "clearmax")) { ++ dl_arg_inc(dl); ++ return cmd_sb_occ_clearmax(dl); ++ } ++ pr_err("Command \"%s\" not found\n", dl_argv(dl)); ++ return -ENOENT; ++} ++ + static int cmd_sb(struct dl *dl) + { + if (dl_argv_match(dl, "help")) { +@@ -1493,6 +1868,9 @@ static int cmd_sb(struct dl *dl) + } else if (dl_argv_match(dl, "tc")) { + dl_arg_inc(dl); + return cmd_sb_tc(dl); ++ } else if (dl_argv_match(dl, "occupancy")) { ++ dl_arg_inc(dl); ++ return cmd_sb_occ(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +-- +2.9.3 + diff --git a/devlink-kernel-headers.patch b/devlink-kernel-headers.patch new file mode 100644 index 0000000..b46c702 --- /dev/null +++ b/devlink-kernel-headers.patch @@ -0,0 +1,88 @@ +diff --git a/include/linux/devlink.h b/include/linux/devlink.h +index a96e1a0..0e21d00 100644 +--- a/include/linux/devlink.h ++++ b/include/linux/devlink.h +@@ -33,6 +33,30 @@ enum devlink_command { + DEVLINK_CMD_PORT_SPLIT, + DEVLINK_CMD_PORT_UNSPLIT, + ++ DEVLINK_CMD_SB_GET, /* can dump */ ++ DEVLINK_CMD_SB_SET, ++ DEVLINK_CMD_SB_NEW, ++ DEVLINK_CMD_SB_DEL, ++ ++ DEVLINK_CMD_SB_POOL_GET, /* can dump */ ++ DEVLINK_CMD_SB_POOL_SET, ++ DEVLINK_CMD_SB_POOL_NEW, ++ DEVLINK_CMD_SB_POOL_DEL, ++ ++ DEVLINK_CMD_SB_PORT_POOL_GET, /* can dump */ ++ DEVLINK_CMD_SB_PORT_POOL_SET, ++ DEVLINK_CMD_SB_PORT_POOL_NEW, ++ DEVLINK_CMD_SB_PORT_POOL_DEL, ++ ++ DEVLINK_CMD_SB_TC_POOL_BIND_GET, /* can dump */ ++ DEVLINK_CMD_SB_TC_POOL_BIND_SET, ++ DEVLINK_CMD_SB_TC_POOL_BIND_NEW, ++ DEVLINK_CMD_SB_TC_POOL_BIND_DEL, ++ ++ /* Shared buffer occupancy monitoring commands */ ++ DEVLINK_CMD_SB_OCC_SNAPSHOT, ++ DEVLINK_CMD_SB_OCC_MAX_CLEAR, ++ + /* add new commands above here */ + + __DEVLINK_CMD_MAX, +@@ -46,6 +70,31 @@ enum devlink_port_type { + DEVLINK_PORT_TYPE_IB, + }; + ++enum devlink_sb_pool_type { ++ DEVLINK_SB_POOL_TYPE_INGRESS, ++ DEVLINK_SB_POOL_TYPE_EGRESS, ++}; ++ ++/* static threshold - limiting the maximum number of bytes. ++ * dynamic threshold - limiting the maximum number of bytes ++ * based on the currently available free space in the shared buffer pool. ++ * In this mode, the maximum quota is calculated based ++ * on the following formula: ++ * max_quota = alpha / (1 + alpha) * Free_Buffer ++ * While Free_Buffer is the amount of none-occupied buffer associated to ++ * the relevant pool. ++ * The value range which can be passed is 0-20 and serves ++ * for computation of alpha by following formula: ++ * alpha = 2 ^ (passed_value - 10) ++ */ ++ ++enum devlink_sb_threshold_type { ++ DEVLINK_SB_THRESHOLD_TYPE_STATIC, ++ DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC, ++}; ++ ++#define DEVLINK_SB_THRESHOLD_TO_ALPHA_MAX 20 ++ + enum devlink_attr { + /* don't change the order or add anything between, this is ABI! */ + DEVLINK_ATTR_UNSPEC, +@@ -62,6 +111,20 @@ enum devlink_attr { + DEVLINK_ATTR_PORT_IBDEV_NAME, /* string */ + DEVLINK_ATTR_PORT_SPLIT_COUNT, /* u32 */ + DEVLINK_ATTR_PORT_SPLIT_GROUP, /* u32 */ ++ DEVLINK_ATTR_SB_INDEX, /* u32 */ ++ DEVLINK_ATTR_SB_SIZE, /* u32 */ ++ DEVLINK_ATTR_SB_INGRESS_POOL_COUNT, /* u16 */ ++ DEVLINK_ATTR_SB_EGRESS_POOL_COUNT, /* u16 */ ++ DEVLINK_ATTR_SB_INGRESS_TC_COUNT, /* u16 */ ++ DEVLINK_ATTR_SB_EGRESS_TC_COUNT, /* u16 */ ++ DEVLINK_ATTR_SB_POOL_INDEX, /* u16 */ ++ DEVLINK_ATTR_SB_POOL_TYPE, /* u8 */ ++ DEVLINK_ATTR_SB_POOL_SIZE, /* u32 */ ++ DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, /* u8 */ ++ DEVLINK_ATTR_SB_THRESHOLD, /* u32 */ ++ DEVLINK_ATTR_SB_TC_INDEX, /* u16 */ ++ DEVLINK_ATTR_SB_OCC_CUR, /* u32 */ ++ DEVLINK_ATTR_SB_OCC_MAX, /* u32 */ + + /* add new attributes above here, update the policy in devlink.c */ + diff --git a/iproute.spec b/iproute.spec index 02c921e..50e92c3 100644 --- a/iproute.spec +++ b/iproute.spec @@ -2,7 +2,7 @@ Summary: Advanced IP routing and network device configuration tools Name: iproute Version: 4.6.0 -Release: 1%{?dist} +Release: 2%{?dist} Group: Applications/System URL: http://kernel.org/pub/linux/utils/net/%{name}2/ Source0: http://kernel.org/pub/linux/utils/net/%{name}2/%{name}2-%{version}.tar.xz @@ -16,6 +16,16 @@ Source2: avpkt # https://github.com/pavlix/iproute2/commits/fedora Patch1: 0001-Documentation-fixes.patch +# devlink shared buffer support +# +# Accepted by upstream +# +# https://patchwork.ozlabs.org/patch/622240/ +# https://patchwork.ozlabs.org/patch/622241/ +Patch2: devlink-kernel-headers.patch +Patch3: 0001-devlink-implement-shared-buffer-support.patch +Patch4: 0002-devlink-implement-shared-buffer-occupancy-control.patch + License: GPLv2+ and Public Domain BuildRequires: bison BuildRequires: elfutils-libelf-devel @@ -78,6 +88,9 @@ The libnetlink static library. %prep %setup -q -n %{name}2-%{version} %patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 %build export CFLAGS="%{optflags}" @@ -161,6 +174,9 @@ rm -rf '%{buildroot}%{_docdir}' %{_includedir}/libnetlink.h %changelog +* Fri Nov 25 2016 Ido Schimmel - 4.6.0-2 +- Add devlink shared buffer patches + * Wed May 04 2016 Phil Sutter - 4.6.0-1 - New version 4.6.0 From 294ff72abcf04e6ce96b98393c3195d951aa5c66 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 25 Nov 2016 18:19:40 +0200 Subject: [PATCH 02/11] Add Makefile patches to install devlink manpages Signed-off-by: Phil Sutter --- ...an-Add-devlink-man-pages-to-Makefile.patch | 28 +++++++++++++++++++ ...-to-devlink-sb-from-devlink-man-page.patch | 26 +++++++++++++++++ iproute.spec | 16 ++++++++++- 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 0001-man-Add-devlink-man-pages-to-Makefile.patch create mode 100644 0002-man-Point-to-devlink-sb-from-devlink-man-page.patch diff --git a/0001-man-Add-devlink-man-pages-to-Makefile.patch b/0001-man-Add-devlink-man-pages-to-Makefile.patch new file mode 100644 index 0000000..5850571 --- /dev/null +++ b/0001-man-Add-devlink-man-pages-to-Makefile.patch @@ -0,0 +1,28 @@ +From e3da7a45bad1672328d67f016627e026cb41feba Mon Sep 17 00:00:00 2001 +From: Ido Schimmel +Date: Wed, 13 Jul 2016 09:53:53 +0300 +Subject: [PATCH 1/2] man: Add devlink man pages to Makefile + +Signed-off-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + man/man8/Makefile | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/man/man8/Makefile b/man/man8/Makefile +index 929826e..9badbed 100644 +--- a/man/man8/Makefile ++++ b/man/man8/Makefile +@@ -16,7 +16,8 @@ MAN8PAGES = $(TARGETS) ip.8 arpd.8 lnstat.8 routel.8 rtacct.8 rtmon.8 rtpr.8 ss. + tc-basic.8 tc-cgroup.8 tc-flow.8 tc-flower.8 tc-fw.8 tc-route.8 \ + tc-tcindex.8 tc-u32.8 \ + tc-connmark.8 tc-csum.8 tc-mirred.8 tc-nat.8 tc-pedit.8 tc-police.8 \ +- tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 ++ tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 \ ++ devlink.8 devlink-dev.8 devlink-monitor.8 devlink-port.8 devlink-sb.8 + + all: $(TARGETS) + +-- +2.9.3 + diff --git a/0002-man-Point-to-devlink-sb-from-devlink-man-page.patch b/0002-man-Point-to-devlink-sb-from-devlink-man-page.patch new file mode 100644 index 0000000..ea1b1df --- /dev/null +++ b/0002-man-Point-to-devlink-sb-from-devlink-man-page.patch @@ -0,0 +1,26 @@ +From 78c610e6ea8554e87e2204f540cf0ce61ef52695 Mon Sep 17 00:00:00 2001 +From: Ido Schimmel +Date: Wed, 13 Jul 2016 09:53:54 +0300 +Subject: [PATCH 2/2] man: Point to 'devlink-sb' from 'devlink' man page + +Signed-off-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + man/man8/devlink.8 | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/man/man8/devlink.8 b/man/man8/devlink.8 +index df00f4f..cf0563b 100644 +--- a/man/man8/devlink.8 ++++ b/man/man8/devlink.8 +@@ -76,6 +76,7 @@ Exit status is 0 if command was successful or a positive integer upon failure. + .BR devlink-dev (8), + .BR devlink-port (8), + .BR devlink-monitor (8), ++.BR devlink-sb (8), + .br + + .SH REPORTING BUGS +-- +2.9.3 + diff --git a/iproute.spec b/iproute.spec index 50e92c3..7e92eb2 100644 --- a/iproute.spec +++ b/iproute.spec @@ -2,7 +2,7 @@ Summary: Advanced IP routing and network device configuration tools Name: iproute Version: 4.6.0 -Release: 2%{?dist} +Release: 3%{?dist} Group: Applications/System URL: http://kernel.org/pub/linux/utils/net/%{name}2/ Source0: http://kernel.org/pub/linux/utils/net/%{name}2/%{name}2-%{version}.tar.xz @@ -26,6 +26,15 @@ Patch2: devlink-kernel-headers.patch Patch3: 0001-devlink-implement-shared-buffer-support.patch Patch4: 0002-devlink-implement-shared-buffer-occupancy-control.patch +# devlink manpages installation +# +# Accepted by upstream +# +# https://patchwork.ozlabs.org/patch/647766/ +# https://patchwork.ozlabs.org/patch/647764/ +Patch5: 0001-man-Add-devlink-man-pages-to-Makefile.patch +Patch6: 0002-man-Point-to-devlink-sb-from-devlink-man-page.patch + License: GPLv2+ and Public Domain BuildRequires: bison BuildRequires: elfutils-libelf-devel @@ -91,6 +100,8 @@ The libnetlink static library. %patch2 -p1 %patch3 -p1 %patch4 -p1 +%patch5 -p1 +%patch6 -p1 %build export CFLAGS="%{optflags}" @@ -174,6 +185,9 @@ rm -rf '%{buildroot}%{_docdir}' %{_includedir}/libnetlink.h %changelog +* Fri Nov 25 2016 Ido Schimmel - 4.6.0-3 +- Add Makefile patches to install devlink manpages + * Fri Nov 25 2016 Ido Schimmel - 4.6.0-2 - Add devlink shared buffer patches From 914365a924ac569cc57b13924ea58bc25ee437a1 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 25 Nov 2016 18:32:58 +0200 Subject: [PATCH 03/11] Add devlink JSON patches Signed-off-by: Phil Sutter --- ...-write-usage-help-messages-to-stderr.patch | 100 +++ ...k-add-option-to-generate-JSON-output.patch | 738 ++++++++++++++++++ iproute.spec | 16 +- 3 files changed, 853 insertions(+), 1 deletion(-) create mode 100644 0001-devlink-write-usage-help-messages-to-stderr.patch create mode 100644 0002-devlink-add-option-to-generate-JSON-output.patch diff --git a/0001-devlink-write-usage-help-messages-to-stderr.patch b/0001-devlink-write-usage-help-messages-to-stderr.patch new file mode 100644 index 0000000..7413789 --- /dev/null +++ b/0001-devlink-write-usage-help-messages-to-stderr.patch @@ -0,0 +1,100 @@ +From 7a9466dbcba1918a1c93de8f93b9ff3d62418fcf Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Fri, 22 Jul 2016 18:34:29 +0200 +Subject: [PATCH 1/2] devlink: write usage help messages to stderr + +In order to not confuse reader, write help messages into stderr. + +Signed-off-by: Jiri Pirko +--- + devlink/devlink.c | 46 +++++++++++++++++++++++----------------------- + 1 file changed, 23 insertions(+), 23 deletions(-) + +diff --git a/devlink/devlink.c b/devlink/devlink.c +index ffefa86..f73ba95 100644 +--- a/devlink/devlink.c ++++ b/devlink/devlink.c +@@ -909,7 +909,7 @@ static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) + + static void cmd_dev_help(void) + { +- pr_out("Usage: devlink dev show [ DEV ]\n"); ++ pr_err("Usage: devlink dev show [ DEV ]\n"); + } + + static void __pr_out_handle(const char *bus_name, const char *dev_name) +@@ -1024,10 +1024,10 @@ static int cmd_dev(struct dl *dl) + + static void cmd_port_help(void) + { +- pr_out("Usage: devlink port show [ DEV/PORT_INDEX ]\n"); +- pr_out(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n"); +- pr_out(" devlink port split DEV/PORT_INDEX count COUNT\n"); +- pr_out(" devlink port unsplit DEV/PORT_INDEX\n"); ++ pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n"); ++ pr_err(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n"); ++ pr_err(" devlink port split DEV/PORT_INDEX count COUNT\n"); ++ pr_err(" devlink port unsplit DEV/PORT_INDEX\n"); + } + + static const char *port_type_name(uint32_t type) +@@ -1174,22 +1174,22 @@ static int cmd_port(struct dl *dl) + + static void cmd_sb_help(void) + { +- pr_out("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n"); +- pr_out(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n"); +- pr_out(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n"); +- pr_out(" size POOL_SIZE thtype { static | dynamic }\n"); +- pr_out(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n"); +- pr_out(" pool POOL_INDEX ]\n"); +- pr_out(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n"); +- pr_out(" pool POOL_INDEX th THRESHOLD\n"); +- pr_out(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); +- pr_out(" type { ingress | egress } ]\n"); +- pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); +- pr_out(" type { ingress | egress } pool POOL_INDEX\n"); +- pr_out(" th THRESHOLD\n"); +- pr_out(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n"); +- pr_out(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n"); +- pr_out(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); ++ pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n"); ++ pr_err(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n"); ++ pr_err(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n"); ++ pr_err(" size POOL_SIZE thtype { static | dynamic }\n"); ++ pr_err(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n"); ++ pr_err(" pool POOL_INDEX ]\n"); ++ pr_err(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n"); ++ pr_err(" pool POOL_INDEX th THRESHOLD\n"); ++ pr_err(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); ++ pr_err(" type { ingress | egress } ]\n"); ++ pr_err(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); ++ pr_err(" type { ingress | egress } pool POOL_INDEX\n"); ++ pr_err(" th THRESHOLD\n"); ++ pr_err(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n"); ++ pr_err(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n"); ++ pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); + } + + static void pr_out_sb(struct nlattr **tb) +@@ -1991,7 +1991,7 @@ static int cmd_mon_show(struct dl *dl) + + static void cmd_mon_help(void) + { +- pr_out("Usage: devlink monitor [ all | OBJECT-LIST ]\n" ++ pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n" + "where OBJECT-LIST := { dev | port }\n"); + } + +@@ -2010,7 +2010,7 @@ static int cmd_mon(struct dl *dl) + + static void help(void) + { +- pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" ++ pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" + "where OBJECT := { dev | port | sb | monitor }\n" + " OPTIONS := { -V[ersion] | -n[no-nice-names] }\n"); + } +-- +2.9.3 + diff --git a/0002-devlink-add-option-to-generate-JSON-output.patch b/0002-devlink-add-option-to-generate-JSON-output.patch new file mode 100644 index 0000000..96c7a68 --- /dev/null +++ b/0002-devlink-add-option-to-generate-JSON-output.patch @@ -0,0 +1,738 @@ +From e3d0f0c0e3d8ac6432884e19aefd169e5c4ae179 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Fri, 22 Jul 2016 18:34:30 +0200 +Subject: [PATCH 2/2] devlink: add option to generate JSON output + +For parsing by another app it is convenient to produce output in JSON +format. + +Signed-off-by: Jiri Pirko +--- + devlink/devlink.c | 455 +++++++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 362 insertions(+), 93 deletions(-) + +diff --git a/devlink/devlink.c b/devlink/devlink.c +index f73ba95..84fa51e 100644 +--- a/devlink/devlink.c ++++ b/devlink/devlink.c +@@ -24,6 +24,7 @@ + #include "SNAPSHOT.h" + #include "list.h" + #include "mnlg.h" ++#include "json_writer.h" + + #define pr_err(args...) fprintf(stderr, ##args) + #define pr_out(args...) fprintf(stdout, ##args) +@@ -151,6 +152,15 @@ struct dl { + char **argv; + bool no_nice_names; + struct dl_opts opts; ++ json_writer_t *jw; ++ bool json_output; ++ bool pretty_output; ++ struct { ++ bool present; ++ char *bus_name; ++ char *dev_name; ++ uint32_t port_index; ++ } arr_last; + }; + + static int dl_argc(struct dl *dl) +@@ -912,52 +922,161 @@ static void cmd_dev_help(void) + pr_err("Usage: devlink dev show [ DEV ]\n"); + } + +-static void __pr_out_handle(const char *bus_name, const char *dev_name) ++static bool cmp_arr_last_handle(struct dl *dl, const char *bus_name, ++ const char *dev_name) + { +- pr_out("%s/%s", bus_name, dev_name); ++ if (!dl->arr_last.present) ++ return false; ++ return strcmp(dl->arr_last.bus_name, bus_name) == 0 && ++ strcmp(dl->arr_last.dev_name, dev_name) == 0; + } + +-static void pr_out_handle(struct nlattr **tb) ++static void arr_last_handle_set(struct dl *dl, const char *bus_name, ++ const char *dev_name) + { +- __pr_out_handle(mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]), +- mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME])); ++ dl->arr_last.present = true; ++ free(dl->arr_last.dev_name); ++ free(dl->arr_last.bus_name); ++ dl->arr_last.bus_name = strdup(bus_name); ++ dl->arr_last.dev_name = strdup(dev_name); + } + +-static void __pr_out_port_handle(const char *bus_name, const char *dev_name, +- uint32_t port_index) ++static bool should_arr_last_handle_start(struct dl *dl, const char *bus_name, ++ const char *dev_name) + { +- __pr_out_handle(bus_name, dev_name); +- pr_out("/%d", port_index); ++ return !cmp_arr_last_handle(dl, bus_name, dev_name); + } + +-static void pr_out_port_handle(struct nlattr **tb) ++static bool should_arr_last_handle_end(struct dl *dl, const char *bus_name, ++ const char *dev_name) + { +- __pr_out_port_handle(mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]), +- mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]), +- mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX])); ++ return dl->arr_last.present && ++ !cmp_arr_last_handle(dl, bus_name, dev_name); + } + +-static void __pr_out_port_handle_nice(struct dl *dl, const char *bus_name, +- const char *dev_name, uint32_t port_index) ++static void __pr_out_handle_start(struct dl *dl, struct nlattr **tb, ++ bool content, bool array) + { +- char *ifname; +- int err; ++ const char *bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); ++ const char *dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); ++ char buf[32]; + +- if (dl->no_nice_names) +- goto no_nice_names; ++ sprintf(buf, "%s/%s", bus_name, dev_name); + +- err = ifname_map_rev_lookup(dl, bus_name, dev_name, +- port_index, &ifname); +- if (err) +- goto no_nice_names; +- pr_out("%s", ifname); +- return; ++ if (dl->json_output) { ++ if (array) { ++ if (should_arr_last_handle_end(dl, bus_name, dev_name)) ++ jsonw_end_array(dl->jw); ++ if (should_arr_last_handle_start(dl, bus_name, ++ dev_name)) { ++ jsonw_name(dl->jw, buf); ++ jsonw_start_array(dl->jw); ++ jsonw_start_object(dl->jw); ++ arr_last_handle_set(dl, bus_name, dev_name); ++ } else { ++ jsonw_start_object(dl->jw); ++ } ++ } else { ++ jsonw_name(dl->jw, buf); ++ jsonw_start_object(dl->jw); ++ } ++ } else { ++ pr_out("%s%s", buf, content ? ":" : ""); ++ } ++} + +-no_nice_names: +- __pr_out_port_handle(bus_name, dev_name, port_index); ++static void pr_out_handle_start_arr(struct dl *dl, struct nlattr **tb) ++{ ++ __pr_out_handle_start(dl, tb, true, true); + } + +-static void pr_out_port_handle_nice(struct dl *dl, struct nlattr **tb) ++static void pr_out_handle_end(struct dl *dl) ++{ ++ if (dl->json_output) ++ jsonw_end_object(dl->jw); ++ else ++ pr_out("\n"); ++} ++ ++static void pr_out_handle(struct dl *dl, struct nlattr **tb) ++{ ++ __pr_out_handle_start(dl, tb, false, false); ++ pr_out_handle_end(dl); ++} ++ ++static bool cmp_arr_last_port_handle(struct dl *dl, const char *bus_name, ++ const char *dev_name, uint32_t port_index) ++{ ++ return cmp_arr_last_handle(dl, bus_name, dev_name) && ++ dl->arr_last.port_index == port_index; ++} ++ ++static void arr_last_port_handle_set(struct dl *dl, const char *bus_name, ++ const char *dev_name, uint32_t port_index) ++{ ++ arr_last_handle_set(dl, bus_name, dev_name); ++ dl->arr_last.port_index = port_index; ++} ++ ++static bool should_arr_last_port_handle_start(struct dl *dl, ++ const char *bus_name, ++ const char *dev_name, ++ uint32_t port_index) ++{ ++ return !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index); ++} ++ ++static bool should_arr_last_port_handle_end(struct dl *dl, ++ const char *bus_name, ++ const char *dev_name, ++ uint32_t port_index) ++{ ++ return dl->arr_last.present && ++ !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index); ++} ++ ++static void __pr_out_port_handle_start(struct dl *dl, const char *bus_name, ++ const char *dev_name, ++ uint32_t port_index, bool try_nice, ++ bool array) ++{ ++ static char buf[32]; ++ char *ifname = NULL; ++ ++ if (dl->no_nice_names || !try_nice || ++ ifname_map_rev_lookup(dl, bus_name, dev_name, ++ port_index, &ifname) != 0) ++ sprintf(buf, "%s/%s/%d", bus_name, dev_name, port_index); ++ else ++ sprintf(buf, "%s", ifname); ++ ++ if (dl->json_output) { ++ if (array) { ++ if (should_arr_last_port_handle_end(dl, bus_name, ++ dev_name, ++ port_index)) ++ jsonw_end_array(dl->jw); ++ if (should_arr_last_port_handle_start(dl, bus_name, ++ dev_name, ++ port_index)) { ++ jsonw_name(dl->jw, buf); ++ jsonw_start_array(dl->jw); ++ jsonw_start_object(dl->jw); ++ arr_last_port_handle_set(dl, bus_name, dev_name, ++ port_index); ++ } else { ++ jsonw_start_object(dl->jw); ++ } ++ } else { ++ jsonw_name(dl->jw, buf); ++ jsonw_start_object(dl->jw); ++ } ++ } else { ++ pr_out("%s:", buf); ++ } ++} ++ ++static void pr_out_port_handle_start(struct dl *dl, struct nlattr **tb, bool try_nice) + { + const char *bus_name; + const char *dev_name; +@@ -966,25 +1085,80 @@ static void pr_out_port_handle_nice(struct dl *dl, struct nlattr **tb) + bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); + dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); + port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); ++ __pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, false); ++} ++ ++static void pr_out_port_handle_start_arr(struct dl *dl, struct nlattr **tb, bool try_nice) ++{ ++ const char *bus_name; ++ const char *dev_name; ++ uint32_t port_index; + +- __pr_out_port_handle_nice(dl, bus_name, dev_name, port_index); ++ bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); ++ dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); ++ port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); ++ __pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, true); + } + +-static void pr_out_dev(struct nlattr **tb) ++static void pr_out_port_handle_end(struct dl *dl) + { +- pr_out_handle(tb); +- pr_out("\n"); ++ if (dl->json_output) ++ jsonw_end_object(dl->jw); ++ else ++ pr_out("\n"); ++} ++ ++ ++static void pr_out_str(struct dl *dl, const char *name, const char *val) ++{ ++ if (dl->json_output) ++ jsonw_string_field(dl->jw, name, val); ++ else ++ pr_out(" %s %s", name, val); ++} ++ ++static void pr_out_uint(struct dl *dl, const char *name, unsigned int val) ++{ ++ if (dl->json_output) ++ jsonw_uint_field(dl->jw, name, val); ++ else ++ pr_out(" %s %u", name, val); ++} ++ ++static void pr_out_dev(struct dl *dl, struct nlattr **tb) ++{ ++ pr_out_handle(dl, tb); ++} ++ ++static void pr_out_section_start(struct dl *dl, const char *name) ++{ ++ if (dl->json_output) { ++ jsonw_start_object(dl->jw); ++ jsonw_name(dl->jw, name); ++ jsonw_start_object(dl->jw); ++ } ++} ++ ++static void pr_out_section_end(struct dl *dl) ++{ ++ if (dl->json_output) { ++ if (dl->arr_last.present) ++ jsonw_end_array(dl->jw); ++ jsonw_end_object(dl->jw); ++ jsonw_end_object(dl->jw); ++ } + } + + static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data) + { ++ struct dl *dl = data; + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME]) + return MNL_CB_ERROR; +- pr_out_dev(tb); ++ pr_out_dev(dl, tb); + return MNL_CB_OK; + } + +@@ -1005,7 +1179,10 @@ static int cmd_dev_show(struct dl *dl) + return err; + } + +- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, NULL); ++ pr_out_section_start(dl, "dev"); ++ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, dl); ++ pr_out_section_end(dl); ++ return err; + } + + static int cmd_dev(struct dl *dl) +@@ -1041,38 +1218,39 @@ static const char *port_type_name(uint32_t type) + } + } + +-static void pr_out_port(struct nlattr **tb) ++static void pr_out_port(struct dl *dl, struct nlattr **tb) + { + struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE]; + struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE]; + +- pr_out_port_handle(tb); +- pr_out(":"); ++ pr_out_port_handle_start(dl, tb, false); + if (pt_attr) { + uint16_t port_type = mnl_attr_get_u16(pt_attr); + +- pr_out(" type %s", port_type_name(port_type)); ++ pr_out_str(dl, "type", port_type_name(port_type)); + if (dpt_attr) { + uint16_t des_port_type = mnl_attr_get_u16(dpt_attr); + + if (port_type != des_port_type) +- pr_out("(%s)", port_type_name(des_port_type)); ++ pr_out_str(dl, "des_type", ++ port_type_name(des_port_type)); + } + } + if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME]) +- pr_out(" netdev %s", +- mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME])); ++ pr_out_str(dl, "netdev", ++ mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME])); + if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME]) +- pr_out(" ibdev %s", +- mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME])); ++ pr_out_str(dl, "ibdev", ++ mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME])); + if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]) +- pr_out(" split_group %u", +- mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])); +- pr_out("\n"); ++ pr_out_uint(dl, "split_group", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])); ++ pr_out_port_handle_end(dl); + } + + static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data) + { ++ struct dl *dl = data; + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + +@@ -1080,7 +1258,7 @@ static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data) + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_PORT_INDEX]) + return MNL_CB_ERROR; +- pr_out_port(tb); ++ pr_out_port(dl, tb); + return MNL_CB_OK; + } + +@@ -1101,7 +1279,10 @@ static int cmd_port_show(struct dl *dl) + return err; + } + +- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, NULL); ++ pr_out_section_start(dl, "port"); ++ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, dl); ++ pr_out_section_end(dl); ++ return err; + } + + static int cmd_port_set(struct dl *dl) +@@ -1192,20 +1373,27 @@ static void cmd_sb_help(void) + pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); + } + +-static void pr_out_sb(struct nlattr **tb) ++static void pr_out_sb(struct dl *dl, struct nlattr **tb) + { +- pr_out_handle(tb); +- pr_out(": sb %u size %u ing_pools %u eg_pools %u ing_tcs %u eg_tcs %u\n", +- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), +- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]), +- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]), +- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]), +- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]), +- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])); ++ pr_out_handle_start_arr(dl, tb); ++ pr_out_uint(dl, "sb", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX])); ++ pr_out_uint(dl, "size", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE])); ++ pr_out_uint(dl, "ing_pools", ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT])); ++ pr_out_uint(dl, "eg_pools", ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT])); ++ pr_out_uint(dl, "ing_tcs", ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT])); ++ pr_out_uint(dl, "eg_tcs", ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])); ++ pr_out_handle_end(dl); + } + + static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data) + { ++ struct dl *dl = data; + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + +@@ -1217,7 +1405,7 @@ static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data) + !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] || + !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]) + return MNL_CB_ERROR; +- pr_out_sb(tb); ++ pr_out_sb(dl, tb); + return MNL_CB_OK; + } + +@@ -1238,7 +1426,10 @@ static int cmd_sb_show(struct dl *dl) + return err; + } + +- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, NULL); ++ pr_out_section_start(dl, "sb"); ++ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, dl); ++ pr_out_section_end(dl); ++ return err; + } + + static const char *pool_type_name(uint8_t type) +@@ -1259,19 +1450,25 @@ static const char *threshold_type_name(uint8_t type) + } + } + +-static void pr_out_sb_pool(struct nlattr **tb) ++static void pr_out_sb_pool(struct dl *dl, struct nlattr **tb) + { +- pr_out_handle(tb); +- pr_out(": sb %u pool %u type %s size %u thtype %s\n", +- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), +- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), +- pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), +- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]), +- threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]))); ++ pr_out_handle_start_arr(dl, tb); ++ pr_out_uint(dl, "sb", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX])); ++ pr_out_uint(dl, "pool", ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX])); ++ pr_out_str(dl, "type", ++ pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]))); ++ pr_out_uint(dl, "size", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE])); ++ pr_out_str(dl, "thtype", ++ threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]))); ++ pr_out_handle_end(dl); + } + + static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data) + { ++ struct dl *dl = data; + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + +@@ -1281,7 +1478,7 @@ static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data) + !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] || + !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]) + return MNL_CB_ERROR; +- pr_out_sb_pool(tb); ++ pr_out_sb_pool(dl, tb); + return MNL_CB_OK; + } + +@@ -1303,7 +1500,10 @@ static int cmd_sb_pool_show(struct dl *dl) + return err; + } + +- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, NULL); ++ pr_out_section_start(dl, "pool"); ++ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, dl); ++ pr_out_section_end(dl); ++ return err; + } + + static int cmd_sb_pool_set(struct dl *dl) +@@ -1341,11 +1541,14 @@ static int cmd_sb_pool(struct dl *dl) + + static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb) + { +- pr_out_port_handle_nice(dl, tb); +- pr_out(": sb %u pool %u threshold %u\n", +- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), +- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), +- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); ++ pr_out_port_handle_start_arr(dl, tb, true); ++ pr_out_uint(dl, "sb", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX])); ++ pr_out_uint(dl, "pool", ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX])); ++ pr_out_uint(dl, "threshold", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); ++ pr_out_port_handle_end(dl); + } + + static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data) +@@ -1382,7 +1585,10 @@ static int cmd_sb_port_pool_show(struct dl *dl) + return err; + } + +- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl); ++ pr_out_section_start(dl, "port_pool"); ++ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl); ++ pr_out_section_end(dl); ++ return 0; + } + + static int cmd_sb_port_pool_set(struct dl *dl) +@@ -1433,13 +1639,18 @@ static int cmd_sb_port(struct dl *dl) + + static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb) + { +- pr_out_port_handle_nice(dl, tb); +- pr_out(": sb %u tc %u type %s pool %u threshold %u\n", +- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), +- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]), +- pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), +- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), ++ pr_out_port_handle_start_arr(dl, tb, true); ++ pr_out_uint(dl, "sb", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX])); ++ pr_out_uint(dl, "tc", ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX])); ++ pr_out_str(dl, "type", ++ pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]))); ++ pr_out_uint(dl, "pool", ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX])); ++ pr_out_uint(dl, "threshold", + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); ++ pr_out_port_handle_end(dl); + } + + static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data) +@@ -1476,7 +1687,10 @@ static int cmd_sb_tc_bind_show(struct dl *dl) + return err; + } + +- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl); ++ pr_out_section_start(dl, "tc_bind"); ++ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl); ++ pr_out_section_end(dl); ++ return err; + } + + static int cmd_sb_tc_bind_set(struct dl *dl) +@@ -1649,11 +1863,44 @@ static void pr_out_occ_show_item_list(const char *label, struct list_head *list, + pr_out("\n"); + } + +-static void pr_out_occ_show_port(struct occ_port *occ_port) ++static void pr_out_json_occ_show_item_list(struct dl *dl, const char *label, ++ struct list_head *list, ++ bool bound_pool) ++{ ++ struct occ_item *occ_item; ++ char buf[32]; ++ ++ jsonw_name(dl->jw, label); ++ jsonw_start_object(dl->jw); ++ list_for_each_entry(occ_item, list, list) { ++ sprintf(buf, "%u", occ_item->index); ++ jsonw_name(dl->jw, buf); ++ jsonw_start_object(dl->jw); ++ if (bound_pool) ++ jsonw_uint_field(dl->jw, "bound_pool", ++ occ_item->bound_pool_index); ++ jsonw_uint_field(dl->jw, "current", occ_item->cur); ++ jsonw_uint_field(dl->jw, "max", occ_item->max); ++ jsonw_end_object(dl->jw); ++ } ++ jsonw_end_object(dl->jw); ++} ++ ++static void pr_out_occ_show_port(struct dl *dl, struct occ_port *occ_port) + { +- pr_out_occ_show_item_list("pool", &occ_port->pool_list, false); +- pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true); +- pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true); ++ if (dl->json_output) { ++ pr_out_json_occ_show_item_list(dl, "pool", ++ &occ_port->pool_list, false); ++ pr_out_json_occ_show_item_list(dl, "itc", ++ &occ_port->ing_tc_list, true); ++ pr_out_json_occ_show_item_list(dl, "etc", ++ &occ_port->eg_tc_list, true); ++ } else { ++ pr_out("\n"); ++ pr_out_occ_show_item_list("pool", &occ_port->pool_list, false); ++ pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true); ++ pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true); ++ } + } + + static void pr_out_occ_show(struct occ_show *occ_show) +@@ -1663,10 +1910,10 @@ static void pr_out_occ_show(struct occ_show *occ_show) + struct occ_port *occ_port; + + list_for_each_entry(occ_port, &occ_show->port_list, list) { +- __pr_out_port_handle_nice(dl, opts->bus_name, opts->dev_name, +- occ_port->port_index); +- pr_out(":\n"); +- pr_out_occ_show_port(occ_port); ++ __pr_out_port_handle_start(dl, opts->bus_name, opts->dev_name, ++ occ_port->port_index, true, false); ++ pr_out_occ_show_port(dl, occ_port); ++ pr_out_port_handle_end(dl); + } + } + +@@ -1793,7 +2040,9 @@ static int cmd_sb_occ_show(struct dl *dl) + if (err) + goto out; + ++ pr_out_section_start(dl, "occupancy"); + pr_out_occ_show(occ_show); ++ pr_out_section_end(dl); + + out: + occ_show_free(occ_show); +@@ -1949,7 +2198,7 @@ static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data) + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME]) + return MNL_CB_ERROR; + pr_out_mon_header(genl->cmd); +- pr_out_dev(tb); ++ pr_out_dev(dl, tb); + break; + case DEVLINK_CMD_PORT_GET: /* fall through */ + case DEVLINK_CMD_PORT_SET: /* fall through */ +@@ -1960,7 +2209,7 @@ static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data) + !tb[DEVLINK_ATTR_PORT_INDEX]) + return MNL_CB_ERROR; + pr_out_mon_header(genl->cmd); +- pr_out_port(tb); ++ pr_out_port(dl, tb); + break; + } + return MNL_CB_OK; +@@ -2055,8 +2304,18 @@ static int dl_init(struct dl *dl, int argc, char **argv) + pr_err("Failed to create index map\n"); + goto err_ifname_map_create; + } ++ if (dl->json_output) { ++ dl->jw = jsonw_new(stdout); ++ if (!dl->jw) { ++ pr_err("Failed to create JSON writer\n"); ++ goto err_json_new; ++ } ++ jsonw_pretty(dl->jw, dl->pretty_output); ++ } + return 0; + ++err_json_new: ++ ifname_map_fini(dl); + err_ifname_map_create: + mnlg_socket_close(dl->nlg); + return err; +@@ -2064,6 +2323,8 @@ err_ifname_map_create: + + static void dl_fini(struct dl *dl) + { ++ if (dl->json_output) ++ jsonw_destroy(&dl->jw); + ifname_map_fini(dl); + mnlg_socket_close(dl->nlg); + } +@@ -2088,6 +2349,8 @@ int main(int argc, char **argv) + static const struct option long_options[] = { + { "Version", no_argument, NULL, 'V' }, + { "no-nice-names", no_argument, NULL, 'n' }, ++ { "json", no_argument, NULL, 'j' }, ++ { "pretty", no_argument, NULL, 'p' }, + { NULL, 0, NULL, 0 } + }; + struct dl *dl; +@@ -2101,7 +2364,7 @@ int main(int argc, char **argv) + return EXIT_FAILURE; + } + +- while ((opt = getopt_long(argc, argv, "Vn", ++ while ((opt = getopt_long(argc, argv, "Vnjp", + long_options, NULL)) >= 0) { + + switch (opt) { +@@ -2111,6 +2374,12 @@ int main(int argc, char **argv) + case 'n': + dl->no_nice_names = true; + break; ++ case 'j': ++ dl->json_output = true; ++ break; ++ case 'p': ++ dl->pretty_output = true; ++ break; + default: + pr_err("Unknown option.\n"); + help(); +-- +2.9.3 + diff --git a/iproute.spec b/iproute.spec index 7e92eb2..e1479ef 100644 --- a/iproute.spec +++ b/iproute.spec @@ -2,7 +2,7 @@ Summary: Advanced IP routing and network device configuration tools Name: iproute Version: 4.6.0 -Release: 3%{?dist} +Release: 4%{?dist} Group: Applications/System URL: http://kernel.org/pub/linux/utils/net/%{name}2/ Source0: http://kernel.org/pub/linux/utils/net/%{name}2/%{name}2-%{version}.tar.xz @@ -35,6 +35,15 @@ Patch4: 0002-devlink-implement-shared-buffer-occupancy-control.patch Patch5: 0001-man-Add-devlink-man-pages-to-Makefile.patch Patch6: 0002-man-Point-to-devlink-sb-from-devlink-man-page.patch +# devlink JSON support +# +# Accepted by upstream +# +# https://patchwork.ozlabs.org/patch/651711/ +# https://patchwork.ozlabs.org/patch/651712/ +Patch7: 0001-devlink-write-usage-help-messages-to-stderr.patch +Patch8: 0002-devlink-add-option-to-generate-JSON-output.patch + License: GPLv2+ and Public Domain BuildRequires: bison BuildRequires: elfutils-libelf-devel @@ -102,6 +111,8 @@ The libnetlink static library. %patch4 -p1 %patch5 -p1 %patch6 -p1 +%patch7 -p1 +%patch8 -p1 %build export CFLAGS="%{optflags}" @@ -185,6 +196,9 @@ rm -rf '%{buildroot}%{_docdir}' %{_includedir}/libnetlink.h %changelog +* Fri Nov 25 2016 Ido Schimmel - 4.6.0-4 +- Add devlink JSON patches + * Fri Nov 25 2016 Ido Schimmel - 4.6.0-3 - Add Makefile patches to install devlink manpages From 34311e1c0b1c048b1fd130449df1538a6c355822 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 25 Nov 2016 18:39:41 +0200 Subject: [PATCH 04/11] Add matchall classifier patches Signed-off-by: Phil Sutter --- ...-for-the-matchall-traffic-classifier.patch | 186 ++++++++++++++++++ ...an-entry-for-the-matchall-classifier.patch | 132 +++++++++++++ iproute.spec | 18 +- matchall-kernel-headers.patch | 32 +++ 4 files changed, 367 insertions(+), 1 deletion(-) create mode 100644 0001-tc-Add-support-for-the-matchall-traffic-classifier.patch create mode 100644 0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch create mode 100644 matchall-kernel-headers.patch diff --git a/0001-tc-Add-support-for-the-matchall-traffic-classifier.patch b/0001-tc-Add-support-for-the-matchall-traffic-classifier.patch new file mode 100644 index 0000000..af450c4 --- /dev/null +++ b/0001-tc-Add-support-for-the-matchall-traffic-classifier.patch @@ -0,0 +1,186 @@ +From d5cbf3ff0561b6c8158c3538c7fe1946add9dec3 Mon Sep 17 00:00:00 2001 +From: Yotam Gigi +Date: Wed, 31 Aug 2016 09:28:26 +0200 +Subject: [PATCH 1/2] tc: Add support for the matchall traffic classifier. + +The matchall classifier matches every packet and allows the user to apply +actions on it. In addition, it supports the skip_sw and skip_hw (as can +be found on u32 and flower filter) that direct the kernel to skip the +software/hardware processing of the actions. + +This filter is very useful in usecases where every packet should be +matched. For example, packet mirroring (SPAN) can be setup very easily +using that filter. + +Signed-off-by: Yotam Gigi +Signed-off-by: Jiri Pirko +--- + tc/Makefile | 1 + + tc/f_matchall.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 144 insertions(+) + create mode 100644 tc/f_matchall.c + +diff --git a/tc/Makefile b/tc/Makefile +index 42747c5..8917eaf 100644 +--- a/tc/Makefile ++++ b/tc/Makefile +@@ -67,6 +67,7 @@ TCMODULES += q_pie.o + TCMODULES += q_hhf.o + TCMODULES += q_clsact.o + TCMODULES += e_bpf.o ++TCMODULES += f_matchall.o + + ifeq ($(TC_CONFIG_IPSET), y) + ifeq ($(TC_CONFIG_XT), y) +diff --git a/tc/f_matchall.c b/tc/f_matchall.c +new file mode 100644 +index 0000000..04e524e +--- /dev/null ++++ b/tc/f_matchall.c +@@ -0,0 +1,143 @@ ++/* ++ * f_matchall.c Match-all Classifier ++ * ++ * This program is free software; you can distribute 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: Jiri Pirko , Yotam Gigi ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "utils.h" ++#include "tc_util.h" ++ ++static void explain(void) ++{ ++ fprintf(stderr, "Usage: ... matchall [skip_sw | skip_hw]\n"); ++ fprintf(stderr, " [ action ACTION_SPEC ] [ classid CLASSID ]\n"); ++ fprintf(stderr, "\n"); ++ fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n"); ++ fprintf(stderr, " FILTERID := X:Y:Z\n"); ++ fprintf(stderr, " ACTION_SPEC := ... look at individual actions\n"); ++ fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n"); ++} ++ ++static int matchall_parse_opt(struct filter_util *qu, char *handle, ++ int argc, char **argv, struct nlmsghdr *n) ++{ ++ struct tcmsg *t = NLMSG_DATA(n); ++ struct rtattr *tail; ++ __u32 flags = 0; ++ long h = 0; ++ ++ if (handle) { ++ h = strtol(handle, NULL, 0); ++ if (h == LONG_MIN || h == LONG_MAX) { ++ fprintf(stderr, "Illegal handle \"%s\", must be numeric.\n", ++ handle); ++ return -1; ++ } ++ } ++ t->tcm_handle = h; ++ ++ if (argc == 0) ++ return 0; ++ ++ tail = (struct rtattr *)(((void *)n)+NLMSG_ALIGN(n->nlmsg_len)); ++ addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0); ++ ++ while (argc > 0) { ++ if (matches(*argv, "classid") == 0 || ++ strcmp(*argv, "flowid") == 0) { ++ unsigned int handle; ++ ++ NEXT_ARG(); ++ if (get_tc_classid(&handle, *argv)) { ++ fprintf(stderr, "Illegal \"classid\"\n"); ++ return -1; ++ } ++ addattr_l(n, MAX_MSG, TCA_MATCHALL_CLASSID, &handle, 4); ++ } else if (matches(*argv, "action") == 0) { ++ NEXT_ARG(); ++ if (parse_action(&argc, &argv, TCA_MATCHALL_ACT, n)) { ++ fprintf(stderr, "Illegal \"action\"\n"); ++ return -1; ++ } ++ continue; ++ ++ } else if (strcmp(*argv, "skip_hw") == 0) { ++ NEXT_ARG(); ++ flags |= TCA_CLS_FLAGS_SKIP_HW; ++ continue; ++ } else if (strcmp(*argv, "skip_sw") == 0) { ++ NEXT_ARG(); ++ flags |= TCA_CLS_FLAGS_SKIP_SW; ++ continue; ++ } else if (strcmp(*argv, "help") == 0) { ++ explain(); ++ return -1; ++ } else { ++ fprintf(stderr, "What is \"%s\"?\n", *argv); ++ explain(); ++ return -1; ++ } ++ argc--; argv++; ++ } ++ ++ if (flags) { ++ if (!(flags ^ (TCA_CLS_FLAGS_SKIP_HW | ++ TCA_CLS_FLAGS_SKIP_SW))) { ++ fprintf(stderr, ++ "skip_hw and skip_sw are mutually exclusive\n"); ++ return -1; ++ } ++ addattr_l(n, MAX_MSG, TCA_MATCHALL_FLAGS, &flags, 4); ++ } ++ ++ tail->rta_len = (((void *)n)+n->nlmsg_len) - (void *)tail; ++ return 0; ++} ++ ++static int matchall_print_opt(struct filter_util *qu, FILE *f, ++ struct rtattr *opt, __u32 handle) ++{ ++ struct rtattr *tb[TCA_MATCHALL_MAX+1]; ++ ++ if (opt == NULL) ++ return 0; ++ ++ parse_rtattr_nested(tb, TCA_MATCHALL_MAX, opt); ++ ++ if (handle) ++ fprintf(f, "handle 0x%x ", handle); ++ ++ if (tb[TCA_MATCHALL_CLASSID]) { ++ SPRINT_BUF(b1); ++ fprintf(f, "flowid %s ", ++ sprint_tc_classid(rta_getattr_u32(tb[TCA_MATCHALL_CLASSID]), b1)); ++ } ++ ++ if (tb[TCA_MATCHALL_ACT]) ++ tc_print_action(f, tb[TCA_MATCHALL_ACT]); ++ ++ return 0; ++} ++ ++struct filter_util matchall_filter_util = { ++ .id = "matchall", ++ .parse_fopt = matchall_parse_opt, ++ .print_fopt = matchall_print_opt, ++}; +-- +2.9.3 + diff --git a/0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch b/0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch new file mode 100644 index 0000000..1909c22 --- /dev/null +++ b/0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch @@ -0,0 +1,132 @@ +From 0501294bca39a19090dae302dc491684470b1a0d Mon Sep 17 00:00:00 2001 +From: Yotam Gigi +Date: Wed, 31 Aug 2016 09:28:27 +0200 +Subject: [PATCH 2/2] tc: man: Add man entry for the matchall classifier. + +In addition to providing information about the mathcall filter and its +configurations, the man entry contains examples for creating port +mirorring entries. + +Signed-off-by: Yotam Gigi +Signed-off-by: Jiri Pirko +--- + man/man8/Makefile | 2 +- + man/man8/tc-matchall.8 | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ + man/man8/tc.8 | 5 ++++ + 3 files changed, 82 insertions(+), 1 deletion(-) + create mode 100644 man/man8/tc-matchall.8 + +diff --git a/man/man8/Makefile b/man/man8/Makefile +index 9badbed..9213769 100644 +--- a/man/man8/Makefile ++++ b/man/man8/Makefile +@@ -14,7 +14,7 @@ MAN8PAGES = $(TARGETS) ip.8 arpd.8 lnstat.8 routel.8 rtacct.8 rtmon.8 rtpr.8 ss. + tipc.8 tipc-bearer.8 tipc-link.8 tipc-media.8 tipc-nametable.8 \ + tipc-node.8 tipc-socket.8 \ + tc-basic.8 tc-cgroup.8 tc-flow.8 tc-flower.8 tc-fw.8 tc-route.8 \ +- tc-tcindex.8 tc-u32.8 \ ++ tc-tcindex.8 tc-u32.8 tc-matchall.8 \ + tc-connmark.8 tc-csum.8 tc-mirred.8 tc-nat.8 tc-pedit.8 tc-police.8 \ + tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 \ + devlink.8 devlink-dev.8 devlink-monitor.8 devlink-port.8 devlink-sb.8 +diff --git a/man/man8/tc-matchall.8 b/man/man8/tc-matchall.8 +new file mode 100644 +index 0000000..f920922 +--- /dev/null ++++ b/man/man8/tc-matchall.8 +@@ -0,0 +1,76 @@ ++.TH "Match-all classifier in tc" 8 "21 Oct 2015" "iproute2" "Linux" ++ ++.SH NAME ++matchall \- traffic control filter that matches every packet ++.SH SYNOPSIS ++.in +8 ++.ti -8 ++.BR tc " " filter " ... " matchall " [ " ++.BR skip_sw " | " skip_hw ++.R " ] [ " ++.B action ++.IR ACTION_SPEC " ] [ " ++.B classid ++.IR CLASSID " ]" ++.SH DESCRIPTION ++The ++.B matchall ++filter allows to classify every packet that flows on the port and run a ++action on it. ++.SH OPTIONS ++.TP ++.BI action " ACTION_SPEC" ++Apply an action from the generic actions framework on matching packets. ++.TP ++.BI classid " CLASSID" ++Push matching packets into the class identified by ++.IR CLASSID . ++.TP ++.BI skip_sw ++Do not process filter by software. If hardware has no offload support for this ++filter, or TC offload is not enabled for the interface, operation will fail. ++.TP ++.BI skip_hw ++Do not process filter by hardware. ++.SH EXAMPLES ++To create ingress mirroring from port eth1 to port eth2: ++.RS ++.EX ++ ++tc qdisc add dev eth1 handle ffff: ingress ++tc filter add dev eth1 parent ffff: \\ ++ matchall skip_sw \\ ++ action mirred egress mirror \\ ++ dev eth2 ++.EE ++.RE ++ ++The first command creats an ingress qdisc with handle ++.BR ffff: ++on device ++.BR eth1 ++where the second command attaches a matchall filters on it that mirrors the ++packets to device eth2. ++ ++To create egress mirroring from port eth1 to port eth2: ++.EX ++ ++tc qdisc add dev eth1 handle 1: root prio ++tc filter add dev eth1 parent 1: \\ ++ matchall skip_sw \\ ++ action mirred egress mirror \\ ++ dev eth2 ++.EE ++.RE ++ ++The first command creats an egress qdisc with handle ++.BR 1: ++that replaces the root qdisc on device ++.BR eth1 ++where the second command attaches a matchall filters on it that mirrors the ++packets to device eth2. ++ ++ ++.EE ++.SH SEE ALSO ++.BR tc (8), +diff --git a/man/man8/tc.8 b/man/man8/tc.8 +index 4e99dca..7ee1c9c 100644 +--- a/man/man8/tc.8 ++++ b/man/man8/tc.8 +@@ -187,6 +187,11 @@ u32 + Generic filtering on arbitrary packet data, assisted by syntax to abstract common operations. See + .BR tc-u32 (8) + for details. ++.TP ++matchall ++Traffic control filter that matches every packet. See ++.BR tc-matchall (8) ++for details. + + .SH CLASSLESS QDISCS + The classless qdiscs are: +-- +2.9.3 + diff --git a/iproute.spec b/iproute.spec index e1479ef..cbae61d 100644 --- a/iproute.spec +++ b/iproute.spec @@ -2,7 +2,7 @@ Summary: Advanced IP routing and network device configuration tools Name: iproute Version: 4.6.0 -Release: 4%{?dist} +Release: 5%{?dist} Group: Applications/System URL: http://kernel.org/pub/linux/utils/net/%{name}2/ Source0: http://kernel.org/pub/linux/utils/net/%{name}2/%{name}2-%{version}.tar.xz @@ -44,6 +44,16 @@ Patch6: 0002-man-Point-to-devlink-sb-from-devlink-man-page.patch Patch7: 0001-devlink-write-usage-help-messages-to-stderr.patch Patch8: 0002-devlink-add-option-to-generate-JSON-output.patch +# matchall classifier +# +# Accepted by upstream +# +# https://patchwork.ozlabs.org/patch/664374/ +# https://patchwork.ozlabs.org/patch/664375/ +Patch9: matchall-kernel-headers.patch +Patch10: 0001-tc-Add-support-for-the-matchall-traffic-classifier.patch +Patch11: 0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch + License: GPLv2+ and Public Domain BuildRequires: bison BuildRequires: elfutils-libelf-devel @@ -113,6 +123,9 @@ The libnetlink static library. %patch6 -p1 %patch7 -p1 %patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 %build export CFLAGS="%{optflags}" @@ -196,6 +209,9 @@ rm -rf '%{buildroot}%{_docdir}' %{_includedir}/libnetlink.h %changelog +* Fri Nov 25 2016 Ido Schimmel - 4.6.0-5 +- Add matchall classifier + * Fri Nov 25 2016 Ido Schimmel - 4.6.0-4 - Add devlink JSON patches diff --git a/matchall-kernel-headers.patch b/matchall-kernel-headers.patch new file mode 100644 index 0000000..8c9d673 --- /dev/null +++ b/matchall-kernel-headers.patch @@ -0,0 +1,32 @@ +diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h +index b69358b..18fb87e 100644 +--- a/include/linux/pkt_cls.h ++++ b/include/linux/pkt_cls.h +@@ -96,6 +96,10 @@ enum { + + #define TCA_POLICE_MAX (__TCA_POLICE_MAX - 1) + ++/* tca flags definitions */ ++#define TCA_CLS_FLAGS_SKIP_HW (1 << 0) ++#define TCA_CLS_FLAGS_SKIP_SW (1 << 1) ++ + /* U32 filters */ + + #define TC_U32_HTID(h) ((h)&0xFFF00000) +@@ -370,6 +374,16 @@ enum { + + #define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1) + ++enum { ++ TCA_MATCHALL_UNSPEC, ++ TCA_MATCHALL_CLASSID, ++ TCA_MATCHALL_ACT, ++ TCA_MATCHALL_FLAGS, ++ __TCA_MATCHALL_MAX, ++}; ++ ++#define TCA_MATCHALL_MAX (__TCA_MATCHALL_MAX - 1) ++ + /* Extended Matches */ + + struct tcf_ematch_tree_hdr { From 3834e1098e04a250eafda36820a4ba1231d3084f Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 13 Jan 2017 14:46:17 +0100 Subject: [PATCH 05/11] Resolve bz#1411127 --- ..._xt-Fix-segfault-with-iptables-1.6.0.patch | 36 +++++++++++++++++++ iproute.spec | 12 ++++++- 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 0001-tc-m_xt-Fix-segfault-with-iptables-1.6.0.patch diff --git a/0001-tc-m_xt-Fix-segfault-with-iptables-1.6.0.patch b/0001-tc-m_xt-Fix-segfault-with-iptables-1.6.0.patch new file mode 100644 index 0000000..103a486 --- /dev/null +++ b/0001-tc-m_xt-Fix-segfault-with-iptables-1.6.0.patch @@ -0,0 +1,36 @@ +From 34ea60b5b7645e96c600b8073dd82ac65144d711 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Thu, 12 Jan 2017 15:12:26 +0100 +Subject: [iproute PATCH] tc: m_xt: Fix segfault with iptables-1.6.0 + +Said iptables version introduced struct xtables_globals field +'compat_rev', a function pointer. Initializing it is mandatory as +libxtables calls it without existence check. + +Without this, tc segfaults when using the xt action like so: + +| tc filter add dev d0 parent ffff: u32 match u32 0 0 \ +| action xt -j MARK --set-mark 20 + +Signed-off-by: Phil Sutter +--- + tc/m_xt.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tc/m_xt.c b/tc/m_xt.c +index dbb54981462ee..57ed40d7aa3a8 100644 +--- a/tc/m_xt.c ++++ b/tc/m_xt.c +@@ -77,6 +77,9 @@ static struct xtables_globals tcipt_globals = { + .orig_opts = original_opts, + .opts = original_opts, + .exit_err = NULL, ++#if (XTABLES_VERSION_CODE >= 11) ++ .compat_rev = xtables_compatible_revision, ++#endif + }; + + /* +-- +2.11.0 + diff --git a/iproute.spec b/iproute.spec index cbae61d..52b7737 100644 --- a/iproute.spec +++ b/iproute.spec @@ -2,7 +2,7 @@ Summary: Advanced IP routing and network device configuration tools Name: iproute Version: 4.6.0 -Release: 5%{?dist} +Release: 6%{?dist} Group: Applications/System URL: http://kernel.org/pub/linux/utils/net/%{name}2/ Source0: http://kernel.org/pub/linux/utils/net/%{name}2/%{name}2-%{version}.tar.xz @@ -54,6 +54,12 @@ Patch9: matchall-kernel-headers.patch Patch10: 0001-tc-Add-support-for-the-matchall-traffic-classifier.patch Patch11: 0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch +# Fix for bz#1411127 +# +# Accepted upstream: +# https://patchwork.ozlabs.org/patch/714480/ +Patch12: 0001-tc-m_xt-Fix-segfault-with-iptables-1.6.0.patch + License: GPLv2+ and Public Domain BuildRequires: bison BuildRequires: elfutils-libelf-devel @@ -126,6 +132,7 @@ The libnetlink static library. %patch9 -p1 %patch10 -p1 %patch11 -p1 +%patch12 -p1 %build export CFLAGS="%{optflags}" @@ -209,6 +216,9 @@ rm -rf '%{buildroot}%{_docdir}' %{_includedir}/libnetlink.h %changelog +* Fri Jan 13 2017 Phil Sutter - 4.6.0-6 +- Fix segfault in xt action + * Fri Nov 25 2016 Ido Schimmel - 4.6.0-5 - Add matchall classifier From c2655da31c79b188fa79727f3a9f5cc0a4e21971 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 28 Jan 2017 13:26:39 +0100 Subject: [PATCH 06/11] update to 4.9 - XXX: WiP, do not push! --- 0001-Documentation-fixes.patch | 27 - ...link-implement-shared-buffer-support.patch | 779 ------------------ ...-write-usage-help-messages-to-stderr.patch | 100 --- ...an-Add-devlink-man-pages-to-Makefile.patch | 28 - ...-for-the-matchall-traffic-classifier.patch | 186 ----- ...k-add-option-to-generate-JSON-output.patch | 738 ----------------- ...ment-shared-buffer-occupancy-control.patch | 441 ---------- ...-to-devlink-sb-from-devlink-man-page.patch | 26 - ...an-entry-for-the-matchall-classifier.patch | 132 --- devlink-kernel-headers.patch | 88 -- iproute.spec | 65 +- matchall-kernel-headers.patch | 32 - 12 files changed, 6 insertions(+), 2636 deletions(-) delete mode 100644 0001-Documentation-fixes.patch delete mode 100644 0001-devlink-implement-shared-buffer-support.patch delete mode 100644 0001-devlink-write-usage-help-messages-to-stderr.patch delete mode 100644 0001-man-Add-devlink-man-pages-to-Makefile.patch delete mode 100644 0001-tc-Add-support-for-the-matchall-traffic-classifier.patch delete mode 100644 0002-devlink-add-option-to-generate-JSON-output.patch delete mode 100644 0002-devlink-implement-shared-buffer-occupancy-control.patch delete mode 100644 0002-man-Point-to-devlink-sb-from-devlink-man-page.patch delete mode 100644 0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch delete mode 100644 devlink-kernel-headers.patch delete mode 100644 matchall-kernel-headers.patch diff --git a/0001-Documentation-fixes.patch b/0001-Documentation-fixes.patch deleted file mode 100644 index 0a149e6..0000000 --- a/0001-Documentation-fixes.patch +++ /dev/null @@ -1,27 +0,0 @@ -diff -Nurp iproute2-4.5.0.orig/man/man8/cbq.8 iproute2-4.5.0/man/man8/cbq.8 ---- iproute2-4.5.0.orig/man/man8/cbq.8 1970-01-01 01:00:00.000000000 +0100 -+++ iproute2-4.5.0/man/man8/cbq.8 2016-03-18 13:17:00.673773197 +0100 -@@ -0,0 +1 @@ -+.so man8/tc-cbq.8 -\ No newline at end of file -diff -Nurp iproute2-4.5.0.orig/man/man8/ss.8 iproute2-4.5.0/man/man8/ss.8 ---- iproute2-4.5.0.orig/man/man8/ss.8 2016-03-18 13:16:45.046773197 +0100 -+++ iproute2-4.5.0/man/man8/ss.8 2016-03-18 13:17:05.910773197 +0100 -@@ -136,7 +136,7 @@ Read filter information from FILE. - Each line of FILE is interpreted like single command line option. If FILE is - stdin is used. - .TP - .B FILTER := [ state STATE-FILTER ] [ EXPRESSION ] --Please take a look at the official documentation (Debian package iproute-doc) for details regarding filters. -+Please take a look at the official documentation (package iproute\-doc) for details regarding filters. - - .SH STATE-FILTER - -@@ -191,7 +191,7 @@ Find all local processes connected to X - List all the tcp sockets in state FIN-WAIT-1 for our apache to network 193.233.7/24 and look at their timers. - .SH SEE ALSO - .BR ip (8), --.BR /usr/share/doc/iproute-doc/ss.html " (package iproute­doc)", -+.BR /usr/share/doc/iproute-doc/ss.ps " (package iproute\-doc)", - .br - .BR RFC " 793 " - - https://tools.ietf.org/rfc/rfc793.txt (TCP states) diff --git a/0001-devlink-implement-shared-buffer-support.patch b/0001-devlink-implement-shared-buffer-support.patch deleted file mode 100644 index 608518a..0000000 --- a/0001-devlink-implement-shared-buffer-support.patch +++ /dev/null @@ -1,779 +0,0 @@ -From e6d7367d795a41abeea4acc1af8f3885c8918ba7 Mon Sep 17 00:00:00 2001 -From: Jiri Pirko -Date: Sat, 14 May 2016 15:21:01 +0200 -Subject: [PATCH 1/2] devlink: implement shared buffer support - -Implement kernel devlink shared buffer interface. Introduce new object -"sb" and allow to browse the shared buffer parameters and also change -configuration. - -Signed-off-by: Jiri Pirko ---- - devlink/devlink.c | 653 +++++++++++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 652 insertions(+), 1 deletion(-) - -diff --git a/devlink/devlink.c b/devlink/devlink.c -index 89a3083..ca3f586 100644 ---- a/devlink/devlink.c -+++ b/devlink/devlink.c -@@ -114,6 +114,13 @@ static void ifname_map_free(struct ifname_map *ifname_map) - #define DL_OPT_HANDLEP BIT(1) - #define DL_OPT_PORT_TYPE BIT(2) - #define DL_OPT_PORT_COUNT BIT(3) -+#define DL_OPT_SB BIT(4) -+#define DL_OPT_SB_POOL BIT(5) -+#define DL_OPT_SB_SIZE BIT(6) -+#define DL_OPT_SB_TYPE BIT(7) -+#define DL_OPT_SB_THTYPE BIT(8) -+#define DL_OPT_SB_TH BIT(9) -+#define DL_OPT_SB_TC BIT(10) - - struct dl_opts { - uint32_t present; /* flags of present items */ -@@ -122,6 +129,13 @@ struct dl_opts { - uint32_t port_index; - enum devlink_port_type port_type; - uint32_t port_count; -+ uint32_t sb_index; -+ uint16_t sb_pool_index; -+ uint32_t sb_pool_size; -+ enum devlink_sb_pool_type sb_pool_type; -+ enum devlink_sb_threshold_type sb_pool_thtype; -+ uint32_t sb_threshold; -+ uint16_t sb_tc_index; - }; - - struct dl { -@@ -225,6 +239,42 @@ static int attr_cb(const struct nlattr *attr, void *data) - if (type == DEVLINK_ATTR_PORT_IBDEV_NAME && - mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) - return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_INDEX && -+ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_SIZE && -+ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_INGRESS_POOL_COUNT && -+ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_EGRESS_POOL_COUNT && -+ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_INGRESS_TC_COUNT && -+ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_EGRESS_TC_COUNT && -+ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_POOL_INDEX && -+ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_POOL_TYPE && -+ mnl_attr_validate(attr, MNL_TYPE_U8) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_POOL_SIZE && -+ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE && -+ mnl_attr_validate(attr, MNL_TYPE_U8) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_THRESHOLD && -+ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_TC_INDEX && -+ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) -+ return MNL_CB_ERROR; - tb[type] = attr; - return MNL_CB_OK; - } -@@ -307,6 +357,23 @@ static int ifname_map_lookup(struct dl *dl, const char *ifname, - return -ENOENT; - } - -+static int ifname_map_rev_lookup(struct dl *dl, const char *bus_name, -+ const char *dev_name, uint32_t port_index, -+ char **p_ifname) -+{ -+ struct ifname_map *ifname_map; -+ -+ list_for_each_entry(ifname_map, &dl->ifname_map_list, list) { -+ if (strcmp(bus_name, ifname_map->bus_name) == 0 && -+ strcmp(dev_name, ifname_map->dev_name) == 0 && -+ port_index == ifname_map->port_index) { -+ *p_ifname = ifname_map->ifname; -+ return 0; -+ } -+ } -+ return -ENOENT; -+} -+ - static unsigned int strslashcount(char *str) - { - unsigned int count = 0; -@@ -346,6 +413,20 @@ static int strtouint32_t(const char *str, uint32_t *p_val) - return 0; - } - -+static int strtouint16_t(const char *str, uint16_t *p_val) -+{ -+ char *endptr; -+ unsigned long int val; -+ -+ val = strtoul(str, &endptr, 10); -+ if (endptr == str || *endptr != '\0') -+ return -EINVAL; -+ if (val > USHRT_MAX) -+ return -ERANGE; -+ *p_val = val; -+ return 0; -+} -+ - static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name) - { - strslashrsplit(str, p_bus_name, p_dev_name); -@@ -486,6 +567,24 @@ static int dl_argv_uint32_t(struct dl *dl, uint32_t *p_val) - return 0; - } - -+static int dl_argv_uint16_t(struct dl *dl, uint16_t *p_val) -+{ -+ char *str = dl_argv_next(dl); -+ int err; -+ -+ if (!str) { -+ pr_err("Unsigned number argument expected\n"); -+ return -EINVAL; -+ } -+ -+ err = strtouint16_t(str, p_val); -+ if (err) { -+ pr_err("\"%s\" is not a number or not within range\n", str); -+ return err; -+ } -+ return 0; -+} -+ - static int dl_argv_str(struct dl *dl, const char **p_str) - { - const char *str = dl_argv_next(dl); -@@ -513,6 +612,33 @@ static int port_type_get(const char *typestr, enum devlink_port_type *p_type) - return 0; - } - -+static int pool_type_get(const char *typestr, enum devlink_sb_pool_type *p_type) -+{ -+ if (strcmp(typestr, "ingress") == 0) { -+ *p_type = DEVLINK_SB_POOL_TYPE_INGRESS; -+ } else if (strcmp(typestr, "egress") == 0) { -+ *p_type = DEVLINK_SB_POOL_TYPE_EGRESS; -+ } else { -+ pr_err("Unknown pool type \"%s\"\n", typestr); -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+static int threshold_type_get(const char *typestr, -+ enum devlink_sb_threshold_type *p_type) -+{ -+ if (strcmp(typestr, "static") == 0) { -+ *p_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC; -+ } else if (strcmp(typestr, "dynamic") == 0) { -+ *p_type = DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC; -+ } else { -+ pr_err("Unknown threshold type \"%s\"\n", typestr); -+ return -EINVAL; -+ } -+ return 0; -+} -+ - static int dl_argv_parse(struct dl *dl, uint32_t o_required, - uint32_t o_optional) - { -@@ -562,6 +688,66 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, - if (err) - return err; - o_found |= DL_OPT_PORT_COUNT; -+ } else if (dl_argv_match(dl, "sb") && -+ (o_all & DL_OPT_SB)) { -+ dl_arg_inc(dl); -+ err = dl_argv_uint32_t(dl, &opts->sb_index); -+ if (err) -+ return err; -+ o_found |= DL_OPT_SB; -+ } else if (dl_argv_match(dl, "pool") && -+ (o_all & DL_OPT_SB_POOL)) { -+ dl_arg_inc(dl); -+ err = dl_argv_uint16_t(dl, &opts->sb_pool_index); -+ if (err) -+ return err; -+ o_found |= DL_OPT_SB_POOL; -+ } else if (dl_argv_match(dl, "size") && -+ (o_all & DL_OPT_SB_SIZE)) { -+ dl_arg_inc(dl); -+ err = dl_argv_uint32_t(dl, &opts->sb_pool_size); -+ if (err) -+ return err; -+ o_found |= DL_OPT_SB_SIZE; -+ } else if (dl_argv_match(dl, "type") && -+ (o_all & DL_OPT_SB_TYPE)) { -+ const char *typestr; -+ -+ dl_arg_inc(dl); -+ err = dl_argv_str(dl, &typestr); -+ if (err) -+ return err; -+ err = pool_type_get(typestr, &opts->sb_pool_type); -+ if (err) -+ return err; -+ o_found |= DL_OPT_SB_TYPE; -+ } else if (dl_argv_match(dl, "thtype") && -+ (o_all & DL_OPT_SB_THTYPE)) { -+ const char *typestr; -+ -+ dl_arg_inc(dl); -+ err = dl_argv_str(dl, &typestr); -+ if (err) -+ return err; -+ err = threshold_type_get(typestr, -+ &opts->sb_pool_thtype); -+ if (err) -+ return err; -+ o_found |= DL_OPT_SB_THTYPE; -+ } else if (dl_argv_match(dl, "th") && -+ (o_all & DL_OPT_SB_TH)) { -+ dl_arg_inc(dl); -+ err = dl_argv_uint32_t(dl, &opts->sb_threshold); -+ if (err) -+ return err; -+ o_found |= DL_OPT_SB_TH; -+ } else if (dl_argv_match(dl, "tc") && -+ (o_all & DL_OPT_SB_TC)) { -+ dl_arg_inc(dl); -+ err = dl_argv_uint16_t(dl, &opts->sb_tc_index); -+ if (err) -+ return err; -+ o_found |= DL_OPT_SB_TC; - } else { - pr_err("Unknown option \"%s\"\n", dl_argv(dl)); - return -EINVAL; -@@ -570,6 +756,11 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, - - opts->present = o_found; - -+ if ((o_optional & DL_OPT_SB) && !(o_found & DL_OPT_SB)) { -+ opts->sb_index = 0; -+ opts->present |= DL_OPT_SB; -+ } -+ - if ((o_required & DL_OPT_PORT_TYPE) && !(o_found & DL_OPT_PORT_TYPE)) { - pr_err("Port type option expected.\n"); - return -EINVAL; -@@ -581,6 +772,35 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, - return -EINVAL; - } - -+ if ((o_required & DL_OPT_SB_POOL) && !(o_found & DL_OPT_SB_POOL)) { -+ pr_err("Pool index option expected.\n"); -+ return -EINVAL; -+ } -+ -+ if ((o_required & DL_OPT_SB_SIZE) && !(o_found & DL_OPT_SB_SIZE)) { -+ pr_err("Pool size option expected.\n"); -+ return -EINVAL; -+ } -+ -+ if ((o_required & DL_OPT_SB_TYPE) && !(o_found & DL_OPT_SB_TYPE)) { -+ pr_err("Pool type option expected.\n"); -+ return -EINVAL; -+ } -+ -+ if ((o_required & DL_OPT_SB_THTYPE) && !(o_found & DL_OPT_SB_THTYPE)) { -+ pr_err("Pool threshold type option expected.\n"); -+ return -EINVAL; -+ } -+ -+ if ((o_required & DL_OPT_SB_TH) && !(o_found & DL_OPT_SB_TH)) { -+ pr_err("Threshold option expected.\n"); -+ return -EINVAL; -+ } -+ -+ if ((o_required & DL_OPT_SB_TC) && !(o_found & DL_OPT_SB_TC)) { -+ pr_err("TC index option expected.\n"); -+ return -EINVAL; -+ } - return 0; - } - -@@ -603,6 +823,27 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl) - if (opts->present & DL_OPT_PORT_COUNT) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT, - opts->port_count); -+ if (opts->present & DL_OPT_SB) -+ mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, -+ opts->sb_index); -+ if (opts->present & DL_OPT_SB_POOL) -+ mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, -+ opts->sb_pool_index); -+ if (opts->present & DL_OPT_SB_SIZE) -+ mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_POOL_SIZE, -+ opts->sb_pool_size); -+ if (opts->present & DL_OPT_SB_TYPE) -+ mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE, -+ opts->sb_pool_type); -+ if (opts->present & DL_OPT_SB_THTYPE) -+ mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, -+ opts->sb_pool_thtype); -+ if (opts->present & DL_OPT_SB_TH) -+ mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD, -+ opts->sb_threshold); -+ if (opts->present & DL_OPT_SB_TC) -+ mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX, -+ opts->sb_tc_index); - } - - static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, -@@ -648,6 +889,39 @@ static void pr_out_port_handle(struct nlattr **tb) - mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX])); - } - -+static void __pr_out_port_handle_nice(struct dl *dl, const char *bus_name, -+ const char *dev_name, uint32_t port_index) -+{ -+ char *ifname; -+ int err; -+ -+ if (dl->no_nice_names) -+ goto no_nice_names; -+ -+ err = ifname_map_rev_lookup(dl, bus_name, dev_name, -+ port_index, &ifname); -+ if (err) -+ goto no_nice_names; -+ pr_out("%s", ifname); -+ return; -+ -+no_nice_names: -+ __pr_out_port_handle(bus_name, dev_name, port_index); -+} -+ -+static void pr_out_port_handle_nice(struct dl *dl, struct nlattr **tb) -+{ -+ const char *bus_name; -+ const char *dev_name; -+ uint32_t port_index; -+ -+ bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); -+ dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); -+ port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); -+ -+ __pr_out_port_handle_nice(dl, bus_name, dev_name, port_index); -+} -+ - static void pr_out_dev(struct nlattr **tb) - { - pr_out_handle(tb); -@@ -850,6 +1124,380 @@ static int cmd_port(struct dl *dl) - return -ENOENT; - } - -+static void cmd_sb_help(void) -+{ -+ pr_out("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n"); -+ pr_out(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n"); -+ pr_out(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n"); -+ pr_out(" size POOL_SIZE thtype { static | dynamic }\n"); -+ pr_out(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n"); -+ pr_out(" pool POOL_INDEX ]\n"); -+ pr_out(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n"); -+ pr_out(" pool POOL_INDEX th THRESHOLD\n"); -+ pr_out(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); -+ pr_out(" type { ingress | egress } ]\n"); -+ pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); -+ pr_out(" type { ingress | egress } pool POOL_INDEX\n"); -+ pr_out(" th THRESHOLD\n"); -+} -+ -+static void pr_out_sb(struct nlattr **tb) -+{ -+ pr_out_handle(tb); -+ pr_out(": sb %u size %u ing_pools %u eg_pools %u ing_tcs %u eg_tcs %u\n", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]), -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]), -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]), -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]), -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])); -+} -+ -+static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data) -+{ -+ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; -+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); -+ -+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); -+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || -+ !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_SIZE] || -+ !tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] || -+ !tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] || -+ !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] || -+ !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]) -+ return MNL_CB_ERROR; -+ pr_out_sb(tb); -+ return MNL_CB_OK; -+} -+ -+static int cmd_sb_show(struct dl *dl) -+{ -+ struct nlmsghdr *nlh; -+ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; -+ int err; -+ -+ if (dl_argc(dl) == 0) -+ flags |= NLM_F_DUMP; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_GET, flags); -+ -+ if (dl_argc(dl) > 0) { -+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); -+ if (err) -+ return err; -+ } -+ -+ return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, NULL); -+} -+ -+static const char *pool_type_name(uint8_t type) -+{ -+ switch (type) { -+ case DEVLINK_SB_POOL_TYPE_INGRESS: return "ingress"; -+ case DEVLINK_SB_POOL_TYPE_EGRESS: return "egress"; -+ default: return ""; -+ } -+} -+ -+static const char *threshold_type_name(uint8_t type) -+{ -+ switch (type) { -+ case DEVLINK_SB_THRESHOLD_TYPE_STATIC: return "static"; -+ case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC: return "dynamic"; -+ default: return ""; -+ } -+} -+ -+static void pr_out_sb_pool(struct nlattr **tb) -+{ -+ pr_out_handle(tb); -+ pr_out(": sb %u pool %u type %s size %u thtype %s\n", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), -+ pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]), -+ threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]))); -+} -+ -+static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data) -+{ -+ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; -+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); -+ -+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); -+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || -+ !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_INDEX] || -+ !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] || -+ !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]) -+ return MNL_CB_ERROR; -+ pr_out_sb_pool(tb); -+ return MNL_CB_OK; -+} -+ -+static int cmd_sb_pool_show(struct dl *dl) -+{ -+ struct nlmsghdr *nlh; -+ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; -+ int err; -+ -+ if (dl_argc(dl) == 0) -+ flags |= NLM_F_DUMP; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags); -+ -+ if (dl_argc(dl) > 0) { -+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL, -+ DL_OPT_SB); -+ if (err) -+ return err; -+ } -+ -+ return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, NULL); -+} -+ -+static int cmd_sb_pool_set(struct dl *dl) -+{ -+ struct nlmsghdr *nlh; -+ int err; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_SET, -+ NLM_F_REQUEST | NLM_F_ACK); -+ -+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL | -+ DL_OPT_SB_SIZE | DL_OPT_SB_THTYPE, DL_OPT_SB); -+ if (err) -+ return err; -+ -+ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); -+} -+ -+static int cmd_sb_pool(struct dl *dl) -+{ -+ if (dl_argv_match(dl, "help")) { -+ cmd_sb_help(); -+ return 0; -+ } else if (dl_argv_match(dl, "show") || -+ dl_argv_match(dl, "list") || dl_no_arg(dl)) { -+ dl_arg_inc(dl); -+ return cmd_sb_pool_show(dl); -+ } else if (dl_argv_match(dl, "set")) { -+ dl_arg_inc(dl); -+ return cmd_sb_pool_set(dl); -+ } -+ pr_err("Command \"%s\" not found\n", dl_argv(dl)); -+ return -ENOENT; -+} -+ -+static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb) -+{ -+ pr_out_port_handle_nice(dl, tb); -+ pr_out(": sb %u pool %u threshold %u\n", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); -+} -+ -+static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data) -+{ -+ struct dl *dl = data; -+ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; -+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); -+ -+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); -+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || -+ !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || -+ !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD]) -+ return MNL_CB_ERROR; -+ pr_out_sb_port_pool(dl, tb); -+ return MNL_CB_OK; -+} -+ -+static int cmd_sb_port_pool_show(struct dl *dl) -+{ -+ struct nlmsghdr *nlh; -+ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; -+ int err; -+ -+ if (dl_argc(dl) == 0) -+ flags |= NLM_F_DUMP; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); -+ -+ if (dl_argc(dl) > 0) { -+ err = dl_argv_parse_put(nlh, dl, -+ DL_OPT_HANDLEP | DL_OPT_SB_POOL, -+ DL_OPT_SB); -+ if (err) -+ return err; -+ } -+ -+ return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl); -+} -+ -+static int cmd_sb_port_pool_set(struct dl *dl) -+{ -+ struct nlmsghdr *nlh; -+ int err; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET, -+ NLM_F_REQUEST | NLM_F_ACK); -+ -+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL | -+ DL_OPT_SB_TH, DL_OPT_SB); -+ if (err) -+ return err; -+ -+ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); -+} -+ -+static int cmd_sb_port_pool(struct dl *dl) -+{ -+ if (dl_argv_match(dl, "help")) { -+ cmd_sb_help(); -+ return 0; -+ } else if (dl_argv_match(dl, "show") || -+ dl_argv_match(dl, "list") || dl_no_arg(dl)) { -+ dl_arg_inc(dl); -+ return cmd_sb_port_pool_show(dl); -+ } else if (dl_argv_match(dl, "set")) { -+ dl_arg_inc(dl); -+ return cmd_sb_port_pool_set(dl); -+ } -+ pr_err("Command \"%s\" not found\n", dl_argv(dl)); -+ return -ENOENT; -+} -+ -+static int cmd_sb_port(struct dl *dl) -+{ -+ if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { -+ cmd_sb_help(); -+ return 0; -+ } else if (dl_argv_match(dl, "pool")) { -+ dl_arg_inc(dl); -+ return cmd_sb_port_pool(dl); -+ } -+ pr_err("Command \"%s\" not found\n", dl_argv(dl)); -+ return -ENOENT; -+} -+ -+static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb) -+{ -+ pr_out_port_handle_nice(dl, tb); -+ pr_out(": sb %u tc %u type %s pool %u threshold %u\n", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]), -+ pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); -+} -+ -+static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data) -+{ -+ struct dl *dl = data; -+ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; -+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); -+ -+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); -+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || -+ !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || -+ !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] || -+ !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD]) -+ return MNL_CB_ERROR; -+ pr_out_sb_tc_bind(dl, tb); -+ return MNL_CB_OK; -+} -+ -+static int cmd_sb_tc_bind_show(struct dl *dl) -+{ -+ struct nlmsghdr *nlh; -+ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; -+ int err; -+ -+ if (dl_argc(dl) == 0) -+ flags |= NLM_F_DUMP; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); -+ -+ if (dl_argc(dl) > 0) { -+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC | -+ DL_OPT_SB_TYPE, DL_OPT_SB); -+ if (err) -+ return err; -+ } -+ -+ return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl); -+} -+ -+static int cmd_sb_tc_bind_set(struct dl *dl) -+{ -+ struct nlmsghdr *nlh; -+ int err; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET, -+ NLM_F_REQUEST | NLM_F_ACK); -+ -+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC | -+ DL_OPT_SB_TYPE | DL_OPT_SB_POOL | DL_OPT_SB_TH, -+ DL_OPT_SB); -+ if (err) -+ return err; -+ -+ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); -+} -+ -+static int cmd_sb_tc_bind(struct dl *dl) -+{ -+ if (dl_argv_match(dl, "help")) { -+ cmd_sb_help(); -+ return 0; -+ } else if (dl_argv_match(dl, "show") || -+ dl_argv_match(dl, "list") || dl_no_arg(dl)) { -+ dl_arg_inc(dl); -+ return cmd_sb_tc_bind_show(dl); -+ } else if (dl_argv_match(dl, "set")) { -+ dl_arg_inc(dl); -+ return cmd_sb_tc_bind_set(dl); -+ } -+ pr_err("Command \"%s\" not found\n", dl_argv(dl)); -+ return -ENOENT; -+} -+ -+static int cmd_sb_tc(struct dl *dl) -+{ -+ if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { -+ cmd_sb_help(); -+ return 0; -+ } else if (dl_argv_match(dl, "bind")) { -+ dl_arg_inc(dl); -+ return cmd_sb_tc_bind(dl); -+ } -+ pr_err("Command \"%s\" not found\n", dl_argv(dl)); -+ return -ENOENT; -+} -+ -+static int cmd_sb(struct dl *dl) -+{ -+ if (dl_argv_match(dl, "help")) { -+ cmd_sb_help(); -+ return 0; -+ } else if (dl_argv_match(dl, "show") || -+ dl_argv_match(dl, "list") || dl_no_arg(dl)) { -+ dl_arg_inc(dl); -+ return cmd_sb_show(dl); -+ } else if (dl_argv_match(dl, "pool")) { -+ dl_arg_inc(dl); -+ return cmd_sb_pool(dl); -+ } else if (dl_argv_match(dl, "port")) { -+ dl_arg_inc(dl); -+ return cmd_sb_port(dl); -+ } else if (dl_argv_match(dl, "tc")) { -+ dl_arg_inc(dl); -+ return cmd_sb_tc(dl); -+ } -+ pr_err("Command \"%s\" not found\n", dl_argv(dl)); -+ return -ENOENT; -+} -+ - static const char *cmd_name(uint8_t cmd) - { - switch (cmd) { -@@ -985,7 +1633,7 @@ static int cmd_mon(struct dl *dl) - static void help(void) - { - pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" -- "where OBJECT := { dev | port | monitor }\n" -+ "where OBJECT := { dev | port | sb | monitor }\n" - " OPTIONS := { -V[ersion] | -n[no-nice-names] }\n"); - } - -@@ -1000,6 +1648,9 @@ static int dl_cmd(struct dl *dl) - } else if (dl_argv_match(dl, "port")) { - dl_arg_inc(dl); - return cmd_port(dl); -+ } else if (dl_argv_match(dl, "sb")) { -+ dl_arg_inc(dl); -+ return cmd_sb(dl); - } else if (dl_argv_match(dl, "monitor")) { - dl_arg_inc(dl); - return cmd_mon(dl); --- -2.9.3 - diff --git a/0001-devlink-write-usage-help-messages-to-stderr.patch b/0001-devlink-write-usage-help-messages-to-stderr.patch deleted file mode 100644 index 7413789..0000000 --- a/0001-devlink-write-usage-help-messages-to-stderr.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 7a9466dbcba1918a1c93de8f93b9ff3d62418fcf Mon Sep 17 00:00:00 2001 -From: Jiri Pirko -Date: Fri, 22 Jul 2016 18:34:29 +0200 -Subject: [PATCH 1/2] devlink: write usage help messages to stderr - -In order to not confuse reader, write help messages into stderr. - -Signed-off-by: Jiri Pirko ---- - devlink/devlink.c | 46 +++++++++++++++++++++++----------------------- - 1 file changed, 23 insertions(+), 23 deletions(-) - -diff --git a/devlink/devlink.c b/devlink/devlink.c -index ffefa86..f73ba95 100644 ---- a/devlink/devlink.c -+++ b/devlink/devlink.c -@@ -909,7 +909,7 @@ static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) - - static void cmd_dev_help(void) - { -- pr_out("Usage: devlink dev show [ DEV ]\n"); -+ pr_err("Usage: devlink dev show [ DEV ]\n"); - } - - static void __pr_out_handle(const char *bus_name, const char *dev_name) -@@ -1024,10 +1024,10 @@ static int cmd_dev(struct dl *dl) - - static void cmd_port_help(void) - { -- pr_out("Usage: devlink port show [ DEV/PORT_INDEX ]\n"); -- pr_out(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n"); -- pr_out(" devlink port split DEV/PORT_INDEX count COUNT\n"); -- pr_out(" devlink port unsplit DEV/PORT_INDEX\n"); -+ pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n"); -+ pr_err(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n"); -+ pr_err(" devlink port split DEV/PORT_INDEX count COUNT\n"); -+ pr_err(" devlink port unsplit DEV/PORT_INDEX\n"); - } - - static const char *port_type_name(uint32_t type) -@@ -1174,22 +1174,22 @@ static int cmd_port(struct dl *dl) - - static void cmd_sb_help(void) - { -- pr_out("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n"); -- pr_out(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n"); -- pr_out(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n"); -- pr_out(" size POOL_SIZE thtype { static | dynamic }\n"); -- pr_out(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n"); -- pr_out(" pool POOL_INDEX ]\n"); -- pr_out(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n"); -- pr_out(" pool POOL_INDEX th THRESHOLD\n"); -- pr_out(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); -- pr_out(" type { ingress | egress } ]\n"); -- pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); -- pr_out(" type { ingress | egress } pool POOL_INDEX\n"); -- pr_out(" th THRESHOLD\n"); -- pr_out(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n"); -- pr_out(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n"); -- pr_out(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); -+ pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n"); -+ pr_err(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n"); -+ pr_err(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n"); -+ pr_err(" size POOL_SIZE thtype { static | dynamic }\n"); -+ pr_err(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n"); -+ pr_err(" pool POOL_INDEX ]\n"); -+ pr_err(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n"); -+ pr_err(" pool POOL_INDEX th THRESHOLD\n"); -+ pr_err(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); -+ pr_err(" type { ingress | egress } ]\n"); -+ pr_err(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); -+ pr_err(" type { ingress | egress } pool POOL_INDEX\n"); -+ pr_err(" th THRESHOLD\n"); -+ pr_err(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n"); -+ pr_err(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n"); -+ pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); - } - - static void pr_out_sb(struct nlattr **tb) -@@ -1991,7 +1991,7 @@ static int cmd_mon_show(struct dl *dl) - - static void cmd_mon_help(void) - { -- pr_out("Usage: devlink monitor [ all | OBJECT-LIST ]\n" -+ pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n" - "where OBJECT-LIST := { dev | port }\n"); - } - -@@ -2010,7 +2010,7 @@ static int cmd_mon(struct dl *dl) - - static void help(void) - { -- pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" -+ pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" - "where OBJECT := { dev | port | sb | monitor }\n" - " OPTIONS := { -V[ersion] | -n[no-nice-names] }\n"); - } --- -2.9.3 - diff --git a/0001-man-Add-devlink-man-pages-to-Makefile.patch b/0001-man-Add-devlink-man-pages-to-Makefile.patch deleted file mode 100644 index 5850571..0000000 --- a/0001-man-Add-devlink-man-pages-to-Makefile.patch +++ /dev/null @@ -1,28 +0,0 @@ -From e3da7a45bad1672328d67f016627e026cb41feba Mon Sep 17 00:00:00 2001 -From: Ido Schimmel -Date: Wed, 13 Jul 2016 09:53:53 +0300 -Subject: [PATCH 1/2] man: Add devlink man pages to Makefile - -Signed-off-by: Jiri Pirko -Signed-off-by: Ido Schimmel ---- - man/man8/Makefile | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/man/man8/Makefile b/man/man8/Makefile -index 929826e..9badbed 100644 ---- a/man/man8/Makefile -+++ b/man/man8/Makefile -@@ -16,7 +16,8 @@ MAN8PAGES = $(TARGETS) ip.8 arpd.8 lnstat.8 routel.8 rtacct.8 rtmon.8 rtpr.8 ss. - tc-basic.8 tc-cgroup.8 tc-flow.8 tc-flower.8 tc-fw.8 tc-route.8 \ - tc-tcindex.8 tc-u32.8 \ - tc-connmark.8 tc-csum.8 tc-mirred.8 tc-nat.8 tc-pedit.8 tc-police.8 \ -- tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 -+ tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 \ -+ devlink.8 devlink-dev.8 devlink-monitor.8 devlink-port.8 devlink-sb.8 - - all: $(TARGETS) - --- -2.9.3 - diff --git a/0001-tc-Add-support-for-the-matchall-traffic-classifier.patch b/0001-tc-Add-support-for-the-matchall-traffic-classifier.patch deleted file mode 100644 index af450c4..0000000 --- a/0001-tc-Add-support-for-the-matchall-traffic-classifier.patch +++ /dev/null @@ -1,186 +0,0 @@ -From d5cbf3ff0561b6c8158c3538c7fe1946add9dec3 Mon Sep 17 00:00:00 2001 -From: Yotam Gigi -Date: Wed, 31 Aug 2016 09:28:26 +0200 -Subject: [PATCH 1/2] tc: Add support for the matchall traffic classifier. - -The matchall classifier matches every packet and allows the user to apply -actions on it. In addition, it supports the skip_sw and skip_hw (as can -be found on u32 and flower filter) that direct the kernel to skip the -software/hardware processing of the actions. - -This filter is very useful in usecases where every packet should be -matched. For example, packet mirroring (SPAN) can be setup very easily -using that filter. - -Signed-off-by: Yotam Gigi -Signed-off-by: Jiri Pirko ---- - tc/Makefile | 1 + - tc/f_matchall.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 144 insertions(+) - create mode 100644 tc/f_matchall.c - -diff --git a/tc/Makefile b/tc/Makefile -index 42747c5..8917eaf 100644 ---- a/tc/Makefile -+++ b/tc/Makefile -@@ -67,6 +67,7 @@ TCMODULES += q_pie.o - TCMODULES += q_hhf.o - TCMODULES += q_clsact.o - TCMODULES += e_bpf.o -+TCMODULES += f_matchall.o - - ifeq ($(TC_CONFIG_IPSET), y) - ifeq ($(TC_CONFIG_XT), y) -diff --git a/tc/f_matchall.c b/tc/f_matchall.c -new file mode 100644 -index 0000000..04e524e ---- /dev/null -+++ b/tc/f_matchall.c -@@ -0,0 +1,143 @@ -+/* -+ * f_matchall.c Match-all Classifier -+ * -+ * This program is free software; you can distribute 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: Jiri Pirko , Yotam Gigi -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "utils.h" -+#include "tc_util.h" -+ -+static void explain(void) -+{ -+ fprintf(stderr, "Usage: ... matchall [skip_sw | skip_hw]\n"); -+ fprintf(stderr, " [ action ACTION_SPEC ] [ classid CLASSID ]\n"); -+ fprintf(stderr, "\n"); -+ fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n"); -+ fprintf(stderr, " FILTERID := X:Y:Z\n"); -+ fprintf(stderr, " ACTION_SPEC := ... look at individual actions\n"); -+ fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n"); -+} -+ -+static int matchall_parse_opt(struct filter_util *qu, char *handle, -+ int argc, char **argv, struct nlmsghdr *n) -+{ -+ struct tcmsg *t = NLMSG_DATA(n); -+ struct rtattr *tail; -+ __u32 flags = 0; -+ long h = 0; -+ -+ if (handle) { -+ h = strtol(handle, NULL, 0); -+ if (h == LONG_MIN || h == LONG_MAX) { -+ fprintf(stderr, "Illegal handle \"%s\", must be numeric.\n", -+ handle); -+ return -1; -+ } -+ } -+ t->tcm_handle = h; -+ -+ if (argc == 0) -+ return 0; -+ -+ tail = (struct rtattr *)(((void *)n)+NLMSG_ALIGN(n->nlmsg_len)); -+ addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0); -+ -+ while (argc > 0) { -+ if (matches(*argv, "classid") == 0 || -+ strcmp(*argv, "flowid") == 0) { -+ unsigned int handle; -+ -+ NEXT_ARG(); -+ if (get_tc_classid(&handle, *argv)) { -+ fprintf(stderr, "Illegal \"classid\"\n"); -+ return -1; -+ } -+ addattr_l(n, MAX_MSG, TCA_MATCHALL_CLASSID, &handle, 4); -+ } else if (matches(*argv, "action") == 0) { -+ NEXT_ARG(); -+ if (parse_action(&argc, &argv, TCA_MATCHALL_ACT, n)) { -+ fprintf(stderr, "Illegal \"action\"\n"); -+ return -1; -+ } -+ continue; -+ -+ } else if (strcmp(*argv, "skip_hw") == 0) { -+ NEXT_ARG(); -+ flags |= TCA_CLS_FLAGS_SKIP_HW; -+ continue; -+ } else if (strcmp(*argv, "skip_sw") == 0) { -+ NEXT_ARG(); -+ flags |= TCA_CLS_FLAGS_SKIP_SW; -+ continue; -+ } else if (strcmp(*argv, "help") == 0) { -+ explain(); -+ return -1; -+ } else { -+ fprintf(stderr, "What is \"%s\"?\n", *argv); -+ explain(); -+ return -1; -+ } -+ argc--; argv++; -+ } -+ -+ if (flags) { -+ if (!(flags ^ (TCA_CLS_FLAGS_SKIP_HW | -+ TCA_CLS_FLAGS_SKIP_SW))) { -+ fprintf(stderr, -+ "skip_hw and skip_sw are mutually exclusive\n"); -+ return -1; -+ } -+ addattr_l(n, MAX_MSG, TCA_MATCHALL_FLAGS, &flags, 4); -+ } -+ -+ tail->rta_len = (((void *)n)+n->nlmsg_len) - (void *)tail; -+ return 0; -+} -+ -+static int matchall_print_opt(struct filter_util *qu, FILE *f, -+ struct rtattr *opt, __u32 handle) -+{ -+ struct rtattr *tb[TCA_MATCHALL_MAX+1]; -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_MATCHALL_MAX, opt); -+ -+ if (handle) -+ fprintf(f, "handle 0x%x ", handle); -+ -+ if (tb[TCA_MATCHALL_CLASSID]) { -+ SPRINT_BUF(b1); -+ fprintf(f, "flowid %s ", -+ sprint_tc_classid(rta_getattr_u32(tb[TCA_MATCHALL_CLASSID]), b1)); -+ } -+ -+ if (tb[TCA_MATCHALL_ACT]) -+ tc_print_action(f, tb[TCA_MATCHALL_ACT]); -+ -+ return 0; -+} -+ -+struct filter_util matchall_filter_util = { -+ .id = "matchall", -+ .parse_fopt = matchall_parse_opt, -+ .print_fopt = matchall_print_opt, -+}; --- -2.9.3 - diff --git a/0002-devlink-add-option-to-generate-JSON-output.patch b/0002-devlink-add-option-to-generate-JSON-output.patch deleted file mode 100644 index 96c7a68..0000000 --- a/0002-devlink-add-option-to-generate-JSON-output.patch +++ /dev/null @@ -1,738 +0,0 @@ -From e3d0f0c0e3d8ac6432884e19aefd169e5c4ae179 Mon Sep 17 00:00:00 2001 -From: Jiri Pirko -Date: Fri, 22 Jul 2016 18:34:30 +0200 -Subject: [PATCH 2/2] devlink: add option to generate JSON output - -For parsing by another app it is convenient to produce output in JSON -format. - -Signed-off-by: Jiri Pirko ---- - devlink/devlink.c | 455 +++++++++++++++++++++++++++++++++++++++++++----------- - 1 file changed, 362 insertions(+), 93 deletions(-) - -diff --git a/devlink/devlink.c b/devlink/devlink.c -index f73ba95..84fa51e 100644 ---- a/devlink/devlink.c -+++ b/devlink/devlink.c -@@ -24,6 +24,7 @@ - #include "SNAPSHOT.h" - #include "list.h" - #include "mnlg.h" -+#include "json_writer.h" - - #define pr_err(args...) fprintf(stderr, ##args) - #define pr_out(args...) fprintf(stdout, ##args) -@@ -151,6 +152,15 @@ struct dl { - char **argv; - bool no_nice_names; - struct dl_opts opts; -+ json_writer_t *jw; -+ bool json_output; -+ bool pretty_output; -+ struct { -+ bool present; -+ char *bus_name; -+ char *dev_name; -+ uint32_t port_index; -+ } arr_last; - }; - - static int dl_argc(struct dl *dl) -@@ -912,52 +922,161 @@ static void cmd_dev_help(void) - pr_err("Usage: devlink dev show [ DEV ]\n"); - } - --static void __pr_out_handle(const char *bus_name, const char *dev_name) -+static bool cmp_arr_last_handle(struct dl *dl, const char *bus_name, -+ const char *dev_name) - { -- pr_out("%s/%s", bus_name, dev_name); -+ if (!dl->arr_last.present) -+ return false; -+ return strcmp(dl->arr_last.bus_name, bus_name) == 0 && -+ strcmp(dl->arr_last.dev_name, dev_name) == 0; - } - --static void pr_out_handle(struct nlattr **tb) -+static void arr_last_handle_set(struct dl *dl, const char *bus_name, -+ const char *dev_name) - { -- __pr_out_handle(mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]), -- mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME])); -+ dl->arr_last.present = true; -+ free(dl->arr_last.dev_name); -+ free(dl->arr_last.bus_name); -+ dl->arr_last.bus_name = strdup(bus_name); -+ dl->arr_last.dev_name = strdup(dev_name); - } - --static void __pr_out_port_handle(const char *bus_name, const char *dev_name, -- uint32_t port_index) -+static bool should_arr_last_handle_start(struct dl *dl, const char *bus_name, -+ const char *dev_name) - { -- __pr_out_handle(bus_name, dev_name); -- pr_out("/%d", port_index); -+ return !cmp_arr_last_handle(dl, bus_name, dev_name); - } - --static void pr_out_port_handle(struct nlattr **tb) -+static bool should_arr_last_handle_end(struct dl *dl, const char *bus_name, -+ const char *dev_name) - { -- __pr_out_port_handle(mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]), -- mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]), -- mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX])); -+ return dl->arr_last.present && -+ !cmp_arr_last_handle(dl, bus_name, dev_name); - } - --static void __pr_out_port_handle_nice(struct dl *dl, const char *bus_name, -- const char *dev_name, uint32_t port_index) -+static void __pr_out_handle_start(struct dl *dl, struct nlattr **tb, -+ bool content, bool array) - { -- char *ifname; -- int err; -+ const char *bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); -+ const char *dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); -+ char buf[32]; - -- if (dl->no_nice_names) -- goto no_nice_names; -+ sprintf(buf, "%s/%s", bus_name, dev_name); - -- err = ifname_map_rev_lookup(dl, bus_name, dev_name, -- port_index, &ifname); -- if (err) -- goto no_nice_names; -- pr_out("%s", ifname); -- return; -+ if (dl->json_output) { -+ if (array) { -+ if (should_arr_last_handle_end(dl, bus_name, dev_name)) -+ jsonw_end_array(dl->jw); -+ if (should_arr_last_handle_start(dl, bus_name, -+ dev_name)) { -+ jsonw_name(dl->jw, buf); -+ jsonw_start_array(dl->jw); -+ jsonw_start_object(dl->jw); -+ arr_last_handle_set(dl, bus_name, dev_name); -+ } else { -+ jsonw_start_object(dl->jw); -+ } -+ } else { -+ jsonw_name(dl->jw, buf); -+ jsonw_start_object(dl->jw); -+ } -+ } else { -+ pr_out("%s%s", buf, content ? ":" : ""); -+ } -+} - --no_nice_names: -- __pr_out_port_handle(bus_name, dev_name, port_index); -+static void pr_out_handle_start_arr(struct dl *dl, struct nlattr **tb) -+{ -+ __pr_out_handle_start(dl, tb, true, true); - } - --static void pr_out_port_handle_nice(struct dl *dl, struct nlattr **tb) -+static void pr_out_handle_end(struct dl *dl) -+{ -+ if (dl->json_output) -+ jsonw_end_object(dl->jw); -+ else -+ pr_out("\n"); -+} -+ -+static void pr_out_handle(struct dl *dl, struct nlattr **tb) -+{ -+ __pr_out_handle_start(dl, tb, false, false); -+ pr_out_handle_end(dl); -+} -+ -+static bool cmp_arr_last_port_handle(struct dl *dl, const char *bus_name, -+ const char *dev_name, uint32_t port_index) -+{ -+ return cmp_arr_last_handle(dl, bus_name, dev_name) && -+ dl->arr_last.port_index == port_index; -+} -+ -+static void arr_last_port_handle_set(struct dl *dl, const char *bus_name, -+ const char *dev_name, uint32_t port_index) -+{ -+ arr_last_handle_set(dl, bus_name, dev_name); -+ dl->arr_last.port_index = port_index; -+} -+ -+static bool should_arr_last_port_handle_start(struct dl *dl, -+ const char *bus_name, -+ const char *dev_name, -+ uint32_t port_index) -+{ -+ return !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index); -+} -+ -+static bool should_arr_last_port_handle_end(struct dl *dl, -+ const char *bus_name, -+ const char *dev_name, -+ uint32_t port_index) -+{ -+ return dl->arr_last.present && -+ !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index); -+} -+ -+static void __pr_out_port_handle_start(struct dl *dl, const char *bus_name, -+ const char *dev_name, -+ uint32_t port_index, bool try_nice, -+ bool array) -+{ -+ static char buf[32]; -+ char *ifname = NULL; -+ -+ if (dl->no_nice_names || !try_nice || -+ ifname_map_rev_lookup(dl, bus_name, dev_name, -+ port_index, &ifname) != 0) -+ sprintf(buf, "%s/%s/%d", bus_name, dev_name, port_index); -+ else -+ sprintf(buf, "%s", ifname); -+ -+ if (dl->json_output) { -+ if (array) { -+ if (should_arr_last_port_handle_end(dl, bus_name, -+ dev_name, -+ port_index)) -+ jsonw_end_array(dl->jw); -+ if (should_arr_last_port_handle_start(dl, bus_name, -+ dev_name, -+ port_index)) { -+ jsonw_name(dl->jw, buf); -+ jsonw_start_array(dl->jw); -+ jsonw_start_object(dl->jw); -+ arr_last_port_handle_set(dl, bus_name, dev_name, -+ port_index); -+ } else { -+ jsonw_start_object(dl->jw); -+ } -+ } else { -+ jsonw_name(dl->jw, buf); -+ jsonw_start_object(dl->jw); -+ } -+ } else { -+ pr_out("%s:", buf); -+ } -+} -+ -+static void pr_out_port_handle_start(struct dl *dl, struct nlattr **tb, bool try_nice) - { - const char *bus_name; - const char *dev_name; -@@ -966,25 +1085,80 @@ static void pr_out_port_handle_nice(struct dl *dl, struct nlattr **tb) - bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); - dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); - port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); -+ __pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, false); -+} -+ -+static void pr_out_port_handle_start_arr(struct dl *dl, struct nlattr **tb, bool try_nice) -+{ -+ const char *bus_name; -+ const char *dev_name; -+ uint32_t port_index; - -- __pr_out_port_handle_nice(dl, bus_name, dev_name, port_index); -+ bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); -+ dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); -+ port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); -+ __pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, true); - } - --static void pr_out_dev(struct nlattr **tb) -+static void pr_out_port_handle_end(struct dl *dl) - { -- pr_out_handle(tb); -- pr_out("\n"); -+ if (dl->json_output) -+ jsonw_end_object(dl->jw); -+ else -+ pr_out("\n"); -+} -+ -+ -+static void pr_out_str(struct dl *dl, const char *name, const char *val) -+{ -+ if (dl->json_output) -+ jsonw_string_field(dl->jw, name, val); -+ else -+ pr_out(" %s %s", name, val); -+} -+ -+static void pr_out_uint(struct dl *dl, const char *name, unsigned int val) -+{ -+ if (dl->json_output) -+ jsonw_uint_field(dl->jw, name, val); -+ else -+ pr_out(" %s %u", name, val); -+} -+ -+static void pr_out_dev(struct dl *dl, struct nlattr **tb) -+{ -+ pr_out_handle(dl, tb); -+} -+ -+static void pr_out_section_start(struct dl *dl, const char *name) -+{ -+ if (dl->json_output) { -+ jsonw_start_object(dl->jw); -+ jsonw_name(dl->jw, name); -+ jsonw_start_object(dl->jw); -+ } -+} -+ -+static void pr_out_section_end(struct dl *dl) -+{ -+ if (dl->json_output) { -+ if (dl->arr_last.present) -+ jsonw_end_array(dl->jw); -+ jsonw_end_object(dl->jw); -+ jsonw_end_object(dl->jw); -+ } - } - - static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data) - { -+ struct dl *dl = data; - struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - - mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); - if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME]) - return MNL_CB_ERROR; -- pr_out_dev(tb); -+ pr_out_dev(dl, tb); - return MNL_CB_OK; - } - -@@ -1005,7 +1179,10 @@ static int cmd_dev_show(struct dl *dl) - return err; - } - -- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, NULL); -+ pr_out_section_start(dl, "dev"); -+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, dl); -+ pr_out_section_end(dl); -+ return err; - } - - static int cmd_dev(struct dl *dl) -@@ -1041,38 +1218,39 @@ static const char *port_type_name(uint32_t type) - } - } - --static void pr_out_port(struct nlattr **tb) -+static void pr_out_port(struct dl *dl, struct nlattr **tb) - { - struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE]; - struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE]; - -- pr_out_port_handle(tb); -- pr_out(":"); -+ pr_out_port_handle_start(dl, tb, false); - if (pt_attr) { - uint16_t port_type = mnl_attr_get_u16(pt_attr); - -- pr_out(" type %s", port_type_name(port_type)); -+ pr_out_str(dl, "type", port_type_name(port_type)); - if (dpt_attr) { - uint16_t des_port_type = mnl_attr_get_u16(dpt_attr); - - if (port_type != des_port_type) -- pr_out("(%s)", port_type_name(des_port_type)); -+ pr_out_str(dl, "des_type", -+ port_type_name(des_port_type)); - } - } - if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME]) -- pr_out(" netdev %s", -- mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME])); -+ pr_out_str(dl, "netdev", -+ mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME])); - if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME]) -- pr_out(" ibdev %s", -- mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME])); -+ pr_out_str(dl, "ibdev", -+ mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME])); - if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]) -- pr_out(" split_group %u", -- mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])); -- pr_out("\n"); -+ pr_out_uint(dl, "split_group", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])); -+ pr_out_port_handle_end(dl); - } - - static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data) - { -+ struct dl *dl = data; - struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - -@@ -1080,7 +1258,7 @@ static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data) - if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || - !tb[DEVLINK_ATTR_PORT_INDEX]) - return MNL_CB_ERROR; -- pr_out_port(tb); -+ pr_out_port(dl, tb); - return MNL_CB_OK; - } - -@@ -1101,7 +1279,10 @@ static int cmd_port_show(struct dl *dl) - return err; - } - -- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, NULL); -+ pr_out_section_start(dl, "port"); -+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, dl); -+ pr_out_section_end(dl); -+ return err; - } - - static int cmd_port_set(struct dl *dl) -@@ -1192,20 +1373,27 @@ static void cmd_sb_help(void) - pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); - } - --static void pr_out_sb(struct nlattr **tb) -+static void pr_out_sb(struct dl *dl, struct nlattr **tb) - { -- pr_out_handle(tb); -- pr_out(": sb %u size %u ing_pools %u eg_pools %u ing_tcs %u eg_tcs %u\n", -- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), -- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]), -- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]), -- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]), -- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]), -- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])); -+ pr_out_handle_start_arr(dl, tb); -+ pr_out_uint(dl, "sb", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX])); -+ pr_out_uint(dl, "size", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE])); -+ pr_out_uint(dl, "ing_pools", -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT])); -+ pr_out_uint(dl, "eg_pools", -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT])); -+ pr_out_uint(dl, "ing_tcs", -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT])); -+ pr_out_uint(dl, "eg_tcs", -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])); -+ pr_out_handle_end(dl); - } - - static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data) - { -+ struct dl *dl = data; - struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - -@@ -1217,7 +1405,7 @@ static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data) - !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] || - !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]) - return MNL_CB_ERROR; -- pr_out_sb(tb); -+ pr_out_sb(dl, tb); - return MNL_CB_OK; - } - -@@ -1238,7 +1426,10 @@ static int cmd_sb_show(struct dl *dl) - return err; - } - -- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, NULL); -+ pr_out_section_start(dl, "sb"); -+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, dl); -+ pr_out_section_end(dl); -+ return err; - } - - static const char *pool_type_name(uint8_t type) -@@ -1259,19 +1450,25 @@ static const char *threshold_type_name(uint8_t type) - } - } - --static void pr_out_sb_pool(struct nlattr **tb) -+static void pr_out_sb_pool(struct dl *dl, struct nlattr **tb) - { -- pr_out_handle(tb); -- pr_out(": sb %u pool %u type %s size %u thtype %s\n", -- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), -- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), -- pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), -- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]), -- threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]))); -+ pr_out_handle_start_arr(dl, tb); -+ pr_out_uint(dl, "sb", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX])); -+ pr_out_uint(dl, "pool", -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX])); -+ pr_out_str(dl, "type", -+ pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]))); -+ pr_out_uint(dl, "size", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE])); -+ pr_out_str(dl, "thtype", -+ threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]))); -+ pr_out_handle_end(dl); - } - - static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data) - { -+ struct dl *dl = data; - struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - -@@ -1281,7 +1478,7 @@ static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data) - !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] || - !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]) - return MNL_CB_ERROR; -- pr_out_sb_pool(tb); -+ pr_out_sb_pool(dl, tb); - return MNL_CB_OK; - } - -@@ -1303,7 +1500,10 @@ static int cmd_sb_pool_show(struct dl *dl) - return err; - } - -- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, NULL); -+ pr_out_section_start(dl, "pool"); -+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, dl); -+ pr_out_section_end(dl); -+ return err; - } - - static int cmd_sb_pool_set(struct dl *dl) -@@ -1341,11 +1541,14 @@ static int cmd_sb_pool(struct dl *dl) - - static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb) - { -- pr_out_port_handle_nice(dl, tb); -- pr_out(": sb %u pool %u threshold %u\n", -- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), -- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), -- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); -+ pr_out_port_handle_start_arr(dl, tb, true); -+ pr_out_uint(dl, "sb", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX])); -+ pr_out_uint(dl, "pool", -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX])); -+ pr_out_uint(dl, "threshold", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); -+ pr_out_port_handle_end(dl); - } - - static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data) -@@ -1382,7 +1585,10 @@ static int cmd_sb_port_pool_show(struct dl *dl) - return err; - } - -- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl); -+ pr_out_section_start(dl, "port_pool"); -+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl); -+ pr_out_section_end(dl); -+ return 0; - } - - static int cmd_sb_port_pool_set(struct dl *dl) -@@ -1433,13 +1639,18 @@ static int cmd_sb_port(struct dl *dl) - - static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb) - { -- pr_out_port_handle_nice(dl, tb); -- pr_out(": sb %u tc %u type %s pool %u threshold %u\n", -- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), -- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]), -- pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), -- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), -+ pr_out_port_handle_start_arr(dl, tb, true); -+ pr_out_uint(dl, "sb", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX])); -+ pr_out_uint(dl, "tc", -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX])); -+ pr_out_str(dl, "type", -+ pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]))); -+ pr_out_uint(dl, "pool", -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX])); -+ pr_out_uint(dl, "threshold", - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); -+ pr_out_port_handle_end(dl); - } - - static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data) -@@ -1476,7 +1687,10 @@ static int cmd_sb_tc_bind_show(struct dl *dl) - return err; - } - -- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl); -+ pr_out_section_start(dl, "tc_bind"); -+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl); -+ pr_out_section_end(dl); -+ return err; - } - - static int cmd_sb_tc_bind_set(struct dl *dl) -@@ -1649,11 +1863,44 @@ static void pr_out_occ_show_item_list(const char *label, struct list_head *list, - pr_out("\n"); - } - --static void pr_out_occ_show_port(struct occ_port *occ_port) -+static void pr_out_json_occ_show_item_list(struct dl *dl, const char *label, -+ struct list_head *list, -+ bool bound_pool) -+{ -+ struct occ_item *occ_item; -+ char buf[32]; -+ -+ jsonw_name(dl->jw, label); -+ jsonw_start_object(dl->jw); -+ list_for_each_entry(occ_item, list, list) { -+ sprintf(buf, "%u", occ_item->index); -+ jsonw_name(dl->jw, buf); -+ jsonw_start_object(dl->jw); -+ if (bound_pool) -+ jsonw_uint_field(dl->jw, "bound_pool", -+ occ_item->bound_pool_index); -+ jsonw_uint_field(dl->jw, "current", occ_item->cur); -+ jsonw_uint_field(dl->jw, "max", occ_item->max); -+ jsonw_end_object(dl->jw); -+ } -+ jsonw_end_object(dl->jw); -+} -+ -+static void pr_out_occ_show_port(struct dl *dl, struct occ_port *occ_port) - { -- pr_out_occ_show_item_list("pool", &occ_port->pool_list, false); -- pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true); -- pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true); -+ if (dl->json_output) { -+ pr_out_json_occ_show_item_list(dl, "pool", -+ &occ_port->pool_list, false); -+ pr_out_json_occ_show_item_list(dl, "itc", -+ &occ_port->ing_tc_list, true); -+ pr_out_json_occ_show_item_list(dl, "etc", -+ &occ_port->eg_tc_list, true); -+ } else { -+ pr_out("\n"); -+ pr_out_occ_show_item_list("pool", &occ_port->pool_list, false); -+ pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true); -+ pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true); -+ } - } - - static void pr_out_occ_show(struct occ_show *occ_show) -@@ -1663,10 +1910,10 @@ static void pr_out_occ_show(struct occ_show *occ_show) - struct occ_port *occ_port; - - list_for_each_entry(occ_port, &occ_show->port_list, list) { -- __pr_out_port_handle_nice(dl, opts->bus_name, opts->dev_name, -- occ_port->port_index); -- pr_out(":\n"); -- pr_out_occ_show_port(occ_port); -+ __pr_out_port_handle_start(dl, opts->bus_name, opts->dev_name, -+ occ_port->port_index, true, false); -+ pr_out_occ_show_port(dl, occ_port); -+ pr_out_port_handle_end(dl); - } - } - -@@ -1793,7 +2040,9 @@ static int cmd_sb_occ_show(struct dl *dl) - if (err) - goto out; - -+ pr_out_section_start(dl, "occupancy"); - pr_out_occ_show(occ_show); -+ pr_out_section_end(dl); - - out: - occ_show_free(occ_show); -@@ -1949,7 +2198,7 @@ static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data) - if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME]) - return MNL_CB_ERROR; - pr_out_mon_header(genl->cmd); -- pr_out_dev(tb); -+ pr_out_dev(dl, tb); - break; - case DEVLINK_CMD_PORT_GET: /* fall through */ - case DEVLINK_CMD_PORT_SET: /* fall through */ -@@ -1960,7 +2209,7 @@ static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data) - !tb[DEVLINK_ATTR_PORT_INDEX]) - return MNL_CB_ERROR; - pr_out_mon_header(genl->cmd); -- pr_out_port(tb); -+ pr_out_port(dl, tb); - break; - } - return MNL_CB_OK; -@@ -2055,8 +2304,18 @@ static int dl_init(struct dl *dl, int argc, char **argv) - pr_err("Failed to create index map\n"); - goto err_ifname_map_create; - } -+ if (dl->json_output) { -+ dl->jw = jsonw_new(stdout); -+ if (!dl->jw) { -+ pr_err("Failed to create JSON writer\n"); -+ goto err_json_new; -+ } -+ jsonw_pretty(dl->jw, dl->pretty_output); -+ } - return 0; - -+err_json_new: -+ ifname_map_fini(dl); - err_ifname_map_create: - mnlg_socket_close(dl->nlg); - return err; -@@ -2064,6 +2323,8 @@ err_ifname_map_create: - - static void dl_fini(struct dl *dl) - { -+ if (dl->json_output) -+ jsonw_destroy(&dl->jw); - ifname_map_fini(dl); - mnlg_socket_close(dl->nlg); - } -@@ -2088,6 +2349,8 @@ int main(int argc, char **argv) - static const struct option long_options[] = { - { "Version", no_argument, NULL, 'V' }, - { "no-nice-names", no_argument, NULL, 'n' }, -+ { "json", no_argument, NULL, 'j' }, -+ { "pretty", no_argument, NULL, 'p' }, - { NULL, 0, NULL, 0 } - }; - struct dl *dl; -@@ -2101,7 +2364,7 @@ int main(int argc, char **argv) - return EXIT_FAILURE; - } - -- while ((opt = getopt_long(argc, argv, "Vn", -+ while ((opt = getopt_long(argc, argv, "Vnjp", - long_options, NULL)) >= 0) { - - switch (opt) { -@@ -2111,6 +2374,12 @@ int main(int argc, char **argv) - case 'n': - dl->no_nice_names = true; - break; -+ case 'j': -+ dl->json_output = true; -+ break; -+ case 'p': -+ dl->pretty_output = true; -+ break; - default: - pr_err("Unknown option.\n"); - help(); --- -2.9.3 - diff --git a/0002-devlink-implement-shared-buffer-occupancy-control.patch b/0002-devlink-implement-shared-buffer-occupancy-control.patch deleted file mode 100644 index 1194bdf..0000000 --- a/0002-devlink-implement-shared-buffer-occupancy-control.patch +++ /dev/null @@ -1,441 +0,0 @@ -From 25ec49be2cdfa571d5151f19a7395a7e462d2f49 Mon Sep 17 00:00:00 2001 -From: Jiri Pirko -Date: Sat, 14 May 2016 15:21:02 +0200 -Subject: [PATCH 2/2] devlink: implement shared buffer occupancy control - -Use kernel shared buffer occupancy control commands to make snapshot and -clear occupancy watermarks. Also, allow to show occupancy values in a -nice way. - -Signed-off-by: Jiri Pirko ---- - devlink/devlink.c | 378 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 378 insertions(+) - -diff --git a/devlink/devlink.c b/devlink/devlink.c -index ca3f586..ffefa86 100644 ---- a/devlink/devlink.c -+++ b/devlink/devlink.c -@@ -27,6 +27,12 @@ - - #define pr_err(args...) fprintf(stderr, ##args) - #define pr_out(args...) fprintf(stdout, ##args) -+#define pr_out_sp(num, args...) \ -+ do { \ -+ int ret = fprintf(stdout, ##args); \ -+ if (ret < num) \ -+ fprintf(stdout, "%*s", num - ret, ""); \ -+ } while (0) - - static int _mnlg_socket_recv_run(struct mnlg_socket *nlg, - mnl_cb_t data_cb, void *data) -@@ -275,6 +281,12 @@ static int attr_cb(const struct nlattr *attr, void *data) - if (type == DEVLINK_ATTR_SB_TC_INDEX && - mnl_attr_validate(attr, MNL_TYPE_U16) < 0) - return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_OCC_CUR && -+ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_OCC_MAX && -+ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) -+ return MNL_CB_ERROR; - tb[type] = attr; - return MNL_CB_OK; - } -@@ -858,6 +870,42 @@ static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, - return 0; - } - -+static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) -+{ -+ struct dl_opts *opts = &dl->opts; -+ struct nlattr *attr_bus_name = tb[DEVLINK_ATTR_BUS_NAME]; -+ struct nlattr *attr_dev_name = tb[DEVLINK_ATTR_DEV_NAME]; -+ struct nlattr *attr_port_index = tb[DEVLINK_ATTR_PORT_INDEX]; -+ struct nlattr *attr_sb_index = tb[DEVLINK_ATTR_SB_INDEX]; -+ -+ if (opts->present & DL_OPT_HANDLE && -+ attr_bus_name && attr_dev_name) { -+ const char *bus_name = mnl_attr_get_str(attr_bus_name); -+ const char *dev_name = mnl_attr_get_str(attr_dev_name); -+ -+ if (strcmp(bus_name, opts->bus_name) != 0 || -+ strcmp(dev_name, opts->dev_name) != 0) -+ return false; -+ } -+ if (opts->present & DL_OPT_HANDLEP && -+ attr_bus_name && attr_dev_name && attr_port_index) { -+ const char *bus_name = mnl_attr_get_str(attr_bus_name); -+ const char *dev_name = mnl_attr_get_str(attr_dev_name); -+ uint32_t port_index = mnl_attr_get_u32(attr_port_index); -+ -+ if (strcmp(bus_name, opts->bus_name) != 0 || -+ strcmp(dev_name, opts->dev_name) != 0 || -+ port_index != opts->port_index) -+ return false; -+ } -+ if (opts->present & DL_OPT_SB && attr_sb_index) { -+ uint32_t sb_index = mnl_attr_get_u32(attr_sb_index); -+ -+ if (sb_index != opts->sb_index) -+ return false; -+ } -+ return true; -+} - - static void cmd_dev_help(void) - { -@@ -1139,6 +1187,9 @@ static void cmd_sb_help(void) - pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); - pr_out(" type { ingress | egress } pool POOL_INDEX\n"); - pr_out(" th THRESHOLD\n"); -+ pr_out(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n"); -+ pr_out(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n"); -+ pr_out(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); - } - - static void pr_out_sb(struct nlattr **tb) -@@ -1475,6 +1526,330 @@ static int cmd_sb_tc(struct dl *dl) - return -ENOENT; - } - -+struct occ_item { -+ struct list_head list; -+ uint32_t index; -+ uint32_t cur; -+ uint32_t max; -+ uint32_t bound_pool_index; -+}; -+ -+struct occ_port { -+ struct list_head list; -+ char *bus_name; -+ char *dev_name; -+ uint32_t port_index; -+ uint32_t sb_index; -+ struct list_head pool_list; -+ struct list_head ing_tc_list; -+ struct list_head eg_tc_list; -+}; -+ -+struct occ_show { -+ struct dl *dl; -+ int err; -+ struct list_head port_list; -+}; -+ -+static struct occ_item *occ_item_alloc(void) -+{ -+ return calloc(1, sizeof(struct occ_item)); -+} -+ -+static void occ_item_free(struct occ_item *occ_item) -+{ -+ free(occ_item); -+} -+ -+static struct occ_port *occ_port_alloc(uint32_t port_index) -+{ -+ struct occ_port *occ_port; -+ -+ occ_port = calloc(1, sizeof(*occ_port)); -+ if (!occ_port) -+ return NULL; -+ occ_port->port_index = port_index; -+ INIT_LIST_HEAD(&occ_port->pool_list); -+ INIT_LIST_HEAD(&occ_port->ing_tc_list); -+ INIT_LIST_HEAD(&occ_port->eg_tc_list); -+ return occ_port; -+} -+ -+static void occ_port_free(struct occ_port *occ_port) -+{ -+ struct occ_item *occ_item, *tmp; -+ -+ list_for_each_entry_safe(occ_item, tmp, &occ_port->pool_list, list) -+ occ_item_free(occ_item); -+ list_for_each_entry_safe(occ_item, tmp, &occ_port->ing_tc_list, list) -+ occ_item_free(occ_item); -+ list_for_each_entry_safe(occ_item, tmp, &occ_port->eg_tc_list, list) -+ occ_item_free(occ_item); -+} -+ -+static struct occ_show *occ_show_alloc(struct dl *dl) -+{ -+ struct occ_show *occ_show; -+ -+ occ_show = calloc(1, sizeof(*occ_show)); -+ if (!occ_show) -+ return NULL; -+ occ_show->dl = dl; -+ INIT_LIST_HEAD(&occ_show->port_list); -+ return occ_show; -+} -+ -+static void occ_show_free(struct occ_show *occ_show) -+{ -+ struct occ_port *occ_port, *tmp; -+ -+ list_for_each_entry_safe(occ_port, tmp, &occ_show->port_list, list) -+ occ_port_free(occ_port); -+} -+ -+static struct occ_port *occ_port_get(struct occ_show *occ_show, -+ struct nlattr **tb) -+{ -+ struct occ_port *occ_port; -+ uint32_t port_index; -+ -+ port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); -+ -+ list_for_each_entry_reverse(occ_port, &occ_show->port_list, list) { -+ if (occ_port->port_index == port_index) -+ return occ_port; -+ } -+ occ_port = occ_port_alloc(port_index); -+ if (!occ_port) -+ return NULL; -+ list_add_tail(&occ_port->list, &occ_show->port_list); -+ return occ_port; -+} -+ -+static void pr_out_occ_show_item_list(const char *label, struct list_head *list, -+ bool bound_pool) -+{ -+ struct occ_item *occ_item; -+ int i = 1; -+ -+ pr_out_sp(7, " %s:", label); -+ list_for_each_entry(occ_item, list, list) { -+ if ((i - 1) % 4 == 0 && i != 1) -+ pr_out_sp(7, " "); -+ if (bound_pool) -+ pr_out_sp(7, "%2u(%u):", occ_item->index, -+ occ_item->bound_pool_index); -+ else -+ pr_out_sp(7, "%2u:", occ_item->index); -+ pr_out_sp(15, "%7u/%u", occ_item->cur, occ_item->max); -+ if (i++ % 4 == 0) -+ pr_out("\n"); -+ } -+ if ((i - 1) % 4 != 0) -+ pr_out("\n"); -+} -+ -+static void pr_out_occ_show_port(struct occ_port *occ_port) -+{ -+ pr_out_occ_show_item_list("pool", &occ_port->pool_list, false); -+ pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true); -+ pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true); -+} -+ -+static void pr_out_occ_show(struct occ_show *occ_show) -+{ -+ struct dl *dl = occ_show->dl; -+ struct dl_opts *opts = &dl->opts; -+ struct occ_port *occ_port; -+ -+ list_for_each_entry(occ_port, &occ_show->port_list, list) { -+ __pr_out_port_handle_nice(dl, opts->bus_name, opts->dev_name, -+ occ_port->port_index); -+ pr_out(":\n"); -+ pr_out_occ_show_port(occ_port); -+ } -+} -+ -+static void cmd_sb_occ_port_pool_process(struct occ_show *occ_show, -+ struct nlattr **tb) -+{ -+ struct occ_port *occ_port; -+ struct occ_item *occ_item; -+ -+ if (occ_show->err || !dl_dump_filter(occ_show->dl, tb)) -+ return; -+ -+ occ_port = occ_port_get(occ_show, tb); -+ if (!occ_port) { -+ occ_show->err = -ENOMEM; -+ return; -+ } -+ -+ occ_item = occ_item_alloc(); -+ if (!occ_item) { -+ occ_show->err = -ENOMEM; -+ return; -+ } -+ occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]); -+ occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]); -+ occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]); -+ list_add_tail(&occ_item->list, &occ_port->pool_list); -+} -+ -+static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr *nlh, void *data) -+{ -+ struct occ_show *occ_show = data; -+ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; -+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); -+ -+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); -+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || -+ !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || -+ !tb[DEVLINK_ATTR_SB_POOL_INDEX] || -+ !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX]) -+ return MNL_CB_ERROR; -+ cmd_sb_occ_port_pool_process(occ_show, tb); -+ return MNL_CB_OK; -+} -+ -+static void cmd_sb_occ_tc_pool_process(struct occ_show *occ_show, -+ struct nlattr **tb) -+{ -+ struct occ_port *occ_port; -+ struct occ_item *occ_item; -+ uint8_t pool_type; -+ -+ if (occ_show->err || !dl_dump_filter(occ_show->dl, tb)) -+ return; -+ -+ occ_port = occ_port_get(occ_show, tb); -+ if (!occ_port) { -+ occ_show->err = -ENOMEM; -+ return; -+ } -+ -+ occ_item = occ_item_alloc(); -+ if (!occ_item) { -+ occ_show->err = -ENOMEM; -+ return; -+ } -+ occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]); -+ occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]); -+ occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]); -+ occ_item->bound_pool_index = -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]); -+ pool_type = mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]); -+ if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS) -+ list_add_tail(&occ_item->list, &occ_port->ing_tc_list); -+ else if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS) -+ list_add_tail(&occ_item->list, &occ_port->eg_tc_list); -+ else -+ occ_item_free(occ_item); -+} -+ -+static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr *nlh, void *data) -+{ -+ struct occ_show *occ_show = data; -+ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; -+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); -+ -+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); -+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || -+ !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || -+ !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] || -+ !tb[DEVLINK_ATTR_SB_POOL_INDEX] || -+ !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX]) -+ return MNL_CB_ERROR; -+ cmd_sb_occ_tc_pool_process(occ_show, tb); -+ return MNL_CB_OK; -+} -+ -+static int cmd_sb_occ_show(struct dl *dl) -+{ -+ struct nlmsghdr *nlh; -+ struct occ_show *occ_show; -+ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP; -+ int err; -+ -+ err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP, DL_OPT_SB); -+ if (err) -+ return err; -+ -+ occ_show = occ_show_alloc(dl); -+ if (!occ_show) -+ return -ENOMEM; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); -+ -+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, -+ cmd_sb_occ_port_pool_process_cb, occ_show); -+ if (err) -+ goto out; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); -+ -+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, -+ cmd_sb_occ_tc_pool_process_cb, occ_show); -+ if (err) -+ goto out; -+ -+ pr_out_occ_show(occ_show); -+ -+out: -+ occ_show_free(occ_show); -+ return err; -+} -+ -+static int cmd_sb_occ_snapshot(struct dl *dl) -+{ -+ struct nlmsghdr *nlh; -+ int err; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_SNAPSHOT, -+ NLM_F_REQUEST | NLM_F_ACK); -+ -+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); -+ if (err) -+ return err; -+ -+ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); -+} -+ -+static int cmd_sb_occ_clearmax(struct dl *dl) -+{ -+ struct nlmsghdr *nlh; -+ int err; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_MAX_CLEAR, -+ NLM_F_REQUEST | NLM_F_ACK); -+ -+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); -+ if (err) -+ return err; -+ -+ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); -+} -+ -+static int cmd_sb_occ(struct dl *dl) -+{ -+ if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { -+ cmd_sb_help(); -+ return 0; -+ } else if (dl_argv_match(dl, "show") || -+ dl_argv_match(dl, "list")) { -+ dl_arg_inc(dl); -+ return cmd_sb_occ_show(dl); -+ } else if (dl_argv_match(dl, "snapshot")) { -+ dl_arg_inc(dl); -+ return cmd_sb_occ_snapshot(dl); -+ } else if (dl_argv_match(dl, "clearmax")) { -+ dl_arg_inc(dl); -+ return cmd_sb_occ_clearmax(dl); -+ } -+ pr_err("Command \"%s\" not found\n", dl_argv(dl)); -+ return -ENOENT; -+} -+ - static int cmd_sb(struct dl *dl) - { - if (dl_argv_match(dl, "help")) { -@@ -1493,6 +1868,9 @@ static int cmd_sb(struct dl *dl) - } else if (dl_argv_match(dl, "tc")) { - dl_arg_inc(dl); - return cmd_sb_tc(dl); -+ } else if (dl_argv_match(dl, "occupancy")) { -+ dl_arg_inc(dl); -+ return cmd_sb_occ(dl); - } - pr_err("Command \"%s\" not found\n", dl_argv(dl)); - return -ENOENT; --- -2.9.3 - diff --git a/0002-man-Point-to-devlink-sb-from-devlink-man-page.patch b/0002-man-Point-to-devlink-sb-from-devlink-man-page.patch deleted file mode 100644 index ea1b1df..0000000 --- a/0002-man-Point-to-devlink-sb-from-devlink-man-page.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 78c610e6ea8554e87e2204f540cf0ce61ef52695 Mon Sep 17 00:00:00 2001 -From: Ido Schimmel -Date: Wed, 13 Jul 2016 09:53:54 +0300 -Subject: [PATCH 2/2] man: Point to 'devlink-sb' from 'devlink' man page - -Signed-off-by: Jiri Pirko -Signed-off-by: Ido Schimmel ---- - man/man8/devlink.8 | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/man/man8/devlink.8 b/man/man8/devlink.8 -index df00f4f..cf0563b 100644 ---- a/man/man8/devlink.8 -+++ b/man/man8/devlink.8 -@@ -76,6 +76,7 @@ Exit status is 0 if command was successful or a positive integer upon failure. - .BR devlink-dev (8), - .BR devlink-port (8), - .BR devlink-monitor (8), -+.BR devlink-sb (8), - .br - - .SH REPORTING BUGS --- -2.9.3 - diff --git a/0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch b/0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch deleted file mode 100644 index 1909c22..0000000 --- a/0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch +++ /dev/null @@ -1,132 +0,0 @@ -From 0501294bca39a19090dae302dc491684470b1a0d Mon Sep 17 00:00:00 2001 -From: Yotam Gigi -Date: Wed, 31 Aug 2016 09:28:27 +0200 -Subject: [PATCH 2/2] tc: man: Add man entry for the matchall classifier. - -In addition to providing information about the mathcall filter and its -configurations, the man entry contains examples for creating port -mirorring entries. - -Signed-off-by: Yotam Gigi -Signed-off-by: Jiri Pirko ---- - man/man8/Makefile | 2 +- - man/man8/tc-matchall.8 | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ - man/man8/tc.8 | 5 ++++ - 3 files changed, 82 insertions(+), 1 deletion(-) - create mode 100644 man/man8/tc-matchall.8 - -diff --git a/man/man8/Makefile b/man/man8/Makefile -index 9badbed..9213769 100644 ---- a/man/man8/Makefile -+++ b/man/man8/Makefile -@@ -14,7 +14,7 @@ MAN8PAGES = $(TARGETS) ip.8 arpd.8 lnstat.8 routel.8 rtacct.8 rtmon.8 rtpr.8 ss. - tipc.8 tipc-bearer.8 tipc-link.8 tipc-media.8 tipc-nametable.8 \ - tipc-node.8 tipc-socket.8 \ - tc-basic.8 tc-cgroup.8 tc-flow.8 tc-flower.8 tc-fw.8 tc-route.8 \ -- tc-tcindex.8 tc-u32.8 \ -+ tc-tcindex.8 tc-u32.8 tc-matchall.8 \ - tc-connmark.8 tc-csum.8 tc-mirred.8 tc-nat.8 tc-pedit.8 tc-police.8 \ - tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 \ - devlink.8 devlink-dev.8 devlink-monitor.8 devlink-port.8 devlink-sb.8 -diff --git a/man/man8/tc-matchall.8 b/man/man8/tc-matchall.8 -new file mode 100644 -index 0000000..f920922 ---- /dev/null -+++ b/man/man8/tc-matchall.8 -@@ -0,0 +1,76 @@ -+.TH "Match-all classifier in tc" 8 "21 Oct 2015" "iproute2" "Linux" -+ -+.SH NAME -+matchall \- traffic control filter that matches every packet -+.SH SYNOPSIS -+.in +8 -+.ti -8 -+.BR tc " " filter " ... " matchall " [ " -+.BR skip_sw " | " skip_hw -+.R " ] [ " -+.B action -+.IR ACTION_SPEC " ] [ " -+.B classid -+.IR CLASSID " ]" -+.SH DESCRIPTION -+The -+.B matchall -+filter allows to classify every packet that flows on the port and run a -+action on it. -+.SH OPTIONS -+.TP -+.BI action " ACTION_SPEC" -+Apply an action from the generic actions framework on matching packets. -+.TP -+.BI classid " CLASSID" -+Push matching packets into the class identified by -+.IR CLASSID . -+.TP -+.BI skip_sw -+Do not process filter by software. If hardware has no offload support for this -+filter, or TC offload is not enabled for the interface, operation will fail. -+.TP -+.BI skip_hw -+Do not process filter by hardware. -+.SH EXAMPLES -+To create ingress mirroring from port eth1 to port eth2: -+.RS -+.EX -+ -+tc qdisc add dev eth1 handle ffff: ingress -+tc filter add dev eth1 parent ffff: \\ -+ matchall skip_sw \\ -+ action mirred egress mirror \\ -+ dev eth2 -+.EE -+.RE -+ -+The first command creats an ingress qdisc with handle -+.BR ffff: -+on device -+.BR eth1 -+where the second command attaches a matchall filters on it that mirrors the -+packets to device eth2. -+ -+To create egress mirroring from port eth1 to port eth2: -+.EX -+ -+tc qdisc add dev eth1 handle 1: root prio -+tc filter add dev eth1 parent 1: \\ -+ matchall skip_sw \\ -+ action mirred egress mirror \\ -+ dev eth2 -+.EE -+.RE -+ -+The first command creats an egress qdisc with handle -+.BR 1: -+that replaces the root qdisc on device -+.BR eth1 -+where the second command attaches a matchall filters on it that mirrors the -+packets to device eth2. -+ -+ -+.EE -+.SH SEE ALSO -+.BR tc (8), -diff --git a/man/man8/tc.8 b/man/man8/tc.8 -index 4e99dca..7ee1c9c 100644 ---- a/man/man8/tc.8 -+++ b/man/man8/tc.8 -@@ -187,6 +187,11 @@ u32 - Generic filtering on arbitrary packet data, assisted by syntax to abstract common operations. See - .BR tc-u32 (8) - for details. -+.TP -+matchall -+Traffic control filter that matches every packet. See -+.BR tc-matchall (8) -+for details. - - .SH CLASSLESS QDISCS - The classless qdiscs are: --- -2.9.3 - diff --git a/devlink-kernel-headers.patch b/devlink-kernel-headers.patch deleted file mode 100644 index b46c702..0000000 --- a/devlink-kernel-headers.patch +++ /dev/null @@ -1,88 +0,0 @@ -diff --git a/include/linux/devlink.h b/include/linux/devlink.h -index a96e1a0..0e21d00 100644 ---- a/include/linux/devlink.h -+++ b/include/linux/devlink.h -@@ -33,6 +33,30 @@ enum devlink_command { - DEVLINK_CMD_PORT_SPLIT, - DEVLINK_CMD_PORT_UNSPLIT, - -+ DEVLINK_CMD_SB_GET, /* can dump */ -+ DEVLINK_CMD_SB_SET, -+ DEVLINK_CMD_SB_NEW, -+ DEVLINK_CMD_SB_DEL, -+ -+ DEVLINK_CMD_SB_POOL_GET, /* can dump */ -+ DEVLINK_CMD_SB_POOL_SET, -+ DEVLINK_CMD_SB_POOL_NEW, -+ DEVLINK_CMD_SB_POOL_DEL, -+ -+ DEVLINK_CMD_SB_PORT_POOL_GET, /* can dump */ -+ DEVLINK_CMD_SB_PORT_POOL_SET, -+ DEVLINK_CMD_SB_PORT_POOL_NEW, -+ DEVLINK_CMD_SB_PORT_POOL_DEL, -+ -+ DEVLINK_CMD_SB_TC_POOL_BIND_GET, /* can dump */ -+ DEVLINK_CMD_SB_TC_POOL_BIND_SET, -+ DEVLINK_CMD_SB_TC_POOL_BIND_NEW, -+ DEVLINK_CMD_SB_TC_POOL_BIND_DEL, -+ -+ /* Shared buffer occupancy monitoring commands */ -+ DEVLINK_CMD_SB_OCC_SNAPSHOT, -+ DEVLINK_CMD_SB_OCC_MAX_CLEAR, -+ - /* add new commands above here */ - - __DEVLINK_CMD_MAX, -@@ -46,6 +70,31 @@ enum devlink_port_type { - DEVLINK_PORT_TYPE_IB, - }; - -+enum devlink_sb_pool_type { -+ DEVLINK_SB_POOL_TYPE_INGRESS, -+ DEVLINK_SB_POOL_TYPE_EGRESS, -+}; -+ -+/* static threshold - limiting the maximum number of bytes. -+ * dynamic threshold - limiting the maximum number of bytes -+ * based on the currently available free space in the shared buffer pool. -+ * In this mode, the maximum quota is calculated based -+ * on the following formula: -+ * max_quota = alpha / (1 + alpha) * Free_Buffer -+ * While Free_Buffer is the amount of none-occupied buffer associated to -+ * the relevant pool. -+ * The value range which can be passed is 0-20 and serves -+ * for computation of alpha by following formula: -+ * alpha = 2 ^ (passed_value - 10) -+ */ -+ -+enum devlink_sb_threshold_type { -+ DEVLINK_SB_THRESHOLD_TYPE_STATIC, -+ DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC, -+}; -+ -+#define DEVLINK_SB_THRESHOLD_TO_ALPHA_MAX 20 -+ - enum devlink_attr { - /* don't change the order or add anything between, this is ABI! */ - DEVLINK_ATTR_UNSPEC, -@@ -62,6 +111,20 @@ enum devlink_attr { - DEVLINK_ATTR_PORT_IBDEV_NAME, /* string */ - DEVLINK_ATTR_PORT_SPLIT_COUNT, /* u32 */ - DEVLINK_ATTR_PORT_SPLIT_GROUP, /* u32 */ -+ DEVLINK_ATTR_SB_INDEX, /* u32 */ -+ DEVLINK_ATTR_SB_SIZE, /* u32 */ -+ DEVLINK_ATTR_SB_INGRESS_POOL_COUNT, /* u16 */ -+ DEVLINK_ATTR_SB_EGRESS_POOL_COUNT, /* u16 */ -+ DEVLINK_ATTR_SB_INGRESS_TC_COUNT, /* u16 */ -+ DEVLINK_ATTR_SB_EGRESS_TC_COUNT, /* u16 */ -+ DEVLINK_ATTR_SB_POOL_INDEX, /* u16 */ -+ DEVLINK_ATTR_SB_POOL_TYPE, /* u8 */ -+ DEVLINK_ATTR_SB_POOL_SIZE, /* u32 */ -+ DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, /* u8 */ -+ DEVLINK_ATTR_SB_THRESHOLD, /* u32 */ -+ DEVLINK_ATTR_SB_TC_INDEX, /* u16 */ -+ DEVLINK_ATTR_SB_OCC_CUR, /* u32 */ -+ DEVLINK_ATTR_SB_OCC_MAX, /* u32 */ - - /* add new attributes above here, update the policy in devlink.c */ - diff --git a/iproute.spec b/iproute.spec index 52b7737..8304f8d 100644 --- a/iproute.spec +++ b/iproute.spec @@ -1,64 +1,19 @@ %global cbq_version v0.7.3 Summary: Advanced IP routing and network device configuration tools Name: iproute -Version: 4.6.0 -Release: 6%{?dist} +Version: 4.9.0 +Release: 1%{?dist} Group: Applications/System URL: http://kernel.org/pub/linux/utils/net/%{name}2/ Source0: http://kernel.org/pub/linux/utils/net/%{name}2/%{name}2-%{version}.tar.xz Source1: cbq-0000.example Source2: avpkt -# manpage/help improvements -# -# * Piece by piece absorbed upstream. -# -# https://github.com/pavlix/iproute2/commits/fedora -Patch1: 0001-Documentation-fixes.patch - -# devlink shared buffer support -# -# Accepted by upstream -# -# https://patchwork.ozlabs.org/patch/622240/ -# https://patchwork.ozlabs.org/patch/622241/ -Patch2: devlink-kernel-headers.patch -Patch3: 0001-devlink-implement-shared-buffer-support.patch -Patch4: 0002-devlink-implement-shared-buffer-occupancy-control.patch - -# devlink manpages installation -# -# Accepted by upstream -# -# https://patchwork.ozlabs.org/patch/647766/ -# https://patchwork.ozlabs.org/patch/647764/ -Patch5: 0001-man-Add-devlink-man-pages-to-Makefile.patch -Patch6: 0002-man-Point-to-devlink-sb-from-devlink-man-page.patch - -# devlink JSON support -# -# Accepted by upstream -# -# https://patchwork.ozlabs.org/patch/651711/ -# https://patchwork.ozlabs.org/patch/651712/ -Patch7: 0001-devlink-write-usage-help-messages-to-stderr.patch -Patch8: 0002-devlink-add-option-to-generate-JSON-output.patch - -# matchall classifier -# -# Accepted by upstream -# -# https://patchwork.ozlabs.org/patch/664374/ -# https://patchwork.ozlabs.org/patch/664375/ -Patch9: matchall-kernel-headers.patch -Patch10: 0001-tc-Add-support-for-the-matchall-traffic-classifier.patch -Patch11: 0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch - # Fix for bz#1411127 # # Accepted upstream: # https://patchwork.ozlabs.org/patch/714480/ -Patch12: 0001-tc-m_xt-Fix-segfault-with-iptables-1.6.0.patch +Patch1: 0001-tc-m_xt-Fix-segfault-with-iptables-1.6.0.patch License: GPLv2+ and Public Domain BuildRequires: bison @@ -122,17 +77,6 @@ The libnetlink static library. %prep %setup -q -n %{name}2-%{version} %patch1 -p1 -%patch2 -p1 -%patch3 -p1 -%patch4 -p1 -%patch5 -p1 -%patch6 -p1 -%patch7 -p1 -%patch8 -p1 -%patch9 -p1 -%patch10 -p1 -%patch11 -p1 -%patch12 -p1 %build export CFLAGS="%{optflags}" @@ -216,6 +160,9 @@ rm -rf '%{buildroot}%{_docdir}' %{_includedir}/libnetlink.h %changelog +* Sat Jan 28 2017 Phil Sutter - 4.9.0-1 +- Update to version 4.9.0 to match kernel package. + * Fri Jan 13 2017 Phil Sutter - 4.6.0-6 - Fix segfault in xt action diff --git a/matchall-kernel-headers.patch b/matchall-kernel-headers.patch deleted file mode 100644 index 8c9d673..0000000 --- a/matchall-kernel-headers.patch +++ /dev/null @@ -1,32 +0,0 @@ -diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h -index b69358b..18fb87e 100644 ---- a/include/linux/pkt_cls.h -+++ b/include/linux/pkt_cls.h -@@ -96,6 +96,10 @@ enum { - - #define TCA_POLICE_MAX (__TCA_POLICE_MAX - 1) - -+/* tca flags definitions */ -+#define TCA_CLS_FLAGS_SKIP_HW (1 << 0) -+#define TCA_CLS_FLAGS_SKIP_SW (1 << 1) -+ - /* U32 filters */ - - #define TC_U32_HTID(h) ((h)&0xFFF00000) -@@ -370,6 +374,16 @@ enum { - - #define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1) - -+enum { -+ TCA_MATCHALL_UNSPEC, -+ TCA_MATCHALL_CLASSID, -+ TCA_MATCHALL_ACT, -+ TCA_MATCHALL_FLAGS, -+ __TCA_MATCHALL_MAX, -+}; -+ -+#define TCA_MATCHALL_MAX (__TCA_MATCHALL_MAX - 1) -+ - /* Extended Matches */ - - struct tcf_ematch_tree_hdr { From 924c06ad2ffd61c27ccceb4b92c901337736ee55 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 14 Mar 2017 14:44:49 +0100 Subject: [PATCH 07/11] Revert "update to 4.9 - XXX: WiP, do not push!" This reverts commit c2655da31c79b188fa79727f3a9f5cc0a4e21971. --- 0001-Documentation-fixes.patch | 27 + ...link-implement-shared-buffer-support.patch | 779 ++++++++++++++++++ ...-write-usage-help-messages-to-stderr.patch | 100 +++ ...an-Add-devlink-man-pages-to-Makefile.patch | 28 + ...-for-the-matchall-traffic-classifier.patch | 186 +++++ ...k-add-option-to-generate-JSON-output.patch | 738 +++++++++++++++++ ...ment-shared-buffer-occupancy-control.patch | 441 ++++++++++ ...-to-devlink-sb-from-devlink-man-page.patch | 26 + ...an-entry-for-the-matchall-classifier.patch | 132 +++ devlink-kernel-headers.patch | 88 ++ iproute.spec | 65 +- matchall-kernel-headers.patch | 32 + 12 files changed, 2636 insertions(+), 6 deletions(-) create mode 100644 0001-Documentation-fixes.patch create mode 100644 0001-devlink-implement-shared-buffer-support.patch create mode 100644 0001-devlink-write-usage-help-messages-to-stderr.patch create mode 100644 0001-man-Add-devlink-man-pages-to-Makefile.patch create mode 100644 0001-tc-Add-support-for-the-matchall-traffic-classifier.patch create mode 100644 0002-devlink-add-option-to-generate-JSON-output.patch create mode 100644 0002-devlink-implement-shared-buffer-occupancy-control.patch create mode 100644 0002-man-Point-to-devlink-sb-from-devlink-man-page.patch create mode 100644 0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch create mode 100644 devlink-kernel-headers.patch create mode 100644 matchall-kernel-headers.patch diff --git a/0001-Documentation-fixes.patch b/0001-Documentation-fixes.patch new file mode 100644 index 0000000..0a149e6 --- /dev/null +++ b/0001-Documentation-fixes.patch @@ -0,0 +1,27 @@ +diff -Nurp iproute2-4.5.0.orig/man/man8/cbq.8 iproute2-4.5.0/man/man8/cbq.8 +--- iproute2-4.5.0.orig/man/man8/cbq.8 1970-01-01 01:00:00.000000000 +0100 ++++ iproute2-4.5.0/man/man8/cbq.8 2016-03-18 13:17:00.673773197 +0100 +@@ -0,0 +1 @@ ++.so man8/tc-cbq.8 +\ No newline at end of file +diff -Nurp iproute2-4.5.0.orig/man/man8/ss.8 iproute2-4.5.0/man/man8/ss.8 +--- iproute2-4.5.0.orig/man/man8/ss.8 2016-03-18 13:16:45.046773197 +0100 ++++ iproute2-4.5.0/man/man8/ss.8 2016-03-18 13:17:05.910773197 +0100 +@@ -136,7 +136,7 @@ Read filter information from FILE. + Each line of FILE is interpreted like single command line option. If FILE is - stdin is used. + .TP + .B FILTER := [ state STATE-FILTER ] [ EXPRESSION ] +-Please take a look at the official documentation (Debian package iproute-doc) for details regarding filters. ++Please take a look at the official documentation (package iproute\-doc) for details regarding filters. + + .SH STATE-FILTER + +@@ -191,7 +191,7 @@ Find all local processes connected to X + List all the tcp sockets in state FIN-WAIT-1 for our apache to network 193.233.7/24 and look at their timers. + .SH SEE ALSO + .BR ip (8), +-.BR /usr/share/doc/iproute-doc/ss.html " (package iproute­doc)", ++.BR /usr/share/doc/iproute-doc/ss.ps " (package iproute\-doc)", + .br + .BR RFC " 793 " + - https://tools.ietf.org/rfc/rfc793.txt (TCP states) diff --git a/0001-devlink-implement-shared-buffer-support.patch b/0001-devlink-implement-shared-buffer-support.patch new file mode 100644 index 0000000..608518a --- /dev/null +++ b/0001-devlink-implement-shared-buffer-support.patch @@ -0,0 +1,779 @@ +From e6d7367d795a41abeea4acc1af8f3885c8918ba7 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Sat, 14 May 2016 15:21:01 +0200 +Subject: [PATCH 1/2] devlink: implement shared buffer support + +Implement kernel devlink shared buffer interface. Introduce new object +"sb" and allow to browse the shared buffer parameters and also change +configuration. + +Signed-off-by: Jiri Pirko +--- + devlink/devlink.c | 653 +++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 652 insertions(+), 1 deletion(-) + +diff --git a/devlink/devlink.c b/devlink/devlink.c +index 89a3083..ca3f586 100644 +--- a/devlink/devlink.c ++++ b/devlink/devlink.c +@@ -114,6 +114,13 @@ static void ifname_map_free(struct ifname_map *ifname_map) + #define DL_OPT_HANDLEP BIT(1) + #define DL_OPT_PORT_TYPE BIT(2) + #define DL_OPT_PORT_COUNT BIT(3) ++#define DL_OPT_SB BIT(4) ++#define DL_OPT_SB_POOL BIT(5) ++#define DL_OPT_SB_SIZE BIT(6) ++#define DL_OPT_SB_TYPE BIT(7) ++#define DL_OPT_SB_THTYPE BIT(8) ++#define DL_OPT_SB_TH BIT(9) ++#define DL_OPT_SB_TC BIT(10) + + struct dl_opts { + uint32_t present; /* flags of present items */ +@@ -122,6 +129,13 @@ struct dl_opts { + uint32_t port_index; + enum devlink_port_type port_type; + uint32_t port_count; ++ uint32_t sb_index; ++ uint16_t sb_pool_index; ++ uint32_t sb_pool_size; ++ enum devlink_sb_pool_type sb_pool_type; ++ enum devlink_sb_threshold_type sb_pool_thtype; ++ uint32_t sb_threshold; ++ uint16_t sb_tc_index; + }; + + struct dl { +@@ -225,6 +239,42 @@ static int attr_cb(const struct nlattr *attr, void *data) + if (type == DEVLINK_ATTR_PORT_IBDEV_NAME && + mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) + return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_INDEX && ++ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_SIZE && ++ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_INGRESS_POOL_COUNT && ++ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_EGRESS_POOL_COUNT && ++ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_INGRESS_TC_COUNT && ++ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_EGRESS_TC_COUNT && ++ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_POOL_INDEX && ++ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_POOL_TYPE && ++ mnl_attr_validate(attr, MNL_TYPE_U8) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_POOL_SIZE && ++ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE && ++ mnl_attr_validate(attr, MNL_TYPE_U8) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_THRESHOLD && ++ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_TC_INDEX && ++ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) ++ return MNL_CB_ERROR; + tb[type] = attr; + return MNL_CB_OK; + } +@@ -307,6 +357,23 @@ static int ifname_map_lookup(struct dl *dl, const char *ifname, + return -ENOENT; + } + ++static int ifname_map_rev_lookup(struct dl *dl, const char *bus_name, ++ const char *dev_name, uint32_t port_index, ++ char **p_ifname) ++{ ++ struct ifname_map *ifname_map; ++ ++ list_for_each_entry(ifname_map, &dl->ifname_map_list, list) { ++ if (strcmp(bus_name, ifname_map->bus_name) == 0 && ++ strcmp(dev_name, ifname_map->dev_name) == 0 && ++ port_index == ifname_map->port_index) { ++ *p_ifname = ifname_map->ifname; ++ return 0; ++ } ++ } ++ return -ENOENT; ++} ++ + static unsigned int strslashcount(char *str) + { + unsigned int count = 0; +@@ -346,6 +413,20 @@ static int strtouint32_t(const char *str, uint32_t *p_val) + return 0; + } + ++static int strtouint16_t(const char *str, uint16_t *p_val) ++{ ++ char *endptr; ++ unsigned long int val; ++ ++ val = strtoul(str, &endptr, 10); ++ if (endptr == str || *endptr != '\0') ++ return -EINVAL; ++ if (val > USHRT_MAX) ++ return -ERANGE; ++ *p_val = val; ++ return 0; ++} ++ + static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name) + { + strslashrsplit(str, p_bus_name, p_dev_name); +@@ -486,6 +567,24 @@ static int dl_argv_uint32_t(struct dl *dl, uint32_t *p_val) + return 0; + } + ++static int dl_argv_uint16_t(struct dl *dl, uint16_t *p_val) ++{ ++ char *str = dl_argv_next(dl); ++ int err; ++ ++ if (!str) { ++ pr_err("Unsigned number argument expected\n"); ++ return -EINVAL; ++ } ++ ++ err = strtouint16_t(str, p_val); ++ if (err) { ++ pr_err("\"%s\" is not a number or not within range\n", str); ++ return err; ++ } ++ return 0; ++} ++ + static int dl_argv_str(struct dl *dl, const char **p_str) + { + const char *str = dl_argv_next(dl); +@@ -513,6 +612,33 @@ static int port_type_get(const char *typestr, enum devlink_port_type *p_type) + return 0; + } + ++static int pool_type_get(const char *typestr, enum devlink_sb_pool_type *p_type) ++{ ++ if (strcmp(typestr, "ingress") == 0) { ++ *p_type = DEVLINK_SB_POOL_TYPE_INGRESS; ++ } else if (strcmp(typestr, "egress") == 0) { ++ *p_type = DEVLINK_SB_POOL_TYPE_EGRESS; ++ } else { ++ pr_err("Unknown pool type \"%s\"\n", typestr); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++static int threshold_type_get(const char *typestr, ++ enum devlink_sb_threshold_type *p_type) ++{ ++ if (strcmp(typestr, "static") == 0) { ++ *p_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC; ++ } else if (strcmp(typestr, "dynamic") == 0) { ++ *p_type = DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC; ++ } else { ++ pr_err("Unknown threshold type \"%s\"\n", typestr); ++ return -EINVAL; ++ } ++ return 0; ++} ++ + static int dl_argv_parse(struct dl *dl, uint32_t o_required, + uint32_t o_optional) + { +@@ -562,6 +688,66 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, + if (err) + return err; + o_found |= DL_OPT_PORT_COUNT; ++ } else if (dl_argv_match(dl, "sb") && ++ (o_all & DL_OPT_SB)) { ++ dl_arg_inc(dl); ++ err = dl_argv_uint32_t(dl, &opts->sb_index); ++ if (err) ++ return err; ++ o_found |= DL_OPT_SB; ++ } else if (dl_argv_match(dl, "pool") && ++ (o_all & DL_OPT_SB_POOL)) { ++ dl_arg_inc(dl); ++ err = dl_argv_uint16_t(dl, &opts->sb_pool_index); ++ if (err) ++ return err; ++ o_found |= DL_OPT_SB_POOL; ++ } else if (dl_argv_match(dl, "size") && ++ (o_all & DL_OPT_SB_SIZE)) { ++ dl_arg_inc(dl); ++ err = dl_argv_uint32_t(dl, &opts->sb_pool_size); ++ if (err) ++ return err; ++ o_found |= DL_OPT_SB_SIZE; ++ } else if (dl_argv_match(dl, "type") && ++ (o_all & DL_OPT_SB_TYPE)) { ++ const char *typestr; ++ ++ dl_arg_inc(dl); ++ err = dl_argv_str(dl, &typestr); ++ if (err) ++ return err; ++ err = pool_type_get(typestr, &opts->sb_pool_type); ++ if (err) ++ return err; ++ o_found |= DL_OPT_SB_TYPE; ++ } else if (dl_argv_match(dl, "thtype") && ++ (o_all & DL_OPT_SB_THTYPE)) { ++ const char *typestr; ++ ++ dl_arg_inc(dl); ++ err = dl_argv_str(dl, &typestr); ++ if (err) ++ return err; ++ err = threshold_type_get(typestr, ++ &opts->sb_pool_thtype); ++ if (err) ++ return err; ++ o_found |= DL_OPT_SB_THTYPE; ++ } else if (dl_argv_match(dl, "th") && ++ (o_all & DL_OPT_SB_TH)) { ++ dl_arg_inc(dl); ++ err = dl_argv_uint32_t(dl, &opts->sb_threshold); ++ if (err) ++ return err; ++ o_found |= DL_OPT_SB_TH; ++ } else if (dl_argv_match(dl, "tc") && ++ (o_all & DL_OPT_SB_TC)) { ++ dl_arg_inc(dl); ++ err = dl_argv_uint16_t(dl, &opts->sb_tc_index); ++ if (err) ++ return err; ++ o_found |= DL_OPT_SB_TC; + } else { + pr_err("Unknown option \"%s\"\n", dl_argv(dl)); + return -EINVAL; +@@ -570,6 +756,11 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, + + opts->present = o_found; + ++ if ((o_optional & DL_OPT_SB) && !(o_found & DL_OPT_SB)) { ++ opts->sb_index = 0; ++ opts->present |= DL_OPT_SB; ++ } ++ + if ((o_required & DL_OPT_PORT_TYPE) && !(o_found & DL_OPT_PORT_TYPE)) { + pr_err("Port type option expected.\n"); + return -EINVAL; +@@ -581,6 +772,35 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, + return -EINVAL; + } + ++ if ((o_required & DL_OPT_SB_POOL) && !(o_found & DL_OPT_SB_POOL)) { ++ pr_err("Pool index option expected.\n"); ++ return -EINVAL; ++ } ++ ++ if ((o_required & DL_OPT_SB_SIZE) && !(o_found & DL_OPT_SB_SIZE)) { ++ pr_err("Pool size option expected.\n"); ++ return -EINVAL; ++ } ++ ++ if ((o_required & DL_OPT_SB_TYPE) && !(o_found & DL_OPT_SB_TYPE)) { ++ pr_err("Pool type option expected.\n"); ++ return -EINVAL; ++ } ++ ++ if ((o_required & DL_OPT_SB_THTYPE) && !(o_found & DL_OPT_SB_THTYPE)) { ++ pr_err("Pool threshold type option expected.\n"); ++ return -EINVAL; ++ } ++ ++ if ((o_required & DL_OPT_SB_TH) && !(o_found & DL_OPT_SB_TH)) { ++ pr_err("Threshold option expected.\n"); ++ return -EINVAL; ++ } ++ ++ if ((o_required & DL_OPT_SB_TC) && !(o_found & DL_OPT_SB_TC)) { ++ pr_err("TC index option expected.\n"); ++ return -EINVAL; ++ } + return 0; + } + +@@ -603,6 +823,27 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl) + if (opts->present & DL_OPT_PORT_COUNT) + mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT, + opts->port_count); ++ if (opts->present & DL_OPT_SB) ++ mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, ++ opts->sb_index); ++ if (opts->present & DL_OPT_SB_POOL) ++ mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, ++ opts->sb_pool_index); ++ if (opts->present & DL_OPT_SB_SIZE) ++ mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_POOL_SIZE, ++ opts->sb_pool_size); ++ if (opts->present & DL_OPT_SB_TYPE) ++ mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE, ++ opts->sb_pool_type); ++ if (opts->present & DL_OPT_SB_THTYPE) ++ mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, ++ opts->sb_pool_thtype); ++ if (opts->present & DL_OPT_SB_TH) ++ mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD, ++ opts->sb_threshold); ++ if (opts->present & DL_OPT_SB_TC) ++ mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX, ++ opts->sb_tc_index); + } + + static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, +@@ -648,6 +889,39 @@ static void pr_out_port_handle(struct nlattr **tb) + mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX])); + } + ++static void __pr_out_port_handle_nice(struct dl *dl, const char *bus_name, ++ const char *dev_name, uint32_t port_index) ++{ ++ char *ifname; ++ int err; ++ ++ if (dl->no_nice_names) ++ goto no_nice_names; ++ ++ err = ifname_map_rev_lookup(dl, bus_name, dev_name, ++ port_index, &ifname); ++ if (err) ++ goto no_nice_names; ++ pr_out("%s", ifname); ++ return; ++ ++no_nice_names: ++ __pr_out_port_handle(bus_name, dev_name, port_index); ++} ++ ++static void pr_out_port_handle_nice(struct dl *dl, struct nlattr **tb) ++{ ++ const char *bus_name; ++ const char *dev_name; ++ uint32_t port_index; ++ ++ bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); ++ dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); ++ port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); ++ ++ __pr_out_port_handle_nice(dl, bus_name, dev_name, port_index); ++} ++ + static void pr_out_dev(struct nlattr **tb) + { + pr_out_handle(tb); +@@ -850,6 +1124,380 @@ static int cmd_port(struct dl *dl) + return -ENOENT; + } + ++static void cmd_sb_help(void) ++{ ++ pr_out("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n"); ++ pr_out(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n"); ++ pr_out(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n"); ++ pr_out(" size POOL_SIZE thtype { static | dynamic }\n"); ++ pr_out(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n"); ++ pr_out(" pool POOL_INDEX ]\n"); ++ pr_out(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n"); ++ pr_out(" pool POOL_INDEX th THRESHOLD\n"); ++ pr_out(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); ++ pr_out(" type { ingress | egress } ]\n"); ++ pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); ++ pr_out(" type { ingress | egress } pool POOL_INDEX\n"); ++ pr_out(" th THRESHOLD\n"); ++} ++ ++static void pr_out_sb(struct nlattr **tb) ++{ ++ pr_out_handle(tb); ++ pr_out(": sb %u size %u ing_pools %u eg_pools %u ing_tcs %u eg_tcs %u\n", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]), ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]), ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]), ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]), ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])); ++} ++ ++static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data) ++{ ++ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; ++ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); ++ ++ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); ++ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || ++ !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_SIZE] || ++ !tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] || ++ !tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] || ++ !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] || ++ !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]) ++ return MNL_CB_ERROR; ++ pr_out_sb(tb); ++ return MNL_CB_OK; ++} ++ ++static int cmd_sb_show(struct dl *dl) ++{ ++ struct nlmsghdr *nlh; ++ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; ++ int err; ++ ++ if (dl_argc(dl) == 0) ++ flags |= NLM_F_DUMP; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_GET, flags); ++ ++ if (dl_argc(dl) > 0) { ++ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); ++ if (err) ++ return err; ++ } ++ ++ return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, NULL); ++} ++ ++static const char *pool_type_name(uint8_t type) ++{ ++ switch (type) { ++ case DEVLINK_SB_POOL_TYPE_INGRESS: return "ingress"; ++ case DEVLINK_SB_POOL_TYPE_EGRESS: return "egress"; ++ default: return ""; ++ } ++} ++ ++static const char *threshold_type_name(uint8_t type) ++{ ++ switch (type) { ++ case DEVLINK_SB_THRESHOLD_TYPE_STATIC: return "static"; ++ case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC: return "dynamic"; ++ default: return ""; ++ } ++} ++ ++static void pr_out_sb_pool(struct nlattr **tb) ++{ ++ pr_out_handle(tb); ++ pr_out(": sb %u pool %u type %s size %u thtype %s\n", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), ++ pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]), ++ threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]))); ++} ++ ++static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data) ++{ ++ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; ++ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); ++ ++ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); ++ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || ++ !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_INDEX] || ++ !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] || ++ !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]) ++ return MNL_CB_ERROR; ++ pr_out_sb_pool(tb); ++ return MNL_CB_OK; ++} ++ ++static int cmd_sb_pool_show(struct dl *dl) ++{ ++ struct nlmsghdr *nlh; ++ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; ++ int err; ++ ++ if (dl_argc(dl) == 0) ++ flags |= NLM_F_DUMP; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags); ++ ++ if (dl_argc(dl) > 0) { ++ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL, ++ DL_OPT_SB); ++ if (err) ++ return err; ++ } ++ ++ return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, NULL); ++} ++ ++static int cmd_sb_pool_set(struct dl *dl) ++{ ++ struct nlmsghdr *nlh; ++ int err; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_SET, ++ NLM_F_REQUEST | NLM_F_ACK); ++ ++ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL | ++ DL_OPT_SB_SIZE | DL_OPT_SB_THTYPE, DL_OPT_SB); ++ if (err) ++ return err; ++ ++ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); ++} ++ ++static int cmd_sb_pool(struct dl *dl) ++{ ++ if (dl_argv_match(dl, "help")) { ++ cmd_sb_help(); ++ return 0; ++ } else if (dl_argv_match(dl, "show") || ++ dl_argv_match(dl, "list") || dl_no_arg(dl)) { ++ dl_arg_inc(dl); ++ return cmd_sb_pool_show(dl); ++ } else if (dl_argv_match(dl, "set")) { ++ dl_arg_inc(dl); ++ return cmd_sb_pool_set(dl); ++ } ++ pr_err("Command \"%s\" not found\n", dl_argv(dl)); ++ return -ENOENT; ++} ++ ++static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb) ++{ ++ pr_out_port_handle_nice(dl, tb); ++ pr_out(": sb %u pool %u threshold %u\n", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); ++} ++ ++static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data) ++{ ++ struct dl *dl = data; ++ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; ++ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); ++ ++ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); ++ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || ++ !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || ++ !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD]) ++ return MNL_CB_ERROR; ++ pr_out_sb_port_pool(dl, tb); ++ return MNL_CB_OK; ++} ++ ++static int cmd_sb_port_pool_show(struct dl *dl) ++{ ++ struct nlmsghdr *nlh; ++ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; ++ int err; ++ ++ if (dl_argc(dl) == 0) ++ flags |= NLM_F_DUMP; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); ++ ++ if (dl_argc(dl) > 0) { ++ err = dl_argv_parse_put(nlh, dl, ++ DL_OPT_HANDLEP | DL_OPT_SB_POOL, ++ DL_OPT_SB); ++ if (err) ++ return err; ++ } ++ ++ return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl); ++} ++ ++static int cmd_sb_port_pool_set(struct dl *dl) ++{ ++ struct nlmsghdr *nlh; ++ int err; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET, ++ NLM_F_REQUEST | NLM_F_ACK); ++ ++ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL | ++ DL_OPT_SB_TH, DL_OPT_SB); ++ if (err) ++ return err; ++ ++ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); ++} ++ ++static int cmd_sb_port_pool(struct dl *dl) ++{ ++ if (dl_argv_match(dl, "help")) { ++ cmd_sb_help(); ++ return 0; ++ } else if (dl_argv_match(dl, "show") || ++ dl_argv_match(dl, "list") || dl_no_arg(dl)) { ++ dl_arg_inc(dl); ++ return cmd_sb_port_pool_show(dl); ++ } else if (dl_argv_match(dl, "set")) { ++ dl_arg_inc(dl); ++ return cmd_sb_port_pool_set(dl); ++ } ++ pr_err("Command \"%s\" not found\n", dl_argv(dl)); ++ return -ENOENT; ++} ++ ++static int cmd_sb_port(struct dl *dl) ++{ ++ if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { ++ cmd_sb_help(); ++ return 0; ++ } else if (dl_argv_match(dl, "pool")) { ++ dl_arg_inc(dl); ++ return cmd_sb_port_pool(dl); ++ } ++ pr_err("Command \"%s\" not found\n", dl_argv(dl)); ++ return -ENOENT; ++} ++ ++static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb) ++{ ++ pr_out_port_handle_nice(dl, tb); ++ pr_out(": sb %u tc %u type %s pool %u threshold %u\n", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]), ++ pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); ++} ++ ++static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data) ++{ ++ struct dl *dl = data; ++ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; ++ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); ++ ++ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); ++ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || ++ !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || ++ !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] || ++ !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD]) ++ return MNL_CB_ERROR; ++ pr_out_sb_tc_bind(dl, tb); ++ return MNL_CB_OK; ++} ++ ++static int cmd_sb_tc_bind_show(struct dl *dl) ++{ ++ struct nlmsghdr *nlh; ++ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; ++ int err; ++ ++ if (dl_argc(dl) == 0) ++ flags |= NLM_F_DUMP; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); ++ ++ if (dl_argc(dl) > 0) { ++ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC | ++ DL_OPT_SB_TYPE, DL_OPT_SB); ++ if (err) ++ return err; ++ } ++ ++ return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl); ++} ++ ++static int cmd_sb_tc_bind_set(struct dl *dl) ++{ ++ struct nlmsghdr *nlh; ++ int err; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET, ++ NLM_F_REQUEST | NLM_F_ACK); ++ ++ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC | ++ DL_OPT_SB_TYPE | DL_OPT_SB_POOL | DL_OPT_SB_TH, ++ DL_OPT_SB); ++ if (err) ++ return err; ++ ++ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); ++} ++ ++static int cmd_sb_tc_bind(struct dl *dl) ++{ ++ if (dl_argv_match(dl, "help")) { ++ cmd_sb_help(); ++ return 0; ++ } else if (dl_argv_match(dl, "show") || ++ dl_argv_match(dl, "list") || dl_no_arg(dl)) { ++ dl_arg_inc(dl); ++ return cmd_sb_tc_bind_show(dl); ++ } else if (dl_argv_match(dl, "set")) { ++ dl_arg_inc(dl); ++ return cmd_sb_tc_bind_set(dl); ++ } ++ pr_err("Command \"%s\" not found\n", dl_argv(dl)); ++ return -ENOENT; ++} ++ ++static int cmd_sb_tc(struct dl *dl) ++{ ++ if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { ++ cmd_sb_help(); ++ return 0; ++ } else if (dl_argv_match(dl, "bind")) { ++ dl_arg_inc(dl); ++ return cmd_sb_tc_bind(dl); ++ } ++ pr_err("Command \"%s\" not found\n", dl_argv(dl)); ++ return -ENOENT; ++} ++ ++static int cmd_sb(struct dl *dl) ++{ ++ if (dl_argv_match(dl, "help")) { ++ cmd_sb_help(); ++ return 0; ++ } else if (dl_argv_match(dl, "show") || ++ dl_argv_match(dl, "list") || dl_no_arg(dl)) { ++ dl_arg_inc(dl); ++ return cmd_sb_show(dl); ++ } else if (dl_argv_match(dl, "pool")) { ++ dl_arg_inc(dl); ++ return cmd_sb_pool(dl); ++ } else if (dl_argv_match(dl, "port")) { ++ dl_arg_inc(dl); ++ return cmd_sb_port(dl); ++ } else if (dl_argv_match(dl, "tc")) { ++ dl_arg_inc(dl); ++ return cmd_sb_tc(dl); ++ } ++ pr_err("Command \"%s\" not found\n", dl_argv(dl)); ++ return -ENOENT; ++} ++ + static const char *cmd_name(uint8_t cmd) + { + switch (cmd) { +@@ -985,7 +1633,7 @@ static int cmd_mon(struct dl *dl) + static void help(void) + { + pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" +- "where OBJECT := { dev | port | monitor }\n" ++ "where OBJECT := { dev | port | sb | monitor }\n" + " OPTIONS := { -V[ersion] | -n[no-nice-names] }\n"); + } + +@@ -1000,6 +1648,9 @@ static int dl_cmd(struct dl *dl) + } else if (dl_argv_match(dl, "port")) { + dl_arg_inc(dl); + return cmd_port(dl); ++ } else if (dl_argv_match(dl, "sb")) { ++ dl_arg_inc(dl); ++ return cmd_sb(dl); + } else if (dl_argv_match(dl, "monitor")) { + dl_arg_inc(dl); + return cmd_mon(dl); +-- +2.9.3 + diff --git a/0001-devlink-write-usage-help-messages-to-stderr.patch b/0001-devlink-write-usage-help-messages-to-stderr.patch new file mode 100644 index 0000000..7413789 --- /dev/null +++ b/0001-devlink-write-usage-help-messages-to-stderr.patch @@ -0,0 +1,100 @@ +From 7a9466dbcba1918a1c93de8f93b9ff3d62418fcf Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Fri, 22 Jul 2016 18:34:29 +0200 +Subject: [PATCH 1/2] devlink: write usage help messages to stderr + +In order to not confuse reader, write help messages into stderr. + +Signed-off-by: Jiri Pirko +--- + devlink/devlink.c | 46 +++++++++++++++++++++++----------------------- + 1 file changed, 23 insertions(+), 23 deletions(-) + +diff --git a/devlink/devlink.c b/devlink/devlink.c +index ffefa86..f73ba95 100644 +--- a/devlink/devlink.c ++++ b/devlink/devlink.c +@@ -909,7 +909,7 @@ static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) + + static void cmd_dev_help(void) + { +- pr_out("Usage: devlink dev show [ DEV ]\n"); ++ pr_err("Usage: devlink dev show [ DEV ]\n"); + } + + static void __pr_out_handle(const char *bus_name, const char *dev_name) +@@ -1024,10 +1024,10 @@ static int cmd_dev(struct dl *dl) + + static void cmd_port_help(void) + { +- pr_out("Usage: devlink port show [ DEV/PORT_INDEX ]\n"); +- pr_out(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n"); +- pr_out(" devlink port split DEV/PORT_INDEX count COUNT\n"); +- pr_out(" devlink port unsplit DEV/PORT_INDEX\n"); ++ pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n"); ++ pr_err(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n"); ++ pr_err(" devlink port split DEV/PORT_INDEX count COUNT\n"); ++ pr_err(" devlink port unsplit DEV/PORT_INDEX\n"); + } + + static const char *port_type_name(uint32_t type) +@@ -1174,22 +1174,22 @@ static int cmd_port(struct dl *dl) + + static void cmd_sb_help(void) + { +- pr_out("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n"); +- pr_out(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n"); +- pr_out(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n"); +- pr_out(" size POOL_SIZE thtype { static | dynamic }\n"); +- pr_out(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n"); +- pr_out(" pool POOL_INDEX ]\n"); +- pr_out(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n"); +- pr_out(" pool POOL_INDEX th THRESHOLD\n"); +- pr_out(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); +- pr_out(" type { ingress | egress } ]\n"); +- pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); +- pr_out(" type { ingress | egress } pool POOL_INDEX\n"); +- pr_out(" th THRESHOLD\n"); +- pr_out(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n"); +- pr_out(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n"); +- pr_out(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); ++ pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n"); ++ pr_err(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n"); ++ pr_err(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n"); ++ pr_err(" size POOL_SIZE thtype { static | dynamic }\n"); ++ pr_err(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n"); ++ pr_err(" pool POOL_INDEX ]\n"); ++ pr_err(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n"); ++ pr_err(" pool POOL_INDEX th THRESHOLD\n"); ++ pr_err(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); ++ pr_err(" type { ingress | egress } ]\n"); ++ pr_err(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); ++ pr_err(" type { ingress | egress } pool POOL_INDEX\n"); ++ pr_err(" th THRESHOLD\n"); ++ pr_err(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n"); ++ pr_err(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n"); ++ pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); + } + + static void pr_out_sb(struct nlattr **tb) +@@ -1991,7 +1991,7 @@ static int cmd_mon_show(struct dl *dl) + + static void cmd_mon_help(void) + { +- pr_out("Usage: devlink monitor [ all | OBJECT-LIST ]\n" ++ pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n" + "where OBJECT-LIST := { dev | port }\n"); + } + +@@ -2010,7 +2010,7 @@ static int cmd_mon(struct dl *dl) + + static void help(void) + { +- pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" ++ pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" + "where OBJECT := { dev | port | sb | monitor }\n" + " OPTIONS := { -V[ersion] | -n[no-nice-names] }\n"); + } +-- +2.9.3 + diff --git a/0001-man-Add-devlink-man-pages-to-Makefile.patch b/0001-man-Add-devlink-man-pages-to-Makefile.patch new file mode 100644 index 0000000..5850571 --- /dev/null +++ b/0001-man-Add-devlink-man-pages-to-Makefile.patch @@ -0,0 +1,28 @@ +From e3da7a45bad1672328d67f016627e026cb41feba Mon Sep 17 00:00:00 2001 +From: Ido Schimmel +Date: Wed, 13 Jul 2016 09:53:53 +0300 +Subject: [PATCH 1/2] man: Add devlink man pages to Makefile + +Signed-off-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + man/man8/Makefile | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/man/man8/Makefile b/man/man8/Makefile +index 929826e..9badbed 100644 +--- a/man/man8/Makefile ++++ b/man/man8/Makefile +@@ -16,7 +16,8 @@ MAN8PAGES = $(TARGETS) ip.8 arpd.8 lnstat.8 routel.8 rtacct.8 rtmon.8 rtpr.8 ss. + tc-basic.8 tc-cgroup.8 tc-flow.8 tc-flower.8 tc-fw.8 tc-route.8 \ + tc-tcindex.8 tc-u32.8 \ + tc-connmark.8 tc-csum.8 tc-mirred.8 tc-nat.8 tc-pedit.8 tc-police.8 \ +- tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 ++ tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 \ ++ devlink.8 devlink-dev.8 devlink-monitor.8 devlink-port.8 devlink-sb.8 + + all: $(TARGETS) + +-- +2.9.3 + diff --git a/0001-tc-Add-support-for-the-matchall-traffic-classifier.patch b/0001-tc-Add-support-for-the-matchall-traffic-classifier.patch new file mode 100644 index 0000000..af450c4 --- /dev/null +++ b/0001-tc-Add-support-for-the-matchall-traffic-classifier.patch @@ -0,0 +1,186 @@ +From d5cbf3ff0561b6c8158c3538c7fe1946add9dec3 Mon Sep 17 00:00:00 2001 +From: Yotam Gigi +Date: Wed, 31 Aug 2016 09:28:26 +0200 +Subject: [PATCH 1/2] tc: Add support for the matchall traffic classifier. + +The matchall classifier matches every packet and allows the user to apply +actions on it. In addition, it supports the skip_sw and skip_hw (as can +be found on u32 and flower filter) that direct the kernel to skip the +software/hardware processing of the actions. + +This filter is very useful in usecases where every packet should be +matched. For example, packet mirroring (SPAN) can be setup very easily +using that filter. + +Signed-off-by: Yotam Gigi +Signed-off-by: Jiri Pirko +--- + tc/Makefile | 1 + + tc/f_matchall.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 144 insertions(+) + create mode 100644 tc/f_matchall.c + +diff --git a/tc/Makefile b/tc/Makefile +index 42747c5..8917eaf 100644 +--- a/tc/Makefile ++++ b/tc/Makefile +@@ -67,6 +67,7 @@ TCMODULES += q_pie.o + TCMODULES += q_hhf.o + TCMODULES += q_clsact.o + TCMODULES += e_bpf.o ++TCMODULES += f_matchall.o + + ifeq ($(TC_CONFIG_IPSET), y) + ifeq ($(TC_CONFIG_XT), y) +diff --git a/tc/f_matchall.c b/tc/f_matchall.c +new file mode 100644 +index 0000000..04e524e +--- /dev/null ++++ b/tc/f_matchall.c +@@ -0,0 +1,143 @@ ++/* ++ * f_matchall.c Match-all Classifier ++ * ++ * This program is free software; you can distribute 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: Jiri Pirko , Yotam Gigi ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "utils.h" ++#include "tc_util.h" ++ ++static void explain(void) ++{ ++ fprintf(stderr, "Usage: ... matchall [skip_sw | skip_hw]\n"); ++ fprintf(stderr, " [ action ACTION_SPEC ] [ classid CLASSID ]\n"); ++ fprintf(stderr, "\n"); ++ fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n"); ++ fprintf(stderr, " FILTERID := X:Y:Z\n"); ++ fprintf(stderr, " ACTION_SPEC := ... look at individual actions\n"); ++ fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n"); ++} ++ ++static int matchall_parse_opt(struct filter_util *qu, char *handle, ++ int argc, char **argv, struct nlmsghdr *n) ++{ ++ struct tcmsg *t = NLMSG_DATA(n); ++ struct rtattr *tail; ++ __u32 flags = 0; ++ long h = 0; ++ ++ if (handle) { ++ h = strtol(handle, NULL, 0); ++ if (h == LONG_MIN || h == LONG_MAX) { ++ fprintf(stderr, "Illegal handle \"%s\", must be numeric.\n", ++ handle); ++ return -1; ++ } ++ } ++ t->tcm_handle = h; ++ ++ if (argc == 0) ++ return 0; ++ ++ tail = (struct rtattr *)(((void *)n)+NLMSG_ALIGN(n->nlmsg_len)); ++ addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0); ++ ++ while (argc > 0) { ++ if (matches(*argv, "classid") == 0 || ++ strcmp(*argv, "flowid") == 0) { ++ unsigned int handle; ++ ++ NEXT_ARG(); ++ if (get_tc_classid(&handle, *argv)) { ++ fprintf(stderr, "Illegal \"classid\"\n"); ++ return -1; ++ } ++ addattr_l(n, MAX_MSG, TCA_MATCHALL_CLASSID, &handle, 4); ++ } else if (matches(*argv, "action") == 0) { ++ NEXT_ARG(); ++ if (parse_action(&argc, &argv, TCA_MATCHALL_ACT, n)) { ++ fprintf(stderr, "Illegal \"action\"\n"); ++ return -1; ++ } ++ continue; ++ ++ } else if (strcmp(*argv, "skip_hw") == 0) { ++ NEXT_ARG(); ++ flags |= TCA_CLS_FLAGS_SKIP_HW; ++ continue; ++ } else if (strcmp(*argv, "skip_sw") == 0) { ++ NEXT_ARG(); ++ flags |= TCA_CLS_FLAGS_SKIP_SW; ++ continue; ++ } else if (strcmp(*argv, "help") == 0) { ++ explain(); ++ return -1; ++ } else { ++ fprintf(stderr, "What is \"%s\"?\n", *argv); ++ explain(); ++ return -1; ++ } ++ argc--; argv++; ++ } ++ ++ if (flags) { ++ if (!(flags ^ (TCA_CLS_FLAGS_SKIP_HW | ++ TCA_CLS_FLAGS_SKIP_SW))) { ++ fprintf(stderr, ++ "skip_hw and skip_sw are mutually exclusive\n"); ++ return -1; ++ } ++ addattr_l(n, MAX_MSG, TCA_MATCHALL_FLAGS, &flags, 4); ++ } ++ ++ tail->rta_len = (((void *)n)+n->nlmsg_len) - (void *)tail; ++ return 0; ++} ++ ++static int matchall_print_opt(struct filter_util *qu, FILE *f, ++ struct rtattr *opt, __u32 handle) ++{ ++ struct rtattr *tb[TCA_MATCHALL_MAX+1]; ++ ++ if (opt == NULL) ++ return 0; ++ ++ parse_rtattr_nested(tb, TCA_MATCHALL_MAX, opt); ++ ++ if (handle) ++ fprintf(f, "handle 0x%x ", handle); ++ ++ if (tb[TCA_MATCHALL_CLASSID]) { ++ SPRINT_BUF(b1); ++ fprintf(f, "flowid %s ", ++ sprint_tc_classid(rta_getattr_u32(tb[TCA_MATCHALL_CLASSID]), b1)); ++ } ++ ++ if (tb[TCA_MATCHALL_ACT]) ++ tc_print_action(f, tb[TCA_MATCHALL_ACT]); ++ ++ return 0; ++} ++ ++struct filter_util matchall_filter_util = { ++ .id = "matchall", ++ .parse_fopt = matchall_parse_opt, ++ .print_fopt = matchall_print_opt, ++}; +-- +2.9.3 + diff --git a/0002-devlink-add-option-to-generate-JSON-output.patch b/0002-devlink-add-option-to-generate-JSON-output.patch new file mode 100644 index 0000000..96c7a68 --- /dev/null +++ b/0002-devlink-add-option-to-generate-JSON-output.patch @@ -0,0 +1,738 @@ +From e3d0f0c0e3d8ac6432884e19aefd169e5c4ae179 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Fri, 22 Jul 2016 18:34:30 +0200 +Subject: [PATCH 2/2] devlink: add option to generate JSON output + +For parsing by another app it is convenient to produce output in JSON +format. + +Signed-off-by: Jiri Pirko +--- + devlink/devlink.c | 455 +++++++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 362 insertions(+), 93 deletions(-) + +diff --git a/devlink/devlink.c b/devlink/devlink.c +index f73ba95..84fa51e 100644 +--- a/devlink/devlink.c ++++ b/devlink/devlink.c +@@ -24,6 +24,7 @@ + #include "SNAPSHOT.h" + #include "list.h" + #include "mnlg.h" ++#include "json_writer.h" + + #define pr_err(args...) fprintf(stderr, ##args) + #define pr_out(args...) fprintf(stdout, ##args) +@@ -151,6 +152,15 @@ struct dl { + char **argv; + bool no_nice_names; + struct dl_opts opts; ++ json_writer_t *jw; ++ bool json_output; ++ bool pretty_output; ++ struct { ++ bool present; ++ char *bus_name; ++ char *dev_name; ++ uint32_t port_index; ++ } arr_last; + }; + + static int dl_argc(struct dl *dl) +@@ -912,52 +922,161 @@ static void cmd_dev_help(void) + pr_err("Usage: devlink dev show [ DEV ]\n"); + } + +-static void __pr_out_handle(const char *bus_name, const char *dev_name) ++static bool cmp_arr_last_handle(struct dl *dl, const char *bus_name, ++ const char *dev_name) + { +- pr_out("%s/%s", bus_name, dev_name); ++ if (!dl->arr_last.present) ++ return false; ++ return strcmp(dl->arr_last.bus_name, bus_name) == 0 && ++ strcmp(dl->arr_last.dev_name, dev_name) == 0; + } + +-static void pr_out_handle(struct nlattr **tb) ++static void arr_last_handle_set(struct dl *dl, const char *bus_name, ++ const char *dev_name) + { +- __pr_out_handle(mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]), +- mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME])); ++ dl->arr_last.present = true; ++ free(dl->arr_last.dev_name); ++ free(dl->arr_last.bus_name); ++ dl->arr_last.bus_name = strdup(bus_name); ++ dl->arr_last.dev_name = strdup(dev_name); + } + +-static void __pr_out_port_handle(const char *bus_name, const char *dev_name, +- uint32_t port_index) ++static bool should_arr_last_handle_start(struct dl *dl, const char *bus_name, ++ const char *dev_name) + { +- __pr_out_handle(bus_name, dev_name); +- pr_out("/%d", port_index); ++ return !cmp_arr_last_handle(dl, bus_name, dev_name); + } + +-static void pr_out_port_handle(struct nlattr **tb) ++static bool should_arr_last_handle_end(struct dl *dl, const char *bus_name, ++ const char *dev_name) + { +- __pr_out_port_handle(mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]), +- mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]), +- mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX])); ++ return dl->arr_last.present && ++ !cmp_arr_last_handle(dl, bus_name, dev_name); + } + +-static void __pr_out_port_handle_nice(struct dl *dl, const char *bus_name, +- const char *dev_name, uint32_t port_index) ++static void __pr_out_handle_start(struct dl *dl, struct nlattr **tb, ++ bool content, bool array) + { +- char *ifname; +- int err; ++ const char *bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); ++ const char *dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); ++ char buf[32]; + +- if (dl->no_nice_names) +- goto no_nice_names; ++ sprintf(buf, "%s/%s", bus_name, dev_name); + +- err = ifname_map_rev_lookup(dl, bus_name, dev_name, +- port_index, &ifname); +- if (err) +- goto no_nice_names; +- pr_out("%s", ifname); +- return; ++ if (dl->json_output) { ++ if (array) { ++ if (should_arr_last_handle_end(dl, bus_name, dev_name)) ++ jsonw_end_array(dl->jw); ++ if (should_arr_last_handle_start(dl, bus_name, ++ dev_name)) { ++ jsonw_name(dl->jw, buf); ++ jsonw_start_array(dl->jw); ++ jsonw_start_object(dl->jw); ++ arr_last_handle_set(dl, bus_name, dev_name); ++ } else { ++ jsonw_start_object(dl->jw); ++ } ++ } else { ++ jsonw_name(dl->jw, buf); ++ jsonw_start_object(dl->jw); ++ } ++ } else { ++ pr_out("%s%s", buf, content ? ":" : ""); ++ } ++} + +-no_nice_names: +- __pr_out_port_handle(bus_name, dev_name, port_index); ++static void pr_out_handle_start_arr(struct dl *dl, struct nlattr **tb) ++{ ++ __pr_out_handle_start(dl, tb, true, true); + } + +-static void pr_out_port_handle_nice(struct dl *dl, struct nlattr **tb) ++static void pr_out_handle_end(struct dl *dl) ++{ ++ if (dl->json_output) ++ jsonw_end_object(dl->jw); ++ else ++ pr_out("\n"); ++} ++ ++static void pr_out_handle(struct dl *dl, struct nlattr **tb) ++{ ++ __pr_out_handle_start(dl, tb, false, false); ++ pr_out_handle_end(dl); ++} ++ ++static bool cmp_arr_last_port_handle(struct dl *dl, const char *bus_name, ++ const char *dev_name, uint32_t port_index) ++{ ++ return cmp_arr_last_handle(dl, bus_name, dev_name) && ++ dl->arr_last.port_index == port_index; ++} ++ ++static void arr_last_port_handle_set(struct dl *dl, const char *bus_name, ++ const char *dev_name, uint32_t port_index) ++{ ++ arr_last_handle_set(dl, bus_name, dev_name); ++ dl->arr_last.port_index = port_index; ++} ++ ++static bool should_arr_last_port_handle_start(struct dl *dl, ++ const char *bus_name, ++ const char *dev_name, ++ uint32_t port_index) ++{ ++ return !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index); ++} ++ ++static bool should_arr_last_port_handle_end(struct dl *dl, ++ const char *bus_name, ++ const char *dev_name, ++ uint32_t port_index) ++{ ++ return dl->arr_last.present && ++ !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index); ++} ++ ++static void __pr_out_port_handle_start(struct dl *dl, const char *bus_name, ++ const char *dev_name, ++ uint32_t port_index, bool try_nice, ++ bool array) ++{ ++ static char buf[32]; ++ char *ifname = NULL; ++ ++ if (dl->no_nice_names || !try_nice || ++ ifname_map_rev_lookup(dl, bus_name, dev_name, ++ port_index, &ifname) != 0) ++ sprintf(buf, "%s/%s/%d", bus_name, dev_name, port_index); ++ else ++ sprintf(buf, "%s", ifname); ++ ++ if (dl->json_output) { ++ if (array) { ++ if (should_arr_last_port_handle_end(dl, bus_name, ++ dev_name, ++ port_index)) ++ jsonw_end_array(dl->jw); ++ if (should_arr_last_port_handle_start(dl, bus_name, ++ dev_name, ++ port_index)) { ++ jsonw_name(dl->jw, buf); ++ jsonw_start_array(dl->jw); ++ jsonw_start_object(dl->jw); ++ arr_last_port_handle_set(dl, bus_name, dev_name, ++ port_index); ++ } else { ++ jsonw_start_object(dl->jw); ++ } ++ } else { ++ jsonw_name(dl->jw, buf); ++ jsonw_start_object(dl->jw); ++ } ++ } else { ++ pr_out("%s:", buf); ++ } ++} ++ ++static void pr_out_port_handle_start(struct dl *dl, struct nlattr **tb, bool try_nice) + { + const char *bus_name; + const char *dev_name; +@@ -966,25 +1085,80 @@ static void pr_out_port_handle_nice(struct dl *dl, struct nlattr **tb) + bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); + dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); + port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); ++ __pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, false); ++} ++ ++static void pr_out_port_handle_start_arr(struct dl *dl, struct nlattr **tb, bool try_nice) ++{ ++ const char *bus_name; ++ const char *dev_name; ++ uint32_t port_index; + +- __pr_out_port_handle_nice(dl, bus_name, dev_name, port_index); ++ bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); ++ dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); ++ port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); ++ __pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, true); + } + +-static void pr_out_dev(struct nlattr **tb) ++static void pr_out_port_handle_end(struct dl *dl) + { +- pr_out_handle(tb); +- pr_out("\n"); ++ if (dl->json_output) ++ jsonw_end_object(dl->jw); ++ else ++ pr_out("\n"); ++} ++ ++ ++static void pr_out_str(struct dl *dl, const char *name, const char *val) ++{ ++ if (dl->json_output) ++ jsonw_string_field(dl->jw, name, val); ++ else ++ pr_out(" %s %s", name, val); ++} ++ ++static void pr_out_uint(struct dl *dl, const char *name, unsigned int val) ++{ ++ if (dl->json_output) ++ jsonw_uint_field(dl->jw, name, val); ++ else ++ pr_out(" %s %u", name, val); ++} ++ ++static void pr_out_dev(struct dl *dl, struct nlattr **tb) ++{ ++ pr_out_handle(dl, tb); ++} ++ ++static void pr_out_section_start(struct dl *dl, const char *name) ++{ ++ if (dl->json_output) { ++ jsonw_start_object(dl->jw); ++ jsonw_name(dl->jw, name); ++ jsonw_start_object(dl->jw); ++ } ++} ++ ++static void pr_out_section_end(struct dl *dl) ++{ ++ if (dl->json_output) { ++ if (dl->arr_last.present) ++ jsonw_end_array(dl->jw); ++ jsonw_end_object(dl->jw); ++ jsonw_end_object(dl->jw); ++ } + } + + static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data) + { ++ struct dl *dl = data; + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + + mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME]) + return MNL_CB_ERROR; +- pr_out_dev(tb); ++ pr_out_dev(dl, tb); + return MNL_CB_OK; + } + +@@ -1005,7 +1179,10 @@ static int cmd_dev_show(struct dl *dl) + return err; + } + +- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, NULL); ++ pr_out_section_start(dl, "dev"); ++ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, dl); ++ pr_out_section_end(dl); ++ return err; + } + + static int cmd_dev(struct dl *dl) +@@ -1041,38 +1218,39 @@ static const char *port_type_name(uint32_t type) + } + } + +-static void pr_out_port(struct nlattr **tb) ++static void pr_out_port(struct dl *dl, struct nlattr **tb) + { + struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE]; + struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE]; + +- pr_out_port_handle(tb); +- pr_out(":"); ++ pr_out_port_handle_start(dl, tb, false); + if (pt_attr) { + uint16_t port_type = mnl_attr_get_u16(pt_attr); + +- pr_out(" type %s", port_type_name(port_type)); ++ pr_out_str(dl, "type", port_type_name(port_type)); + if (dpt_attr) { + uint16_t des_port_type = mnl_attr_get_u16(dpt_attr); + + if (port_type != des_port_type) +- pr_out("(%s)", port_type_name(des_port_type)); ++ pr_out_str(dl, "des_type", ++ port_type_name(des_port_type)); + } + } + if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME]) +- pr_out(" netdev %s", +- mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME])); ++ pr_out_str(dl, "netdev", ++ mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME])); + if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME]) +- pr_out(" ibdev %s", +- mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME])); ++ pr_out_str(dl, "ibdev", ++ mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME])); + if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]) +- pr_out(" split_group %u", +- mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])); +- pr_out("\n"); ++ pr_out_uint(dl, "split_group", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])); ++ pr_out_port_handle_end(dl); + } + + static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data) + { ++ struct dl *dl = data; + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + +@@ -1080,7 +1258,7 @@ static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data) + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || + !tb[DEVLINK_ATTR_PORT_INDEX]) + return MNL_CB_ERROR; +- pr_out_port(tb); ++ pr_out_port(dl, tb); + return MNL_CB_OK; + } + +@@ -1101,7 +1279,10 @@ static int cmd_port_show(struct dl *dl) + return err; + } + +- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, NULL); ++ pr_out_section_start(dl, "port"); ++ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, dl); ++ pr_out_section_end(dl); ++ return err; + } + + static int cmd_port_set(struct dl *dl) +@@ -1192,20 +1373,27 @@ static void cmd_sb_help(void) + pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); + } + +-static void pr_out_sb(struct nlattr **tb) ++static void pr_out_sb(struct dl *dl, struct nlattr **tb) + { +- pr_out_handle(tb); +- pr_out(": sb %u size %u ing_pools %u eg_pools %u ing_tcs %u eg_tcs %u\n", +- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), +- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]), +- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]), +- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]), +- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]), +- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])); ++ pr_out_handle_start_arr(dl, tb); ++ pr_out_uint(dl, "sb", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX])); ++ pr_out_uint(dl, "size", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE])); ++ pr_out_uint(dl, "ing_pools", ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT])); ++ pr_out_uint(dl, "eg_pools", ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT])); ++ pr_out_uint(dl, "ing_tcs", ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT])); ++ pr_out_uint(dl, "eg_tcs", ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])); ++ pr_out_handle_end(dl); + } + + static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data) + { ++ struct dl *dl = data; + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + +@@ -1217,7 +1405,7 @@ static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data) + !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] || + !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]) + return MNL_CB_ERROR; +- pr_out_sb(tb); ++ pr_out_sb(dl, tb); + return MNL_CB_OK; + } + +@@ -1238,7 +1426,10 @@ static int cmd_sb_show(struct dl *dl) + return err; + } + +- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, NULL); ++ pr_out_section_start(dl, "sb"); ++ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, dl); ++ pr_out_section_end(dl); ++ return err; + } + + static const char *pool_type_name(uint8_t type) +@@ -1259,19 +1450,25 @@ static const char *threshold_type_name(uint8_t type) + } + } + +-static void pr_out_sb_pool(struct nlattr **tb) ++static void pr_out_sb_pool(struct dl *dl, struct nlattr **tb) + { +- pr_out_handle(tb); +- pr_out(": sb %u pool %u type %s size %u thtype %s\n", +- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), +- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), +- pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), +- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]), +- threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]))); ++ pr_out_handle_start_arr(dl, tb); ++ pr_out_uint(dl, "sb", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX])); ++ pr_out_uint(dl, "pool", ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX])); ++ pr_out_str(dl, "type", ++ pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]))); ++ pr_out_uint(dl, "size", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE])); ++ pr_out_str(dl, "thtype", ++ threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]))); ++ pr_out_handle_end(dl); + } + + static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data) + { ++ struct dl *dl = data; + struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; + struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); + +@@ -1281,7 +1478,7 @@ static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data) + !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] || + !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]) + return MNL_CB_ERROR; +- pr_out_sb_pool(tb); ++ pr_out_sb_pool(dl, tb); + return MNL_CB_OK; + } + +@@ -1303,7 +1500,10 @@ static int cmd_sb_pool_show(struct dl *dl) + return err; + } + +- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, NULL); ++ pr_out_section_start(dl, "pool"); ++ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, dl); ++ pr_out_section_end(dl); ++ return err; + } + + static int cmd_sb_pool_set(struct dl *dl) +@@ -1341,11 +1541,14 @@ static int cmd_sb_pool(struct dl *dl) + + static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb) + { +- pr_out_port_handle_nice(dl, tb); +- pr_out(": sb %u pool %u threshold %u\n", +- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), +- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), +- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); ++ pr_out_port_handle_start_arr(dl, tb, true); ++ pr_out_uint(dl, "sb", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX])); ++ pr_out_uint(dl, "pool", ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX])); ++ pr_out_uint(dl, "threshold", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); ++ pr_out_port_handle_end(dl); + } + + static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data) +@@ -1382,7 +1585,10 @@ static int cmd_sb_port_pool_show(struct dl *dl) + return err; + } + +- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl); ++ pr_out_section_start(dl, "port_pool"); ++ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl); ++ pr_out_section_end(dl); ++ return 0; + } + + static int cmd_sb_port_pool_set(struct dl *dl) +@@ -1433,13 +1639,18 @@ static int cmd_sb_port(struct dl *dl) + + static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb) + { +- pr_out_port_handle_nice(dl, tb); +- pr_out(": sb %u tc %u type %s pool %u threshold %u\n", +- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), +- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]), +- pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), +- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), ++ pr_out_port_handle_start_arr(dl, tb, true); ++ pr_out_uint(dl, "sb", ++ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX])); ++ pr_out_uint(dl, "tc", ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX])); ++ pr_out_str(dl, "type", ++ pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]))); ++ pr_out_uint(dl, "pool", ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX])); ++ pr_out_uint(dl, "threshold", + mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); ++ pr_out_port_handle_end(dl); + } + + static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data) +@@ -1476,7 +1687,10 @@ static int cmd_sb_tc_bind_show(struct dl *dl) + return err; + } + +- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl); ++ pr_out_section_start(dl, "tc_bind"); ++ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl); ++ pr_out_section_end(dl); ++ return err; + } + + static int cmd_sb_tc_bind_set(struct dl *dl) +@@ -1649,11 +1863,44 @@ static void pr_out_occ_show_item_list(const char *label, struct list_head *list, + pr_out("\n"); + } + +-static void pr_out_occ_show_port(struct occ_port *occ_port) ++static void pr_out_json_occ_show_item_list(struct dl *dl, const char *label, ++ struct list_head *list, ++ bool bound_pool) ++{ ++ struct occ_item *occ_item; ++ char buf[32]; ++ ++ jsonw_name(dl->jw, label); ++ jsonw_start_object(dl->jw); ++ list_for_each_entry(occ_item, list, list) { ++ sprintf(buf, "%u", occ_item->index); ++ jsonw_name(dl->jw, buf); ++ jsonw_start_object(dl->jw); ++ if (bound_pool) ++ jsonw_uint_field(dl->jw, "bound_pool", ++ occ_item->bound_pool_index); ++ jsonw_uint_field(dl->jw, "current", occ_item->cur); ++ jsonw_uint_field(dl->jw, "max", occ_item->max); ++ jsonw_end_object(dl->jw); ++ } ++ jsonw_end_object(dl->jw); ++} ++ ++static void pr_out_occ_show_port(struct dl *dl, struct occ_port *occ_port) + { +- pr_out_occ_show_item_list("pool", &occ_port->pool_list, false); +- pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true); +- pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true); ++ if (dl->json_output) { ++ pr_out_json_occ_show_item_list(dl, "pool", ++ &occ_port->pool_list, false); ++ pr_out_json_occ_show_item_list(dl, "itc", ++ &occ_port->ing_tc_list, true); ++ pr_out_json_occ_show_item_list(dl, "etc", ++ &occ_port->eg_tc_list, true); ++ } else { ++ pr_out("\n"); ++ pr_out_occ_show_item_list("pool", &occ_port->pool_list, false); ++ pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true); ++ pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true); ++ } + } + + static void pr_out_occ_show(struct occ_show *occ_show) +@@ -1663,10 +1910,10 @@ static void pr_out_occ_show(struct occ_show *occ_show) + struct occ_port *occ_port; + + list_for_each_entry(occ_port, &occ_show->port_list, list) { +- __pr_out_port_handle_nice(dl, opts->bus_name, opts->dev_name, +- occ_port->port_index); +- pr_out(":\n"); +- pr_out_occ_show_port(occ_port); ++ __pr_out_port_handle_start(dl, opts->bus_name, opts->dev_name, ++ occ_port->port_index, true, false); ++ pr_out_occ_show_port(dl, occ_port); ++ pr_out_port_handle_end(dl); + } + } + +@@ -1793,7 +2040,9 @@ static int cmd_sb_occ_show(struct dl *dl) + if (err) + goto out; + ++ pr_out_section_start(dl, "occupancy"); + pr_out_occ_show(occ_show); ++ pr_out_section_end(dl); + + out: + occ_show_free(occ_show); +@@ -1949,7 +2198,7 @@ static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data) + if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME]) + return MNL_CB_ERROR; + pr_out_mon_header(genl->cmd); +- pr_out_dev(tb); ++ pr_out_dev(dl, tb); + break; + case DEVLINK_CMD_PORT_GET: /* fall through */ + case DEVLINK_CMD_PORT_SET: /* fall through */ +@@ -1960,7 +2209,7 @@ static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data) + !tb[DEVLINK_ATTR_PORT_INDEX]) + return MNL_CB_ERROR; + pr_out_mon_header(genl->cmd); +- pr_out_port(tb); ++ pr_out_port(dl, tb); + break; + } + return MNL_CB_OK; +@@ -2055,8 +2304,18 @@ static int dl_init(struct dl *dl, int argc, char **argv) + pr_err("Failed to create index map\n"); + goto err_ifname_map_create; + } ++ if (dl->json_output) { ++ dl->jw = jsonw_new(stdout); ++ if (!dl->jw) { ++ pr_err("Failed to create JSON writer\n"); ++ goto err_json_new; ++ } ++ jsonw_pretty(dl->jw, dl->pretty_output); ++ } + return 0; + ++err_json_new: ++ ifname_map_fini(dl); + err_ifname_map_create: + mnlg_socket_close(dl->nlg); + return err; +@@ -2064,6 +2323,8 @@ err_ifname_map_create: + + static void dl_fini(struct dl *dl) + { ++ if (dl->json_output) ++ jsonw_destroy(&dl->jw); + ifname_map_fini(dl); + mnlg_socket_close(dl->nlg); + } +@@ -2088,6 +2349,8 @@ int main(int argc, char **argv) + static const struct option long_options[] = { + { "Version", no_argument, NULL, 'V' }, + { "no-nice-names", no_argument, NULL, 'n' }, ++ { "json", no_argument, NULL, 'j' }, ++ { "pretty", no_argument, NULL, 'p' }, + { NULL, 0, NULL, 0 } + }; + struct dl *dl; +@@ -2101,7 +2364,7 @@ int main(int argc, char **argv) + return EXIT_FAILURE; + } + +- while ((opt = getopt_long(argc, argv, "Vn", ++ while ((opt = getopt_long(argc, argv, "Vnjp", + long_options, NULL)) >= 0) { + + switch (opt) { +@@ -2111,6 +2374,12 @@ int main(int argc, char **argv) + case 'n': + dl->no_nice_names = true; + break; ++ case 'j': ++ dl->json_output = true; ++ break; ++ case 'p': ++ dl->pretty_output = true; ++ break; + default: + pr_err("Unknown option.\n"); + help(); +-- +2.9.3 + diff --git a/0002-devlink-implement-shared-buffer-occupancy-control.patch b/0002-devlink-implement-shared-buffer-occupancy-control.patch new file mode 100644 index 0000000..1194bdf --- /dev/null +++ b/0002-devlink-implement-shared-buffer-occupancy-control.patch @@ -0,0 +1,441 @@ +From 25ec49be2cdfa571d5151f19a7395a7e462d2f49 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Sat, 14 May 2016 15:21:02 +0200 +Subject: [PATCH 2/2] devlink: implement shared buffer occupancy control + +Use kernel shared buffer occupancy control commands to make snapshot and +clear occupancy watermarks. Also, allow to show occupancy values in a +nice way. + +Signed-off-by: Jiri Pirko +--- + devlink/devlink.c | 378 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 378 insertions(+) + +diff --git a/devlink/devlink.c b/devlink/devlink.c +index ca3f586..ffefa86 100644 +--- a/devlink/devlink.c ++++ b/devlink/devlink.c +@@ -27,6 +27,12 @@ + + #define pr_err(args...) fprintf(stderr, ##args) + #define pr_out(args...) fprintf(stdout, ##args) ++#define pr_out_sp(num, args...) \ ++ do { \ ++ int ret = fprintf(stdout, ##args); \ ++ if (ret < num) \ ++ fprintf(stdout, "%*s", num - ret, ""); \ ++ } while (0) + + static int _mnlg_socket_recv_run(struct mnlg_socket *nlg, + mnl_cb_t data_cb, void *data) +@@ -275,6 +281,12 @@ static int attr_cb(const struct nlattr *attr, void *data) + if (type == DEVLINK_ATTR_SB_TC_INDEX && + mnl_attr_validate(attr, MNL_TYPE_U16) < 0) + return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_OCC_CUR && ++ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) ++ return MNL_CB_ERROR; ++ if (type == DEVLINK_ATTR_SB_OCC_MAX && ++ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) ++ return MNL_CB_ERROR; + tb[type] = attr; + return MNL_CB_OK; + } +@@ -858,6 +870,42 @@ static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, + return 0; + } + ++static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) ++{ ++ struct dl_opts *opts = &dl->opts; ++ struct nlattr *attr_bus_name = tb[DEVLINK_ATTR_BUS_NAME]; ++ struct nlattr *attr_dev_name = tb[DEVLINK_ATTR_DEV_NAME]; ++ struct nlattr *attr_port_index = tb[DEVLINK_ATTR_PORT_INDEX]; ++ struct nlattr *attr_sb_index = tb[DEVLINK_ATTR_SB_INDEX]; ++ ++ if (opts->present & DL_OPT_HANDLE && ++ attr_bus_name && attr_dev_name) { ++ const char *bus_name = mnl_attr_get_str(attr_bus_name); ++ const char *dev_name = mnl_attr_get_str(attr_dev_name); ++ ++ if (strcmp(bus_name, opts->bus_name) != 0 || ++ strcmp(dev_name, opts->dev_name) != 0) ++ return false; ++ } ++ if (opts->present & DL_OPT_HANDLEP && ++ attr_bus_name && attr_dev_name && attr_port_index) { ++ const char *bus_name = mnl_attr_get_str(attr_bus_name); ++ const char *dev_name = mnl_attr_get_str(attr_dev_name); ++ uint32_t port_index = mnl_attr_get_u32(attr_port_index); ++ ++ if (strcmp(bus_name, opts->bus_name) != 0 || ++ strcmp(dev_name, opts->dev_name) != 0 || ++ port_index != opts->port_index) ++ return false; ++ } ++ if (opts->present & DL_OPT_SB && attr_sb_index) { ++ uint32_t sb_index = mnl_attr_get_u32(attr_sb_index); ++ ++ if (sb_index != opts->sb_index) ++ return false; ++ } ++ return true; ++} + + static void cmd_dev_help(void) + { +@@ -1139,6 +1187,9 @@ static void cmd_sb_help(void) + pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); + pr_out(" type { ingress | egress } pool POOL_INDEX\n"); + pr_out(" th THRESHOLD\n"); ++ pr_out(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n"); ++ pr_out(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n"); ++ pr_out(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); + } + + static void pr_out_sb(struct nlattr **tb) +@@ -1475,6 +1526,330 @@ static int cmd_sb_tc(struct dl *dl) + return -ENOENT; + } + ++struct occ_item { ++ struct list_head list; ++ uint32_t index; ++ uint32_t cur; ++ uint32_t max; ++ uint32_t bound_pool_index; ++}; ++ ++struct occ_port { ++ struct list_head list; ++ char *bus_name; ++ char *dev_name; ++ uint32_t port_index; ++ uint32_t sb_index; ++ struct list_head pool_list; ++ struct list_head ing_tc_list; ++ struct list_head eg_tc_list; ++}; ++ ++struct occ_show { ++ struct dl *dl; ++ int err; ++ struct list_head port_list; ++}; ++ ++static struct occ_item *occ_item_alloc(void) ++{ ++ return calloc(1, sizeof(struct occ_item)); ++} ++ ++static void occ_item_free(struct occ_item *occ_item) ++{ ++ free(occ_item); ++} ++ ++static struct occ_port *occ_port_alloc(uint32_t port_index) ++{ ++ struct occ_port *occ_port; ++ ++ occ_port = calloc(1, sizeof(*occ_port)); ++ if (!occ_port) ++ return NULL; ++ occ_port->port_index = port_index; ++ INIT_LIST_HEAD(&occ_port->pool_list); ++ INIT_LIST_HEAD(&occ_port->ing_tc_list); ++ INIT_LIST_HEAD(&occ_port->eg_tc_list); ++ return occ_port; ++} ++ ++static void occ_port_free(struct occ_port *occ_port) ++{ ++ struct occ_item *occ_item, *tmp; ++ ++ list_for_each_entry_safe(occ_item, tmp, &occ_port->pool_list, list) ++ occ_item_free(occ_item); ++ list_for_each_entry_safe(occ_item, tmp, &occ_port->ing_tc_list, list) ++ occ_item_free(occ_item); ++ list_for_each_entry_safe(occ_item, tmp, &occ_port->eg_tc_list, list) ++ occ_item_free(occ_item); ++} ++ ++static struct occ_show *occ_show_alloc(struct dl *dl) ++{ ++ struct occ_show *occ_show; ++ ++ occ_show = calloc(1, sizeof(*occ_show)); ++ if (!occ_show) ++ return NULL; ++ occ_show->dl = dl; ++ INIT_LIST_HEAD(&occ_show->port_list); ++ return occ_show; ++} ++ ++static void occ_show_free(struct occ_show *occ_show) ++{ ++ struct occ_port *occ_port, *tmp; ++ ++ list_for_each_entry_safe(occ_port, tmp, &occ_show->port_list, list) ++ occ_port_free(occ_port); ++} ++ ++static struct occ_port *occ_port_get(struct occ_show *occ_show, ++ struct nlattr **tb) ++{ ++ struct occ_port *occ_port; ++ uint32_t port_index; ++ ++ port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); ++ ++ list_for_each_entry_reverse(occ_port, &occ_show->port_list, list) { ++ if (occ_port->port_index == port_index) ++ return occ_port; ++ } ++ occ_port = occ_port_alloc(port_index); ++ if (!occ_port) ++ return NULL; ++ list_add_tail(&occ_port->list, &occ_show->port_list); ++ return occ_port; ++} ++ ++static void pr_out_occ_show_item_list(const char *label, struct list_head *list, ++ bool bound_pool) ++{ ++ struct occ_item *occ_item; ++ int i = 1; ++ ++ pr_out_sp(7, " %s:", label); ++ list_for_each_entry(occ_item, list, list) { ++ if ((i - 1) % 4 == 0 && i != 1) ++ pr_out_sp(7, " "); ++ if (bound_pool) ++ pr_out_sp(7, "%2u(%u):", occ_item->index, ++ occ_item->bound_pool_index); ++ else ++ pr_out_sp(7, "%2u:", occ_item->index); ++ pr_out_sp(15, "%7u/%u", occ_item->cur, occ_item->max); ++ if (i++ % 4 == 0) ++ pr_out("\n"); ++ } ++ if ((i - 1) % 4 != 0) ++ pr_out("\n"); ++} ++ ++static void pr_out_occ_show_port(struct occ_port *occ_port) ++{ ++ pr_out_occ_show_item_list("pool", &occ_port->pool_list, false); ++ pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true); ++ pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true); ++} ++ ++static void pr_out_occ_show(struct occ_show *occ_show) ++{ ++ struct dl *dl = occ_show->dl; ++ struct dl_opts *opts = &dl->opts; ++ struct occ_port *occ_port; ++ ++ list_for_each_entry(occ_port, &occ_show->port_list, list) { ++ __pr_out_port_handle_nice(dl, opts->bus_name, opts->dev_name, ++ occ_port->port_index); ++ pr_out(":\n"); ++ pr_out_occ_show_port(occ_port); ++ } ++} ++ ++static void cmd_sb_occ_port_pool_process(struct occ_show *occ_show, ++ struct nlattr **tb) ++{ ++ struct occ_port *occ_port; ++ struct occ_item *occ_item; ++ ++ if (occ_show->err || !dl_dump_filter(occ_show->dl, tb)) ++ return; ++ ++ occ_port = occ_port_get(occ_show, tb); ++ if (!occ_port) { ++ occ_show->err = -ENOMEM; ++ return; ++ } ++ ++ occ_item = occ_item_alloc(); ++ if (!occ_item) { ++ occ_show->err = -ENOMEM; ++ return; ++ } ++ occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]); ++ occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]); ++ occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]); ++ list_add_tail(&occ_item->list, &occ_port->pool_list); ++} ++ ++static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr *nlh, void *data) ++{ ++ struct occ_show *occ_show = data; ++ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; ++ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); ++ ++ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); ++ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || ++ !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || ++ !tb[DEVLINK_ATTR_SB_POOL_INDEX] || ++ !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX]) ++ return MNL_CB_ERROR; ++ cmd_sb_occ_port_pool_process(occ_show, tb); ++ return MNL_CB_OK; ++} ++ ++static void cmd_sb_occ_tc_pool_process(struct occ_show *occ_show, ++ struct nlattr **tb) ++{ ++ struct occ_port *occ_port; ++ struct occ_item *occ_item; ++ uint8_t pool_type; ++ ++ if (occ_show->err || !dl_dump_filter(occ_show->dl, tb)) ++ return; ++ ++ occ_port = occ_port_get(occ_show, tb); ++ if (!occ_port) { ++ occ_show->err = -ENOMEM; ++ return; ++ } ++ ++ occ_item = occ_item_alloc(); ++ if (!occ_item) { ++ occ_show->err = -ENOMEM; ++ return; ++ } ++ occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]); ++ occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]); ++ occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]); ++ occ_item->bound_pool_index = ++ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]); ++ pool_type = mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]); ++ if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS) ++ list_add_tail(&occ_item->list, &occ_port->ing_tc_list); ++ else if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS) ++ list_add_tail(&occ_item->list, &occ_port->eg_tc_list); ++ else ++ occ_item_free(occ_item); ++} ++ ++static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr *nlh, void *data) ++{ ++ struct occ_show *occ_show = data; ++ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; ++ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); ++ ++ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); ++ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || ++ !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || ++ !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] || ++ !tb[DEVLINK_ATTR_SB_POOL_INDEX] || ++ !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX]) ++ return MNL_CB_ERROR; ++ cmd_sb_occ_tc_pool_process(occ_show, tb); ++ return MNL_CB_OK; ++} ++ ++static int cmd_sb_occ_show(struct dl *dl) ++{ ++ struct nlmsghdr *nlh; ++ struct occ_show *occ_show; ++ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP; ++ int err; ++ ++ err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP, DL_OPT_SB); ++ if (err) ++ return err; ++ ++ occ_show = occ_show_alloc(dl); ++ if (!occ_show) ++ return -ENOMEM; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); ++ ++ err = _mnlg_socket_sndrcv(dl->nlg, nlh, ++ cmd_sb_occ_port_pool_process_cb, occ_show); ++ if (err) ++ goto out; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); ++ ++ err = _mnlg_socket_sndrcv(dl->nlg, nlh, ++ cmd_sb_occ_tc_pool_process_cb, occ_show); ++ if (err) ++ goto out; ++ ++ pr_out_occ_show(occ_show); ++ ++out: ++ occ_show_free(occ_show); ++ return err; ++} ++ ++static int cmd_sb_occ_snapshot(struct dl *dl) ++{ ++ struct nlmsghdr *nlh; ++ int err; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_SNAPSHOT, ++ NLM_F_REQUEST | NLM_F_ACK); ++ ++ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); ++ if (err) ++ return err; ++ ++ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); ++} ++ ++static int cmd_sb_occ_clearmax(struct dl *dl) ++{ ++ struct nlmsghdr *nlh; ++ int err; ++ ++ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_MAX_CLEAR, ++ NLM_F_REQUEST | NLM_F_ACK); ++ ++ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); ++ if (err) ++ return err; ++ ++ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); ++} ++ ++static int cmd_sb_occ(struct dl *dl) ++{ ++ if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { ++ cmd_sb_help(); ++ return 0; ++ } else if (dl_argv_match(dl, "show") || ++ dl_argv_match(dl, "list")) { ++ dl_arg_inc(dl); ++ return cmd_sb_occ_show(dl); ++ } else if (dl_argv_match(dl, "snapshot")) { ++ dl_arg_inc(dl); ++ return cmd_sb_occ_snapshot(dl); ++ } else if (dl_argv_match(dl, "clearmax")) { ++ dl_arg_inc(dl); ++ return cmd_sb_occ_clearmax(dl); ++ } ++ pr_err("Command \"%s\" not found\n", dl_argv(dl)); ++ return -ENOENT; ++} ++ + static int cmd_sb(struct dl *dl) + { + if (dl_argv_match(dl, "help")) { +@@ -1493,6 +1868,9 @@ static int cmd_sb(struct dl *dl) + } else if (dl_argv_match(dl, "tc")) { + dl_arg_inc(dl); + return cmd_sb_tc(dl); ++ } else if (dl_argv_match(dl, "occupancy")) { ++ dl_arg_inc(dl); ++ return cmd_sb_occ(dl); + } + pr_err("Command \"%s\" not found\n", dl_argv(dl)); + return -ENOENT; +-- +2.9.3 + diff --git a/0002-man-Point-to-devlink-sb-from-devlink-man-page.patch b/0002-man-Point-to-devlink-sb-from-devlink-man-page.patch new file mode 100644 index 0000000..ea1b1df --- /dev/null +++ b/0002-man-Point-to-devlink-sb-from-devlink-man-page.patch @@ -0,0 +1,26 @@ +From 78c610e6ea8554e87e2204f540cf0ce61ef52695 Mon Sep 17 00:00:00 2001 +From: Ido Schimmel +Date: Wed, 13 Jul 2016 09:53:54 +0300 +Subject: [PATCH 2/2] man: Point to 'devlink-sb' from 'devlink' man page + +Signed-off-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + man/man8/devlink.8 | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/man/man8/devlink.8 b/man/man8/devlink.8 +index df00f4f..cf0563b 100644 +--- a/man/man8/devlink.8 ++++ b/man/man8/devlink.8 +@@ -76,6 +76,7 @@ Exit status is 0 if command was successful or a positive integer upon failure. + .BR devlink-dev (8), + .BR devlink-port (8), + .BR devlink-monitor (8), ++.BR devlink-sb (8), + .br + + .SH REPORTING BUGS +-- +2.9.3 + diff --git a/0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch b/0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch new file mode 100644 index 0000000..1909c22 --- /dev/null +++ b/0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch @@ -0,0 +1,132 @@ +From 0501294bca39a19090dae302dc491684470b1a0d Mon Sep 17 00:00:00 2001 +From: Yotam Gigi +Date: Wed, 31 Aug 2016 09:28:27 +0200 +Subject: [PATCH 2/2] tc: man: Add man entry for the matchall classifier. + +In addition to providing information about the mathcall filter and its +configurations, the man entry contains examples for creating port +mirorring entries. + +Signed-off-by: Yotam Gigi +Signed-off-by: Jiri Pirko +--- + man/man8/Makefile | 2 +- + man/man8/tc-matchall.8 | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ + man/man8/tc.8 | 5 ++++ + 3 files changed, 82 insertions(+), 1 deletion(-) + create mode 100644 man/man8/tc-matchall.8 + +diff --git a/man/man8/Makefile b/man/man8/Makefile +index 9badbed..9213769 100644 +--- a/man/man8/Makefile ++++ b/man/man8/Makefile +@@ -14,7 +14,7 @@ MAN8PAGES = $(TARGETS) ip.8 arpd.8 lnstat.8 routel.8 rtacct.8 rtmon.8 rtpr.8 ss. + tipc.8 tipc-bearer.8 tipc-link.8 tipc-media.8 tipc-nametable.8 \ + tipc-node.8 tipc-socket.8 \ + tc-basic.8 tc-cgroup.8 tc-flow.8 tc-flower.8 tc-fw.8 tc-route.8 \ +- tc-tcindex.8 tc-u32.8 \ ++ tc-tcindex.8 tc-u32.8 tc-matchall.8 \ + tc-connmark.8 tc-csum.8 tc-mirred.8 tc-nat.8 tc-pedit.8 tc-police.8 \ + tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 \ + devlink.8 devlink-dev.8 devlink-monitor.8 devlink-port.8 devlink-sb.8 +diff --git a/man/man8/tc-matchall.8 b/man/man8/tc-matchall.8 +new file mode 100644 +index 0000000..f920922 +--- /dev/null ++++ b/man/man8/tc-matchall.8 +@@ -0,0 +1,76 @@ ++.TH "Match-all classifier in tc" 8 "21 Oct 2015" "iproute2" "Linux" ++ ++.SH NAME ++matchall \- traffic control filter that matches every packet ++.SH SYNOPSIS ++.in +8 ++.ti -8 ++.BR tc " " filter " ... " matchall " [ " ++.BR skip_sw " | " skip_hw ++.R " ] [ " ++.B action ++.IR ACTION_SPEC " ] [ " ++.B classid ++.IR CLASSID " ]" ++.SH DESCRIPTION ++The ++.B matchall ++filter allows to classify every packet that flows on the port and run a ++action on it. ++.SH OPTIONS ++.TP ++.BI action " ACTION_SPEC" ++Apply an action from the generic actions framework on matching packets. ++.TP ++.BI classid " CLASSID" ++Push matching packets into the class identified by ++.IR CLASSID . ++.TP ++.BI skip_sw ++Do not process filter by software. If hardware has no offload support for this ++filter, or TC offload is not enabled for the interface, operation will fail. ++.TP ++.BI skip_hw ++Do not process filter by hardware. ++.SH EXAMPLES ++To create ingress mirroring from port eth1 to port eth2: ++.RS ++.EX ++ ++tc qdisc add dev eth1 handle ffff: ingress ++tc filter add dev eth1 parent ffff: \\ ++ matchall skip_sw \\ ++ action mirred egress mirror \\ ++ dev eth2 ++.EE ++.RE ++ ++The first command creats an ingress qdisc with handle ++.BR ffff: ++on device ++.BR eth1 ++where the second command attaches a matchall filters on it that mirrors the ++packets to device eth2. ++ ++To create egress mirroring from port eth1 to port eth2: ++.EX ++ ++tc qdisc add dev eth1 handle 1: root prio ++tc filter add dev eth1 parent 1: \\ ++ matchall skip_sw \\ ++ action mirred egress mirror \\ ++ dev eth2 ++.EE ++.RE ++ ++The first command creats an egress qdisc with handle ++.BR 1: ++that replaces the root qdisc on device ++.BR eth1 ++where the second command attaches a matchall filters on it that mirrors the ++packets to device eth2. ++ ++ ++.EE ++.SH SEE ALSO ++.BR tc (8), +diff --git a/man/man8/tc.8 b/man/man8/tc.8 +index 4e99dca..7ee1c9c 100644 +--- a/man/man8/tc.8 ++++ b/man/man8/tc.8 +@@ -187,6 +187,11 @@ u32 + Generic filtering on arbitrary packet data, assisted by syntax to abstract common operations. See + .BR tc-u32 (8) + for details. ++.TP ++matchall ++Traffic control filter that matches every packet. See ++.BR tc-matchall (8) ++for details. + + .SH CLASSLESS QDISCS + The classless qdiscs are: +-- +2.9.3 + diff --git a/devlink-kernel-headers.patch b/devlink-kernel-headers.patch new file mode 100644 index 0000000..b46c702 --- /dev/null +++ b/devlink-kernel-headers.patch @@ -0,0 +1,88 @@ +diff --git a/include/linux/devlink.h b/include/linux/devlink.h +index a96e1a0..0e21d00 100644 +--- a/include/linux/devlink.h ++++ b/include/linux/devlink.h +@@ -33,6 +33,30 @@ enum devlink_command { + DEVLINK_CMD_PORT_SPLIT, + DEVLINK_CMD_PORT_UNSPLIT, + ++ DEVLINK_CMD_SB_GET, /* can dump */ ++ DEVLINK_CMD_SB_SET, ++ DEVLINK_CMD_SB_NEW, ++ DEVLINK_CMD_SB_DEL, ++ ++ DEVLINK_CMD_SB_POOL_GET, /* can dump */ ++ DEVLINK_CMD_SB_POOL_SET, ++ DEVLINK_CMD_SB_POOL_NEW, ++ DEVLINK_CMD_SB_POOL_DEL, ++ ++ DEVLINK_CMD_SB_PORT_POOL_GET, /* can dump */ ++ DEVLINK_CMD_SB_PORT_POOL_SET, ++ DEVLINK_CMD_SB_PORT_POOL_NEW, ++ DEVLINK_CMD_SB_PORT_POOL_DEL, ++ ++ DEVLINK_CMD_SB_TC_POOL_BIND_GET, /* can dump */ ++ DEVLINK_CMD_SB_TC_POOL_BIND_SET, ++ DEVLINK_CMD_SB_TC_POOL_BIND_NEW, ++ DEVLINK_CMD_SB_TC_POOL_BIND_DEL, ++ ++ /* Shared buffer occupancy monitoring commands */ ++ DEVLINK_CMD_SB_OCC_SNAPSHOT, ++ DEVLINK_CMD_SB_OCC_MAX_CLEAR, ++ + /* add new commands above here */ + + __DEVLINK_CMD_MAX, +@@ -46,6 +70,31 @@ enum devlink_port_type { + DEVLINK_PORT_TYPE_IB, + }; + ++enum devlink_sb_pool_type { ++ DEVLINK_SB_POOL_TYPE_INGRESS, ++ DEVLINK_SB_POOL_TYPE_EGRESS, ++}; ++ ++/* static threshold - limiting the maximum number of bytes. ++ * dynamic threshold - limiting the maximum number of bytes ++ * based on the currently available free space in the shared buffer pool. ++ * In this mode, the maximum quota is calculated based ++ * on the following formula: ++ * max_quota = alpha / (1 + alpha) * Free_Buffer ++ * While Free_Buffer is the amount of none-occupied buffer associated to ++ * the relevant pool. ++ * The value range which can be passed is 0-20 and serves ++ * for computation of alpha by following formula: ++ * alpha = 2 ^ (passed_value - 10) ++ */ ++ ++enum devlink_sb_threshold_type { ++ DEVLINK_SB_THRESHOLD_TYPE_STATIC, ++ DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC, ++}; ++ ++#define DEVLINK_SB_THRESHOLD_TO_ALPHA_MAX 20 ++ + enum devlink_attr { + /* don't change the order or add anything between, this is ABI! */ + DEVLINK_ATTR_UNSPEC, +@@ -62,6 +111,20 @@ enum devlink_attr { + DEVLINK_ATTR_PORT_IBDEV_NAME, /* string */ + DEVLINK_ATTR_PORT_SPLIT_COUNT, /* u32 */ + DEVLINK_ATTR_PORT_SPLIT_GROUP, /* u32 */ ++ DEVLINK_ATTR_SB_INDEX, /* u32 */ ++ DEVLINK_ATTR_SB_SIZE, /* u32 */ ++ DEVLINK_ATTR_SB_INGRESS_POOL_COUNT, /* u16 */ ++ DEVLINK_ATTR_SB_EGRESS_POOL_COUNT, /* u16 */ ++ DEVLINK_ATTR_SB_INGRESS_TC_COUNT, /* u16 */ ++ DEVLINK_ATTR_SB_EGRESS_TC_COUNT, /* u16 */ ++ DEVLINK_ATTR_SB_POOL_INDEX, /* u16 */ ++ DEVLINK_ATTR_SB_POOL_TYPE, /* u8 */ ++ DEVLINK_ATTR_SB_POOL_SIZE, /* u32 */ ++ DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, /* u8 */ ++ DEVLINK_ATTR_SB_THRESHOLD, /* u32 */ ++ DEVLINK_ATTR_SB_TC_INDEX, /* u16 */ ++ DEVLINK_ATTR_SB_OCC_CUR, /* u32 */ ++ DEVLINK_ATTR_SB_OCC_MAX, /* u32 */ + + /* add new attributes above here, update the policy in devlink.c */ + diff --git a/iproute.spec b/iproute.spec index 8304f8d..52b7737 100644 --- a/iproute.spec +++ b/iproute.spec @@ -1,19 +1,64 @@ %global cbq_version v0.7.3 Summary: Advanced IP routing and network device configuration tools Name: iproute -Version: 4.9.0 -Release: 1%{?dist} +Version: 4.6.0 +Release: 6%{?dist} Group: Applications/System URL: http://kernel.org/pub/linux/utils/net/%{name}2/ Source0: http://kernel.org/pub/linux/utils/net/%{name}2/%{name}2-%{version}.tar.xz Source1: cbq-0000.example Source2: avpkt +# manpage/help improvements +# +# * Piece by piece absorbed upstream. +# +# https://github.com/pavlix/iproute2/commits/fedora +Patch1: 0001-Documentation-fixes.patch + +# devlink shared buffer support +# +# Accepted by upstream +# +# https://patchwork.ozlabs.org/patch/622240/ +# https://patchwork.ozlabs.org/patch/622241/ +Patch2: devlink-kernel-headers.patch +Patch3: 0001-devlink-implement-shared-buffer-support.patch +Patch4: 0002-devlink-implement-shared-buffer-occupancy-control.patch + +# devlink manpages installation +# +# Accepted by upstream +# +# https://patchwork.ozlabs.org/patch/647766/ +# https://patchwork.ozlabs.org/patch/647764/ +Patch5: 0001-man-Add-devlink-man-pages-to-Makefile.patch +Patch6: 0002-man-Point-to-devlink-sb-from-devlink-man-page.patch + +# devlink JSON support +# +# Accepted by upstream +# +# https://patchwork.ozlabs.org/patch/651711/ +# https://patchwork.ozlabs.org/patch/651712/ +Patch7: 0001-devlink-write-usage-help-messages-to-stderr.patch +Patch8: 0002-devlink-add-option-to-generate-JSON-output.patch + +# matchall classifier +# +# Accepted by upstream +# +# https://patchwork.ozlabs.org/patch/664374/ +# https://patchwork.ozlabs.org/patch/664375/ +Patch9: matchall-kernel-headers.patch +Patch10: 0001-tc-Add-support-for-the-matchall-traffic-classifier.patch +Patch11: 0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch + # Fix for bz#1411127 # # Accepted upstream: # https://patchwork.ozlabs.org/patch/714480/ -Patch1: 0001-tc-m_xt-Fix-segfault-with-iptables-1.6.0.patch +Patch12: 0001-tc-m_xt-Fix-segfault-with-iptables-1.6.0.patch License: GPLv2+ and Public Domain BuildRequires: bison @@ -77,6 +122,17 @@ The libnetlink static library. %prep %setup -q -n %{name}2-%{version} %patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 %build export CFLAGS="%{optflags}" @@ -160,9 +216,6 @@ rm -rf '%{buildroot}%{_docdir}' %{_includedir}/libnetlink.h %changelog -* Sat Jan 28 2017 Phil Sutter - 4.9.0-1 -- Update to version 4.9.0 to match kernel package. - * Fri Jan 13 2017 Phil Sutter - 4.6.0-6 - Fix segfault in xt action diff --git a/matchall-kernel-headers.patch b/matchall-kernel-headers.patch new file mode 100644 index 0000000..8c9d673 --- /dev/null +++ b/matchall-kernel-headers.patch @@ -0,0 +1,32 @@ +diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h +index b69358b..18fb87e 100644 +--- a/include/linux/pkt_cls.h ++++ b/include/linux/pkt_cls.h +@@ -96,6 +96,10 @@ enum { + + #define TCA_POLICE_MAX (__TCA_POLICE_MAX - 1) + ++/* tca flags definitions */ ++#define TCA_CLS_FLAGS_SKIP_HW (1 << 0) ++#define TCA_CLS_FLAGS_SKIP_SW (1 << 1) ++ + /* U32 filters */ + + #define TC_U32_HTID(h) ((h)&0xFFF00000) +@@ -370,6 +374,16 @@ enum { + + #define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1) + ++enum { ++ TCA_MATCHALL_UNSPEC, ++ TCA_MATCHALL_CLASSID, ++ TCA_MATCHALL_ACT, ++ TCA_MATCHALL_FLAGS, ++ __TCA_MATCHALL_MAX, ++}; ++ ++#define TCA_MATCHALL_MAX (__TCA_MATCHALL_MAX - 1) ++ + /* Extended Matches */ + + struct tcf_ematch_tree_hdr { From 4b06b382ecd053362af5f428657ac99893a97216 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 17 Mar 2017 22:19:23 +0100 Subject: [PATCH 08/11] Rebase package on top of iproute2-4.10.0 --- .gitignore | 2 +- 0001-Documentation-fixes.patch | 34 +- ...link-implement-shared-buffer-support.patch | 779 ------------------ ...-write-usage-help-messages-to-stderr.patch | 100 --- ...an-Add-devlink-man-pages-to-Makefile.patch | 28 - ...-for-the-matchall-traffic-classifier.patch | 186 ----- ..._xt-Fix-segfault-with-iptables-1.6.0.patch | 36 - ...k-add-option-to-generate-JSON-output.patch | 738 ----------------- ...ment-shared-buffer-occupancy-control.patch | 441 ---------- ...-to-devlink-sb-from-devlink-man-page.patch | 26 - ...rrect-type-when-calling-flower_icmp_.patch | 38 + ...an-entry-for-the-matchall-classifier.patch | 132 --- ...t-for-valid-type-in-bpf_get_work_dir.patch | 38 + devlink-kernel-headers.patch | 88 -- iproute.spec | 64 +- matchall-kernel-headers.patch | 32 - sources | 2 +- 17 files changed, 113 insertions(+), 2651 deletions(-) delete mode 100644 0001-devlink-implement-shared-buffer-support.patch delete mode 100644 0001-devlink-write-usage-help-messages-to-stderr.patch delete mode 100644 0001-man-Add-devlink-man-pages-to-Makefile.patch delete mode 100644 0001-tc-Add-support-for-the-matchall-traffic-classifier.patch delete mode 100644 0001-tc-m_xt-Fix-segfault-with-iptables-1.6.0.patch delete mode 100644 0002-devlink-add-option-to-generate-JSON-output.patch delete mode 100644 0002-devlink-implement-shared-buffer-occupancy-control.patch delete mode 100644 0002-man-Point-to-devlink-sb-from-devlink-man-page.patch create mode 100644 0002-tc-flower-use-correct-type-when-calling-flower_icmp_.patch delete mode 100644 0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch create mode 100644 0003-bpf-test-for-valid-type-in-bpf_get_work_dir.patch delete mode 100644 devlink-kernel-headers.patch delete mode 100644 matchall-kernel-headers.patch diff --git a/.gitignore b/.gitignore index 3bdca63..da24855 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -/iproute2-4.6.0.tar.xz +/iproute2-4.10.0.tar.xz diff --git a/0001-Documentation-fixes.patch b/0001-Documentation-fixes.patch index 0a149e6..3e8856a 100644 --- a/0001-Documentation-fixes.patch +++ b/0001-Documentation-fixes.patch @@ -1,13 +1,26 @@ -diff -Nurp iproute2-4.5.0.orig/man/man8/cbq.8 iproute2-4.5.0/man/man8/cbq.8 ---- iproute2-4.5.0.orig/man/man8/cbq.8 1970-01-01 01:00:00.000000000 +0100 -+++ iproute2-4.5.0/man/man8/cbq.8 2016-03-18 13:17:00.673773197 +0100 +From 7f27c8433061f2732925f120b11f5ca3c06caf28 Mon Sep 17 00:00:00 2001 +From: Phil Sutter +Date: Sat, 28 Jan 2017 12:56:24 +0100 +Subject: [PATCH] Documentation fixes + +--- + man/man8/cbq.8 | 1 + + man/man8/ss.8 | 4 ++-- + 2 files changed, 3 insertions(+), 2 deletions(-) + create mode 100644 man/man8/cbq.8 + +diff --git a/man/man8/cbq.8 b/man/man8/cbq.8 +new file mode 100644 +index 00000000..bef35201 +--- /dev/null ++++ b/man/man8/cbq.8 @@ -0,0 +1 @@ +.so man8/tc-cbq.8 -\ No newline at end of file -diff -Nurp iproute2-4.5.0.orig/man/man8/ss.8 iproute2-4.5.0/man/man8/ss.8 ---- iproute2-4.5.0.orig/man/man8/ss.8 2016-03-18 13:16:45.046773197 +0100 -+++ iproute2-4.5.0/man/man8/ss.8 2016-03-18 13:17:05.910773197 +0100 -@@ -136,7 +136,7 @@ Read filter information from FILE. +diff --git a/man/man8/ss.8 b/man/man8/ss.8 +index 4ef11523..3898bdbd 100644 +--- a/man/man8/ss.8 ++++ b/man/man8/ss.8 +@@ -142,7 +142,7 @@ Read filter information from FILE. Each line of FILE is interpreted like single command line option. If FILE is - stdin is used. .TP .B FILTER := [ state STATE-FILTER ] [ EXPRESSION ] @@ -16,7 +29,7 @@ diff -Nurp iproute2-4.5.0.orig/man/man8/ss.8 iproute2-4.5.0/man/man8/ss.8 .SH STATE-FILTER -@@ -191,7 +191,7 @@ Find all local processes connected to X +@@ -197,7 +197,7 @@ Find all local processes connected to X server. List all the tcp sockets in state FIN-WAIT-1 for our apache to network 193.233.7/24 and look at their timers. .SH SEE ALSO .BR ip (8), @@ -25,3 +38,6 @@ diff -Nurp iproute2-4.5.0.orig/man/man8/ss.8 iproute2-4.5.0/man/man8/ss.8 .br .BR RFC " 793 " - https://tools.ietf.org/rfc/rfc793.txt (TCP states) +-- +2.11.0 + diff --git a/0001-devlink-implement-shared-buffer-support.patch b/0001-devlink-implement-shared-buffer-support.patch deleted file mode 100644 index 608518a..0000000 --- a/0001-devlink-implement-shared-buffer-support.patch +++ /dev/null @@ -1,779 +0,0 @@ -From e6d7367d795a41abeea4acc1af8f3885c8918ba7 Mon Sep 17 00:00:00 2001 -From: Jiri Pirko -Date: Sat, 14 May 2016 15:21:01 +0200 -Subject: [PATCH 1/2] devlink: implement shared buffer support - -Implement kernel devlink shared buffer interface. Introduce new object -"sb" and allow to browse the shared buffer parameters and also change -configuration. - -Signed-off-by: Jiri Pirko ---- - devlink/devlink.c | 653 +++++++++++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 652 insertions(+), 1 deletion(-) - -diff --git a/devlink/devlink.c b/devlink/devlink.c -index 89a3083..ca3f586 100644 ---- a/devlink/devlink.c -+++ b/devlink/devlink.c -@@ -114,6 +114,13 @@ static void ifname_map_free(struct ifname_map *ifname_map) - #define DL_OPT_HANDLEP BIT(1) - #define DL_OPT_PORT_TYPE BIT(2) - #define DL_OPT_PORT_COUNT BIT(3) -+#define DL_OPT_SB BIT(4) -+#define DL_OPT_SB_POOL BIT(5) -+#define DL_OPT_SB_SIZE BIT(6) -+#define DL_OPT_SB_TYPE BIT(7) -+#define DL_OPT_SB_THTYPE BIT(8) -+#define DL_OPT_SB_TH BIT(9) -+#define DL_OPT_SB_TC BIT(10) - - struct dl_opts { - uint32_t present; /* flags of present items */ -@@ -122,6 +129,13 @@ struct dl_opts { - uint32_t port_index; - enum devlink_port_type port_type; - uint32_t port_count; -+ uint32_t sb_index; -+ uint16_t sb_pool_index; -+ uint32_t sb_pool_size; -+ enum devlink_sb_pool_type sb_pool_type; -+ enum devlink_sb_threshold_type sb_pool_thtype; -+ uint32_t sb_threshold; -+ uint16_t sb_tc_index; - }; - - struct dl { -@@ -225,6 +239,42 @@ static int attr_cb(const struct nlattr *attr, void *data) - if (type == DEVLINK_ATTR_PORT_IBDEV_NAME && - mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) - return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_INDEX && -+ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_SIZE && -+ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_INGRESS_POOL_COUNT && -+ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_EGRESS_POOL_COUNT && -+ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_INGRESS_TC_COUNT && -+ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_EGRESS_TC_COUNT && -+ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_POOL_INDEX && -+ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_POOL_TYPE && -+ mnl_attr_validate(attr, MNL_TYPE_U8) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_POOL_SIZE && -+ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE && -+ mnl_attr_validate(attr, MNL_TYPE_U8) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_THRESHOLD && -+ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_TC_INDEX && -+ mnl_attr_validate(attr, MNL_TYPE_U16) < 0) -+ return MNL_CB_ERROR; - tb[type] = attr; - return MNL_CB_OK; - } -@@ -307,6 +357,23 @@ static int ifname_map_lookup(struct dl *dl, const char *ifname, - return -ENOENT; - } - -+static int ifname_map_rev_lookup(struct dl *dl, const char *bus_name, -+ const char *dev_name, uint32_t port_index, -+ char **p_ifname) -+{ -+ struct ifname_map *ifname_map; -+ -+ list_for_each_entry(ifname_map, &dl->ifname_map_list, list) { -+ if (strcmp(bus_name, ifname_map->bus_name) == 0 && -+ strcmp(dev_name, ifname_map->dev_name) == 0 && -+ port_index == ifname_map->port_index) { -+ *p_ifname = ifname_map->ifname; -+ return 0; -+ } -+ } -+ return -ENOENT; -+} -+ - static unsigned int strslashcount(char *str) - { - unsigned int count = 0; -@@ -346,6 +413,20 @@ static int strtouint32_t(const char *str, uint32_t *p_val) - return 0; - } - -+static int strtouint16_t(const char *str, uint16_t *p_val) -+{ -+ char *endptr; -+ unsigned long int val; -+ -+ val = strtoul(str, &endptr, 10); -+ if (endptr == str || *endptr != '\0') -+ return -EINVAL; -+ if (val > USHRT_MAX) -+ return -ERANGE; -+ *p_val = val; -+ return 0; -+} -+ - static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name) - { - strslashrsplit(str, p_bus_name, p_dev_name); -@@ -486,6 +567,24 @@ static int dl_argv_uint32_t(struct dl *dl, uint32_t *p_val) - return 0; - } - -+static int dl_argv_uint16_t(struct dl *dl, uint16_t *p_val) -+{ -+ char *str = dl_argv_next(dl); -+ int err; -+ -+ if (!str) { -+ pr_err("Unsigned number argument expected\n"); -+ return -EINVAL; -+ } -+ -+ err = strtouint16_t(str, p_val); -+ if (err) { -+ pr_err("\"%s\" is not a number or not within range\n", str); -+ return err; -+ } -+ return 0; -+} -+ - static int dl_argv_str(struct dl *dl, const char **p_str) - { - const char *str = dl_argv_next(dl); -@@ -513,6 +612,33 @@ static int port_type_get(const char *typestr, enum devlink_port_type *p_type) - return 0; - } - -+static int pool_type_get(const char *typestr, enum devlink_sb_pool_type *p_type) -+{ -+ if (strcmp(typestr, "ingress") == 0) { -+ *p_type = DEVLINK_SB_POOL_TYPE_INGRESS; -+ } else if (strcmp(typestr, "egress") == 0) { -+ *p_type = DEVLINK_SB_POOL_TYPE_EGRESS; -+ } else { -+ pr_err("Unknown pool type \"%s\"\n", typestr); -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+static int threshold_type_get(const char *typestr, -+ enum devlink_sb_threshold_type *p_type) -+{ -+ if (strcmp(typestr, "static") == 0) { -+ *p_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC; -+ } else if (strcmp(typestr, "dynamic") == 0) { -+ *p_type = DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC; -+ } else { -+ pr_err("Unknown threshold type \"%s\"\n", typestr); -+ return -EINVAL; -+ } -+ return 0; -+} -+ - static int dl_argv_parse(struct dl *dl, uint32_t o_required, - uint32_t o_optional) - { -@@ -562,6 +688,66 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, - if (err) - return err; - o_found |= DL_OPT_PORT_COUNT; -+ } else if (dl_argv_match(dl, "sb") && -+ (o_all & DL_OPT_SB)) { -+ dl_arg_inc(dl); -+ err = dl_argv_uint32_t(dl, &opts->sb_index); -+ if (err) -+ return err; -+ o_found |= DL_OPT_SB; -+ } else if (dl_argv_match(dl, "pool") && -+ (o_all & DL_OPT_SB_POOL)) { -+ dl_arg_inc(dl); -+ err = dl_argv_uint16_t(dl, &opts->sb_pool_index); -+ if (err) -+ return err; -+ o_found |= DL_OPT_SB_POOL; -+ } else if (dl_argv_match(dl, "size") && -+ (o_all & DL_OPT_SB_SIZE)) { -+ dl_arg_inc(dl); -+ err = dl_argv_uint32_t(dl, &opts->sb_pool_size); -+ if (err) -+ return err; -+ o_found |= DL_OPT_SB_SIZE; -+ } else if (dl_argv_match(dl, "type") && -+ (o_all & DL_OPT_SB_TYPE)) { -+ const char *typestr; -+ -+ dl_arg_inc(dl); -+ err = dl_argv_str(dl, &typestr); -+ if (err) -+ return err; -+ err = pool_type_get(typestr, &opts->sb_pool_type); -+ if (err) -+ return err; -+ o_found |= DL_OPT_SB_TYPE; -+ } else if (dl_argv_match(dl, "thtype") && -+ (o_all & DL_OPT_SB_THTYPE)) { -+ const char *typestr; -+ -+ dl_arg_inc(dl); -+ err = dl_argv_str(dl, &typestr); -+ if (err) -+ return err; -+ err = threshold_type_get(typestr, -+ &opts->sb_pool_thtype); -+ if (err) -+ return err; -+ o_found |= DL_OPT_SB_THTYPE; -+ } else if (dl_argv_match(dl, "th") && -+ (o_all & DL_OPT_SB_TH)) { -+ dl_arg_inc(dl); -+ err = dl_argv_uint32_t(dl, &opts->sb_threshold); -+ if (err) -+ return err; -+ o_found |= DL_OPT_SB_TH; -+ } else if (dl_argv_match(dl, "tc") && -+ (o_all & DL_OPT_SB_TC)) { -+ dl_arg_inc(dl); -+ err = dl_argv_uint16_t(dl, &opts->sb_tc_index); -+ if (err) -+ return err; -+ o_found |= DL_OPT_SB_TC; - } else { - pr_err("Unknown option \"%s\"\n", dl_argv(dl)); - return -EINVAL; -@@ -570,6 +756,11 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, - - opts->present = o_found; - -+ if ((o_optional & DL_OPT_SB) && !(o_found & DL_OPT_SB)) { -+ opts->sb_index = 0; -+ opts->present |= DL_OPT_SB; -+ } -+ - if ((o_required & DL_OPT_PORT_TYPE) && !(o_found & DL_OPT_PORT_TYPE)) { - pr_err("Port type option expected.\n"); - return -EINVAL; -@@ -581,6 +772,35 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, - return -EINVAL; - } - -+ if ((o_required & DL_OPT_SB_POOL) && !(o_found & DL_OPT_SB_POOL)) { -+ pr_err("Pool index option expected.\n"); -+ return -EINVAL; -+ } -+ -+ if ((o_required & DL_OPT_SB_SIZE) && !(o_found & DL_OPT_SB_SIZE)) { -+ pr_err("Pool size option expected.\n"); -+ return -EINVAL; -+ } -+ -+ if ((o_required & DL_OPT_SB_TYPE) && !(o_found & DL_OPT_SB_TYPE)) { -+ pr_err("Pool type option expected.\n"); -+ return -EINVAL; -+ } -+ -+ if ((o_required & DL_OPT_SB_THTYPE) && !(o_found & DL_OPT_SB_THTYPE)) { -+ pr_err("Pool threshold type option expected.\n"); -+ return -EINVAL; -+ } -+ -+ if ((o_required & DL_OPT_SB_TH) && !(o_found & DL_OPT_SB_TH)) { -+ pr_err("Threshold option expected.\n"); -+ return -EINVAL; -+ } -+ -+ if ((o_required & DL_OPT_SB_TC) && !(o_found & DL_OPT_SB_TC)) { -+ pr_err("TC index option expected.\n"); -+ return -EINVAL; -+ } - return 0; - } - -@@ -603,6 +823,27 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl) - if (opts->present & DL_OPT_PORT_COUNT) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT, - opts->port_count); -+ if (opts->present & DL_OPT_SB) -+ mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, -+ opts->sb_index); -+ if (opts->present & DL_OPT_SB_POOL) -+ mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, -+ opts->sb_pool_index); -+ if (opts->present & DL_OPT_SB_SIZE) -+ mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_POOL_SIZE, -+ opts->sb_pool_size); -+ if (opts->present & DL_OPT_SB_TYPE) -+ mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE, -+ opts->sb_pool_type); -+ if (opts->present & DL_OPT_SB_THTYPE) -+ mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, -+ opts->sb_pool_thtype); -+ if (opts->present & DL_OPT_SB_TH) -+ mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD, -+ opts->sb_threshold); -+ if (opts->present & DL_OPT_SB_TC) -+ mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX, -+ opts->sb_tc_index); - } - - static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, -@@ -648,6 +889,39 @@ static void pr_out_port_handle(struct nlattr **tb) - mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX])); - } - -+static void __pr_out_port_handle_nice(struct dl *dl, const char *bus_name, -+ const char *dev_name, uint32_t port_index) -+{ -+ char *ifname; -+ int err; -+ -+ if (dl->no_nice_names) -+ goto no_nice_names; -+ -+ err = ifname_map_rev_lookup(dl, bus_name, dev_name, -+ port_index, &ifname); -+ if (err) -+ goto no_nice_names; -+ pr_out("%s", ifname); -+ return; -+ -+no_nice_names: -+ __pr_out_port_handle(bus_name, dev_name, port_index); -+} -+ -+static void pr_out_port_handle_nice(struct dl *dl, struct nlattr **tb) -+{ -+ const char *bus_name; -+ const char *dev_name; -+ uint32_t port_index; -+ -+ bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); -+ dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); -+ port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); -+ -+ __pr_out_port_handle_nice(dl, bus_name, dev_name, port_index); -+} -+ - static void pr_out_dev(struct nlattr **tb) - { - pr_out_handle(tb); -@@ -850,6 +1124,380 @@ static int cmd_port(struct dl *dl) - return -ENOENT; - } - -+static void cmd_sb_help(void) -+{ -+ pr_out("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n"); -+ pr_out(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n"); -+ pr_out(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n"); -+ pr_out(" size POOL_SIZE thtype { static | dynamic }\n"); -+ pr_out(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n"); -+ pr_out(" pool POOL_INDEX ]\n"); -+ pr_out(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n"); -+ pr_out(" pool POOL_INDEX th THRESHOLD\n"); -+ pr_out(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); -+ pr_out(" type { ingress | egress } ]\n"); -+ pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); -+ pr_out(" type { ingress | egress } pool POOL_INDEX\n"); -+ pr_out(" th THRESHOLD\n"); -+} -+ -+static void pr_out_sb(struct nlattr **tb) -+{ -+ pr_out_handle(tb); -+ pr_out(": sb %u size %u ing_pools %u eg_pools %u ing_tcs %u eg_tcs %u\n", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]), -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]), -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]), -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]), -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])); -+} -+ -+static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data) -+{ -+ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; -+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); -+ -+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); -+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || -+ !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_SIZE] || -+ !tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] || -+ !tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] || -+ !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] || -+ !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]) -+ return MNL_CB_ERROR; -+ pr_out_sb(tb); -+ return MNL_CB_OK; -+} -+ -+static int cmd_sb_show(struct dl *dl) -+{ -+ struct nlmsghdr *nlh; -+ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; -+ int err; -+ -+ if (dl_argc(dl) == 0) -+ flags |= NLM_F_DUMP; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_GET, flags); -+ -+ if (dl_argc(dl) > 0) { -+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); -+ if (err) -+ return err; -+ } -+ -+ return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, NULL); -+} -+ -+static const char *pool_type_name(uint8_t type) -+{ -+ switch (type) { -+ case DEVLINK_SB_POOL_TYPE_INGRESS: return "ingress"; -+ case DEVLINK_SB_POOL_TYPE_EGRESS: return "egress"; -+ default: return ""; -+ } -+} -+ -+static const char *threshold_type_name(uint8_t type) -+{ -+ switch (type) { -+ case DEVLINK_SB_THRESHOLD_TYPE_STATIC: return "static"; -+ case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC: return "dynamic"; -+ default: return ""; -+ } -+} -+ -+static void pr_out_sb_pool(struct nlattr **tb) -+{ -+ pr_out_handle(tb); -+ pr_out(": sb %u pool %u type %s size %u thtype %s\n", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), -+ pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]), -+ threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]))); -+} -+ -+static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data) -+{ -+ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; -+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); -+ -+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); -+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || -+ !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_INDEX] || -+ !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] || -+ !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]) -+ return MNL_CB_ERROR; -+ pr_out_sb_pool(tb); -+ return MNL_CB_OK; -+} -+ -+static int cmd_sb_pool_show(struct dl *dl) -+{ -+ struct nlmsghdr *nlh; -+ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; -+ int err; -+ -+ if (dl_argc(dl) == 0) -+ flags |= NLM_F_DUMP; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags); -+ -+ if (dl_argc(dl) > 0) { -+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL, -+ DL_OPT_SB); -+ if (err) -+ return err; -+ } -+ -+ return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, NULL); -+} -+ -+static int cmd_sb_pool_set(struct dl *dl) -+{ -+ struct nlmsghdr *nlh; -+ int err; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_SET, -+ NLM_F_REQUEST | NLM_F_ACK); -+ -+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL | -+ DL_OPT_SB_SIZE | DL_OPT_SB_THTYPE, DL_OPT_SB); -+ if (err) -+ return err; -+ -+ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); -+} -+ -+static int cmd_sb_pool(struct dl *dl) -+{ -+ if (dl_argv_match(dl, "help")) { -+ cmd_sb_help(); -+ return 0; -+ } else if (dl_argv_match(dl, "show") || -+ dl_argv_match(dl, "list") || dl_no_arg(dl)) { -+ dl_arg_inc(dl); -+ return cmd_sb_pool_show(dl); -+ } else if (dl_argv_match(dl, "set")) { -+ dl_arg_inc(dl); -+ return cmd_sb_pool_set(dl); -+ } -+ pr_err("Command \"%s\" not found\n", dl_argv(dl)); -+ return -ENOENT; -+} -+ -+static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb) -+{ -+ pr_out_port_handle_nice(dl, tb); -+ pr_out(": sb %u pool %u threshold %u\n", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); -+} -+ -+static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data) -+{ -+ struct dl *dl = data; -+ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; -+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); -+ -+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); -+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || -+ !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || -+ !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD]) -+ return MNL_CB_ERROR; -+ pr_out_sb_port_pool(dl, tb); -+ return MNL_CB_OK; -+} -+ -+static int cmd_sb_port_pool_show(struct dl *dl) -+{ -+ struct nlmsghdr *nlh; -+ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; -+ int err; -+ -+ if (dl_argc(dl) == 0) -+ flags |= NLM_F_DUMP; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); -+ -+ if (dl_argc(dl) > 0) { -+ err = dl_argv_parse_put(nlh, dl, -+ DL_OPT_HANDLEP | DL_OPT_SB_POOL, -+ DL_OPT_SB); -+ if (err) -+ return err; -+ } -+ -+ return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl); -+} -+ -+static int cmd_sb_port_pool_set(struct dl *dl) -+{ -+ struct nlmsghdr *nlh; -+ int err; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET, -+ NLM_F_REQUEST | NLM_F_ACK); -+ -+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL | -+ DL_OPT_SB_TH, DL_OPT_SB); -+ if (err) -+ return err; -+ -+ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); -+} -+ -+static int cmd_sb_port_pool(struct dl *dl) -+{ -+ if (dl_argv_match(dl, "help")) { -+ cmd_sb_help(); -+ return 0; -+ } else if (dl_argv_match(dl, "show") || -+ dl_argv_match(dl, "list") || dl_no_arg(dl)) { -+ dl_arg_inc(dl); -+ return cmd_sb_port_pool_show(dl); -+ } else if (dl_argv_match(dl, "set")) { -+ dl_arg_inc(dl); -+ return cmd_sb_port_pool_set(dl); -+ } -+ pr_err("Command \"%s\" not found\n", dl_argv(dl)); -+ return -ENOENT; -+} -+ -+static int cmd_sb_port(struct dl *dl) -+{ -+ if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { -+ cmd_sb_help(); -+ return 0; -+ } else if (dl_argv_match(dl, "pool")) { -+ dl_arg_inc(dl); -+ return cmd_sb_port_pool(dl); -+ } -+ pr_err("Command \"%s\" not found\n", dl_argv(dl)); -+ return -ENOENT; -+} -+ -+static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb) -+{ -+ pr_out_port_handle_nice(dl, tb); -+ pr_out(": sb %u tc %u type %s pool %u threshold %u\n", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]), -+ pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); -+} -+ -+static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data) -+{ -+ struct dl *dl = data; -+ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; -+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); -+ -+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); -+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || -+ !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || -+ !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] || -+ !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD]) -+ return MNL_CB_ERROR; -+ pr_out_sb_tc_bind(dl, tb); -+ return MNL_CB_OK; -+} -+ -+static int cmd_sb_tc_bind_show(struct dl *dl) -+{ -+ struct nlmsghdr *nlh; -+ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; -+ int err; -+ -+ if (dl_argc(dl) == 0) -+ flags |= NLM_F_DUMP; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); -+ -+ if (dl_argc(dl) > 0) { -+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC | -+ DL_OPT_SB_TYPE, DL_OPT_SB); -+ if (err) -+ return err; -+ } -+ -+ return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl); -+} -+ -+static int cmd_sb_tc_bind_set(struct dl *dl) -+{ -+ struct nlmsghdr *nlh; -+ int err; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET, -+ NLM_F_REQUEST | NLM_F_ACK); -+ -+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC | -+ DL_OPT_SB_TYPE | DL_OPT_SB_POOL | DL_OPT_SB_TH, -+ DL_OPT_SB); -+ if (err) -+ return err; -+ -+ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); -+} -+ -+static int cmd_sb_tc_bind(struct dl *dl) -+{ -+ if (dl_argv_match(dl, "help")) { -+ cmd_sb_help(); -+ return 0; -+ } else if (dl_argv_match(dl, "show") || -+ dl_argv_match(dl, "list") || dl_no_arg(dl)) { -+ dl_arg_inc(dl); -+ return cmd_sb_tc_bind_show(dl); -+ } else if (dl_argv_match(dl, "set")) { -+ dl_arg_inc(dl); -+ return cmd_sb_tc_bind_set(dl); -+ } -+ pr_err("Command \"%s\" not found\n", dl_argv(dl)); -+ return -ENOENT; -+} -+ -+static int cmd_sb_tc(struct dl *dl) -+{ -+ if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { -+ cmd_sb_help(); -+ return 0; -+ } else if (dl_argv_match(dl, "bind")) { -+ dl_arg_inc(dl); -+ return cmd_sb_tc_bind(dl); -+ } -+ pr_err("Command \"%s\" not found\n", dl_argv(dl)); -+ return -ENOENT; -+} -+ -+static int cmd_sb(struct dl *dl) -+{ -+ if (dl_argv_match(dl, "help")) { -+ cmd_sb_help(); -+ return 0; -+ } else if (dl_argv_match(dl, "show") || -+ dl_argv_match(dl, "list") || dl_no_arg(dl)) { -+ dl_arg_inc(dl); -+ return cmd_sb_show(dl); -+ } else if (dl_argv_match(dl, "pool")) { -+ dl_arg_inc(dl); -+ return cmd_sb_pool(dl); -+ } else if (dl_argv_match(dl, "port")) { -+ dl_arg_inc(dl); -+ return cmd_sb_port(dl); -+ } else if (dl_argv_match(dl, "tc")) { -+ dl_arg_inc(dl); -+ return cmd_sb_tc(dl); -+ } -+ pr_err("Command \"%s\" not found\n", dl_argv(dl)); -+ return -ENOENT; -+} -+ - static const char *cmd_name(uint8_t cmd) - { - switch (cmd) { -@@ -985,7 +1633,7 @@ static int cmd_mon(struct dl *dl) - static void help(void) - { - pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" -- "where OBJECT := { dev | port | monitor }\n" -+ "where OBJECT := { dev | port | sb | monitor }\n" - " OPTIONS := { -V[ersion] | -n[no-nice-names] }\n"); - } - -@@ -1000,6 +1648,9 @@ static int dl_cmd(struct dl *dl) - } else if (dl_argv_match(dl, "port")) { - dl_arg_inc(dl); - return cmd_port(dl); -+ } else if (dl_argv_match(dl, "sb")) { -+ dl_arg_inc(dl); -+ return cmd_sb(dl); - } else if (dl_argv_match(dl, "monitor")) { - dl_arg_inc(dl); - return cmd_mon(dl); --- -2.9.3 - diff --git a/0001-devlink-write-usage-help-messages-to-stderr.patch b/0001-devlink-write-usage-help-messages-to-stderr.patch deleted file mode 100644 index 7413789..0000000 --- a/0001-devlink-write-usage-help-messages-to-stderr.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 7a9466dbcba1918a1c93de8f93b9ff3d62418fcf Mon Sep 17 00:00:00 2001 -From: Jiri Pirko -Date: Fri, 22 Jul 2016 18:34:29 +0200 -Subject: [PATCH 1/2] devlink: write usage help messages to stderr - -In order to not confuse reader, write help messages into stderr. - -Signed-off-by: Jiri Pirko ---- - devlink/devlink.c | 46 +++++++++++++++++++++++----------------------- - 1 file changed, 23 insertions(+), 23 deletions(-) - -diff --git a/devlink/devlink.c b/devlink/devlink.c -index ffefa86..f73ba95 100644 ---- a/devlink/devlink.c -+++ b/devlink/devlink.c -@@ -909,7 +909,7 @@ static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) - - static void cmd_dev_help(void) - { -- pr_out("Usage: devlink dev show [ DEV ]\n"); -+ pr_err("Usage: devlink dev show [ DEV ]\n"); - } - - static void __pr_out_handle(const char *bus_name, const char *dev_name) -@@ -1024,10 +1024,10 @@ static int cmd_dev(struct dl *dl) - - static void cmd_port_help(void) - { -- pr_out("Usage: devlink port show [ DEV/PORT_INDEX ]\n"); -- pr_out(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n"); -- pr_out(" devlink port split DEV/PORT_INDEX count COUNT\n"); -- pr_out(" devlink port unsplit DEV/PORT_INDEX\n"); -+ pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n"); -+ pr_err(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n"); -+ pr_err(" devlink port split DEV/PORT_INDEX count COUNT\n"); -+ pr_err(" devlink port unsplit DEV/PORT_INDEX\n"); - } - - static const char *port_type_name(uint32_t type) -@@ -1174,22 +1174,22 @@ static int cmd_port(struct dl *dl) - - static void cmd_sb_help(void) - { -- pr_out("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n"); -- pr_out(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n"); -- pr_out(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n"); -- pr_out(" size POOL_SIZE thtype { static | dynamic }\n"); -- pr_out(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n"); -- pr_out(" pool POOL_INDEX ]\n"); -- pr_out(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n"); -- pr_out(" pool POOL_INDEX th THRESHOLD\n"); -- pr_out(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); -- pr_out(" type { ingress | egress } ]\n"); -- pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); -- pr_out(" type { ingress | egress } pool POOL_INDEX\n"); -- pr_out(" th THRESHOLD\n"); -- pr_out(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n"); -- pr_out(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n"); -- pr_out(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); -+ pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n"); -+ pr_err(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n"); -+ pr_err(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n"); -+ pr_err(" size POOL_SIZE thtype { static | dynamic }\n"); -+ pr_err(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n"); -+ pr_err(" pool POOL_INDEX ]\n"); -+ pr_err(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n"); -+ pr_err(" pool POOL_INDEX th THRESHOLD\n"); -+ pr_err(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); -+ pr_err(" type { ingress | egress } ]\n"); -+ pr_err(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); -+ pr_err(" type { ingress | egress } pool POOL_INDEX\n"); -+ pr_err(" th THRESHOLD\n"); -+ pr_err(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n"); -+ pr_err(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n"); -+ pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); - } - - static void pr_out_sb(struct nlattr **tb) -@@ -1991,7 +1991,7 @@ static int cmd_mon_show(struct dl *dl) - - static void cmd_mon_help(void) - { -- pr_out("Usage: devlink monitor [ all | OBJECT-LIST ]\n" -+ pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n" - "where OBJECT-LIST := { dev | port }\n"); - } - -@@ -2010,7 +2010,7 @@ static int cmd_mon(struct dl *dl) - - static void help(void) - { -- pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" -+ pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" - "where OBJECT := { dev | port | sb | monitor }\n" - " OPTIONS := { -V[ersion] | -n[no-nice-names] }\n"); - } --- -2.9.3 - diff --git a/0001-man-Add-devlink-man-pages-to-Makefile.patch b/0001-man-Add-devlink-man-pages-to-Makefile.patch deleted file mode 100644 index 5850571..0000000 --- a/0001-man-Add-devlink-man-pages-to-Makefile.patch +++ /dev/null @@ -1,28 +0,0 @@ -From e3da7a45bad1672328d67f016627e026cb41feba Mon Sep 17 00:00:00 2001 -From: Ido Schimmel -Date: Wed, 13 Jul 2016 09:53:53 +0300 -Subject: [PATCH 1/2] man: Add devlink man pages to Makefile - -Signed-off-by: Jiri Pirko -Signed-off-by: Ido Schimmel ---- - man/man8/Makefile | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/man/man8/Makefile b/man/man8/Makefile -index 929826e..9badbed 100644 ---- a/man/man8/Makefile -+++ b/man/man8/Makefile -@@ -16,7 +16,8 @@ MAN8PAGES = $(TARGETS) ip.8 arpd.8 lnstat.8 routel.8 rtacct.8 rtmon.8 rtpr.8 ss. - tc-basic.8 tc-cgroup.8 tc-flow.8 tc-flower.8 tc-fw.8 tc-route.8 \ - tc-tcindex.8 tc-u32.8 \ - tc-connmark.8 tc-csum.8 tc-mirred.8 tc-nat.8 tc-pedit.8 tc-police.8 \ -- tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 -+ tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 \ -+ devlink.8 devlink-dev.8 devlink-monitor.8 devlink-port.8 devlink-sb.8 - - all: $(TARGETS) - --- -2.9.3 - diff --git a/0001-tc-Add-support-for-the-matchall-traffic-classifier.patch b/0001-tc-Add-support-for-the-matchall-traffic-classifier.patch deleted file mode 100644 index af450c4..0000000 --- a/0001-tc-Add-support-for-the-matchall-traffic-classifier.patch +++ /dev/null @@ -1,186 +0,0 @@ -From d5cbf3ff0561b6c8158c3538c7fe1946add9dec3 Mon Sep 17 00:00:00 2001 -From: Yotam Gigi -Date: Wed, 31 Aug 2016 09:28:26 +0200 -Subject: [PATCH 1/2] tc: Add support for the matchall traffic classifier. - -The matchall classifier matches every packet and allows the user to apply -actions on it. In addition, it supports the skip_sw and skip_hw (as can -be found on u32 and flower filter) that direct the kernel to skip the -software/hardware processing of the actions. - -This filter is very useful in usecases where every packet should be -matched. For example, packet mirroring (SPAN) can be setup very easily -using that filter. - -Signed-off-by: Yotam Gigi -Signed-off-by: Jiri Pirko ---- - tc/Makefile | 1 + - tc/f_matchall.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 144 insertions(+) - create mode 100644 tc/f_matchall.c - -diff --git a/tc/Makefile b/tc/Makefile -index 42747c5..8917eaf 100644 ---- a/tc/Makefile -+++ b/tc/Makefile -@@ -67,6 +67,7 @@ TCMODULES += q_pie.o - TCMODULES += q_hhf.o - TCMODULES += q_clsact.o - TCMODULES += e_bpf.o -+TCMODULES += f_matchall.o - - ifeq ($(TC_CONFIG_IPSET), y) - ifeq ($(TC_CONFIG_XT), y) -diff --git a/tc/f_matchall.c b/tc/f_matchall.c -new file mode 100644 -index 0000000..04e524e ---- /dev/null -+++ b/tc/f_matchall.c -@@ -0,0 +1,143 @@ -+/* -+ * f_matchall.c Match-all Classifier -+ * -+ * This program is free software; you can distribute 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: Jiri Pirko , Yotam Gigi -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "utils.h" -+#include "tc_util.h" -+ -+static void explain(void) -+{ -+ fprintf(stderr, "Usage: ... matchall [skip_sw | skip_hw]\n"); -+ fprintf(stderr, " [ action ACTION_SPEC ] [ classid CLASSID ]\n"); -+ fprintf(stderr, "\n"); -+ fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n"); -+ fprintf(stderr, " FILTERID := X:Y:Z\n"); -+ fprintf(stderr, " ACTION_SPEC := ... look at individual actions\n"); -+ fprintf(stderr, "\nNOTE: CLASSID is parsed as hexadecimal input.\n"); -+} -+ -+static int matchall_parse_opt(struct filter_util *qu, char *handle, -+ int argc, char **argv, struct nlmsghdr *n) -+{ -+ struct tcmsg *t = NLMSG_DATA(n); -+ struct rtattr *tail; -+ __u32 flags = 0; -+ long h = 0; -+ -+ if (handle) { -+ h = strtol(handle, NULL, 0); -+ if (h == LONG_MIN || h == LONG_MAX) { -+ fprintf(stderr, "Illegal handle \"%s\", must be numeric.\n", -+ handle); -+ return -1; -+ } -+ } -+ t->tcm_handle = h; -+ -+ if (argc == 0) -+ return 0; -+ -+ tail = (struct rtattr *)(((void *)n)+NLMSG_ALIGN(n->nlmsg_len)); -+ addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0); -+ -+ while (argc > 0) { -+ if (matches(*argv, "classid") == 0 || -+ strcmp(*argv, "flowid") == 0) { -+ unsigned int handle; -+ -+ NEXT_ARG(); -+ if (get_tc_classid(&handle, *argv)) { -+ fprintf(stderr, "Illegal \"classid\"\n"); -+ return -1; -+ } -+ addattr_l(n, MAX_MSG, TCA_MATCHALL_CLASSID, &handle, 4); -+ } else if (matches(*argv, "action") == 0) { -+ NEXT_ARG(); -+ if (parse_action(&argc, &argv, TCA_MATCHALL_ACT, n)) { -+ fprintf(stderr, "Illegal \"action\"\n"); -+ return -1; -+ } -+ continue; -+ -+ } else if (strcmp(*argv, "skip_hw") == 0) { -+ NEXT_ARG(); -+ flags |= TCA_CLS_FLAGS_SKIP_HW; -+ continue; -+ } else if (strcmp(*argv, "skip_sw") == 0) { -+ NEXT_ARG(); -+ flags |= TCA_CLS_FLAGS_SKIP_SW; -+ continue; -+ } else if (strcmp(*argv, "help") == 0) { -+ explain(); -+ return -1; -+ } else { -+ fprintf(stderr, "What is \"%s\"?\n", *argv); -+ explain(); -+ return -1; -+ } -+ argc--; argv++; -+ } -+ -+ if (flags) { -+ if (!(flags ^ (TCA_CLS_FLAGS_SKIP_HW | -+ TCA_CLS_FLAGS_SKIP_SW))) { -+ fprintf(stderr, -+ "skip_hw and skip_sw are mutually exclusive\n"); -+ return -1; -+ } -+ addattr_l(n, MAX_MSG, TCA_MATCHALL_FLAGS, &flags, 4); -+ } -+ -+ tail->rta_len = (((void *)n)+n->nlmsg_len) - (void *)tail; -+ return 0; -+} -+ -+static int matchall_print_opt(struct filter_util *qu, FILE *f, -+ struct rtattr *opt, __u32 handle) -+{ -+ struct rtattr *tb[TCA_MATCHALL_MAX+1]; -+ -+ if (opt == NULL) -+ return 0; -+ -+ parse_rtattr_nested(tb, TCA_MATCHALL_MAX, opt); -+ -+ if (handle) -+ fprintf(f, "handle 0x%x ", handle); -+ -+ if (tb[TCA_MATCHALL_CLASSID]) { -+ SPRINT_BUF(b1); -+ fprintf(f, "flowid %s ", -+ sprint_tc_classid(rta_getattr_u32(tb[TCA_MATCHALL_CLASSID]), b1)); -+ } -+ -+ if (tb[TCA_MATCHALL_ACT]) -+ tc_print_action(f, tb[TCA_MATCHALL_ACT]); -+ -+ return 0; -+} -+ -+struct filter_util matchall_filter_util = { -+ .id = "matchall", -+ .parse_fopt = matchall_parse_opt, -+ .print_fopt = matchall_print_opt, -+}; --- -2.9.3 - diff --git a/0001-tc-m_xt-Fix-segfault-with-iptables-1.6.0.patch b/0001-tc-m_xt-Fix-segfault-with-iptables-1.6.0.patch deleted file mode 100644 index 103a486..0000000 --- a/0001-tc-m_xt-Fix-segfault-with-iptables-1.6.0.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 34ea60b5b7645e96c600b8073dd82ac65144d711 Mon Sep 17 00:00:00 2001 -From: Phil Sutter -Date: Thu, 12 Jan 2017 15:12:26 +0100 -Subject: [iproute PATCH] tc: m_xt: Fix segfault with iptables-1.6.0 - -Said iptables version introduced struct xtables_globals field -'compat_rev', a function pointer. Initializing it is mandatory as -libxtables calls it without existence check. - -Without this, tc segfaults when using the xt action like so: - -| tc filter add dev d0 parent ffff: u32 match u32 0 0 \ -| action xt -j MARK --set-mark 20 - -Signed-off-by: Phil Sutter ---- - tc/m_xt.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/tc/m_xt.c b/tc/m_xt.c -index dbb54981462ee..57ed40d7aa3a8 100644 ---- a/tc/m_xt.c -+++ b/tc/m_xt.c -@@ -77,6 +77,9 @@ static struct xtables_globals tcipt_globals = { - .orig_opts = original_opts, - .opts = original_opts, - .exit_err = NULL, -+#if (XTABLES_VERSION_CODE >= 11) -+ .compat_rev = xtables_compatible_revision, -+#endif - }; - - /* --- -2.11.0 - diff --git a/0002-devlink-add-option-to-generate-JSON-output.patch b/0002-devlink-add-option-to-generate-JSON-output.patch deleted file mode 100644 index 96c7a68..0000000 --- a/0002-devlink-add-option-to-generate-JSON-output.patch +++ /dev/null @@ -1,738 +0,0 @@ -From e3d0f0c0e3d8ac6432884e19aefd169e5c4ae179 Mon Sep 17 00:00:00 2001 -From: Jiri Pirko -Date: Fri, 22 Jul 2016 18:34:30 +0200 -Subject: [PATCH 2/2] devlink: add option to generate JSON output - -For parsing by another app it is convenient to produce output in JSON -format. - -Signed-off-by: Jiri Pirko ---- - devlink/devlink.c | 455 +++++++++++++++++++++++++++++++++++++++++++----------- - 1 file changed, 362 insertions(+), 93 deletions(-) - -diff --git a/devlink/devlink.c b/devlink/devlink.c -index f73ba95..84fa51e 100644 ---- a/devlink/devlink.c -+++ b/devlink/devlink.c -@@ -24,6 +24,7 @@ - #include "SNAPSHOT.h" - #include "list.h" - #include "mnlg.h" -+#include "json_writer.h" - - #define pr_err(args...) fprintf(stderr, ##args) - #define pr_out(args...) fprintf(stdout, ##args) -@@ -151,6 +152,15 @@ struct dl { - char **argv; - bool no_nice_names; - struct dl_opts opts; -+ json_writer_t *jw; -+ bool json_output; -+ bool pretty_output; -+ struct { -+ bool present; -+ char *bus_name; -+ char *dev_name; -+ uint32_t port_index; -+ } arr_last; - }; - - static int dl_argc(struct dl *dl) -@@ -912,52 +922,161 @@ static void cmd_dev_help(void) - pr_err("Usage: devlink dev show [ DEV ]\n"); - } - --static void __pr_out_handle(const char *bus_name, const char *dev_name) -+static bool cmp_arr_last_handle(struct dl *dl, const char *bus_name, -+ const char *dev_name) - { -- pr_out("%s/%s", bus_name, dev_name); -+ if (!dl->arr_last.present) -+ return false; -+ return strcmp(dl->arr_last.bus_name, bus_name) == 0 && -+ strcmp(dl->arr_last.dev_name, dev_name) == 0; - } - --static void pr_out_handle(struct nlattr **tb) -+static void arr_last_handle_set(struct dl *dl, const char *bus_name, -+ const char *dev_name) - { -- __pr_out_handle(mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]), -- mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME])); -+ dl->arr_last.present = true; -+ free(dl->arr_last.dev_name); -+ free(dl->arr_last.bus_name); -+ dl->arr_last.bus_name = strdup(bus_name); -+ dl->arr_last.dev_name = strdup(dev_name); - } - --static void __pr_out_port_handle(const char *bus_name, const char *dev_name, -- uint32_t port_index) -+static bool should_arr_last_handle_start(struct dl *dl, const char *bus_name, -+ const char *dev_name) - { -- __pr_out_handle(bus_name, dev_name); -- pr_out("/%d", port_index); -+ return !cmp_arr_last_handle(dl, bus_name, dev_name); - } - --static void pr_out_port_handle(struct nlattr **tb) -+static bool should_arr_last_handle_end(struct dl *dl, const char *bus_name, -+ const char *dev_name) - { -- __pr_out_port_handle(mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]), -- mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]), -- mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX])); -+ return dl->arr_last.present && -+ !cmp_arr_last_handle(dl, bus_name, dev_name); - } - --static void __pr_out_port_handle_nice(struct dl *dl, const char *bus_name, -- const char *dev_name, uint32_t port_index) -+static void __pr_out_handle_start(struct dl *dl, struct nlattr **tb, -+ bool content, bool array) - { -- char *ifname; -- int err; -+ const char *bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); -+ const char *dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); -+ char buf[32]; - -- if (dl->no_nice_names) -- goto no_nice_names; -+ sprintf(buf, "%s/%s", bus_name, dev_name); - -- err = ifname_map_rev_lookup(dl, bus_name, dev_name, -- port_index, &ifname); -- if (err) -- goto no_nice_names; -- pr_out("%s", ifname); -- return; -+ if (dl->json_output) { -+ if (array) { -+ if (should_arr_last_handle_end(dl, bus_name, dev_name)) -+ jsonw_end_array(dl->jw); -+ if (should_arr_last_handle_start(dl, bus_name, -+ dev_name)) { -+ jsonw_name(dl->jw, buf); -+ jsonw_start_array(dl->jw); -+ jsonw_start_object(dl->jw); -+ arr_last_handle_set(dl, bus_name, dev_name); -+ } else { -+ jsonw_start_object(dl->jw); -+ } -+ } else { -+ jsonw_name(dl->jw, buf); -+ jsonw_start_object(dl->jw); -+ } -+ } else { -+ pr_out("%s%s", buf, content ? ":" : ""); -+ } -+} - --no_nice_names: -- __pr_out_port_handle(bus_name, dev_name, port_index); -+static void pr_out_handle_start_arr(struct dl *dl, struct nlattr **tb) -+{ -+ __pr_out_handle_start(dl, tb, true, true); - } - --static void pr_out_port_handle_nice(struct dl *dl, struct nlattr **tb) -+static void pr_out_handle_end(struct dl *dl) -+{ -+ if (dl->json_output) -+ jsonw_end_object(dl->jw); -+ else -+ pr_out("\n"); -+} -+ -+static void pr_out_handle(struct dl *dl, struct nlattr **tb) -+{ -+ __pr_out_handle_start(dl, tb, false, false); -+ pr_out_handle_end(dl); -+} -+ -+static bool cmp_arr_last_port_handle(struct dl *dl, const char *bus_name, -+ const char *dev_name, uint32_t port_index) -+{ -+ return cmp_arr_last_handle(dl, bus_name, dev_name) && -+ dl->arr_last.port_index == port_index; -+} -+ -+static void arr_last_port_handle_set(struct dl *dl, const char *bus_name, -+ const char *dev_name, uint32_t port_index) -+{ -+ arr_last_handle_set(dl, bus_name, dev_name); -+ dl->arr_last.port_index = port_index; -+} -+ -+static bool should_arr_last_port_handle_start(struct dl *dl, -+ const char *bus_name, -+ const char *dev_name, -+ uint32_t port_index) -+{ -+ return !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index); -+} -+ -+static bool should_arr_last_port_handle_end(struct dl *dl, -+ const char *bus_name, -+ const char *dev_name, -+ uint32_t port_index) -+{ -+ return dl->arr_last.present && -+ !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index); -+} -+ -+static void __pr_out_port_handle_start(struct dl *dl, const char *bus_name, -+ const char *dev_name, -+ uint32_t port_index, bool try_nice, -+ bool array) -+{ -+ static char buf[32]; -+ char *ifname = NULL; -+ -+ if (dl->no_nice_names || !try_nice || -+ ifname_map_rev_lookup(dl, bus_name, dev_name, -+ port_index, &ifname) != 0) -+ sprintf(buf, "%s/%s/%d", bus_name, dev_name, port_index); -+ else -+ sprintf(buf, "%s", ifname); -+ -+ if (dl->json_output) { -+ if (array) { -+ if (should_arr_last_port_handle_end(dl, bus_name, -+ dev_name, -+ port_index)) -+ jsonw_end_array(dl->jw); -+ if (should_arr_last_port_handle_start(dl, bus_name, -+ dev_name, -+ port_index)) { -+ jsonw_name(dl->jw, buf); -+ jsonw_start_array(dl->jw); -+ jsonw_start_object(dl->jw); -+ arr_last_port_handle_set(dl, bus_name, dev_name, -+ port_index); -+ } else { -+ jsonw_start_object(dl->jw); -+ } -+ } else { -+ jsonw_name(dl->jw, buf); -+ jsonw_start_object(dl->jw); -+ } -+ } else { -+ pr_out("%s:", buf); -+ } -+} -+ -+static void pr_out_port_handle_start(struct dl *dl, struct nlattr **tb, bool try_nice) - { - const char *bus_name; - const char *dev_name; -@@ -966,25 +1085,80 @@ static void pr_out_port_handle_nice(struct dl *dl, struct nlattr **tb) - bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); - dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); - port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); -+ __pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, false); -+} -+ -+static void pr_out_port_handle_start_arr(struct dl *dl, struct nlattr **tb, bool try_nice) -+{ -+ const char *bus_name; -+ const char *dev_name; -+ uint32_t port_index; - -- __pr_out_port_handle_nice(dl, bus_name, dev_name, port_index); -+ bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); -+ dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); -+ port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); -+ __pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, true); - } - --static void pr_out_dev(struct nlattr **tb) -+static void pr_out_port_handle_end(struct dl *dl) - { -- pr_out_handle(tb); -- pr_out("\n"); -+ if (dl->json_output) -+ jsonw_end_object(dl->jw); -+ else -+ pr_out("\n"); -+} -+ -+ -+static void pr_out_str(struct dl *dl, const char *name, const char *val) -+{ -+ if (dl->json_output) -+ jsonw_string_field(dl->jw, name, val); -+ else -+ pr_out(" %s %s", name, val); -+} -+ -+static void pr_out_uint(struct dl *dl, const char *name, unsigned int val) -+{ -+ if (dl->json_output) -+ jsonw_uint_field(dl->jw, name, val); -+ else -+ pr_out(" %s %u", name, val); -+} -+ -+static void pr_out_dev(struct dl *dl, struct nlattr **tb) -+{ -+ pr_out_handle(dl, tb); -+} -+ -+static void pr_out_section_start(struct dl *dl, const char *name) -+{ -+ if (dl->json_output) { -+ jsonw_start_object(dl->jw); -+ jsonw_name(dl->jw, name); -+ jsonw_start_object(dl->jw); -+ } -+} -+ -+static void pr_out_section_end(struct dl *dl) -+{ -+ if (dl->json_output) { -+ if (dl->arr_last.present) -+ jsonw_end_array(dl->jw); -+ jsonw_end_object(dl->jw); -+ jsonw_end_object(dl->jw); -+ } - } - - static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data) - { -+ struct dl *dl = data; - struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - - mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); - if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME]) - return MNL_CB_ERROR; -- pr_out_dev(tb); -+ pr_out_dev(dl, tb); - return MNL_CB_OK; - } - -@@ -1005,7 +1179,10 @@ static int cmd_dev_show(struct dl *dl) - return err; - } - -- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, NULL); -+ pr_out_section_start(dl, "dev"); -+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, dl); -+ pr_out_section_end(dl); -+ return err; - } - - static int cmd_dev(struct dl *dl) -@@ -1041,38 +1218,39 @@ static const char *port_type_name(uint32_t type) - } - } - --static void pr_out_port(struct nlattr **tb) -+static void pr_out_port(struct dl *dl, struct nlattr **tb) - { - struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE]; - struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE]; - -- pr_out_port_handle(tb); -- pr_out(":"); -+ pr_out_port_handle_start(dl, tb, false); - if (pt_attr) { - uint16_t port_type = mnl_attr_get_u16(pt_attr); - -- pr_out(" type %s", port_type_name(port_type)); -+ pr_out_str(dl, "type", port_type_name(port_type)); - if (dpt_attr) { - uint16_t des_port_type = mnl_attr_get_u16(dpt_attr); - - if (port_type != des_port_type) -- pr_out("(%s)", port_type_name(des_port_type)); -+ pr_out_str(dl, "des_type", -+ port_type_name(des_port_type)); - } - } - if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME]) -- pr_out(" netdev %s", -- mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME])); -+ pr_out_str(dl, "netdev", -+ mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME])); - if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME]) -- pr_out(" ibdev %s", -- mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME])); -+ pr_out_str(dl, "ibdev", -+ mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME])); - if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]) -- pr_out(" split_group %u", -- mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])); -- pr_out("\n"); -+ pr_out_uint(dl, "split_group", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])); -+ pr_out_port_handle_end(dl); - } - - static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data) - { -+ struct dl *dl = data; - struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - -@@ -1080,7 +1258,7 @@ static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data) - if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || - !tb[DEVLINK_ATTR_PORT_INDEX]) - return MNL_CB_ERROR; -- pr_out_port(tb); -+ pr_out_port(dl, tb); - return MNL_CB_OK; - } - -@@ -1101,7 +1279,10 @@ static int cmd_port_show(struct dl *dl) - return err; - } - -- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, NULL); -+ pr_out_section_start(dl, "port"); -+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, dl); -+ pr_out_section_end(dl); -+ return err; - } - - static int cmd_port_set(struct dl *dl) -@@ -1192,20 +1373,27 @@ static void cmd_sb_help(void) - pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); - } - --static void pr_out_sb(struct nlattr **tb) -+static void pr_out_sb(struct dl *dl, struct nlattr **tb) - { -- pr_out_handle(tb); -- pr_out(": sb %u size %u ing_pools %u eg_pools %u ing_tcs %u eg_tcs %u\n", -- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), -- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]), -- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]), -- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]), -- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]), -- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])); -+ pr_out_handle_start_arr(dl, tb); -+ pr_out_uint(dl, "sb", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX])); -+ pr_out_uint(dl, "size", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE])); -+ pr_out_uint(dl, "ing_pools", -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT])); -+ pr_out_uint(dl, "eg_pools", -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT])); -+ pr_out_uint(dl, "ing_tcs", -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT])); -+ pr_out_uint(dl, "eg_tcs", -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])); -+ pr_out_handle_end(dl); - } - - static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data) - { -+ struct dl *dl = data; - struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - -@@ -1217,7 +1405,7 @@ static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data) - !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] || - !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]) - return MNL_CB_ERROR; -- pr_out_sb(tb); -+ pr_out_sb(dl, tb); - return MNL_CB_OK; - } - -@@ -1238,7 +1426,10 @@ static int cmd_sb_show(struct dl *dl) - return err; - } - -- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, NULL); -+ pr_out_section_start(dl, "sb"); -+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, dl); -+ pr_out_section_end(dl); -+ return err; - } - - static const char *pool_type_name(uint8_t type) -@@ -1259,19 +1450,25 @@ static const char *threshold_type_name(uint8_t type) - } - } - --static void pr_out_sb_pool(struct nlattr **tb) -+static void pr_out_sb_pool(struct dl *dl, struct nlattr **tb) - { -- pr_out_handle(tb); -- pr_out(": sb %u pool %u type %s size %u thtype %s\n", -- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), -- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), -- pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), -- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]), -- threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]))); -+ pr_out_handle_start_arr(dl, tb); -+ pr_out_uint(dl, "sb", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX])); -+ pr_out_uint(dl, "pool", -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX])); -+ pr_out_str(dl, "type", -+ pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]))); -+ pr_out_uint(dl, "size", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE])); -+ pr_out_str(dl, "thtype", -+ threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]))); -+ pr_out_handle_end(dl); - } - - static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data) - { -+ struct dl *dl = data; - struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - -@@ -1281,7 +1478,7 @@ static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data) - !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] || - !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]) - return MNL_CB_ERROR; -- pr_out_sb_pool(tb); -+ pr_out_sb_pool(dl, tb); - return MNL_CB_OK; - } - -@@ -1303,7 +1500,10 @@ static int cmd_sb_pool_show(struct dl *dl) - return err; - } - -- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, NULL); -+ pr_out_section_start(dl, "pool"); -+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, dl); -+ pr_out_section_end(dl); -+ return err; - } - - static int cmd_sb_pool_set(struct dl *dl) -@@ -1341,11 +1541,14 @@ static int cmd_sb_pool(struct dl *dl) - - static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb) - { -- pr_out_port_handle_nice(dl, tb); -- pr_out(": sb %u pool %u threshold %u\n", -- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), -- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), -- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); -+ pr_out_port_handle_start_arr(dl, tb, true); -+ pr_out_uint(dl, "sb", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX])); -+ pr_out_uint(dl, "pool", -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX])); -+ pr_out_uint(dl, "threshold", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); -+ pr_out_port_handle_end(dl); - } - - static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data) -@@ -1382,7 +1585,10 @@ static int cmd_sb_port_pool_show(struct dl *dl) - return err; - } - -- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl); -+ pr_out_section_start(dl, "port_pool"); -+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl); -+ pr_out_section_end(dl); -+ return 0; - } - - static int cmd_sb_port_pool_set(struct dl *dl) -@@ -1433,13 +1639,18 @@ static int cmd_sb_port(struct dl *dl) - - static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb) - { -- pr_out_port_handle_nice(dl, tb); -- pr_out(": sb %u tc %u type %s pool %u threshold %u\n", -- mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), -- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]), -- pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), -- mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), -+ pr_out_port_handle_start_arr(dl, tb, true); -+ pr_out_uint(dl, "sb", -+ mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX])); -+ pr_out_uint(dl, "tc", -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX])); -+ pr_out_str(dl, "type", -+ pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]))); -+ pr_out_uint(dl, "pool", -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX])); -+ pr_out_uint(dl, "threshold", - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); -+ pr_out_port_handle_end(dl); - } - - static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data) -@@ -1476,7 +1687,10 @@ static int cmd_sb_tc_bind_show(struct dl *dl) - return err; - } - -- return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl); -+ pr_out_section_start(dl, "tc_bind"); -+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl); -+ pr_out_section_end(dl); -+ return err; - } - - static int cmd_sb_tc_bind_set(struct dl *dl) -@@ -1649,11 +1863,44 @@ static void pr_out_occ_show_item_list(const char *label, struct list_head *list, - pr_out("\n"); - } - --static void pr_out_occ_show_port(struct occ_port *occ_port) -+static void pr_out_json_occ_show_item_list(struct dl *dl, const char *label, -+ struct list_head *list, -+ bool bound_pool) -+{ -+ struct occ_item *occ_item; -+ char buf[32]; -+ -+ jsonw_name(dl->jw, label); -+ jsonw_start_object(dl->jw); -+ list_for_each_entry(occ_item, list, list) { -+ sprintf(buf, "%u", occ_item->index); -+ jsonw_name(dl->jw, buf); -+ jsonw_start_object(dl->jw); -+ if (bound_pool) -+ jsonw_uint_field(dl->jw, "bound_pool", -+ occ_item->bound_pool_index); -+ jsonw_uint_field(dl->jw, "current", occ_item->cur); -+ jsonw_uint_field(dl->jw, "max", occ_item->max); -+ jsonw_end_object(dl->jw); -+ } -+ jsonw_end_object(dl->jw); -+} -+ -+static void pr_out_occ_show_port(struct dl *dl, struct occ_port *occ_port) - { -- pr_out_occ_show_item_list("pool", &occ_port->pool_list, false); -- pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true); -- pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true); -+ if (dl->json_output) { -+ pr_out_json_occ_show_item_list(dl, "pool", -+ &occ_port->pool_list, false); -+ pr_out_json_occ_show_item_list(dl, "itc", -+ &occ_port->ing_tc_list, true); -+ pr_out_json_occ_show_item_list(dl, "etc", -+ &occ_port->eg_tc_list, true); -+ } else { -+ pr_out("\n"); -+ pr_out_occ_show_item_list("pool", &occ_port->pool_list, false); -+ pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true); -+ pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true); -+ } - } - - static void pr_out_occ_show(struct occ_show *occ_show) -@@ -1663,10 +1910,10 @@ static void pr_out_occ_show(struct occ_show *occ_show) - struct occ_port *occ_port; - - list_for_each_entry(occ_port, &occ_show->port_list, list) { -- __pr_out_port_handle_nice(dl, opts->bus_name, opts->dev_name, -- occ_port->port_index); -- pr_out(":\n"); -- pr_out_occ_show_port(occ_port); -+ __pr_out_port_handle_start(dl, opts->bus_name, opts->dev_name, -+ occ_port->port_index, true, false); -+ pr_out_occ_show_port(dl, occ_port); -+ pr_out_port_handle_end(dl); - } - } - -@@ -1793,7 +2040,9 @@ static int cmd_sb_occ_show(struct dl *dl) - if (err) - goto out; - -+ pr_out_section_start(dl, "occupancy"); - pr_out_occ_show(occ_show); -+ pr_out_section_end(dl); - - out: - occ_show_free(occ_show); -@@ -1949,7 +2198,7 @@ static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data) - if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME]) - return MNL_CB_ERROR; - pr_out_mon_header(genl->cmd); -- pr_out_dev(tb); -+ pr_out_dev(dl, tb); - break; - case DEVLINK_CMD_PORT_GET: /* fall through */ - case DEVLINK_CMD_PORT_SET: /* fall through */ -@@ -1960,7 +2209,7 @@ static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data) - !tb[DEVLINK_ATTR_PORT_INDEX]) - return MNL_CB_ERROR; - pr_out_mon_header(genl->cmd); -- pr_out_port(tb); -+ pr_out_port(dl, tb); - break; - } - return MNL_CB_OK; -@@ -2055,8 +2304,18 @@ static int dl_init(struct dl *dl, int argc, char **argv) - pr_err("Failed to create index map\n"); - goto err_ifname_map_create; - } -+ if (dl->json_output) { -+ dl->jw = jsonw_new(stdout); -+ if (!dl->jw) { -+ pr_err("Failed to create JSON writer\n"); -+ goto err_json_new; -+ } -+ jsonw_pretty(dl->jw, dl->pretty_output); -+ } - return 0; - -+err_json_new: -+ ifname_map_fini(dl); - err_ifname_map_create: - mnlg_socket_close(dl->nlg); - return err; -@@ -2064,6 +2323,8 @@ err_ifname_map_create: - - static void dl_fini(struct dl *dl) - { -+ if (dl->json_output) -+ jsonw_destroy(&dl->jw); - ifname_map_fini(dl); - mnlg_socket_close(dl->nlg); - } -@@ -2088,6 +2349,8 @@ int main(int argc, char **argv) - static const struct option long_options[] = { - { "Version", no_argument, NULL, 'V' }, - { "no-nice-names", no_argument, NULL, 'n' }, -+ { "json", no_argument, NULL, 'j' }, -+ { "pretty", no_argument, NULL, 'p' }, - { NULL, 0, NULL, 0 } - }; - struct dl *dl; -@@ -2101,7 +2364,7 @@ int main(int argc, char **argv) - return EXIT_FAILURE; - } - -- while ((opt = getopt_long(argc, argv, "Vn", -+ while ((opt = getopt_long(argc, argv, "Vnjp", - long_options, NULL)) >= 0) { - - switch (opt) { -@@ -2111,6 +2374,12 @@ int main(int argc, char **argv) - case 'n': - dl->no_nice_names = true; - break; -+ case 'j': -+ dl->json_output = true; -+ break; -+ case 'p': -+ dl->pretty_output = true; -+ break; - default: - pr_err("Unknown option.\n"); - help(); --- -2.9.3 - diff --git a/0002-devlink-implement-shared-buffer-occupancy-control.patch b/0002-devlink-implement-shared-buffer-occupancy-control.patch deleted file mode 100644 index 1194bdf..0000000 --- a/0002-devlink-implement-shared-buffer-occupancy-control.patch +++ /dev/null @@ -1,441 +0,0 @@ -From 25ec49be2cdfa571d5151f19a7395a7e462d2f49 Mon Sep 17 00:00:00 2001 -From: Jiri Pirko -Date: Sat, 14 May 2016 15:21:02 +0200 -Subject: [PATCH 2/2] devlink: implement shared buffer occupancy control - -Use kernel shared buffer occupancy control commands to make snapshot and -clear occupancy watermarks. Also, allow to show occupancy values in a -nice way. - -Signed-off-by: Jiri Pirko ---- - devlink/devlink.c | 378 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 378 insertions(+) - -diff --git a/devlink/devlink.c b/devlink/devlink.c -index ca3f586..ffefa86 100644 ---- a/devlink/devlink.c -+++ b/devlink/devlink.c -@@ -27,6 +27,12 @@ - - #define pr_err(args...) fprintf(stderr, ##args) - #define pr_out(args...) fprintf(stdout, ##args) -+#define pr_out_sp(num, args...) \ -+ do { \ -+ int ret = fprintf(stdout, ##args); \ -+ if (ret < num) \ -+ fprintf(stdout, "%*s", num - ret, ""); \ -+ } while (0) - - static int _mnlg_socket_recv_run(struct mnlg_socket *nlg, - mnl_cb_t data_cb, void *data) -@@ -275,6 +281,12 @@ static int attr_cb(const struct nlattr *attr, void *data) - if (type == DEVLINK_ATTR_SB_TC_INDEX && - mnl_attr_validate(attr, MNL_TYPE_U16) < 0) - return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_OCC_CUR && -+ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) -+ return MNL_CB_ERROR; -+ if (type == DEVLINK_ATTR_SB_OCC_MAX && -+ mnl_attr_validate(attr, MNL_TYPE_U32) < 0) -+ return MNL_CB_ERROR; - tb[type] = attr; - return MNL_CB_OK; - } -@@ -858,6 +870,42 @@ static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, - return 0; - } - -+static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) -+{ -+ struct dl_opts *opts = &dl->opts; -+ struct nlattr *attr_bus_name = tb[DEVLINK_ATTR_BUS_NAME]; -+ struct nlattr *attr_dev_name = tb[DEVLINK_ATTR_DEV_NAME]; -+ struct nlattr *attr_port_index = tb[DEVLINK_ATTR_PORT_INDEX]; -+ struct nlattr *attr_sb_index = tb[DEVLINK_ATTR_SB_INDEX]; -+ -+ if (opts->present & DL_OPT_HANDLE && -+ attr_bus_name && attr_dev_name) { -+ const char *bus_name = mnl_attr_get_str(attr_bus_name); -+ const char *dev_name = mnl_attr_get_str(attr_dev_name); -+ -+ if (strcmp(bus_name, opts->bus_name) != 0 || -+ strcmp(dev_name, opts->dev_name) != 0) -+ return false; -+ } -+ if (opts->present & DL_OPT_HANDLEP && -+ attr_bus_name && attr_dev_name && attr_port_index) { -+ const char *bus_name = mnl_attr_get_str(attr_bus_name); -+ const char *dev_name = mnl_attr_get_str(attr_dev_name); -+ uint32_t port_index = mnl_attr_get_u32(attr_port_index); -+ -+ if (strcmp(bus_name, opts->bus_name) != 0 || -+ strcmp(dev_name, opts->dev_name) != 0 || -+ port_index != opts->port_index) -+ return false; -+ } -+ if (opts->present & DL_OPT_SB && attr_sb_index) { -+ uint32_t sb_index = mnl_attr_get_u32(attr_sb_index); -+ -+ if (sb_index != opts->sb_index) -+ return false; -+ } -+ return true; -+} - - static void cmd_dev_help(void) - { -@@ -1139,6 +1187,9 @@ static void cmd_sb_help(void) - pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); - pr_out(" type { ingress | egress } pool POOL_INDEX\n"); - pr_out(" th THRESHOLD\n"); -+ pr_out(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n"); -+ pr_out(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n"); -+ pr_out(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); - } - - static void pr_out_sb(struct nlattr **tb) -@@ -1475,6 +1526,330 @@ static int cmd_sb_tc(struct dl *dl) - return -ENOENT; - } - -+struct occ_item { -+ struct list_head list; -+ uint32_t index; -+ uint32_t cur; -+ uint32_t max; -+ uint32_t bound_pool_index; -+}; -+ -+struct occ_port { -+ struct list_head list; -+ char *bus_name; -+ char *dev_name; -+ uint32_t port_index; -+ uint32_t sb_index; -+ struct list_head pool_list; -+ struct list_head ing_tc_list; -+ struct list_head eg_tc_list; -+}; -+ -+struct occ_show { -+ struct dl *dl; -+ int err; -+ struct list_head port_list; -+}; -+ -+static struct occ_item *occ_item_alloc(void) -+{ -+ return calloc(1, sizeof(struct occ_item)); -+} -+ -+static void occ_item_free(struct occ_item *occ_item) -+{ -+ free(occ_item); -+} -+ -+static struct occ_port *occ_port_alloc(uint32_t port_index) -+{ -+ struct occ_port *occ_port; -+ -+ occ_port = calloc(1, sizeof(*occ_port)); -+ if (!occ_port) -+ return NULL; -+ occ_port->port_index = port_index; -+ INIT_LIST_HEAD(&occ_port->pool_list); -+ INIT_LIST_HEAD(&occ_port->ing_tc_list); -+ INIT_LIST_HEAD(&occ_port->eg_tc_list); -+ return occ_port; -+} -+ -+static void occ_port_free(struct occ_port *occ_port) -+{ -+ struct occ_item *occ_item, *tmp; -+ -+ list_for_each_entry_safe(occ_item, tmp, &occ_port->pool_list, list) -+ occ_item_free(occ_item); -+ list_for_each_entry_safe(occ_item, tmp, &occ_port->ing_tc_list, list) -+ occ_item_free(occ_item); -+ list_for_each_entry_safe(occ_item, tmp, &occ_port->eg_tc_list, list) -+ occ_item_free(occ_item); -+} -+ -+static struct occ_show *occ_show_alloc(struct dl *dl) -+{ -+ struct occ_show *occ_show; -+ -+ occ_show = calloc(1, sizeof(*occ_show)); -+ if (!occ_show) -+ return NULL; -+ occ_show->dl = dl; -+ INIT_LIST_HEAD(&occ_show->port_list); -+ return occ_show; -+} -+ -+static void occ_show_free(struct occ_show *occ_show) -+{ -+ struct occ_port *occ_port, *tmp; -+ -+ list_for_each_entry_safe(occ_port, tmp, &occ_show->port_list, list) -+ occ_port_free(occ_port); -+} -+ -+static struct occ_port *occ_port_get(struct occ_show *occ_show, -+ struct nlattr **tb) -+{ -+ struct occ_port *occ_port; -+ uint32_t port_index; -+ -+ port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); -+ -+ list_for_each_entry_reverse(occ_port, &occ_show->port_list, list) { -+ if (occ_port->port_index == port_index) -+ return occ_port; -+ } -+ occ_port = occ_port_alloc(port_index); -+ if (!occ_port) -+ return NULL; -+ list_add_tail(&occ_port->list, &occ_show->port_list); -+ return occ_port; -+} -+ -+static void pr_out_occ_show_item_list(const char *label, struct list_head *list, -+ bool bound_pool) -+{ -+ struct occ_item *occ_item; -+ int i = 1; -+ -+ pr_out_sp(7, " %s:", label); -+ list_for_each_entry(occ_item, list, list) { -+ if ((i - 1) % 4 == 0 && i != 1) -+ pr_out_sp(7, " "); -+ if (bound_pool) -+ pr_out_sp(7, "%2u(%u):", occ_item->index, -+ occ_item->bound_pool_index); -+ else -+ pr_out_sp(7, "%2u:", occ_item->index); -+ pr_out_sp(15, "%7u/%u", occ_item->cur, occ_item->max); -+ if (i++ % 4 == 0) -+ pr_out("\n"); -+ } -+ if ((i - 1) % 4 != 0) -+ pr_out("\n"); -+} -+ -+static void pr_out_occ_show_port(struct occ_port *occ_port) -+{ -+ pr_out_occ_show_item_list("pool", &occ_port->pool_list, false); -+ pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true); -+ pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true); -+} -+ -+static void pr_out_occ_show(struct occ_show *occ_show) -+{ -+ struct dl *dl = occ_show->dl; -+ struct dl_opts *opts = &dl->opts; -+ struct occ_port *occ_port; -+ -+ list_for_each_entry(occ_port, &occ_show->port_list, list) { -+ __pr_out_port_handle_nice(dl, opts->bus_name, opts->dev_name, -+ occ_port->port_index); -+ pr_out(":\n"); -+ pr_out_occ_show_port(occ_port); -+ } -+} -+ -+static void cmd_sb_occ_port_pool_process(struct occ_show *occ_show, -+ struct nlattr **tb) -+{ -+ struct occ_port *occ_port; -+ struct occ_item *occ_item; -+ -+ if (occ_show->err || !dl_dump_filter(occ_show->dl, tb)) -+ return; -+ -+ occ_port = occ_port_get(occ_show, tb); -+ if (!occ_port) { -+ occ_show->err = -ENOMEM; -+ return; -+ } -+ -+ occ_item = occ_item_alloc(); -+ if (!occ_item) { -+ occ_show->err = -ENOMEM; -+ return; -+ } -+ occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]); -+ occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]); -+ occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]); -+ list_add_tail(&occ_item->list, &occ_port->pool_list); -+} -+ -+static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr *nlh, void *data) -+{ -+ struct occ_show *occ_show = data; -+ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; -+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); -+ -+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); -+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || -+ !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || -+ !tb[DEVLINK_ATTR_SB_POOL_INDEX] || -+ !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX]) -+ return MNL_CB_ERROR; -+ cmd_sb_occ_port_pool_process(occ_show, tb); -+ return MNL_CB_OK; -+} -+ -+static void cmd_sb_occ_tc_pool_process(struct occ_show *occ_show, -+ struct nlattr **tb) -+{ -+ struct occ_port *occ_port; -+ struct occ_item *occ_item; -+ uint8_t pool_type; -+ -+ if (occ_show->err || !dl_dump_filter(occ_show->dl, tb)) -+ return; -+ -+ occ_port = occ_port_get(occ_show, tb); -+ if (!occ_port) { -+ occ_show->err = -ENOMEM; -+ return; -+ } -+ -+ occ_item = occ_item_alloc(); -+ if (!occ_item) { -+ occ_show->err = -ENOMEM; -+ return; -+ } -+ occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]); -+ occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]); -+ occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]); -+ occ_item->bound_pool_index = -+ mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]); -+ pool_type = mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]); -+ if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS) -+ list_add_tail(&occ_item->list, &occ_port->ing_tc_list); -+ else if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS) -+ list_add_tail(&occ_item->list, &occ_port->eg_tc_list); -+ else -+ occ_item_free(occ_item); -+} -+ -+static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr *nlh, void *data) -+{ -+ struct occ_show *occ_show = data; -+ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; -+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); -+ -+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); -+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || -+ !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || -+ !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] || -+ !tb[DEVLINK_ATTR_SB_POOL_INDEX] || -+ !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX]) -+ return MNL_CB_ERROR; -+ cmd_sb_occ_tc_pool_process(occ_show, tb); -+ return MNL_CB_OK; -+} -+ -+static int cmd_sb_occ_show(struct dl *dl) -+{ -+ struct nlmsghdr *nlh; -+ struct occ_show *occ_show; -+ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP; -+ int err; -+ -+ err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP, DL_OPT_SB); -+ if (err) -+ return err; -+ -+ occ_show = occ_show_alloc(dl); -+ if (!occ_show) -+ return -ENOMEM; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); -+ -+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, -+ cmd_sb_occ_port_pool_process_cb, occ_show); -+ if (err) -+ goto out; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); -+ -+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, -+ cmd_sb_occ_tc_pool_process_cb, occ_show); -+ if (err) -+ goto out; -+ -+ pr_out_occ_show(occ_show); -+ -+out: -+ occ_show_free(occ_show); -+ return err; -+} -+ -+static int cmd_sb_occ_snapshot(struct dl *dl) -+{ -+ struct nlmsghdr *nlh; -+ int err; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_SNAPSHOT, -+ NLM_F_REQUEST | NLM_F_ACK); -+ -+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); -+ if (err) -+ return err; -+ -+ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); -+} -+ -+static int cmd_sb_occ_clearmax(struct dl *dl) -+{ -+ struct nlmsghdr *nlh; -+ int err; -+ -+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_MAX_CLEAR, -+ NLM_F_REQUEST | NLM_F_ACK); -+ -+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); -+ if (err) -+ return err; -+ -+ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); -+} -+ -+static int cmd_sb_occ(struct dl *dl) -+{ -+ if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { -+ cmd_sb_help(); -+ return 0; -+ } else if (dl_argv_match(dl, "show") || -+ dl_argv_match(dl, "list")) { -+ dl_arg_inc(dl); -+ return cmd_sb_occ_show(dl); -+ } else if (dl_argv_match(dl, "snapshot")) { -+ dl_arg_inc(dl); -+ return cmd_sb_occ_snapshot(dl); -+ } else if (dl_argv_match(dl, "clearmax")) { -+ dl_arg_inc(dl); -+ return cmd_sb_occ_clearmax(dl); -+ } -+ pr_err("Command \"%s\" not found\n", dl_argv(dl)); -+ return -ENOENT; -+} -+ - static int cmd_sb(struct dl *dl) - { - if (dl_argv_match(dl, "help")) { -@@ -1493,6 +1868,9 @@ static int cmd_sb(struct dl *dl) - } else if (dl_argv_match(dl, "tc")) { - dl_arg_inc(dl); - return cmd_sb_tc(dl); -+ } else if (dl_argv_match(dl, "occupancy")) { -+ dl_arg_inc(dl); -+ return cmd_sb_occ(dl); - } - pr_err("Command \"%s\" not found\n", dl_argv(dl)); - return -ENOENT; --- -2.9.3 - diff --git a/0002-man-Point-to-devlink-sb-from-devlink-man-page.patch b/0002-man-Point-to-devlink-sb-from-devlink-man-page.patch deleted file mode 100644 index ea1b1df..0000000 --- a/0002-man-Point-to-devlink-sb-from-devlink-man-page.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 78c610e6ea8554e87e2204f540cf0ce61ef52695 Mon Sep 17 00:00:00 2001 -From: Ido Schimmel -Date: Wed, 13 Jul 2016 09:53:54 +0300 -Subject: [PATCH 2/2] man: Point to 'devlink-sb' from 'devlink' man page - -Signed-off-by: Jiri Pirko -Signed-off-by: Ido Schimmel ---- - man/man8/devlink.8 | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/man/man8/devlink.8 b/man/man8/devlink.8 -index df00f4f..cf0563b 100644 ---- a/man/man8/devlink.8 -+++ b/man/man8/devlink.8 -@@ -76,6 +76,7 @@ Exit status is 0 if command was successful or a positive integer upon failure. - .BR devlink-dev (8), - .BR devlink-port (8), - .BR devlink-monitor (8), -+.BR devlink-sb (8), - .br - - .SH REPORTING BUGS --- -2.9.3 - diff --git a/0002-tc-flower-use-correct-type-when-calling-flower_icmp_.patch b/0002-tc-flower-use-correct-type-when-calling-flower_icmp_.patch new file mode 100644 index 0000000..6771a07 --- /dev/null +++ b/0002-tc-flower-use-correct-type-when-calling-flower_icmp_.patch @@ -0,0 +1,38 @@ +From ceb67c148b50eadd078e280b2cb6be77fdda80fc Mon Sep 17 00:00:00 2001 +From: Simon Horman +Date: Wed, 8 Feb 2017 13:04:31 +0100 +Subject: [PATCH] tc: flower: use correct type when calling + flower_icmp_attr_type + +Use enum flower_icmp_field rather than bool as type of third parameter +when calling flower_icmp_attr_type. + +Fixes: eb3b5696f163 ("tc: flower: support matching on ICMP type and code") +Signed-off-by: Simon Horman +(cherry picked from commit 81f6e5a7279eaab826ba8b291b98fb2e89df0572) +--- + tc/f_flower.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/tc/f_flower.c b/tc/f_flower.c +index 145a8566..75a3fbbc 100644 +--- a/tc/f_flower.c ++++ b/tc/f_flower.c +@@ -752,10 +752,12 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, + if (nl_type >= 0) + flower_print_port(f, "src_port", tb[nl_type]); + +- nl_type = flower_icmp_attr_type(eth_type, ip_proto, false); ++ nl_type = flower_icmp_attr_type(eth_type, ip_proto, ++ FLOWER_ICMP_FIELD_TYPE); + if (nl_type >= 0) + flower_print_icmp(f, "icmp_type", tb[nl_type]); +- nl_type = flower_icmp_attr_type(eth_type, ip_proto, true); ++ nl_type = flower_icmp_attr_type(eth_type, ip_proto, ++ FLOWER_ICMP_FIELD_CODE); + if (nl_type >= 0) + flower_print_icmp(f, "icmp_code", tb[nl_type]); + +-- +2.11.0 + diff --git a/0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch b/0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch deleted file mode 100644 index 1909c22..0000000 --- a/0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch +++ /dev/null @@ -1,132 +0,0 @@ -From 0501294bca39a19090dae302dc491684470b1a0d Mon Sep 17 00:00:00 2001 -From: Yotam Gigi -Date: Wed, 31 Aug 2016 09:28:27 +0200 -Subject: [PATCH 2/2] tc: man: Add man entry for the matchall classifier. - -In addition to providing information about the mathcall filter and its -configurations, the man entry contains examples for creating port -mirorring entries. - -Signed-off-by: Yotam Gigi -Signed-off-by: Jiri Pirko ---- - man/man8/Makefile | 2 +- - man/man8/tc-matchall.8 | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ - man/man8/tc.8 | 5 ++++ - 3 files changed, 82 insertions(+), 1 deletion(-) - create mode 100644 man/man8/tc-matchall.8 - -diff --git a/man/man8/Makefile b/man/man8/Makefile -index 9badbed..9213769 100644 ---- a/man/man8/Makefile -+++ b/man/man8/Makefile -@@ -14,7 +14,7 @@ MAN8PAGES = $(TARGETS) ip.8 arpd.8 lnstat.8 routel.8 rtacct.8 rtmon.8 rtpr.8 ss. - tipc.8 tipc-bearer.8 tipc-link.8 tipc-media.8 tipc-nametable.8 \ - tipc-node.8 tipc-socket.8 \ - tc-basic.8 tc-cgroup.8 tc-flow.8 tc-flower.8 tc-fw.8 tc-route.8 \ -- tc-tcindex.8 tc-u32.8 \ -+ tc-tcindex.8 tc-u32.8 tc-matchall.8 \ - tc-connmark.8 tc-csum.8 tc-mirred.8 tc-nat.8 tc-pedit.8 tc-police.8 \ - tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 \ - devlink.8 devlink-dev.8 devlink-monitor.8 devlink-port.8 devlink-sb.8 -diff --git a/man/man8/tc-matchall.8 b/man/man8/tc-matchall.8 -new file mode 100644 -index 0000000..f920922 ---- /dev/null -+++ b/man/man8/tc-matchall.8 -@@ -0,0 +1,76 @@ -+.TH "Match-all classifier in tc" 8 "21 Oct 2015" "iproute2" "Linux" -+ -+.SH NAME -+matchall \- traffic control filter that matches every packet -+.SH SYNOPSIS -+.in +8 -+.ti -8 -+.BR tc " " filter " ... " matchall " [ " -+.BR skip_sw " | " skip_hw -+.R " ] [ " -+.B action -+.IR ACTION_SPEC " ] [ " -+.B classid -+.IR CLASSID " ]" -+.SH DESCRIPTION -+The -+.B matchall -+filter allows to classify every packet that flows on the port and run a -+action on it. -+.SH OPTIONS -+.TP -+.BI action " ACTION_SPEC" -+Apply an action from the generic actions framework on matching packets. -+.TP -+.BI classid " CLASSID" -+Push matching packets into the class identified by -+.IR CLASSID . -+.TP -+.BI skip_sw -+Do not process filter by software. If hardware has no offload support for this -+filter, or TC offload is not enabled for the interface, operation will fail. -+.TP -+.BI skip_hw -+Do not process filter by hardware. -+.SH EXAMPLES -+To create ingress mirroring from port eth1 to port eth2: -+.RS -+.EX -+ -+tc qdisc add dev eth1 handle ffff: ingress -+tc filter add dev eth1 parent ffff: \\ -+ matchall skip_sw \\ -+ action mirred egress mirror \\ -+ dev eth2 -+.EE -+.RE -+ -+The first command creats an ingress qdisc with handle -+.BR ffff: -+on device -+.BR eth1 -+where the second command attaches a matchall filters on it that mirrors the -+packets to device eth2. -+ -+To create egress mirroring from port eth1 to port eth2: -+.EX -+ -+tc qdisc add dev eth1 handle 1: root prio -+tc filter add dev eth1 parent 1: \\ -+ matchall skip_sw \\ -+ action mirred egress mirror \\ -+ dev eth2 -+.EE -+.RE -+ -+The first command creats an egress qdisc with handle -+.BR 1: -+that replaces the root qdisc on device -+.BR eth1 -+where the second command attaches a matchall filters on it that mirrors the -+packets to device eth2. -+ -+ -+.EE -+.SH SEE ALSO -+.BR tc (8), -diff --git a/man/man8/tc.8 b/man/man8/tc.8 -index 4e99dca..7ee1c9c 100644 ---- a/man/man8/tc.8 -+++ b/man/man8/tc.8 -@@ -187,6 +187,11 @@ u32 - Generic filtering on arbitrary packet data, assisted by syntax to abstract common operations. See - .BR tc-u32 (8) - for details. -+.TP -+matchall -+Traffic control filter that matches every packet. See -+.BR tc-matchall (8) -+for details. - - .SH CLASSLESS QDISCS - The classless qdiscs are: --- -2.9.3 - diff --git a/0003-bpf-test-for-valid-type-in-bpf_get_work_dir.patch b/0003-bpf-test-for-valid-type-in-bpf_get_work_dir.patch new file mode 100644 index 0000000..fff2c0c --- /dev/null +++ b/0003-bpf-test-for-valid-type-in-bpf_get_work_dir.patch @@ -0,0 +1,38 @@ +From b4bcfe51bfa555281cf583de46058b95c5fded97 Mon Sep 17 00:00:00 2001 +From: Daniel Borkmann +Date: Mon, 6 Mar 2017 13:06:00 +0100 +Subject: [PATCH] bpf: test for valid type in bpf_get_work_dir + +Jan-Erik reported an assertion in bpf_prog_to_subdir() failed where +type was BPF_PROG_TYPE_UNSPEC, which is only used in bpf_init_env() +to auto-mount and cache the bpf fs mount point. + +Therefore, make sure when bpf_init_env() is called multiple times +(f.e. eBPF classifier with eBPF action attached) and bpf_mnt_cached +is set already that the type is also valid. In bpf_init_env(), we're +only interested in the mount point and not a type-specific subdir. + +Fixes: e42256699cac ("bpf: make tc's bpf loader generic and move into lib") +Reported-by: Jan-Erik Rediger +Signed-off-by: Daniel Borkmann +(cherry picked from commit 51361a9f1cfca81259c68515cb24fbaace03136a) +--- + lib/bpf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/bpf.c b/lib/bpf.c +index 64e199b3..fef9cfcd 100644 +--- a/lib/bpf.c ++++ b/lib/bpf.c +@@ -596,7 +596,7 @@ static const char *bpf_get_work_dir(enum bpf_prog_type type) + if (bpf_mnt_cached) { + const char *out = mnt; + +- if (out) { ++ if (out && type) { + snprintf(bpf_tmp, sizeof(bpf_tmp), "%s%s/", + out, bpf_prog_to_subdir(type)); + out = bpf_tmp; +-- +2.11.0 + diff --git a/devlink-kernel-headers.patch b/devlink-kernel-headers.patch deleted file mode 100644 index b46c702..0000000 --- a/devlink-kernel-headers.patch +++ /dev/null @@ -1,88 +0,0 @@ -diff --git a/include/linux/devlink.h b/include/linux/devlink.h -index a96e1a0..0e21d00 100644 ---- a/include/linux/devlink.h -+++ b/include/linux/devlink.h -@@ -33,6 +33,30 @@ enum devlink_command { - DEVLINK_CMD_PORT_SPLIT, - DEVLINK_CMD_PORT_UNSPLIT, - -+ DEVLINK_CMD_SB_GET, /* can dump */ -+ DEVLINK_CMD_SB_SET, -+ DEVLINK_CMD_SB_NEW, -+ DEVLINK_CMD_SB_DEL, -+ -+ DEVLINK_CMD_SB_POOL_GET, /* can dump */ -+ DEVLINK_CMD_SB_POOL_SET, -+ DEVLINK_CMD_SB_POOL_NEW, -+ DEVLINK_CMD_SB_POOL_DEL, -+ -+ DEVLINK_CMD_SB_PORT_POOL_GET, /* can dump */ -+ DEVLINK_CMD_SB_PORT_POOL_SET, -+ DEVLINK_CMD_SB_PORT_POOL_NEW, -+ DEVLINK_CMD_SB_PORT_POOL_DEL, -+ -+ DEVLINK_CMD_SB_TC_POOL_BIND_GET, /* can dump */ -+ DEVLINK_CMD_SB_TC_POOL_BIND_SET, -+ DEVLINK_CMD_SB_TC_POOL_BIND_NEW, -+ DEVLINK_CMD_SB_TC_POOL_BIND_DEL, -+ -+ /* Shared buffer occupancy monitoring commands */ -+ DEVLINK_CMD_SB_OCC_SNAPSHOT, -+ DEVLINK_CMD_SB_OCC_MAX_CLEAR, -+ - /* add new commands above here */ - - __DEVLINK_CMD_MAX, -@@ -46,6 +70,31 @@ enum devlink_port_type { - DEVLINK_PORT_TYPE_IB, - }; - -+enum devlink_sb_pool_type { -+ DEVLINK_SB_POOL_TYPE_INGRESS, -+ DEVLINK_SB_POOL_TYPE_EGRESS, -+}; -+ -+/* static threshold - limiting the maximum number of bytes. -+ * dynamic threshold - limiting the maximum number of bytes -+ * based on the currently available free space in the shared buffer pool. -+ * In this mode, the maximum quota is calculated based -+ * on the following formula: -+ * max_quota = alpha / (1 + alpha) * Free_Buffer -+ * While Free_Buffer is the amount of none-occupied buffer associated to -+ * the relevant pool. -+ * The value range which can be passed is 0-20 and serves -+ * for computation of alpha by following formula: -+ * alpha = 2 ^ (passed_value - 10) -+ */ -+ -+enum devlink_sb_threshold_type { -+ DEVLINK_SB_THRESHOLD_TYPE_STATIC, -+ DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC, -+}; -+ -+#define DEVLINK_SB_THRESHOLD_TO_ALPHA_MAX 20 -+ - enum devlink_attr { - /* don't change the order or add anything between, this is ABI! */ - DEVLINK_ATTR_UNSPEC, -@@ -62,6 +111,20 @@ enum devlink_attr { - DEVLINK_ATTR_PORT_IBDEV_NAME, /* string */ - DEVLINK_ATTR_PORT_SPLIT_COUNT, /* u32 */ - DEVLINK_ATTR_PORT_SPLIT_GROUP, /* u32 */ -+ DEVLINK_ATTR_SB_INDEX, /* u32 */ -+ DEVLINK_ATTR_SB_SIZE, /* u32 */ -+ DEVLINK_ATTR_SB_INGRESS_POOL_COUNT, /* u16 */ -+ DEVLINK_ATTR_SB_EGRESS_POOL_COUNT, /* u16 */ -+ DEVLINK_ATTR_SB_INGRESS_TC_COUNT, /* u16 */ -+ DEVLINK_ATTR_SB_EGRESS_TC_COUNT, /* u16 */ -+ DEVLINK_ATTR_SB_POOL_INDEX, /* u16 */ -+ DEVLINK_ATTR_SB_POOL_TYPE, /* u8 */ -+ DEVLINK_ATTR_SB_POOL_SIZE, /* u32 */ -+ DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, /* u8 */ -+ DEVLINK_ATTR_SB_THRESHOLD, /* u32 */ -+ DEVLINK_ATTR_SB_TC_INDEX, /* u16 */ -+ DEVLINK_ATTR_SB_OCC_CUR, /* u32 */ -+ DEVLINK_ATTR_SB_OCC_MAX, /* u32 */ - - /* add new attributes above here, update the policy in devlink.c */ - diff --git a/iproute.spec b/iproute.spec index 52b7737..549e453 100644 --- a/iproute.spec +++ b/iproute.spec @@ -1,8 +1,8 @@ %global cbq_version v0.7.3 Summary: Advanced IP routing and network device configuration tools Name: iproute -Version: 4.6.0 -Release: 6%{?dist} +Version: 4.10.0 +Release: 1%{?dist} Group: Applications/System URL: http://kernel.org/pub/linux/utils/net/%{name}2/ Source0: http://kernel.org/pub/linux/utils/net/%{name}2/%{name}2-%{version}.tar.xz @@ -16,49 +16,9 @@ Source2: avpkt # https://github.com/pavlix/iproute2/commits/fedora Patch1: 0001-Documentation-fixes.patch -# devlink shared buffer support -# -# Accepted by upstream -# -# https://patchwork.ozlabs.org/patch/622240/ -# https://patchwork.ozlabs.org/patch/622241/ -Patch2: devlink-kernel-headers.patch -Patch3: 0001-devlink-implement-shared-buffer-support.patch -Patch4: 0002-devlink-implement-shared-buffer-occupancy-control.patch - -# devlink manpages installation -# -# Accepted by upstream -# -# https://patchwork.ozlabs.org/patch/647766/ -# https://patchwork.ozlabs.org/patch/647764/ -Patch5: 0001-man-Add-devlink-man-pages-to-Makefile.patch -Patch6: 0002-man-Point-to-devlink-sb-from-devlink-man-page.patch - -# devlink JSON support -# -# Accepted by upstream -# -# https://patchwork.ozlabs.org/patch/651711/ -# https://patchwork.ozlabs.org/patch/651712/ -Patch7: 0001-devlink-write-usage-help-messages-to-stderr.patch -Patch8: 0002-devlink-add-option-to-generate-JSON-output.patch - -# matchall classifier -# -# Accepted by upstream -# -# https://patchwork.ozlabs.org/patch/664374/ -# https://patchwork.ozlabs.org/patch/664375/ -Patch9: matchall-kernel-headers.patch -Patch10: 0001-tc-Add-support-for-the-matchall-traffic-classifier.patch -Patch11: 0002-tc-man-Add-man-entry-for-the-matchall-classifier.patch - -# Fix for bz#1411127 -# -# Accepted upstream: -# https://patchwork.ozlabs.org/patch/714480/ -Patch12: 0001-tc-m_xt-Fix-segfault-with-iptables-1.6.0.patch +# upstream fixes for commits in 4.10.0 release +Patch2: 0002-tc-flower-use-correct-type-when-calling-flower_icmp_.patch +Patch3: 0003-bpf-test-for-valid-type-in-bpf_get_work_dir.patch License: GPLv2+ and Public Domain BuildRequires: bison @@ -124,15 +84,6 @@ The libnetlink static library. %patch1 -p1 %patch2 -p1 %patch3 -p1 -%patch4 -p1 -%patch5 -p1 -%patch6 -p1 -%patch7 -p1 -%patch8 -p1 -%patch9 -p1 -%patch10 -p1 -%patch11 -p1 -%patch12 -p1 %build export CFLAGS="%{optflags}" @@ -214,8 +165,13 @@ rm -rf '%{buildroot}%{_docdir}' %{_mandir}/man3/* %{_libdir}/libnetlink.a %{_includedir}/libnetlink.h +%{_includedir}/iproute2/bpf_elf.h %changelog +* Fri Mar 17 2017 Phil Sutter - 4.10.0-1 +- Add two fixes to 4.10.0 release from upstream +- Rebase onto version 4.10.0 to match kernel version + * Fri Jan 13 2017 Phil Sutter - 4.6.0-6 - Fix segfault in xt action diff --git a/matchall-kernel-headers.patch b/matchall-kernel-headers.patch deleted file mode 100644 index 8c9d673..0000000 --- a/matchall-kernel-headers.patch +++ /dev/null @@ -1,32 +0,0 @@ -diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h -index b69358b..18fb87e 100644 ---- a/include/linux/pkt_cls.h -+++ b/include/linux/pkt_cls.h -@@ -96,6 +96,10 @@ enum { - - #define TCA_POLICE_MAX (__TCA_POLICE_MAX - 1) - -+/* tca flags definitions */ -+#define TCA_CLS_FLAGS_SKIP_HW (1 << 0) -+#define TCA_CLS_FLAGS_SKIP_SW (1 << 1) -+ - /* U32 filters */ - - #define TC_U32_HTID(h) ((h)&0xFFF00000) -@@ -370,6 +374,16 @@ enum { - - #define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1) - -+enum { -+ TCA_MATCHALL_UNSPEC, -+ TCA_MATCHALL_CLASSID, -+ TCA_MATCHALL_ACT, -+ TCA_MATCHALL_FLAGS, -+ __TCA_MATCHALL_MAX, -+}; -+ -+#define TCA_MATCHALL_MAX (__TCA_MATCHALL_MAX - 1) -+ - /* Extended Matches */ - - struct tcf_ematch_tree_hdr { diff --git a/sources b/sources index a83d116..72be43e 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -d015e437e4f744d51d3a1a53341826d5 iproute2-4.6.0.tar.xz +SHA512 (iproute2-4.10.0.tar.xz) = e54477e167455e7ef5da4adc168d63eaa96091b63dc987fffe918cbb005eceed18a62283ca99ee2512dc0e960f47ae21b39ffbe399c1612fd9cea147c34c581b From 4366f834b57a3924965c412709922c9773bec6a4 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 23 May 2017 13:31:58 +0200 Subject: [PATCH 09/11] Rebase package on top of iproute2-4.11.0 --- iproute.spec | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/iproute.spec b/iproute.spec index 549e453..b352751 100644 --- a/iproute.spec +++ b/iproute.spec @@ -1,7 +1,7 @@ %global cbq_version v0.7.3 Summary: Advanced IP routing and network device configuration tools Name: iproute -Version: 4.10.0 +Version: 4.11.0 Release: 1%{?dist} Group: Applications/System URL: http://kernel.org/pub/linux/utils/net/%{name}2/ @@ -9,17 +9,13 @@ Source0: http://kernel.org/pub/linux/utils/net/%{name}2/%{name}2-%{ve Source1: cbq-0000.example Source2: avpkt -# manpage/help improvements -# -# * Piece by piece absorbed upstream. -# -# https://github.com/pavlix/iproute2/commits/fedora +# Fedora local docs changes: +# - We ship cbq.init-v0.7.3 as cbq binary, so have a cbq.8 man page which links +# to tc-cbq.8. +# - Drop reference to Debian from ss.8 man page. +# - We ship ss.ps instead of ss.html. Patch1: 0001-Documentation-fixes.patch -# upstream fixes for commits in 4.10.0 release -Patch2: 0002-tc-flower-use-correct-type-when-calling-flower_icmp_.patch -Patch3: 0003-bpf-test-for-valid-type-in-bpf_get_work_dir.patch - License: GPLv2+ and Public Domain BuildRequires: bison BuildRequires: elfutils-libelf-devel @@ -56,6 +52,7 @@ Group: Applications/System License: GPLv2+ Obsoletes: %{name} < 4.5.0-3 Requires: %{name}%{?_isa} = %{version}-%{release} +Provides: tc %description tc The Traffic Control utility manages queueing disciplines, their classes and @@ -82,8 +79,6 @@ The libnetlink static library. %prep %setup -q -n %{name}2-%{version} %patch1 -p1 -%patch2 -p1 -%patch3 -p1 %build export CFLAGS="%{optflags}" @@ -168,6 +163,10 @@ rm -rf '%{buildroot}%{_docdir}' %{_includedir}/iproute2/bpf_elf.h %changelog +* Tue May 23 2017 Phil Sutter - 4.11.0-1 +- Add virtual capability to tc subpackage so it's easier found +- New version 4.11.0 + * Fri Mar 17 2017 Phil Sutter - 4.10.0-1 - Add two fixes to 4.10.0 release from upstream - Rebase onto version 4.10.0 to match kernel version From d34c741f155e212d0ea6e570dfa6f0279ad1c72a Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Tue, 23 May 2017 14:36:29 +0200 Subject: [PATCH 10/11] Update gitignore and sources files for new package version --- .gitignore | 1 + sources | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index da24855..92b0f31 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /iproute2-4.10.0.tar.xz +/iproute2-4.11.0.tar.xz diff --git a/sources b/sources index 72be43e..045e47d 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (iproute2-4.10.0.tar.xz) = e54477e167455e7ef5da4adc168d63eaa96091b63dc987fffe918cbb005eceed18a62283ca99ee2512dc0e960f47ae21b39ffbe399c1612fd9cea147c34c581b +SHA512 (iproute2-4.11.0.tar.xz) = e6cc3dbe2779670a752ab346c1a432b496033448d1645aa0161b3f7b683b3f9939ab09db12199b794cc64dff257faaf0d151046feea9031a6139176e08b4f4fa From 8c1ec747562db26c4839e91d2f6c3429797f935e Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Fri, 21 Jul 2017 17:04:46 +0200 Subject: [PATCH 11/11] Rebase package on top of iproute2-4.12.0 --- .gitignore | 1 + iproute.spec | 5 ++++- sources | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 92b0f31..28288b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /iproute2-4.10.0.tar.xz /iproute2-4.11.0.tar.xz +/iproute2-4.12.0.tar.xz diff --git a/iproute.spec b/iproute.spec index b352751..e7f4371 100644 --- a/iproute.spec +++ b/iproute.spec @@ -1,7 +1,7 @@ %global cbq_version v0.7.3 Summary: Advanced IP routing and network device configuration tools Name: iproute -Version: 4.11.0 +Version: 4.12.0 Release: 1%{?dist} Group: Applications/System URL: http://kernel.org/pub/linux/utils/net/%{name}2/ @@ -163,6 +163,9 @@ rm -rf '%{buildroot}%{_docdir}' %{_includedir}/iproute2/bpf_elf.h %changelog +* Fri Jul 21 2017 Phil Sutter - 4.12.0-1 +- New version 4.12.0 + * Tue May 23 2017 Phil Sutter - 4.11.0-1 - Add virtual capability to tc subpackage so it's easier found - New version 4.11.0 diff --git a/sources b/sources index 045e47d..60df61a 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (iproute2-4.11.0.tar.xz) = e6cc3dbe2779670a752ab346c1a432b496033448d1645aa0161b3f7b683b3f9939ab09db12199b794cc64dff257faaf0d151046feea9031a6139176e08b4f4fa +SHA512 (iproute2-4.12.0.tar.xz) = 275147f71e7c4698654f0d6d0981ab42f6f108066508c15cfcd5d9e0d3aaf8d33291968d9f06cb03f5494d801cfabf8d53308aaf56fc4fa92c52b137e970a3b0