mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2025-12-30 12:17:37 +00:00
Merge branch 'iproute2-master' into iproute2-next
Conflicts: include/uapi/linux/bpf.h Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
commit
a0bc57e1ef
@ -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)
|
||||
|
||||
@ -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]);
|
||||
|
||||
@ -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 ? : "<unknown>");
|
||||
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 ? : "<unknown>");
|
||||
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");
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
21
tc/tc.c
21
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);
|
||||
|
||||
|
||||
@ -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",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user