diff --git a/devlink/mnlg.c b/devlink/mnlg.c index c33c90be..37cc25dd 100644 --- a/devlink/mnlg.c +++ b/devlink/mnlg.c @@ -199,7 +199,7 @@ int mnlg_socket_group_add(struct mnlg_socket *nlg, const char *group_name) nlh = __mnlg_msg_prepare(nlg, CTRL_CMD_GETFAMILY, NLM_F_REQUEST | NLM_F_ACK, GENL_ID_CTRL, 1); - mnl_attr_put_u32(nlh, CTRL_ATTR_FAMILY_ID, nlg->id); + mnl_attr_put_u16(nlh, CTRL_ATTR_FAMILY_ID, nlg->id); err = mnlg_socket_send(nlg, nlh); if (err < 0) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index ddb8bf87..bcee9ab7 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -853,10 +853,8 @@ int print_linkinfo(const struct sockaddr_nl *who, if (!name) return -1; - if (filter.label && - (!filter.family || filter.family == AF_PACKET) && - fnmatch(filter.label, name, 0)) - return -1; + if (filter.label) + return 0; if (tb[IFLA_GROUP]) { int group = rta_getattr_u32(tb[IFLA_GROUP]); diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index 46a212c8..e6044811 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -177,6 +177,7 @@ static const char *seg6_action_names[SEG6_LOCAL_ACTION_MAX + 1] = { [SEG6_LOCAL_ACTION_END_S] = "End.S", [SEG6_LOCAL_ACTION_END_AS] = "End.AS", [SEG6_LOCAL_ACTION_END_AM] = "End.AM", + [SEG6_LOCAL_ACTION_END_BPF] = "End.BPF", }; static const char *format_action_type(int action) @@ -202,6 +203,27 @@ static int read_action_type(const char *name) return SEG6_LOCAL_ACTION_UNSPEC; } +static void print_encap_bpf_prog(FILE *fp, struct rtattr *encap, + const char *str) +{ + struct rtattr *tb[LWT_BPF_PROG_MAX+1]; + const char *progname = NULL; + + parse_rtattr_nested(tb, LWT_BPF_PROG_MAX, encap); + + if (tb[LWT_BPF_PROG_NAME]) + progname = rta_getattr_str(tb[LWT_BPF_PROG_NAME]); + + if (is_json_context()) + print_string(PRINT_JSON, str, NULL, + progname ? : ""); + else { + fprintf(fp, "%s ", str); + if (progname) + fprintf(fp, "%s ", progname); + } +} + static void print_encap_seg6local(FILE *fp, struct rtattr *encap) { struct rtattr *tb[SEG6_LOCAL_MAX + 1]; @@ -250,6 +272,9 @@ static void print_encap_seg6local(FILE *fp, struct rtattr *encap) print_string(PRINT_ANY, "oif", "oif %s ", ll_index_to_name(oif)); } + + if (tb[SEG6_LOCAL_BPF]) + print_encap_bpf_prog(fp, tb[SEG6_LOCAL_BPF], "endpoint"); } static void print_encap_mpls(FILE *fp, struct rtattr *encap) @@ -356,27 +381,6 @@ static void print_encap_ip6(FILE *fp, struct rtattr *encap) "tc %u ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC])); } -static void print_encap_bpf_prog(FILE *fp, struct rtattr *encap, - const char *str) -{ - struct rtattr *tb[LWT_BPF_PROG_MAX+1]; - const char *progname = NULL; - - parse_rtattr_nested(tb, LWT_BPF_PROG_MAX, encap); - - if (tb[LWT_BPF_PROG_NAME]) - progname = rta_getattr_str(tb[LWT_BPF_PROG_NAME]); - - if (is_json_context()) - print_string(PRINT_JSON, str, NULL, - progname ? : ""); - else { - fprintf(fp, "%s ", str); - if (progname) - fprintf(fp, "%s ", progname); - } -} - static void print_encap_bpf(FILE *fp, struct rtattr *encap) { struct rtattr *tb[LWT_BPF_MAX+1]; @@ -546,11 +550,60 @@ static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp, return 0; } +struct lwt_x { + struct rtattr *rta; + size_t len; +}; + +static void bpf_lwt_cb(void *lwt_ptr, int fd, const char *annotation) +{ + struct lwt_x *x = lwt_ptr; + + rta_addattr32(x->rta, x->len, LWT_BPF_PROG_FD, fd); + rta_addattr_l(x->rta, x->len, LWT_BPF_PROG_NAME, annotation, + strlen(annotation) + 1); +} + +static const struct bpf_cfg_ops bpf_cb_ops = { + .ebpf_cb = bpf_lwt_cb, +}; + +static int lwt_parse_bpf(struct rtattr *rta, size_t len, + int *argcp, char ***argvp, + int attr, const enum bpf_prog_type bpf_type) +{ + struct bpf_cfg_in cfg = { + .type = bpf_type, + .argc = *argcp, + .argv = *argvp, + }; + struct lwt_x x = { + .rta = rta, + .len = len, + }; + struct rtattr *nest; + int err; + + nest = rta_nest(rta, len, attr); + err = bpf_parse_and_load_common(&cfg, &bpf_cb_ops, &x); + if (err < 0) { + fprintf(stderr, "Failed to parse eBPF program: %s\n", + strerror(-err)); + return -1; + } + rta_nest_end(rta, nest); + + *argcp = cfg.argc; + *argvp = cfg.argv; + + return 0; +} + static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp, char ***argvp) { int segs_ok = 0, hmac_ok = 0, table_ok = 0, nh4_ok = 0, nh6_ok = 0; - int iif_ok = 0, oif_ok = 0, action_ok = 0, srh_ok = 0; + int iif_ok = 0, oif_ok = 0, action_ok = 0, srh_ok = 0, bpf_ok = 0; __u32 action = 0, table, iif, oif; struct ipv6_sr_hdr *srh; char **argv = *argvp; @@ -627,6 +680,14 @@ static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp, } else { continue; } + } else if (strcmp(*argv, "endpoint") == 0) { + NEXT_ARG(); + if (bpf_ok++) + duparg2("endpoint", *argv); + + if (lwt_parse_bpf(rta, len, &argc, &argv, SEG6_LOCAL_BPF, + BPF_PROG_TYPE_LWT_SEG6LOCAL) < 0) + exit(-1); } else { break; } @@ -896,55 +957,6 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len, return 0; } -struct lwt_x { - struct rtattr *rta; - size_t len; -}; - -static void bpf_lwt_cb(void *lwt_ptr, int fd, const char *annotation) -{ - struct lwt_x *x = lwt_ptr; - - rta_addattr32(x->rta, x->len, LWT_BPF_PROG_FD, fd); - rta_addattr_l(x->rta, x->len, LWT_BPF_PROG_NAME, annotation, - strlen(annotation) + 1); -} - -static const struct bpf_cfg_ops bpf_cb_ops = { - .ebpf_cb = bpf_lwt_cb, -}; - -static int lwt_parse_bpf(struct rtattr *rta, size_t len, - int *argcp, char ***argvp, - int attr, const enum bpf_prog_type bpf_type) -{ - struct bpf_cfg_in cfg = { - .type = bpf_type, - .argc = *argcp, - .argv = *argvp, - }; - struct lwt_x x = { - .rta = rta, - .len = len, - }; - struct rtattr *nest; - int err; - - nest = rta_nest(rta, len, attr); - err = bpf_parse_and_load_common(&cfg, &bpf_cb_ops, &x); - if (err < 0) { - fprintf(stderr, "Failed to parse eBPF program: %s\n", - strerror(-err)); - return -1; - } - rta_nest_end(rta, nest); - - *argcp = cfg.argc; - *argvp = cfg.argv; - - return 0; -} - static void lwt_bpf_usage(void) { fprintf(stderr, "Usage: ip route ... encap bpf [ in BPF ] [ out BPF ] [ xmit BPF ] [...]\n"); diff --git a/lib/bpf.c b/lib/bpf.c index 794ad199..d093d0bd 100644 --- a/lib/bpf.c +++ b/lib/bpf.c @@ -95,6 +95,11 @@ static const struct bpf_prog_meta __bpf_prog_meta[] = { .subdir = "ip", .section = ELF_SECTION_PROG, }, + [BPF_PROG_TYPE_LWT_SEG6LOCAL] = { + .type = "lwt_seg6local", + .subdir = "ip", + .section = ELF_SECTION_PROG, + }, }; static bool bpf_map_offload_neutral(enum bpf_map_type type) diff --git a/man/man8/devlink.8 b/man/man8/devlink.8 index 4cf6762a..ac61b6ad 100644 --- a/man/man8/devlink.8 +++ b/man/man8/devlink.8 @@ -7,7 +7,7 @@ devlink \- Devlink tool .in +8 .ti -8 .B devlink -.RI "[ " OPTIONS " ] " OBJECT " { " COMMAND " | " +.RI "[ " OPTIONS " ] { " dev | port | monitor | sb | resource " } { " COMMAND " | " .BR help " }" .sp @@ -17,18 +17,6 @@ devlink \- Devlink tool .BI "-batch " filename .sp -.ti -8 -.IR OBJECT " := { " -.BR dev " | " port " | " monitor " | " sb " | " resource " }" -.sp - -.ti -8 -.IR OPTIONS " := { " -\fB\-V\fR[\fIersion\fR] | -\fB\-n\fR[\fIno-nice-names\fR] } -\fB\-j\fR[\fIjson\fR] } -\fB\-p\fR[\fIpretty\fR] } - .SH OPTIONS .TP diff --git a/man/man8/tc-cbs.8 b/man/man8/tc-cbs.8 index 32e1e0d4..ad1d8821 100644 --- a/man/man8/tc-cbs.8 +++ b/man/man8/tc-cbs.8 @@ -28,7 +28,7 @@ defined rate limiting method to the traffic. This queueing discipline is intended to be used by TSN (Time Sensitive Networking) applications, the CBS parameters are derived directly by what is described by the Annex L of the IEEE 802.1Q-2014 -Sepcification. The algorithm and how it affects the latency are +Specification. The algorithm and how it affects the latency are detailed there. CBS is meant to be installed under another qdisc that maps packet @@ -60,7 +60,7 @@ packet size, which is then used for calculating the idleslope. sendslope Sendslope is the rate of credits that is depleted (it should be a negative number of kilobits per second) when a transmission is -ocurring. It can be calculated as follows, (IEEE 802.1Q-2014 Section +occurring. It can be calculated as follows, (IEEE 802.1Q-2014 Section 8.6.8.2 item g): sendslope = idleslope - port_transmit_rate diff --git a/rdma/include/uapi/rdma/ib_user_verbs.h b/rdma/include/uapi/rdma/ib_user_verbs.h index 6aeb0331..4f9991de 100644 --- a/rdma/include/uapi/rdma/ib_user_verbs.h +++ b/rdma/include/uapi/rdma/ib_user_verbs.h @@ -998,6 +998,19 @@ struct ib_uverbs_flow_spec_action_handle { __u32 reserved1; }; +struct ib_uverbs_flow_spec_action_count { + union { + struct ib_uverbs_flow_spec_hdr hdr; + struct { + __u32 type; + __u16 size; + __u16 reserved; + }; + }; + __u32 handle; + __u32 reserved1; +}; + struct ib_uverbs_flow_tunnel_filter { __be32 tunnel_id; }; @@ -1033,6 +1046,56 @@ struct ib_uverbs_flow_spec_esp { struct ib_uverbs_flow_spec_esp_filter mask; }; +struct ib_uverbs_flow_gre_filter { + /* c_ks_res0_ver field is bits 0-15 in offset 0 of a standard GRE header: + * bit 0 - C - checksum bit. + * bit 1 - reserved. set to 0. + * bit 2 - key bit. + * bit 3 - sequence number bit. + * bits 4:12 - reserved. set to 0. + * bits 13:15 - GRE version. + */ + __be16 c_ks_res0_ver; + __be16 protocol; + __be32 key; +}; + +struct ib_uverbs_flow_spec_gre { + union { + struct ib_uverbs_flow_spec_hdr hdr; + struct { + __u32 type; + __u16 size; + __u16 reserved; + }; + }; + struct ib_uverbs_flow_gre_filter val; + struct ib_uverbs_flow_gre_filter mask; +}; + +struct ib_uverbs_flow_mpls_filter { + /* The field includes the entire MPLS label: + * bits 0:19 - label field. + * bits 20:22 - traffic class field. + * bits 23 - bottom of stack bit. + * bits 24:31 - ttl field. + */ + __be32 label; +}; + +struct ib_uverbs_flow_spec_mpls { + union { + struct ib_uverbs_flow_spec_hdr hdr; + struct { + __u32 type; + __u16 size; + __u16 reserved; + }; + }; + struct ib_uverbs_flow_mpls_filter val; + struct ib_uverbs_flow_mpls_filter mask; +}; + struct ib_uverbs_flow_attr { __u32 type; __u16 size; diff --git a/tc/f_flower.c b/tc/f_flower.c index a4cf06aa..9a3fd775 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -1203,7 +1203,7 @@ static void flower_print_ip_attr(char *name, struct rtattr *key_attr, if (mask_attr) sprintf(out + done, "/%x", rta_getattr_u8(mask_attr)); - sprintf(namefrm, "\n %s %%x", name); + sprintf(namefrm, "\n %s %%s", name); print_string(PRINT_ANY, name, namefrm, out); } diff --git a/tc/q_htb.c b/tc/q_htb.c index 7d5f6ce4..b93d31d4 100644 --- a/tc/q_htb.c +++ b/tc/q_htb.c @@ -291,9 +291,9 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) if (RTA_PAYLOAD(tb[TCA_HTB_PARMS]) < sizeof(*hopt)) return -1; if (!hopt->level) { - print_int(PRINT_ANY, "prio", "prio ", (int)hopt->prio); + print_int(PRINT_ANY, "prio", "prio %d ", (int)hopt->prio); if (show_details) - print_int(PRINT_ANY, "quantum", "quantum ", + print_int(PRINT_ANY, "quantum", "quantum %d ", (int)hopt->quantum); } diff --git a/tc/q_mqprio.c b/tc/q_mqprio.c index 207d6441..89b46002 100644 --- a/tc/q_mqprio.c +++ b/tc/q_mqprio.c @@ -173,7 +173,8 @@ static int mqprio_parse_opt(struct qdisc_util *qu, int argc, argc--; argv++; } - tail = addattr_nest_compat(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)); + tail = NLMSG_TAIL(n); + addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)); if (flags & TC_MQPRIO_F_MODE) addattr_l(n, 1024, TCA_MQPRIO_MODE, @@ -208,7 +209,7 @@ static int mqprio_parse_opt(struct qdisc_util *qu, int argc, addattr_nest_end(n, start); } - addattr_nest_compat_end(n, tail); + tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail; return 0; } diff --git a/tc/q_netem.c b/tc/q_netem.c index 623ec903..9f9a9b3d 100644 --- a/tc/q_netem.c +++ b/tc/q_netem.c @@ -422,6 +422,8 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, } } + tail = NLMSG_TAIL(n); + if (reorder.probability) { if (opt.latency == 0) { fprintf(stderr, "reordering not possible without specifying some delay\n"); @@ -450,7 +452,8 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, return -1; } - tail = addattr_nest_compat(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)); + if (addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)) < 0) + return -1; if (present[TCA_NETEM_CORR] && addattr_l(n, 1024, TCA_NETEM_CORR, &cor, sizeof(cor)) < 0) @@ -509,7 +512,7 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, return -1; free(dist_data); } - addattr_nest_compat_end(n, tail); + tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; return 0; } diff --git a/tc/tc.c b/tc/tc.c index 2af67963..fbc23dd9 100644 --- a/tc/tc.c +++ b/tc/tc.c @@ -334,6 +334,7 @@ static int batch(const char *name) int batchsize = 0; size_t len = 0; int ret = 0; + int err; bool send; batch_mode = 1; @@ -402,9 +403,9 @@ static int batch(const char *name) continue; /* blank line */ } - ret = do_cmd(largc, largv, tail == NULL ? NULL : tail->buf, + err = do_cmd(largc, largv, tail == NULL ? NULL : tail->buf, tail == NULL ? 0 : sizeof(tail->buf)); - if (ret != 0) { + if (err != 0) { fprintf(stderr, "Command failed %s:%d\n", name, cmdlineno - 1); ret = 1; @@ -426,15 +427,17 @@ static int batch(const char *name) iov->iov_len = n->nlmsg_len; } - ret = rtnl_talk_iov(&rth, iovs, batchsize, NULL); - if (ret < 0) { - fprintf(stderr, "Command failed %s:%d\n", name, - cmdlineno - (batchsize + ret) - 1); - return 2; - } + err = rtnl_talk_iov(&rth, iovs, batchsize, NULL); put_batch_bufs(&buf_pool, &head, &tail); - batchsize = 0; free(iovs); + if (err < 0) { + fprintf(stderr, "Command failed %s:%d\n", name, + cmdlineno - (batchsize + err) - 1); + ret = 1; + if (!force) + break; + } + batchsize = 0; } } while (!lastline); diff --git a/tc/tc_util.c b/tc/tc_util.c index e0c96291..d7578528 100644 --- a/tc/tc_util.c +++ b/tc/tc_util.c @@ -842,8 +842,6 @@ void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtat memcpy(&re, RTA_DATA(tbs[TCA_STATS_RATE_EST]), MIN(RTA_PAYLOAD(tbs[TCA_STATS_RATE_EST]), sizeof(re))); - fprintf(fp, "\n%srate %s %upps ", - prefix, sprint_rate(re.bps, b1), re.pps); print_string(PRINT_FP, NULL, "\n%s", prefix); print_uint(PRINT_JSON, "rate", NULL, re.bps); print_string(PRINT_FP, NULL, "rate %s",