mirror of
https://git.kernel.org/pub/scm/network/iproute2/iproute2.git
synced 2024-11-15 14:05:22 +08:00
Merge git://git.kernel.org/pub/scm/network/iproute2/iproute2-next
This commit is contained in:
commit
6f9bd171ff
@ -165,6 +165,14 @@ static void print_protinfo(FILE *fp, struct rtattr *attr)
|
||||
if (prtb[IFLA_BRPORT_NEIGH_SUPPRESS])
|
||||
print_on_off(PRINT_ANY, "neigh_suppress", "neigh_suppress %s ",
|
||||
rta_getattr_u8(prtb[IFLA_BRPORT_NEIGH_SUPPRESS]));
|
||||
if (prtb[IFLA_BRPORT_NEIGH_VLAN_SUPPRESS]) {
|
||||
struct rtattr *at;
|
||||
|
||||
at = prtb[IFLA_BRPORT_NEIGH_VLAN_SUPPRESS];
|
||||
print_on_off(PRINT_ANY, "neigh_vlan_suppress",
|
||||
"neigh_vlan_suppress %s ",
|
||||
rta_getattr_u8(at));
|
||||
}
|
||||
if (prtb[IFLA_BRPORT_VLAN_TUNNEL])
|
||||
print_on_off(PRINT_ANY, "vlan_tunnel", "vlan_tunnel %s ",
|
||||
rta_getattr_u8(prtb[IFLA_BRPORT_VLAN_TUNNEL]));
|
||||
@ -296,6 +304,7 @@ static void usage(void)
|
||||
" [ mcast_to_unicast {on | off} ]\n"
|
||||
" [ mcast_max_groups MAX_GROUPS ]\n"
|
||||
" [ neigh_suppress {on | off} ]\n"
|
||||
" [ neigh_vlan_suppress {on | off} ]\n"
|
||||
" [ vlan_tunnel {on | off} ]\n"
|
||||
" [ isolated {on | off} ]\n"
|
||||
" [ locked {on | off} ]\n"
|
||||
@ -322,6 +331,7 @@ static int brlink_modify(int argc, char **argv)
|
||||
char *d = NULL;
|
||||
int backup_port_idx = -1;
|
||||
__s8 neigh_suppress = -1;
|
||||
__s8 neigh_vlan_suppress = -1;
|
||||
__s8 learning = -1;
|
||||
__s8 learning_sync = -1;
|
||||
__s8 flood = -1;
|
||||
@ -447,6 +457,12 @@ static int brlink_modify(int argc, char **argv)
|
||||
neigh_suppress = parse_on_off("neigh_suppress", *argv, &ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else if (strcmp(*argv, "neigh_vlan_suppress") == 0) {
|
||||
NEXT_ARG();
|
||||
neigh_vlan_suppress = parse_on_off("neigh_vlan_suppress",
|
||||
*argv, &ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else if (strcmp(*argv, "vlan_tunnel") == 0) {
|
||||
NEXT_ARG();
|
||||
vlan_tunnel = parse_on_off("vlan_tunnel", *argv, &ret);
|
||||
@ -544,6 +560,9 @@ static int brlink_modify(int argc, char **argv)
|
||||
if (neigh_suppress != -1)
|
||||
addattr8(&req.n, sizeof(req), IFLA_BRPORT_NEIGH_SUPPRESS,
|
||||
neigh_suppress);
|
||||
if (neigh_vlan_suppress != -1)
|
||||
addattr8(&req.n, sizeof(req), IFLA_BRPORT_NEIGH_VLAN_SUPPRESS,
|
||||
neigh_vlan_suppress);
|
||||
if (vlan_tunnel != -1)
|
||||
addattr8(&req.n, sizeof(req), IFLA_BRPORT_VLAN_TUNNEL,
|
||||
vlan_tunnel);
|
||||
|
163
bridge/mdb.c
163
bridge/mdb.c
@ -14,6 +14,7 @@
|
||||
#include <linux/if_ether.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "libnetlink.h"
|
||||
#include "utils.h"
|
||||
@ -32,7 +33,8 @@ static void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: bridge mdb { add | del | replace } dev DEV port PORT grp GROUP [src SOURCE] [permanent | temp] [vid VID]\n"
|
||||
" [ filter_mode { include | exclude } ] [ source_list SOURCE_LIST ] [ proto PROTO ]\n"
|
||||
" [ filter_mode { include | exclude } ] [ source_list SOURCE_LIST ] [ proto PROTO ] [ dst IPADDR ]\n"
|
||||
" [ dst_port DST_PORT ] [ vni VNI ] [ src_vni SRC_VNI ] [ via DEV ]\n"
|
||||
" bridge mdb {show} [ dev DEV ] [ vid VID ]\n");
|
||||
exit(-1);
|
||||
}
|
||||
@ -146,6 +148,21 @@ static void print_src_entry(struct rtattr *src_attr, int af, const char *sep)
|
||||
close_json_object();
|
||||
}
|
||||
|
||||
static void print_dst(const struct rtattr *dst_attr)
|
||||
{
|
||||
SPRINT_BUF(abuf);
|
||||
int af = AF_INET;
|
||||
const void *dst;
|
||||
|
||||
if (RTA_PAYLOAD(dst_attr) == sizeof(struct in6_addr))
|
||||
af = AF_INET6;
|
||||
|
||||
dst = (const void *)RTA_DATA(dst_attr);
|
||||
print_color_string(PRINT_ANY, ifa_family_color(af),
|
||||
"dst", " dst %s",
|
||||
inet_ntop(af, dst, abuf, sizeof(abuf)));
|
||||
}
|
||||
|
||||
static void print_mdb_entry(FILE *f, int ifindex, const struct br_mdb_entry *e,
|
||||
struct nlmsghdr *n, struct rtattr **tb)
|
||||
{
|
||||
@ -240,6 +257,29 @@ static void print_mdb_entry(FILE *f, int ifindex, const struct br_mdb_entry *e,
|
||||
if (e->vid)
|
||||
print_uint(PRINT_ANY, "vid", " vid %u", e->vid);
|
||||
|
||||
if (tb[MDBA_MDB_EATTR_DST])
|
||||
print_dst(tb[MDBA_MDB_EATTR_DST]);
|
||||
|
||||
if (tb[MDBA_MDB_EATTR_DST_PORT])
|
||||
print_uint(PRINT_ANY, "dst_port", " dst_port %u",
|
||||
rta_getattr_u16(tb[MDBA_MDB_EATTR_DST_PORT]));
|
||||
|
||||
if (tb[MDBA_MDB_EATTR_VNI])
|
||||
print_uint(PRINT_ANY, "vni", " vni %u",
|
||||
rta_getattr_u32(tb[MDBA_MDB_EATTR_VNI]));
|
||||
|
||||
if (tb[MDBA_MDB_EATTR_SRC_VNI])
|
||||
print_uint(PRINT_ANY, "src_vni", " src_vni %u",
|
||||
rta_getattr_u32(tb[MDBA_MDB_EATTR_SRC_VNI]));
|
||||
|
||||
if (tb[MDBA_MDB_EATTR_IFINDEX]) {
|
||||
unsigned int ifindex;
|
||||
|
||||
ifindex = rta_getattr_u32(tb[MDBA_MDB_EATTR_IFINDEX]);
|
||||
print_string(PRINT_ANY, "via", " via %s",
|
||||
ll_index_to_name(ifindex));
|
||||
}
|
||||
|
||||
if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) {
|
||||
__u32 timer = rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER]);
|
||||
|
||||
@ -570,6 +610,76 @@ static int mdb_parse_proto(struct nlmsghdr *n, int maxlen, const char *proto)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdb_parse_dst(struct nlmsghdr *n, int maxlen, const char *dst)
|
||||
{
|
||||
struct in6_addr dst_ip6;
|
||||
__be32 dst_ip4;
|
||||
|
||||
if (inet_pton(AF_INET, dst, &dst_ip4)) {
|
||||
addattr32(n, maxlen, MDBE_ATTR_DST, dst_ip4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET6, dst, &dst_ip6)) {
|
||||
addattr_l(n, maxlen, MDBE_ATTR_DST, &dst_ip6,
|
||||
sizeof(dst_ip6));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mdb_parse_dst_port(struct nlmsghdr *n, int maxlen,
|
||||
const char *dst_port)
|
||||
{
|
||||
unsigned long port;
|
||||
char *endptr;
|
||||
|
||||
port = strtoul(dst_port, &endptr, 0);
|
||||
if (endptr && *endptr) {
|
||||
struct servent *pse;
|
||||
|
||||
pse = getservbyname(dst_port, "udp");
|
||||
if (!pse)
|
||||
return -1;
|
||||
port = ntohs(pse->s_port);
|
||||
} else if (port > USHRT_MAX) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
addattr16(n, maxlen, MDBE_ATTR_DST_PORT, port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdb_parse_vni(struct nlmsghdr *n, int maxlen, const char *vni,
|
||||
int attr_type)
|
||||
{
|
||||
unsigned long vni_num;
|
||||
char *endptr;
|
||||
|
||||
vni_num = strtoul(vni, &endptr, 0);
|
||||
if ((endptr && *endptr) || vni_num == ULONG_MAX)
|
||||
return -1;
|
||||
|
||||
addattr32(n, maxlen, attr_type, vni_num);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdb_parse_dev(struct nlmsghdr *n, int maxlen, const char *dev)
|
||||
{
|
||||
unsigned int ifindex;
|
||||
|
||||
ifindex = ll_name_to_index(dev);
|
||||
if (!ifindex)
|
||||
return -1;
|
||||
|
||||
addattr32(n, maxlen, MDBE_ATTR_IFINDEX, ifindex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdb_modify(int cmd, int flags, int argc, char **argv)
|
||||
{
|
||||
struct {
|
||||
@ -583,7 +693,8 @@ static int mdb_modify(int cmd, int flags, int argc, char **argv)
|
||||
.bpm.family = PF_BRIDGE,
|
||||
};
|
||||
char *d = NULL, *p = NULL, *grp = NULL, *src = NULL, *mode = NULL;
|
||||
char *src_list = NULL, *proto = NULL;
|
||||
char *dst_port = NULL, *vni = NULL, *src_vni = NULL, *via = NULL;
|
||||
char *src_list = NULL, *proto = NULL, *dst = NULL;
|
||||
struct br_mdb_entry entry = {};
|
||||
bool set_attrs = false;
|
||||
short vid = 0;
|
||||
@ -622,6 +733,26 @@ static int mdb_modify(int cmd, int flags, int argc, char **argv)
|
||||
NEXT_ARG();
|
||||
proto = *argv;
|
||||
set_attrs = true;
|
||||
} else if (strcmp(*argv, "dst") == 0) {
|
||||
NEXT_ARG();
|
||||
dst = *argv;
|
||||
set_attrs = true;
|
||||
} else if (strcmp(*argv, "dst_port") == 0) {
|
||||
NEXT_ARG();
|
||||
dst_port = *argv;
|
||||
set_attrs = true;
|
||||
} else if (strcmp(*argv, "vni") == 0) {
|
||||
NEXT_ARG();
|
||||
vni = *argv;
|
||||
set_attrs = true;
|
||||
} else if (strcmp(*argv, "src_vni") == 0) {
|
||||
NEXT_ARG();
|
||||
src_vni = *argv;
|
||||
set_attrs = true;
|
||||
} else if (strcmp(*argv, "via") == 0) {
|
||||
NEXT_ARG();
|
||||
via = *argv;
|
||||
set_attrs = true;
|
||||
} else {
|
||||
if (matches(*argv, "help") == 0)
|
||||
usage();
|
||||
@ -675,6 +806,34 @@ static int mdb_modify(int cmd, int flags, int argc, char **argv)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dst && mdb_parse_dst(&req.n, sizeof(req), dst)) {
|
||||
fprintf(stderr, "Invalid underlay destination address \"%s\"\n",
|
||||
dst);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dst_port && mdb_parse_dst_port(&req.n, sizeof(req),
|
||||
dst_port)) {
|
||||
fprintf(stderr, "Invalid destination port \"%s\"\n", dst_port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vni && mdb_parse_vni(&req.n, sizeof(req), vni,
|
||||
MDBE_ATTR_VNI)) {
|
||||
fprintf(stderr, "Invalid destination VNI \"%s\"\n",
|
||||
vni);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (src_vni && mdb_parse_vni(&req.n, sizeof(req), src_vni,
|
||||
MDBE_ATTR_SRC_VNI)) {
|
||||
fprintf(stderr, "Invalid source VNI \"%s\"\n", src_vni);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (via && mdb_parse_dev(&req.n, sizeof(req), via))
|
||||
return nodev(via);
|
||||
|
||||
addattr_nest_end(&req.n, nest);
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,7 @@ static void usage(void)
|
||||
" bridge vlan { set } vid VLAN_ID dev DEV [ state STP_STATE ]\n"
|
||||
" [ mcast_router MULTICAST_ROUTER ]\n"
|
||||
" [ mcast_max_groups MAX_GROUPS ]\n"
|
||||
" [ neigh_suppress {on | off} ]\n"
|
||||
" bridge vlan { show } [ dev DEV ] [ vid VLAN_ID ]\n"
|
||||
" bridge vlan { tunnelshow } [ dev DEV ] [ vid VLAN_ID ]\n"
|
||||
" bridge vlan global { set } vid VLAN_ID dev DEV\n"
|
||||
@ -354,6 +355,18 @@ static int vlan_option_set(int argc, char **argv)
|
||||
addattr32(&req.n, sizeof(req),
|
||||
BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS,
|
||||
max_groups);
|
||||
} else if (strcmp(*argv, "neigh_suppress") == 0) {
|
||||
bool neigh_suppress;
|
||||
int ret;
|
||||
|
||||
NEXT_ARG();
|
||||
neigh_suppress = parse_on_off("neigh_suppress", *argv,
|
||||
&ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
addattr8(&req.n, sizeof(req),
|
||||
BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS,
|
||||
neigh_suppress);
|
||||
} else {
|
||||
if (matches(*argv, "help") == 0)
|
||||
NEXT_ARG();
|
||||
@ -1041,6 +1054,11 @@ static void print_vlan_opts(struct rtattr *a, int ifindex)
|
||||
print_uint(PRINT_ANY, "mcast_max_groups", "mcast_max_groups %u ",
|
||||
rta_getattr_u32(vattr));
|
||||
}
|
||||
if (vtb[BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS]) {
|
||||
vattr = vtb[BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS];
|
||||
print_on_off(PRINT_ANY, "neigh_suppress", "neigh_suppress %s ",
|
||||
rta_getattr_u8(vattr));
|
||||
}
|
||||
print_nl();
|
||||
if (show_stats)
|
||||
__print_one_vlan_stats(&vstats);
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <asm/types.h>
|
||||
|
||||
const char *rtnl_rtprot_n2a(int id, char *buf, int len);
|
||||
const char *rtnl_addrprot_n2a(int id, char *buf, int len);
|
||||
const char *rtnl_rtscope_n2a(int id, char *buf, int len);
|
||||
const char *rtnl_rttable_n2a(__u32 id, char *buf, int len);
|
||||
const char *rtnl_rtrealm_n2a(int id, char *buf, int len);
|
||||
@ -13,6 +14,7 @@ const char *rtnl_dsfield_get_name(int id);
|
||||
const char *rtnl_group_n2a(int id, char *buf, int len);
|
||||
|
||||
int rtnl_rtprot_a2n(__u32 *id, const char *arg);
|
||||
int rtnl_addrprot_a2n(__u32 *id, const char *arg);
|
||||
int rtnl_rtscope_a2n(__u32 *id, const char *arg);
|
||||
int rtnl_rttable_a2n(__u32 *id, const char *arg);
|
||||
int rtnl_rtrealm_a2n(__u32 *id, const char *arg);
|
||||
|
@ -986,6 +986,7 @@ enum bpf_prog_type {
|
||||
BPF_PROG_TYPE_LSM,
|
||||
BPF_PROG_TYPE_SK_LOOKUP,
|
||||
BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */
|
||||
BPF_PROG_TYPE_NETFILTER,
|
||||
};
|
||||
|
||||
enum bpf_attach_type {
|
||||
@ -1033,6 +1034,7 @@ enum bpf_attach_type {
|
||||
BPF_PERF_EVENT,
|
||||
BPF_TRACE_KPROBE_MULTI,
|
||||
BPF_LSM_CGROUP,
|
||||
BPF_STRUCT_OPS,
|
||||
__MAX_BPF_ATTACH_TYPE
|
||||
};
|
||||
|
||||
@ -1049,6 +1051,7 @@ enum bpf_link_type {
|
||||
BPF_LINK_TYPE_PERF_EVENT = 7,
|
||||
BPF_LINK_TYPE_KPROBE_MULTI = 8,
|
||||
BPF_LINK_TYPE_STRUCT_OPS = 9,
|
||||
BPF_LINK_TYPE_NETFILTER = 10,
|
||||
|
||||
MAX_BPF_LINK_TYPE,
|
||||
};
|
||||
@ -1108,7 +1111,7 @@ enum bpf_link_type {
|
||||
*/
|
||||
#define BPF_F_STRICT_ALIGNMENT (1U << 0)
|
||||
|
||||
/* If BPF_F_ANY_ALIGNMENT is used in BPF_PROF_LOAD command, the
|
||||
/* If BPF_F_ANY_ALIGNMENT is used in BPF_PROG_LOAD command, the
|
||||
* verifier will allow any alignment whatsoever. On platforms
|
||||
* with strict alignment requirements for loads ands stores (such
|
||||
* as sparc and mips) the verifier validates that all loads and
|
||||
@ -1266,6 +1269,9 @@ enum {
|
||||
|
||||
/* Create a map that is suitable to be an inner map with dynamic max entries */
|
||||
BPF_F_INNER_MAP = (1U << 12),
|
||||
|
||||
/* Create a map that will be registered/unregesitered by the backed bpf_link */
|
||||
BPF_F_LINK = (1U << 13),
|
||||
};
|
||||
|
||||
/* Flags for BPF_PROG_QUERY. */
|
||||
@ -1403,6 +1409,11 @@ union bpf_attr {
|
||||
__aligned_u64 fd_array; /* array of FDs */
|
||||
__aligned_u64 core_relos;
|
||||
__u32 core_relo_rec_size; /* sizeof(struct bpf_core_relo) */
|
||||
/* output: actual total log contents size (including termintaing zero).
|
||||
* It could be both larger than original log_size (if log was
|
||||
* truncated), or smaller (if log buffer wasn't filled completely).
|
||||
*/
|
||||
__u32 log_true_size;
|
||||
};
|
||||
|
||||
struct { /* anonymous struct used by BPF_OBJ_* commands */
|
||||
@ -1488,6 +1499,11 @@ union bpf_attr {
|
||||
__u32 btf_size;
|
||||
__u32 btf_log_size;
|
||||
__u32 btf_log_level;
|
||||
/* output: actual total log contents size (including termintaing zero).
|
||||
* It could be both larger than original log_size (if log was
|
||||
* truncated), or smaller (if log buffer wasn't filled completely).
|
||||
*/
|
||||
__u32 btf_log_true_size;
|
||||
};
|
||||
|
||||
struct {
|
||||
@ -1507,7 +1523,10 @@ union bpf_attr {
|
||||
} task_fd_query;
|
||||
|
||||
struct { /* struct used by BPF_LINK_CREATE command */
|
||||
__u32 prog_fd; /* eBPF program to attach */
|
||||
union {
|
||||
__u32 prog_fd; /* eBPF program to attach */
|
||||
__u32 map_fd; /* struct_ops to attach */
|
||||
};
|
||||
union {
|
||||
__u32 target_fd; /* object to attach to */
|
||||
__u32 target_ifindex; /* target ifindex */
|
||||
@ -1543,17 +1562,34 @@ union bpf_attr {
|
||||
*/
|
||||
__u64 cookie;
|
||||
} tracing;
|
||||
struct {
|
||||
__u32 pf;
|
||||
__u32 hooknum;
|
||||
__s32 priority;
|
||||
__u32 flags;
|
||||
} netfilter;
|
||||
};
|
||||
} link_create;
|
||||
|
||||
struct { /* struct used by BPF_LINK_UPDATE command */
|
||||
__u32 link_fd; /* link fd */
|
||||
/* new program fd to update link with */
|
||||
__u32 new_prog_fd;
|
||||
union {
|
||||
/* new program fd to update link with */
|
||||
__u32 new_prog_fd;
|
||||
/* new struct_ops map fd to update link with */
|
||||
__u32 new_map_fd;
|
||||
};
|
||||
__u32 flags; /* extra flags */
|
||||
/* expected link's program fd; is specified only if
|
||||
* BPF_F_REPLACE flag is set in flags */
|
||||
__u32 old_prog_fd;
|
||||
union {
|
||||
/* expected link's program fd; is specified only if
|
||||
* BPF_F_REPLACE flag is set in flags.
|
||||
*/
|
||||
__u32 old_prog_fd;
|
||||
/* expected link's map fd; is specified only
|
||||
* if BPF_F_REPLACE flag is set.
|
||||
*/
|
||||
__u32 old_map_fd;
|
||||
};
|
||||
} link_update;
|
||||
|
||||
struct {
|
||||
@ -1647,17 +1683,17 @@ union bpf_attr {
|
||||
* Description
|
||||
* This helper is a "printk()-like" facility for debugging. It
|
||||
* prints a message defined by format *fmt* (of size *fmt_size*)
|
||||
* to file *\/sys/kernel/debug/tracing/trace* from DebugFS, if
|
||||
* to file *\/sys/kernel/tracing/trace* from TraceFS, if
|
||||
* available. It can take up to three additional **u64**
|
||||
* arguments (as an eBPF helpers, the total number of arguments is
|
||||
* limited to five).
|
||||
*
|
||||
* Each time the helper is called, it appends a line to the trace.
|
||||
* Lines are discarded while *\/sys/kernel/debug/tracing/trace* is
|
||||
* open, use *\/sys/kernel/debug/tracing/trace_pipe* to avoid this.
|
||||
* Lines are discarded while *\/sys/kernel/tracing/trace* is
|
||||
* open, use *\/sys/kernel/tracing/trace_pipe* to avoid this.
|
||||
* The format of the trace is customizable, and the exact output
|
||||
* one will get depends on the options set in
|
||||
* *\/sys/kernel/debug/tracing/trace_options* (see also the
|
||||
* *\/sys/kernel/tracing/trace_options* (see also the
|
||||
* *README* file under the same directory). However, it usually
|
||||
* defaults to something like:
|
||||
*
|
||||
@ -4969,6 +5005,12 @@ union bpf_attr {
|
||||
* different maps if key/value layout matches across maps.
|
||||
* Every bpf_timer_set_callback() can have different callback_fn.
|
||||
*
|
||||
* *flags* can be one of:
|
||||
*
|
||||
* **BPF_F_TIMER_ABS**
|
||||
* Start the timer in absolute expire value instead of the
|
||||
* default relative one.
|
||||
*
|
||||
* Return
|
||||
* 0 on success.
|
||||
* **-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier
|
||||
@ -5325,11 +5367,22 @@ union bpf_attr {
|
||||
* Description
|
||||
* Write *len* bytes from *src* into *dst*, starting from *offset*
|
||||
* into *dst*.
|
||||
* *flags* is currently unused.
|
||||
*
|
||||
* *flags* must be 0 except for skb-type dynptrs.
|
||||
*
|
||||
* For skb-type dynptrs:
|
||||
* * All data slices of the dynptr are automatically
|
||||
* invalidated after **bpf_dynptr_write**\ (). This is
|
||||
* because writing may pull the skb and change the
|
||||
* underlying packet buffer.
|
||||
*
|
||||
* * For *flags*, please see the flags accepted by
|
||||
* **bpf_skb_store_bytes**\ ().
|
||||
* Return
|
||||
* 0 on success, -E2BIG if *offset* + *len* exceeds the length
|
||||
* of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst*
|
||||
* is a read-only dynptr or if *flags* is not 0.
|
||||
* is a read-only dynptr or if *flags* is not correct. For skb-type dynptrs,
|
||||
* other errors correspond to errors returned by **bpf_skb_store_bytes**\ ().
|
||||
*
|
||||
* void *bpf_dynptr_data(const struct bpf_dynptr *ptr, u32 offset, u32 len)
|
||||
* Description
|
||||
@ -5337,6 +5390,9 @@ union bpf_attr {
|
||||
*
|
||||
* *len* must be a statically known value. The returned data slice
|
||||
* is invalidated whenever the dynptr is invalidated.
|
||||
*
|
||||
* skb and xdp type dynptrs may not use bpf_dynptr_data. They should
|
||||
* instead use bpf_dynptr_slice and bpf_dynptr_slice_rdwr.
|
||||
* Return
|
||||
* Pointer to the underlying dynptr data, NULL if the dynptr is
|
||||
* read-only, if the dynptr is invalid, or if the offset and length
|
||||
@ -6359,6 +6415,15 @@ struct bpf_link_info {
|
||||
struct {
|
||||
__u32 ifindex;
|
||||
} xdp;
|
||||
struct {
|
||||
__u32 map_id;
|
||||
} struct_ops;
|
||||
struct {
|
||||
__u32 pf;
|
||||
__u32 hooknum;
|
||||
__s32 priority;
|
||||
__u32 flags;
|
||||
} netfilter;
|
||||
};
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
@ -6934,6 +6999,10 @@ struct bpf_rb_node {
|
||||
__u64 :64;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
struct bpf_refcount {
|
||||
__u32 :32;
|
||||
} __attribute__((aligned(4)));
|
||||
|
||||
struct bpf_sysctl {
|
||||
__u32 write; /* Sysctl is being read (= 0) or written (= 1).
|
||||
* Allows 1,2,4-byte read, but no write.
|
||||
@ -7083,4 +7152,21 @@ struct bpf_core_relo {
|
||||
enum bpf_core_relo_kind kind;
|
||||
};
|
||||
|
||||
/*
|
||||
* Flags to control bpf_timer_start() behaviour.
|
||||
* - BPF_F_TIMER_ABS: Timeout passed is absolute time, by default it is
|
||||
* relative to current time.
|
||||
*/
|
||||
enum {
|
||||
BPF_F_TIMER_ABS = (1ULL << 0),
|
||||
};
|
||||
|
||||
/* BPF numbers iterator state */
|
||||
struct bpf_iter_num {
|
||||
/* opaque iterator state; having __u64 here allows to preserve correct
|
||||
* alignment requirements in vmlinux.h, generated from BTF
|
||||
*/
|
||||
__u64 __opaque[1];
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
#endif /* __LINUX_BPF_H__ */
|
||||
|
@ -525,6 +525,7 @@ enum {
|
||||
BRIDGE_VLANDB_ENTRY_MCAST_ROUTER,
|
||||
BRIDGE_VLANDB_ENTRY_MCAST_N_GROUPS,
|
||||
BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS,
|
||||
BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS,
|
||||
__BRIDGE_VLANDB_ENTRY_MAX,
|
||||
};
|
||||
#define BRIDGE_VLANDB_ENTRY_MAX (__BRIDGE_VLANDB_ENTRY_MAX - 1)
|
||||
@ -633,6 +634,11 @@ enum {
|
||||
MDBA_MDB_EATTR_GROUP_MODE,
|
||||
MDBA_MDB_EATTR_SOURCE,
|
||||
MDBA_MDB_EATTR_RTPROT,
|
||||
MDBA_MDB_EATTR_DST,
|
||||
MDBA_MDB_EATTR_DST_PORT,
|
||||
MDBA_MDB_EATTR_VNI,
|
||||
MDBA_MDB_EATTR_IFINDEX,
|
||||
MDBA_MDB_EATTR_SRC_VNI,
|
||||
__MDBA_MDB_EATTR_MAX
|
||||
};
|
||||
#define MDBA_MDB_EATTR_MAX (__MDBA_MDB_EATTR_MAX - 1)
|
||||
@ -728,6 +734,11 @@ enum {
|
||||
MDBE_ATTR_SRC_LIST,
|
||||
MDBE_ATTR_GROUP_MODE,
|
||||
MDBE_ATTR_RTPROT,
|
||||
MDBE_ATTR_DST,
|
||||
MDBE_ATTR_DST_PORT,
|
||||
MDBE_ATTR_VNI,
|
||||
MDBE_ATTR_IFINDEX,
|
||||
MDBE_ATTR_SRC_VNI,
|
||||
__MDBE_ATTR_MAX,
|
||||
};
|
||||
#define MDBE_ATTR_MAX (__MDBE_ATTR_MAX - 1)
|
||||
|
@ -567,6 +567,7 @@ enum {
|
||||
IFLA_BRPORT_MAB,
|
||||
IFLA_BRPORT_MCAST_N_GROUPS,
|
||||
IFLA_BRPORT_MCAST_MAX_GROUPS,
|
||||
IFLA_BRPORT_NEIGH_VLAN_SUPPRESS,
|
||||
__IFLA_BRPORT_MAX
|
||||
};
|
||||
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
|
||||
@ -633,6 +634,7 @@ enum {
|
||||
IFLA_MACVLAN_MACADDR_COUNT,
|
||||
IFLA_MACVLAN_BC_QUEUE_LEN,
|
||||
IFLA_MACVLAN_BC_QUEUE_LEN_USED,
|
||||
IFLA_MACVLAN_BC_CUTOFF,
|
||||
__IFLA_MACVLAN_MAX,
|
||||
};
|
||||
|
||||
|
@ -59,6 +59,7 @@ struct sockaddr_ll {
|
||||
#define PACKET_ROLLOVER_STATS 21
|
||||
#define PACKET_FANOUT_DATA 22
|
||||
#define PACKET_IGNORE_OUTGOING 23
|
||||
#define PACKET_VNET_HDR_SZ 24
|
||||
|
||||
#define PACKET_FANOUT_HASH 0
|
||||
#define PACKET_FANOUT_LB 1
|
||||
|
@ -719,6 +719,11 @@ enum {
|
||||
|
||||
#define __TC_MQPRIO_SHAPER_MAX (__TC_MQPRIO_SHAPER_MAX - 1)
|
||||
|
||||
enum {
|
||||
TC_FP_EXPRESS = 1,
|
||||
TC_FP_PREEMPTIBLE = 2,
|
||||
};
|
||||
|
||||
struct tc_mqprio_qopt {
|
||||
__u8 num_tc;
|
||||
__u8 prio_tc_map[TC_QOPT_BITMASK + 1];
|
||||
@ -732,12 +737,23 @@ struct tc_mqprio_qopt {
|
||||
#define TC_MQPRIO_F_MIN_RATE 0x4
|
||||
#define TC_MQPRIO_F_MAX_RATE 0x8
|
||||
|
||||
enum {
|
||||
TCA_MQPRIO_TC_ENTRY_UNSPEC,
|
||||
TCA_MQPRIO_TC_ENTRY_INDEX, /* u32 */
|
||||
TCA_MQPRIO_TC_ENTRY_FP, /* u32 */
|
||||
|
||||
/* add new constants above here */
|
||||
__TCA_MQPRIO_TC_ENTRY_CNT,
|
||||
TCA_MQPRIO_TC_ENTRY_MAX = (__TCA_MQPRIO_TC_ENTRY_CNT - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
TCA_MQPRIO_UNSPEC,
|
||||
TCA_MQPRIO_MODE,
|
||||
TCA_MQPRIO_SHAPER,
|
||||
TCA_MQPRIO_MIN_RATE64,
|
||||
TCA_MQPRIO_MAX_RATE64,
|
||||
TCA_MQPRIO_TC_ENTRY,
|
||||
__TCA_MQPRIO_MAX,
|
||||
};
|
||||
|
||||
@ -1236,6 +1252,7 @@ enum {
|
||||
TCA_TAPRIO_TC_ENTRY_UNSPEC,
|
||||
TCA_TAPRIO_TC_ENTRY_INDEX, /* u32 */
|
||||
TCA_TAPRIO_TC_ENTRY_MAX_SDU, /* u32 */
|
||||
TCA_TAPRIO_TC_ENTRY_FP, /* u32 */
|
||||
|
||||
/* add new constants above here */
|
||||
__TCA_TAPRIO_TC_ENTRY_CNT,
|
||||
|
@ -1205,7 +1205,9 @@ enum sctp_sched_type {
|
||||
SCTP_SS_DEFAULT = SCTP_SS_FCFS,
|
||||
SCTP_SS_PRIO,
|
||||
SCTP_SS_RR,
|
||||
SCTP_SS_MAX = SCTP_SS_RR
|
||||
SCTP_SS_FC,
|
||||
SCTP_SS_WFQ,
|
||||
SCTP_SS_MAX = SCTP_SS_WFQ
|
||||
};
|
||||
|
||||
/* Probe Interval socket option */
|
||||
|
@ -34,6 +34,7 @@ enum {
|
||||
*/
|
||||
TCA_TUNNEL_KEY_ENC_TOS, /* u8 */
|
||||
TCA_TUNNEL_KEY_ENC_TTL, /* u8 */
|
||||
TCA_TUNNEL_KEY_NO_FRAG, /* flag */
|
||||
__TCA_TUNNEL_KEY_MAX,
|
||||
};
|
||||
|
||||
|
@ -61,6 +61,7 @@
|
||||
#define VIRTIO_NET_F_GUEST_USO6 55 /* Guest can handle USOv6 in. */
|
||||
#define VIRTIO_NET_F_HOST_USO 56 /* Host can handle USO in. */
|
||||
#define VIRTIO_NET_F_HASH_REPORT 57 /* Supports hash report */
|
||||
#define VIRTIO_NET_F_GUEST_HDRLEN 59 /* Guest provides the exact hdr_len value. */
|
||||
#define VIRTIO_NET_F_RSS 60 /* Supports RSS RX steering */
|
||||
#define VIRTIO_NET_F_RSC_EXT 61 /* extended coalescing info */
|
||||
#define VIRTIO_NET_F_STANDBY 62 /* Act as standby for another device
|
||||
|
@ -284,6 +284,14 @@ unsigned int print_name_and_link(const char *fmt,
|
||||
_min1 < _min2 ? _min1 : _min2; })
|
||||
#endif
|
||||
|
||||
#ifndef max
|
||||
# define max(x, y) ({ \
|
||||
typeof(x) _max1 = (x); \
|
||||
typeof(y) _max2 = (y); \
|
||||
(void) (&_max1 == &_max2); \
|
||||
_max1 < _max2 ? _max2 : _max1; })
|
||||
#endif
|
||||
|
||||
#ifndef __check_format_string
|
||||
# define __check_format_string(pos_str, pos_args) \
|
||||
__attribute__ ((format (printf, (pos_str), (pos_args))))
|
||||
|
@ -28,6 +28,8 @@ struct link_filter {
|
||||
char *kind;
|
||||
char *slave_kind;
|
||||
int target_nsid;
|
||||
bool have_proto;
|
||||
int proto;
|
||||
};
|
||||
|
||||
const char *get_ip_lib_dir(void);
|
||||
|
@ -57,11 +57,13 @@ static void usage(void)
|
||||
" ip address [ show [ dev IFNAME ] [ scope SCOPE-ID ] [ master DEVICE ]\n"
|
||||
" [ nomaster ]\n"
|
||||
" [ type TYPE ] [ to PREFIX ] [ FLAG-LIST ]\n"
|
||||
" [ label LABEL ] [up] [ vrf NAME ] ]\n"
|
||||
" [ label LABEL ] [up] [ vrf NAME ]\n"
|
||||
" [ proto ADDRPROTO ] ]\n"
|
||||
" ip address {showdump|restore}\n"
|
||||
"IFADDR := PREFIX | ADDR peer PREFIX\n"
|
||||
" [ broadcast ADDR ] [ anycast ADDR ]\n"
|
||||
" [ label IFNAME ] [ scope SCOPE-ID ] [ metric METRIC ]\n"
|
||||
" [ proto ADDRPROTO ]\n"
|
||||
"SCOPE-ID := [ host | link | global | NUMBER ]\n"
|
||||
"FLAG-LIST := [ FLAG-LIST ] FLAG\n"
|
||||
"FLAG := [ permanent | dynamic | secondary | primary |\n"
|
||||
@ -70,7 +72,9 @@ static void usage(void)
|
||||
"CONFFLAG-LIST := [ CONFFLAG-LIST ] CONFFLAG\n"
|
||||
"CONFFLAG := [ home | nodad | mngtmpaddr | noprefixroute | autojoin ]\n"
|
||||
"LIFETIME := [ valid_lft LFT ] [ preferred_lft LFT ]\n"
|
||||
"LFT := forever | SECONDS\n");
|
||||
"LFT := forever | SECONDS\n"
|
||||
"ADDRPROTO := [ NAME | NUMBER ]\n"
|
||||
);
|
||||
iplink_types_usage();
|
||||
|
||||
exit(-1);
|
||||
@ -1568,6 +1572,9 @@ int print_addrinfo(struct nlmsghdr *n, void *arg)
|
||||
|
||||
if (filter.family && filter.family != ifa->ifa_family)
|
||||
return 0;
|
||||
if (filter.have_proto && rta_tb[IFA_PROTO] &&
|
||||
filter.proto != rta_getattr_u8(rta_tb[IFA_PROTO]))
|
||||
return 0;
|
||||
|
||||
if (ifa_label_match_rta(ifa->ifa_index, rta_tb[IFA_LABEL]))
|
||||
return 0;
|
||||
@ -1675,6 +1682,14 @@ int print_addrinfo(struct nlmsghdr *n, void *arg)
|
||||
|
||||
print_ifa_flags(fp, ifa, ifa_flags);
|
||||
|
||||
if (rta_tb[IFA_PROTO]) {
|
||||
__u8 proto = rta_getattr_u8(rta_tb[IFA_PROTO]);
|
||||
|
||||
if (proto || is_json_context())
|
||||
print_string(PRINT_ANY, "protocol", "proto %s ",
|
||||
rtnl_addrprot_n2a(proto, b1, sizeof(b1)));
|
||||
}
|
||||
|
||||
if (rta_tb[IFA_LABEL])
|
||||
print_string(PRINT_ANY,
|
||||
"label",
|
||||
@ -2196,6 +2211,14 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
|
||||
} else {
|
||||
filter.kind = *argv;
|
||||
}
|
||||
} else if (strcmp(*argv, "proto") == 0) {
|
||||
__u8 proto;
|
||||
|
||||
NEXT_ARG();
|
||||
if (get_u8(&proto, *argv, 0))
|
||||
invarg("\"proto\" value is invalid\n", *argv);
|
||||
filter.have_proto = true;
|
||||
filter.proto = proto;
|
||||
} else {
|
||||
if (strcmp(*argv, "dev") == 0)
|
||||
NEXT_ARG();
|
||||
@ -2520,6 +2543,13 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
|
||||
} else {
|
||||
ifa_flags |= flag_data->mask;
|
||||
}
|
||||
} else if (strcmp(*argv, "proto") == 0) {
|
||||
__u8 proto;
|
||||
|
||||
NEXT_ARG();
|
||||
if (get_u8(&proto, *argv, 0))
|
||||
invarg("\"proto\" value is invalid\n", *argv);
|
||||
addattr8(&req.n, sizeof(req), IFA_PROTO, proto);
|
||||
} else {
|
||||
if (strcmp(*argv, "local") == 0)
|
||||
NEXT_ARG();
|
||||
|
@ -37,6 +37,7 @@ static void print_explain(FILE *f)
|
||||
" [ mcast_to_unicast {on | off} ]\n"
|
||||
" [ group_fwd_mask MASK ]\n"
|
||||
" [ neigh_suppress {on | off} ]\n"
|
||||
" [ neigh_vlan_suppress {on | off} ]\n"
|
||||
" [ vlan_tunnel {on | off} ]\n"
|
||||
" [ isolated {on | off} ]\n"
|
||||
" [ locked {on | off} ]\n"
|
||||
@ -261,6 +262,11 @@ static void bridge_slave_print_opt(struct link_util *lu, FILE *f,
|
||||
print_on_off(PRINT_ANY, "neigh_suppress", "neigh_suppress %s ",
|
||||
rta_getattr_u8(tb[IFLA_BRPORT_NEIGH_SUPPRESS]));
|
||||
|
||||
if (tb[IFLA_BRPORT_NEIGH_VLAN_SUPPRESS])
|
||||
print_on_off(PRINT_ANY, "neigh_vlan_suppress",
|
||||
"neigh_vlan_suppress %s ",
|
||||
rta_getattr_u8(tb[IFLA_BRPORT_NEIGH_VLAN_SUPPRESS]));
|
||||
|
||||
if (tb[IFLA_BRPORT_GROUP_FWD_MASK]) {
|
||||
char convbuf[256];
|
||||
__u16 fwd_mask;
|
||||
@ -393,6 +399,10 @@ static int bridge_slave_parse_opt(struct link_util *lu, int argc, char **argv,
|
||||
NEXT_ARG();
|
||||
bridge_slave_parse_on_off("neigh_suppress", *argv, n,
|
||||
IFLA_BRPORT_NEIGH_SUPPRESS);
|
||||
} else if (strcmp(*argv, "neigh_vlan_suppress") == 0) {
|
||||
NEXT_ARG();
|
||||
bridge_slave_parse_on_off("neigh_vlan_suppress", *argv,
|
||||
n, IFLA_BRPORT_NEIGH_VLAN_SUPPRESS);
|
||||
} else if (matches(*argv, "group_fwd_mask") == 0) {
|
||||
__u16 mask;
|
||||
|
||||
|
@ -26,13 +26,14 @@
|
||||
static void print_explain(struct link_util *lu, FILE *f)
|
||||
{
|
||||
fprintf(f,
|
||||
"Usage: ... %s mode MODE [flag MODE_FLAG] MODE_OPTS [bcqueuelen BC_QUEUE_LEN]\n"
|
||||
"Usage: ... %s mode MODE [flag MODE_FLAG] MODE_OPTS [bcqueuelen BC_QUEUE_LEN] [bclim BCLIM]\n"
|
||||
"\n"
|
||||
"MODE: private | vepa | bridge | passthru | source\n"
|
||||
"MODE_FLAG: null | nopromisc | nodst\n"
|
||||
"MODE_OPTS: for mode \"source\":\n"
|
||||
"\tmacaddr { { add | del } <macaddr> | set [ <macaddr> [ <macaddr> ... ] ] | flush }\n"
|
||||
"BC_QUEUE_LEN: Length of the rx queue for broadcast/multicast: [0-4294967295]\n",
|
||||
"BC_QUEUE_LEN: Length of the rx queue for broadcast/multicast: [0-4294967295]\n"
|
||||
"BCLIM: Threshold for broadcast queueing: 32-bit integer\n",
|
||||
lu->id
|
||||
);
|
||||
}
|
||||
@ -67,6 +68,12 @@ static int bc_queue_len_arg(const char *arg)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int bclim_arg(const char *arg)
|
||||
{
|
||||
fprintf(stderr, "Error: illegal value for \"bclim\": \"%s\"\n", arg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
{
|
||||
@ -168,6 +175,15 @@ static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv,
|
||||
return bc_queue_len_arg(*argv);
|
||||
}
|
||||
addattr32(n, 1024, IFLA_MACVLAN_BC_QUEUE_LEN, bc_queue_len);
|
||||
} else if (!strcmp(*argv, "bclim")) {
|
||||
__s32 bclim;
|
||||
NEXT_ARG();
|
||||
|
||||
if (get_s32(&bclim, *argv, 0)) {
|
||||
return bclim_arg(*argv);
|
||||
}
|
||||
addattr_l(n, 1024, IFLA_MACVLAN_BC_CUTOFF,
|
||||
&bclim, sizeof(bclim));
|
||||
} else if (matches(*argv, "help") == 0) {
|
||||
explain(lu);
|
||||
return -1;
|
||||
@ -245,6 +261,12 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]
|
||||
print_luint(PRINT_ANY, "usedbcqueuelen", "usedbcqueuelen %lu ", bc_queue_len);
|
||||
}
|
||||
|
||||
if (tb[IFLA_MACVLAN_BC_CUTOFF] &&
|
||||
RTA_PAYLOAD(tb[IFLA_MACVLAN_BC_CUTOFF]) >= sizeof(__s32)) {
|
||||
__s32 bclim = rta_getattr_s32(tb[IFLA_MACVLAN_BC_CUTOFF]);
|
||||
print_int(PRINT_ANY, "bclim", "bclim %d ", bclim);
|
||||
}
|
||||
|
||||
/* in source mode, there are more options to print */
|
||||
|
||||
if (mode != MACVLAN_MODE_SOURCE)
|
||||
|
@ -226,6 +226,68 @@ int rtnl_rtprot_a2n(__u32 *id, const char *arg)
|
||||
}
|
||||
|
||||
|
||||
static char *rtnl_addrprot_tab[256] = {
|
||||
[IFAPROT_UNSPEC] = "unspec",
|
||||
[IFAPROT_KERNEL_LO] = "kernel_lo",
|
||||
[IFAPROT_KERNEL_RA] = "kernel_ra",
|
||||
[IFAPROT_KERNEL_LL] = "kernel_ll",
|
||||
};
|
||||
static bool rtnl_addrprot_tab_initialized;
|
||||
|
||||
static void rtnl_addrprot_initialize(void)
|
||||
{
|
||||
rtnl_tab_initialize(CONFDIR "/rt_addrprotos",
|
||||
rtnl_addrprot_tab,
|
||||
ARRAY_SIZE(rtnl_addrprot_tab));
|
||||
rtnl_addrprot_tab_initialized = true;
|
||||
}
|
||||
|
||||
const char *rtnl_addrprot_n2a(int id, char *buf, int len)
|
||||
{
|
||||
if (id < 0 || id >= 256 || numeric)
|
||||
goto numeric;
|
||||
if (!rtnl_addrprot_tab_initialized)
|
||||
rtnl_addrprot_initialize();
|
||||
if (rtnl_addrprot_tab[id])
|
||||
return rtnl_addrprot_tab[id];
|
||||
numeric:
|
||||
snprintf(buf, len, "%#x", id);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int rtnl_addrprot_a2n(__u32 *id, const char *arg)
|
||||
{
|
||||
static char *cache;
|
||||
static unsigned long res;
|
||||
char *end;
|
||||
int i;
|
||||
|
||||
if (cache && strcmp(cache, arg) == 0) {
|
||||
*id = res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!rtnl_addrprot_tab_initialized)
|
||||
rtnl_addrprot_initialize();
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (rtnl_addrprot_tab[i] &&
|
||||
strcmp(rtnl_addrprot_tab[i], arg) == 0) {
|
||||
cache = rtnl_addrprot_tab[i];
|
||||
res = i;
|
||||
*id = res;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
res = strtoul(arg, &end, 0);
|
||||
if (!end || end == arg || *end || res > 255)
|
||||
return -1;
|
||||
*id = res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static char *rtnl_rtscope_tab[256] = {
|
||||
[RT_SCOPE_UNIVERSE] = "global",
|
||||
[RT_SCOPE_NOWHERE] = "nowhere",
|
||||
|
@ -53,6 +53,7 @@ bridge \- show / manipulate bridge addresses and devices
|
||||
.IR MULTICAST_ROUTER " ] ["
|
||||
.BR mcast_to_unicast " { " on " | " off " } ] [ "
|
||||
.BR neigh_suppress " { " on " | " off " } ] [ "
|
||||
.BR neigh_vlan_suppress " { " on " | " off " } ] [ "
|
||||
.BR vlan_tunnel " { " on " | " off " } ] [ "
|
||||
.BR isolated " { " on " | " off " } ] [ "
|
||||
.BR locked " { " on " | " off " } ] [ "
|
||||
@ -145,7 +146,17 @@ bridge \- show / manipulate bridge addresses and devices
|
||||
.B source_list
|
||||
.IR SOURCE_LIST " ] [ "
|
||||
.B proto
|
||||
.IR PROTO " ]
|
||||
.IR PROTO " ] [ "
|
||||
.B dst
|
||||
.IR IPADDR " ] [ "
|
||||
.B dst_port
|
||||
.IR DST_PORT " ] [ "
|
||||
.B vni
|
||||
.IR VNI " ] [ "
|
||||
.B src_vni
|
||||
.IR SRC_VNI " ] [ "
|
||||
.B via
|
||||
.IR DEV " ]
|
||||
|
||||
.ti -8
|
||||
.BR "bridge mdb show" " [ "
|
||||
@ -174,7 +185,8 @@ bridge \- show / manipulate bridge addresses and devices
|
||||
.B mcast_max_groups
|
||||
.IR MAX_GROUPS " ] [ "
|
||||
.B mcast_router
|
||||
.IR MULTICAST_ROUTER " ]"
|
||||
.IR MULTICAST_ROUTER " ] [ "
|
||||
.BR neigh_suppress " { " on " | " off " } ]"
|
||||
|
||||
.ti -8
|
||||
.BR "bridge vlan" " [ " show " | " tunnelshow " ] [ "
|
||||
@ -579,6 +591,13 @@ only deliver reports to STAs running a multicast router.
|
||||
Controls whether neigh discovery (arp and nd) proxy and suppression is
|
||||
enabled on the port. By default this flag is off.
|
||||
|
||||
.TP
|
||||
.BR "neigh_vlan_suppress on " or " neigh_vlan_suppress off "
|
||||
Controls whether per-VLAN neigh discovery (arp and nd) proxy and suppression is
|
||||
enabled on the port. When on, the \fBbridge link\fR option \fBneigh_suppress\fR
|
||||
has no effect and the per-VLAN state is set using the \fBbridge vlan\fR option
|
||||
\fBneigh_suppress\fR. By default this flag is off.
|
||||
|
||||
.TP
|
||||
.BR "vlan_tunnel on " or " vlan_tunnel off "
|
||||
Controls whether vlan to tunnel mapping is enabled on the port. By
|
||||
@ -969,6 +988,46 @@ then
|
||||
.B static
|
||||
is assumed.
|
||||
|
||||
.in -8
|
||||
The next command line parameters apply only
|
||||
when the specified device
|
||||
.I DEV
|
||||
is of type VXLAN.
|
||||
|
||||
.TP
|
||||
.BI dst " IPADDR"
|
||||
the IP address of the destination
|
||||
VXLAN tunnel endpoint where the multicast receivers reside.
|
||||
|
||||
.TP
|
||||
.BI dst_port " DST_PORT"
|
||||
the UDP destination port number to use to connect to the remote VXLAN tunnel
|
||||
endpoint. If omitted, the value specified at VXLAN device creation will be
|
||||
used.
|
||||
|
||||
.TP
|
||||
.BI vni " VNI"
|
||||
the VXLAN VNI Network Identifier to use to connect to the remote VXLAN tunnel
|
||||
endpoint. If omitted, the value specified at VXLAN device creation will be used
|
||||
or the source VNI when the VXLAN device is in external mode.
|
||||
|
||||
.TP
|
||||
.BI src_vni " SRC_VNI"
|
||||
the source VNI Network Identifier this entry belongs to. Used only when the
|
||||
VXLAN device is in external mode. If omitted, the value specified at VXLAN
|
||||
device creation will be used.
|
||||
|
||||
.TP
|
||||
.BI via " DEV"
|
||||
device name of the outgoing interface for the VXLAN device to reach the remote
|
||||
VXLAN tunnel endpoint.
|
||||
|
||||
.in -8
|
||||
The 0.0.0.0 and :: MDB entries are special catchall entries used to flood IPv4
|
||||
and IPv6 unregistered multicast packets, respectively. Therefore, when these
|
||||
entries are programmed, the catchall 00:00:00:00:00:00 FDB entry will only
|
||||
flood broadcast, unknown unicast and link-local multicast.
|
||||
|
||||
.in -8
|
||||
.SS bridge mdb delete - delete a multicast group database entry
|
||||
This command removes an existing mdb entry.
|
||||
@ -1154,6 +1213,14 @@ may be either
|
||||
enable multicast traffic forwarding. This mode is available only for ports.
|
||||
.sp
|
||||
|
||||
.TP
|
||||
.BR "neigh_suppress on " or " neigh_suppress off "
|
||||
Controls whether neigh discovery (arp and nd) proxy and suppression is enabled
|
||||
for a given VLAN on a given port. By default this flag is off.
|
||||
|
||||
Note that this option only takes effect when \fBbridge link\fR option
|
||||
\fBneigh_vlan_suppress\fR is enabled for a given port.
|
||||
|
||||
.SS bridge vlan show - list vlan configuration.
|
||||
|
||||
This command displays the current VLAN filter table.
|
||||
|
@ -50,7 +50,9 @@ ip-address \- protocol address management
|
||||
.B vrf
|
||||
.IR NAME " ] [ "
|
||||
.BR up " ] ["
|
||||
.BR nomaster " ] ]"
|
||||
.BR nomaster " ]"
|
||||
.B proto
|
||||
.IR ADDRPROTO " ] ]"
|
||||
|
||||
.ti -8
|
||||
.BR "ip address" " { " showdump " | " restore " }"
|
||||
@ -66,13 +68,19 @@ ip-address \- protocol address management
|
||||
.B label
|
||||
.IR LABEL " ] [ "
|
||||
.B scope
|
||||
.IR SCOPE-ID " ]"
|
||||
.IR SCOPE-ID " ] [ "
|
||||
.B proto
|
||||
.IR ADDRPROTO " ]"
|
||||
|
||||
.ti -8
|
||||
.IR SCOPE-ID " := "
|
||||
.RB "[ " host " | " link " | " global " | "
|
||||
.IR NUMBER " ]"
|
||||
|
||||
.ti -8
|
||||
.IR ADDRPROTO " := [ "
|
||||
.IR NAME " | " NUMBER " ]"
|
||||
|
||||
.ti -8
|
||||
.IR FLAG-LIST " := [ " FLAG-LIST " ] " FLAG
|
||||
|
||||
@ -288,6 +296,36 @@ flag when adding a multicast address enables similar functionality for
|
||||
Openvswitch VXLAN interfaces as well as other tunneling mechanisms that need to
|
||||
receive multicast traffic.
|
||||
|
||||
.TP
|
||||
.BI proto " ADDRPROTO"
|
||||
the protocol identifier of this route.
|
||||
.I ADDRPROTO
|
||||
may be a number or a string from the file
|
||||
.BR "/etc/iproute2/rt_addrprotos" .
|
||||
If the protocol ID is not given,
|
||||
|
||||
.B ip assumes protocol 0. Several protocol
|
||||
values have a fixed interpretation. Namely:
|
||||
|
||||
.in +8
|
||||
.B kernel_lo
|
||||
- The ::1 address that kernel installs on a loopback netdevice has this
|
||||
protocol value
|
||||
.sp
|
||||
|
||||
.B kernel_ra
|
||||
- IPv6 addresses installed in response to router advertisement messages
|
||||
.sp
|
||||
|
||||
.B kernel_ll
|
||||
- Link-local addresses have this protocol value
|
||||
.sp
|
||||
.in -8
|
||||
|
||||
.sp
|
||||
The rest of the values are not reserved and the administrator is free
|
||||
to assign (or not to assign) protocol tags.
|
||||
|
||||
.SS ip address delete - delete protocol address
|
||||
.B Arguments:
|
||||
coincide with the arguments of
|
||||
@ -400,6 +438,13 @@ inverse of
|
||||
This is an alias for
|
||||
.BR temporary " or " secondary .
|
||||
|
||||
.TP
|
||||
.BI proto " ADDRPROTO"
|
||||
Only show addresses with a given protocol, or those for which the kernel
|
||||
response did not include protocol. See the corresponding argument to
|
||||
.B ip addr add
|
||||
for details about address protocols.
|
||||
|
||||
.SS ip address flush - flush protocol addresses
|
||||
This command flushes the protocol addresses selected by some criteria.
|
||||
|
||||
|
@ -1486,6 +1486,7 @@ the following additional arguments are supported:
|
||||
.BR mode " { " private " | " vepa " | " bridge " | " passthru
|
||||
.RB " [ " nopromisc " ] | " source " [ " nodst " ] } "
|
||||
.RB " [ " bcqueuelen " { " LENGTH " } ] "
|
||||
.RB " [ " bclim " " LIMIT " ] "
|
||||
|
||||
.in +8
|
||||
.sp
|
||||
@ -1544,6 +1545,13 @@ will be the maximum length that any macvlan interface has requested.
|
||||
When listing device parameters both the bcqueuelen parameter
|
||||
as well as the actual used bcqueuelen are listed to better help
|
||||
the user understand the setting.
|
||||
|
||||
.BR bclim " " LIMIT
|
||||
- Set the threshold for broadcast queueing.
|
||||
.BR LIMIT " must be a 32-bit integer."
|
||||
Setting this to -1 disables broadcast queueing altogether. Otherwise
|
||||
a multicast address will be queued as broadcast if the number of devices
|
||||
using it is greater than the given value.
|
||||
.in -8
|
||||
|
||||
.TP
|
||||
@ -2509,6 +2517,8 @@ the following additional arguments are supported:
|
||||
] [
|
||||
.BR neigh_suppress " { " on " | " off " }"
|
||||
] [
|
||||
.BR neigh_vlan_suppress " { " on " | " off " }"
|
||||
] [
|
||||
.BR vlan_tunnel " { " on " | " off " }"
|
||||
] [
|
||||
.BR isolated " { " on " | " off " }"
|
||||
@ -2614,6 +2624,12 @@ this port).
|
||||
- controls whether neigh discovery (arp and nd) proxy and suppression
|
||||
is enabled on the port. By default this flag is off.
|
||||
|
||||
.BR neigh_vlan_suppress " { " on " | " off " }"
|
||||
- controls whether per-VLAN neigh discovery (arp and nd) proxy and suppression
|
||||
is enabled on the port. When on, the \fBbridge link\fR option
|
||||
\fBneigh_suppress\fR has no effect and the per-VLAN state is set using the
|
||||
\fBbridge vlan\fR option \fBneigh_suppress\fR. By default this flag is off.
|
||||
|
||||
.BR vlan_tunnel " { " on " | " off " }"
|
||||
- controls whether vlan to tunnel mapping is enabled on the port. By
|
||||
default this flag is off.
|
||||
@ -2711,6 +2727,9 @@ Update the broadcast/multicast queue length.
|
||||
[
|
||||
.BI bcqueuelen " LENGTH "
|
||||
]
|
||||
[
|
||||
.BI bclim " LIMIT "
|
||||
]
|
||||
|
||||
.in +8
|
||||
.BI bcqueuelen " LENGTH "
|
||||
@ -2724,6 +2743,13 @@ will be the maximum length that any macvlan interface has requested.
|
||||
When listing device parameters both the bcqueuelen parameter
|
||||
as well as the actual used bcqueuelen are listed to better help
|
||||
the user understand the setting.
|
||||
|
||||
.BI bclim " LIMIT "
|
||||
- Set the threshold for broadcast queueing.
|
||||
.IR LIMIT " must be a 32-bit integer."
|
||||
Setting this to -1 disables broadcast queueing altogether. Otherwise
|
||||
a multicast address will be queued as broadcast if the number of devices
|
||||
using it is greater than the given value.
|
||||
.in -8
|
||||
|
||||
.TP
|
||||
|
@ -30,9 +30,11 @@ dcb|bw_rlimit ]
|
||||
.B min_rate
|
||||
min_rate1 min_rate2 ... ] [
|
||||
.B max_rate
|
||||
max_rate1 max_rate2 ...
|
||||
.B ]
|
||||
|
||||
max_rate1 max_rate2 ... ]
|
||||
.ti +8
|
||||
[
|
||||
.B fp
|
||||
FP0 FP1 FP2 ... ]
|
||||
|
||||
.SH DESCRIPTION
|
||||
The MQPRIO qdisc is a simple queuing discipline that allows mapping
|
||||
@ -162,6 +164,34 @@ the
|
||||
argument is set to
|
||||
.B 'bw_rlimit'.
|
||||
|
||||
.TP
|
||||
fp
|
||||
Selects whether traffic classes are express (deliver packets via the eMAC) or
|
||||
preemptible (deliver packets via the pMAC), according to IEEE 802.1Q-2018
|
||||
clause 6.7.2 Frame preemption. Takes the form of an array (one element per
|
||||
traffic class) with values being
|
||||
.B 'E'
|
||||
(for express) or
|
||||
.B 'P'
|
||||
(for preemptible).
|
||||
|
||||
Multiple priorities which map to the same traffic class, as well as multiple
|
||||
TXQs which map to the same traffic class, must have the same FP attributes.
|
||||
To interpret the FP as an attribute per priority, the
|
||||
.B 'map'
|
||||
argument can be used for translation. To interpret FP as an attribute per TXQ,
|
||||
the
|
||||
.B 'queues'
|
||||
argument can be used for translation.
|
||||
|
||||
Traffic classes are express by default. The argument is supported only with
|
||||
.B 'hw'
|
||||
set to 1. Preemptible traffic classes are accepted only if the device has a MAC
|
||||
Merge layer configurable through
|
||||
.BR ethtool(8).
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR ethtool(8)
|
||||
|
||||
.SH EXAMPLE
|
||||
|
||||
|
@ -36,6 +36,10 @@ clockid
|
||||
[
|
||||
.B max-sdu
|
||||
<queueMaxSDU[TC 0]> <queueMaxSDU[TC 1]> <queueMaxSDU[TC N]> ]
|
||||
.ti +8
|
||||
[
|
||||
.B fp
|
||||
<adminStatus[TC 0]> <adminStatus[TC 1]> <adminStatus[TC N]> ]
|
||||
|
||||
.SH DESCRIPTION
|
||||
The TAPRIO qdisc implements a simplified version of the scheduling
|
||||
@ -163,6 +167,13 @@ represents the maximum L2 payload size that can egress that traffic class.
|
||||
Elements that are not filled in default to 0. The value 0 means that the
|
||||
traffic class can send packets up to the port's maximum MTU in size.
|
||||
|
||||
.TP
|
||||
fp
|
||||
.br
|
||||
Selects whether traffic classes are express or preemptible. See
|
||||
.BR tc-mqprio(8)
|
||||
for details.
|
||||
|
||||
.SH EXAMPLES
|
||||
|
||||
The following example shows how an traffic schedule with three traffic
|
||||
|
@ -131,6 +131,9 @@ If using
|
||||
.B nocsum
|
||||
with IPv6, be sure you know what you are doing. Zero UDP checksums provide
|
||||
weaker protection against corrupted packets. See RFC6935 for details.
|
||||
.TP
|
||||
.B nofrag
|
||||
disallow IP fragmentation.
|
||||
.RE
|
||||
.SH EXAMPLES
|
||||
The following example encapsulates incoming ICMP packets on eth0 into a vxlan
|
||||
|
@ -26,7 +26,8 @@ static void explain(void)
|
||||
"dst_ip <IP> (mandatory)\n"
|
||||
"dst_port <UDP_PORT>\n"
|
||||
"geneve_opts | vxlan_opts | erspan_opts <OPTIONS>\n"
|
||||
"csum | nocsum (default is \"csum\")\n");
|
||||
"csum | nocsum (default is \"csum\")\n"
|
||||
"nofrag\n");
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
@ -321,7 +322,7 @@ static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
|
||||
int ret;
|
||||
int has_src_ip = 0;
|
||||
int has_dst_ip = 0;
|
||||
int csum = 1;
|
||||
int csum = 1, nofrag = 0;
|
||||
|
||||
if (matches(*argv, "tunnel_key") != 0)
|
||||
return -1;
|
||||
@ -425,6 +426,8 @@ static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
|
||||
csum = 1;
|
||||
} else if (matches(*argv, "nocsum") == 0) {
|
||||
csum = 0;
|
||||
} else if (strcmp(*argv, "nofrag") == 0) {
|
||||
nofrag = 1;
|
||||
} else if (matches(*argv, "help") == 0) {
|
||||
usage();
|
||||
} else {
|
||||
@ -435,6 +438,9 @@ static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
|
||||
|
||||
addattr8(n, MAX_MSG, TCA_TUNNEL_KEY_NO_CSUM, !csum);
|
||||
|
||||
if (nofrag)
|
||||
addattr(n, MAX_MSG, TCA_TUNNEL_KEY_NO_FRAG);
|
||||
|
||||
parse_action_control_dflt(&argc, &argv, &parm.action,
|
||||
false, TC_ACT_PIPE);
|
||||
|
||||
@ -513,15 +519,36 @@ static void tunnel_key_print_dst_port(FILE *f, char *name,
|
||||
rta_getattr_be16(attr));
|
||||
}
|
||||
|
||||
static void tunnel_key_print_flag(FILE *f, const char *name_on,
|
||||
const char *name_off,
|
||||
struct rtattr *attr)
|
||||
static const struct {
|
||||
const char *name;
|
||||
unsigned int nl_flag;
|
||||
} tunnel_key_flag_names[] = {
|
||||
{ "", TCA_TUNNEL_KEY_NO_CSUM }, /* special handling, not bool */
|
||||
{ "nofrag", TCA_TUNNEL_KEY_NO_FRAG },
|
||||
};
|
||||
|
||||
static void tunnel_key_print_flags(struct rtattr *tb[])
|
||||
{
|
||||
if (!attr)
|
||||
return;
|
||||
unsigned int i, nl_flag;
|
||||
|
||||
print_nl();
|
||||
print_string(PRINT_ANY, "flag", "\t%s",
|
||||
rta_getattr_u8(attr) ? name_on : name_off);
|
||||
for (i = 0; i < ARRAY_SIZE(tunnel_key_flag_names); i++) {
|
||||
nl_flag = tunnel_key_flag_names[i].nl_flag;
|
||||
if (nl_flag == TCA_TUNNEL_KEY_NO_CSUM) {
|
||||
/* special handling to preserve csum/nocsum design */
|
||||
if (!tb[nl_flag])
|
||||
continue;
|
||||
print_string(PRINT_ANY, "flag", "\t%s",
|
||||
rta_getattr_u8(tb[nl_flag]) ?
|
||||
"nocsum" : "csum" );
|
||||
} else {
|
||||
if (tb[nl_flag])
|
||||
print_string(PRINT_FP, NULL, "\t%s",
|
||||
tunnel_key_flag_names[i].name);
|
||||
print_bool(PRINT_JSON, tunnel_key_flag_names[i].name,
|
||||
NULL, !!tb[nl_flag]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void tunnel_key_print_geneve_options(struct rtattr *attr)
|
||||
@ -697,8 +724,7 @@ static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg)
|
||||
tunnel_key_print_dst_port(f, "dst_port",
|
||||
tb[TCA_TUNNEL_KEY_ENC_DST_PORT]);
|
||||
tunnel_key_print_key_opt(tb[TCA_TUNNEL_KEY_ENC_OPTS]);
|
||||
tunnel_key_print_flag(f, "nocsum", "csum",
|
||||
tb[TCA_TUNNEL_KEY_NO_CSUM]);
|
||||
tunnel_key_print_flags(tb);
|
||||
tunnel_key_print_tos_ttl(f, "tos",
|
||||
tb[TCA_TUNNEL_KEY_ENC_TOS]);
|
||||
tunnel_key_print_tos_ttl(f, "ttl",
|
||||
|
@ -23,12 +23,29 @@ static void explain(void)
|
||||
"Usage: ... mqprio [num_tc NUMBER] [map P0 P1 ...]\n"
|
||||
" [queues count1@offset1 count2@offset2 ...] "
|
||||
"[hw 1|0]\n"
|
||||
" [fp FP0 FP1 FP2 ...]\n"
|
||||
" [mode dcb|channel]\n"
|
||||
" [shaper bw_rlimit SHAPER_PARAMS]\n"
|
||||
"Where: SHAPER_PARAMS := { min_rate MIN_RATE1 MIN_RATE2 ...|\n"
|
||||
" max_rate MAX_RATE1 MAX_RATE2 ... }\n");
|
||||
}
|
||||
|
||||
static void add_tc_entries(struct nlmsghdr *n, __u32 fp[TC_QOPT_MAX_QUEUE],
|
||||
int num_fp_entries)
|
||||
{
|
||||
struct rtattr *l;
|
||||
__u32 tc;
|
||||
|
||||
for (tc = 0; tc < num_fp_entries; tc++) {
|
||||
l = addattr_nest(n, 1024, TCA_MQPRIO_TC_ENTRY | NLA_F_NESTED);
|
||||
|
||||
addattr32(n, 1024, TCA_MQPRIO_TC_ENTRY_INDEX, tc);
|
||||
addattr32(n, 1024, TCA_MQPRIO_TC_ENTRY_FP, fp[tc]);
|
||||
|
||||
addattr_nest_end(n, l);
|
||||
}
|
||||
}
|
||||
|
||||
static int mqprio_parse_opt(struct qdisc_util *qu, int argc,
|
||||
char **argv, struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
@ -43,7 +60,10 @@ static int mqprio_parse_opt(struct qdisc_util *qu, int argc,
|
||||
__u64 min_rate64[TC_QOPT_MAX_QUEUE] = {0};
|
||||
__u64 max_rate64[TC_QOPT_MAX_QUEUE] = {0};
|
||||
__u16 shaper = TC_MQPRIO_SHAPER_DCB;
|
||||
__u32 fp[TC_QOPT_MAX_QUEUE] = { };
|
||||
__u16 mode = TC_MQPRIO_MODE_DCB;
|
||||
bool have_tc_entries = false;
|
||||
int num_fp_entries = 0;
|
||||
int cnt_off_pairs = 0;
|
||||
struct rtattr *tail;
|
||||
__u32 flags = 0;
|
||||
@ -93,6 +113,21 @@ static int mqprio_parse_opt(struct qdisc_util *qu, int argc,
|
||||
idx++;
|
||||
cnt_off_pairs++;
|
||||
}
|
||||
} else if (strcmp(*argv, "fp") == 0) {
|
||||
while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
|
||||
NEXT_ARG();
|
||||
if (strcmp(*argv, "E") == 0) {
|
||||
fp[idx] = TC_FP_EXPRESS;
|
||||
} else if (strcmp(*argv, "P") == 0) {
|
||||
fp[idx] = TC_FP_PREEMPTIBLE;
|
||||
} else {
|
||||
PREV_ARG();
|
||||
break;
|
||||
}
|
||||
num_fp_entries++;
|
||||
idx++;
|
||||
}
|
||||
have_tc_entries = true;
|
||||
} else if (strcmp(*argv, "hw") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_u8(&opt.hw, *argv, 10)) {
|
||||
@ -187,6 +222,9 @@ static int mqprio_parse_opt(struct qdisc_util *qu, int argc,
|
||||
addattr_l(n, 1024, TCA_MQPRIO_SHAPER,
|
||||
&shaper, sizeof(shaper));
|
||||
|
||||
if (have_tc_entries)
|
||||
add_tc_entries(n, fp, num_fp_entries);
|
||||
|
||||
if (flags & TC_MQPRIO_F_MIN_RATE) {
|
||||
struct rtattr *start;
|
||||
|
||||
@ -218,6 +256,64 @@ static int mqprio_parse_opt(struct qdisc_util *qu, int argc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dump_tc_entry(struct rtattr *rta, __u32 fp[TC_QOPT_MAX_QUEUE],
|
||||
int *max_tc_fp)
|
||||
{
|
||||
struct rtattr *tb[TCA_MQPRIO_TC_ENTRY_MAX + 1];
|
||||
__u32 tc, val = 0;
|
||||
|
||||
parse_rtattr_nested(tb, TCA_MQPRIO_TC_ENTRY_MAX, rta);
|
||||
|
||||
if (!tb[TCA_MQPRIO_TC_ENTRY_INDEX]) {
|
||||
fprintf(stderr, "Missing tc entry index\n");
|
||||
return;
|
||||
}
|
||||
|
||||
tc = rta_getattr_u32(tb[TCA_MQPRIO_TC_ENTRY_INDEX]);
|
||||
/* Prevent array out of bounds access */
|
||||
if (tc >= TC_QOPT_MAX_QUEUE) {
|
||||
fprintf(stderr, "Unexpected tc entry index %d\n", tc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tb[TCA_MQPRIO_TC_ENTRY_FP]) {
|
||||
val = rta_getattr_u32(tb[TCA_MQPRIO_TC_ENTRY_FP]);
|
||||
fp[tc] = val;
|
||||
|
||||
if (*max_tc_fp < (int)tc)
|
||||
*max_tc_fp = tc;
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_tc_entries(FILE *f, struct rtattr *opt, int len)
|
||||
{
|
||||
__u32 fp[TC_QOPT_MAX_QUEUE] = {};
|
||||
int max_tc_fp = -1;
|
||||
struct rtattr *rta;
|
||||
int tc;
|
||||
|
||||
for (rta = opt; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
|
||||
if (rta->rta_type != (TCA_MQPRIO_TC_ENTRY | NLA_F_NESTED))
|
||||
continue;
|
||||
|
||||
dump_tc_entry(rta, fp, &max_tc_fp);
|
||||
}
|
||||
|
||||
if (max_tc_fp >= 0) {
|
||||
open_json_array(PRINT_ANY,
|
||||
is_json_context() ? "fp" : "\n fp:");
|
||||
for (tc = 0; tc <= max_tc_fp; tc++) {
|
||||
print_string(PRINT_ANY, NULL, " %s",
|
||||
fp[tc] == TC_FP_PREEMPTIBLE ? "P" :
|
||||
fp[tc] == TC_FP_EXPRESS ? "E" :
|
||||
"?");
|
||||
}
|
||||
close_json_array(PRINT_ANY, "");
|
||||
|
||||
print_nl();
|
||||
}
|
||||
}
|
||||
|
||||
static int mqprio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
|
||||
{
|
||||
int i;
|
||||
@ -309,7 +405,10 @@ static int mqprio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
|
||||
tc_print_rate(PRINT_ANY, NULL, "%s ", max_rate64[i]);
|
||||
close_json_array(PRINT_ANY, "");
|
||||
}
|
||||
|
||||
dump_tc_entries(f, RTA_DATA(opt) + RTA_ALIGN(sizeof(*qopt)), len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
100
tc/q_taprio.c
100
tc/q_taprio.c
@ -49,6 +49,7 @@ static void explain(void)
|
||||
" [queues COUNT@OFFSET COUNT@OFFSET COUNT@OFFSET ...]\n"
|
||||
" [ [sched-entry index cmd gate-mask interval] ... ]\n"
|
||||
" [base-time time] [txtime-delay delay]\n"
|
||||
" [fp FP0 FP1 FP2 ...]\n"
|
||||
"\n"
|
||||
"CLOCKID must be a valid SYS-V id (i.e. CLOCK_TAI)\n");
|
||||
}
|
||||
@ -148,17 +149,29 @@ static struct sched_entry *create_entry(uint32_t gatemask, uint32_t interval, ui
|
||||
}
|
||||
|
||||
static void add_tc_entries(struct nlmsghdr *n, __u32 max_sdu[TC_QOPT_MAX_QUEUE],
|
||||
int num_max_sdu_entries)
|
||||
int num_max_sdu_entries, __u32 fp[TC_QOPT_MAX_QUEUE],
|
||||
int num_fp_entries)
|
||||
{
|
||||
struct rtattr *l;
|
||||
int num_tc;
|
||||
__u32 tc;
|
||||
|
||||
for (tc = 0; tc < num_max_sdu_entries; tc++) {
|
||||
num_tc = max(num_max_sdu_entries, num_fp_entries);
|
||||
|
||||
for (tc = 0; tc < num_tc; tc++) {
|
||||
l = addattr_nest(n, 1024, TCA_TAPRIO_ATTR_TC_ENTRY | NLA_F_NESTED);
|
||||
|
||||
addattr_l(n, 1024, TCA_TAPRIO_TC_ENTRY_INDEX, &tc, sizeof(tc));
|
||||
addattr_l(n, 1024, TCA_TAPRIO_TC_ENTRY_MAX_SDU,
|
||||
&max_sdu[tc], sizeof(max_sdu[tc]));
|
||||
|
||||
if (tc < num_max_sdu_entries) {
|
||||
addattr_l(n, 1024, TCA_TAPRIO_TC_ENTRY_MAX_SDU,
|
||||
&max_sdu[tc], sizeof(max_sdu[tc]));
|
||||
}
|
||||
|
||||
if (tc < num_fp_entries) {
|
||||
addattr_l(n, 1024, TCA_TAPRIO_TC_ENTRY_FP, &fp[tc],
|
||||
sizeof(fp[tc]));
|
||||
}
|
||||
|
||||
addattr_nest_end(n, l);
|
||||
}
|
||||
@ -168,6 +181,7 @@ static int taprio_parse_opt(struct qdisc_util *qu, int argc,
|
||||
char **argv, struct nlmsghdr *n, const char *dev)
|
||||
{
|
||||
__u32 max_sdu[TC_QOPT_MAX_QUEUE] = { };
|
||||
__u32 fp[TC_QOPT_MAX_QUEUE] = { };
|
||||
__s32 clockid = CLOCKID_INVALID;
|
||||
struct tc_mqprio_qopt opt = { };
|
||||
__s64 cycle_time_extension = 0;
|
||||
@ -175,6 +189,7 @@ static int taprio_parse_opt(struct qdisc_util *qu, int argc,
|
||||
bool have_tc_entries = false;
|
||||
int num_max_sdu_entries = 0;
|
||||
struct rtattr *tail, *l;
|
||||
int num_fp_entries = 0;
|
||||
__u32 taprio_flags = 0;
|
||||
__u32 txtime_delay = 0;
|
||||
__s64 cycle_time = 0;
|
||||
@ -227,6 +242,23 @@ static int taprio_parse_opt(struct qdisc_util *qu, int argc,
|
||||
free(tmp);
|
||||
idx++;
|
||||
}
|
||||
} else if (strcmp(*argv, "fp") == 0) {
|
||||
while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
|
||||
NEXT_ARG();
|
||||
if (strcmp(*argv, "E") == 0) {
|
||||
fp[idx] = TC_FP_EXPRESS;
|
||||
} else if (strcmp(*argv, "P") == 0) {
|
||||
fp[idx] = TC_FP_PREEMPTIBLE;
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Illegal \"fp\" value \"%s\", expected \"E\" or \"P\"\n",
|
||||
*argv);
|
||||
return -1;
|
||||
}
|
||||
num_fp_entries++;
|
||||
idx++;
|
||||
}
|
||||
have_tc_entries = true;
|
||||
} else if (strcmp(*argv, "max-sdu") == 0) {
|
||||
while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
|
||||
NEXT_ARG();
|
||||
@ -369,7 +401,7 @@ static int taprio_parse_opt(struct qdisc_util *qu, int argc,
|
||||
&cycle_time_extension, sizeof(cycle_time_extension));
|
||||
|
||||
if (have_tc_entries)
|
||||
add_tc_entries(n, max_sdu, num_max_sdu_entries);
|
||||
add_tc_entries(n, max_sdu, num_max_sdu_entries, fp, num_fp_entries);
|
||||
|
||||
l = addattr_nest(n, 1024, TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST | NLA_F_NESTED);
|
||||
|
||||
@ -460,9 +492,10 @@ static int print_schedule(FILE *f, struct rtattr **tb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dump_tc_entry(__u32 max_sdu[TC_QOPT_MAX_QUEUE],
|
||||
struct rtattr *item, bool *have_tc_entries,
|
||||
int *max_tc_index)
|
||||
static void dump_tc_entry(struct rtattr *item,
|
||||
__u32 max_sdu[TC_QOPT_MAX_QUEUE],
|
||||
__u32 fp[TC_QOPT_MAX_QUEUE],
|
||||
int *max_tc_max_sdu, int *max_tc_fp)
|
||||
{
|
||||
struct rtattr *tb[TCA_TAPRIO_TC_ENTRY_MAX + 1];
|
||||
__u32 tc, val = 0;
|
||||
@ -481,23 +514,30 @@ static void dump_tc_entry(__u32 max_sdu[TC_QOPT_MAX_QUEUE],
|
||||
return;
|
||||
}
|
||||
|
||||
if (*max_tc_index < tc)
|
||||
*max_tc_index = tc;
|
||||
|
||||
if (tb[TCA_TAPRIO_TC_ENTRY_MAX_SDU])
|
||||
if (tb[TCA_TAPRIO_TC_ENTRY_MAX_SDU]) {
|
||||
val = rta_getattr_u32(tb[TCA_TAPRIO_TC_ENTRY_MAX_SDU]);
|
||||
max_sdu[tc] = val;
|
||||
if (*max_tc_max_sdu < (int)tc)
|
||||
*max_tc_max_sdu = tc;
|
||||
}
|
||||
|
||||
max_sdu[tc] = val;
|
||||
if (tb[TCA_TAPRIO_TC_ENTRY_FP]) {
|
||||
val = rta_getattr_u32(tb[TCA_TAPRIO_TC_ENTRY_FP]);
|
||||
fp[tc] = val;
|
||||
|
||||
*have_tc_entries = true;
|
||||
if (*max_tc_fp < (int)tc)
|
||||
*max_tc_fp = tc;
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_tc_entries(FILE *f, struct rtattr *opt)
|
||||
{
|
||||
__u32 max_sdu[TC_QOPT_MAX_QUEUE] = {};
|
||||
int tc, rem, max_tc_index = 0;
|
||||
bool have_tc_entries = false;
|
||||
__u32 fp[TC_QOPT_MAX_QUEUE] = {};
|
||||
int max_tc_max_sdu = -1;
|
||||
int max_tc_fp = -1;
|
||||
struct rtattr *i;
|
||||
int tc, rem;
|
||||
|
||||
rem = RTA_PAYLOAD(opt);
|
||||
|
||||
@ -505,18 +545,30 @@ static void dump_tc_entries(FILE *f, struct rtattr *opt)
|
||||
if (i->rta_type != (TCA_TAPRIO_ATTR_TC_ENTRY | NLA_F_NESTED))
|
||||
continue;
|
||||
|
||||
dump_tc_entry(max_sdu, i, &have_tc_entries, &max_tc_index);
|
||||
dump_tc_entry(i, max_sdu, fp, &max_tc_max_sdu, &max_tc_fp);
|
||||
}
|
||||
|
||||
if (!have_tc_entries)
|
||||
return;
|
||||
if (max_tc_max_sdu >= 0) {
|
||||
open_json_array(PRINT_ANY, "max-sdu");
|
||||
for (tc = 0; tc <= max_tc_max_sdu; tc++)
|
||||
print_uint(PRINT_ANY, NULL, " %u", max_sdu[tc]);
|
||||
close_json_array(PRINT_ANY, "");
|
||||
|
||||
open_json_array(PRINT_ANY, "max-sdu");
|
||||
for (tc = 0; tc <= max_tc_index; tc++)
|
||||
print_uint(PRINT_ANY, NULL, " %u", max_sdu[tc]);
|
||||
close_json_array(PRINT_ANY, "");
|
||||
print_nl();
|
||||
}
|
||||
|
||||
print_nl();
|
||||
if (max_tc_fp >= 0) {
|
||||
open_json_array(PRINT_ANY, "fp");
|
||||
for (tc = 0; tc <= max_tc_fp; tc++) {
|
||||
print_string(PRINT_ANY, NULL, " %s",
|
||||
fp[tc] == TC_FP_PREEMPTIBLE ? "P" :
|
||||
fp[tc] == TC_FP_EXPRESS ? "E" :
|
||||
"?");
|
||||
}
|
||||
close_json_array(PRINT_ANY, "");
|
||||
|
||||
print_nl();
|
||||
}
|
||||
}
|
||||
|
||||
static int taprio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
|
||||
|
Loading…
Reference in New Issue
Block a user