Compare commits
217 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
73590d9573 | |
|
|
3f77bc6253 | |
|
|
5f8bb902e1 | |
|
|
3184de3797 | |
|
|
79026c1262 | |
|
|
fa58de9b0c | |
|
|
be31c26484 | |
|
|
0e94972590 | |
|
|
9bd5ab0f09 | |
|
|
a787d9ae10 | |
|
|
af96c7b5dd | |
|
|
35c81b18c4 | |
|
|
50b668bdbf | |
|
|
9c56d693f6 | |
|
|
0c263d7c36 | |
|
|
0f7bb8d842 | |
|
|
67f3c7a5cc | |
|
|
fd5e958c49 | |
|
|
8316df6e6d | |
|
|
6e15d27aae | |
|
|
9cae1de564 | |
|
|
258e350ca9 | |
|
|
047e9ae516 | |
|
|
7a8b7573a4 | |
|
|
ad3a118f88 | |
|
|
7a235a101b | |
|
|
e2947f6fd8 | |
|
|
9e009e78e7 | |
|
|
040e52526c | |
|
|
c76a3849ec | |
|
|
76b30805f9 | |
|
|
2be7d99960 | |
|
|
229eaba507 | |
|
|
95cd2a6204 | |
|
|
a936a73fc2 | |
|
|
cee0cf84bd | |
|
|
0ee1950b5c | |
|
|
4b8bca5f9e | |
|
|
99245d1741 | |
|
|
c330d09794 | |
|
|
48c379bc2a | |
|
|
1d819dcc74 | |
|
|
19ba785f16 | |
|
|
7d5cb70e94 | |
|
|
d480cb71f5 | |
|
|
e4ca6a4965 | |
|
|
a31e7b7967 | |
|
|
a500c5ac87 | |
|
|
7c032cac10 | |
|
|
04ee8e6f06 | |
|
|
14802d84d3 | |
|
|
8cd517a805 | |
|
|
763fd793fe | |
|
|
41020eb0fd | |
|
|
8fb522cde3 | |
|
|
897772a735 | |
|
|
b840c620fe | |
|
|
b90174354d | |
|
|
6448ed373c | |
|
|
e7a98a96f0 | |
|
|
ec703e0629 | |
|
|
7ca868a7aa | |
|
|
5d5dc549ce | |
|
|
cb3d18c29e | |
|
|
60a9703032 | |
|
|
53d7c43bd3 | |
|
|
a2ca431215 | |
|
|
945c26db68 | |
|
|
7ec1cee630 | |
|
|
60a7515b89 | |
|
|
cfb0a8729e | |
|
|
371e889da7 | |
|
|
f72789965e | |
|
|
c8c9111a4c | |
|
|
e2cc9840ea | |
|
|
26c5782fab | |
|
|
fd4c1c8168 | |
|
|
c63b769ad4 | |
|
|
399ae00af5 | |
|
|
3a92669b3a | |
|
|
2f5825cb38 | |
|
|
d756c08a3d | |
|
|
ebbb701714 | |
|
|
75c5054e7a | |
|
|
92e32f7791 | |
|
|
0431e1e724 | |
|
|
12b3d6a2ad | |
|
|
917d913b2e | |
|
|
d0cba0d1f6 | |
|
|
ae895504c6 | |
|
|
12fbe3e4eb | |
|
|
db28c944d8 | |
|
|
6d676ad934 | |
|
|
1eaebad2c5 | |
|
|
adddf30cd8 | |
|
|
2c8110881b | |
|
|
e7e0e2ce65 | |
|
|
deef844b1e | |
|
|
a3272b9372 | |
|
|
ceba59308d | |
|
|
7a70524270 | |
|
|
8ab1834e56 | |
|
|
6d0d35bab9 | |
|
|
926ad64104 | |
|
|
c730bd0b11 | |
|
|
df8912ede2 | |
|
|
7e7270bb1f | |
|
|
86c596ed91 | |
|
|
2d83c71082 | |
|
|
f0b3808afa | |
|
|
acbdef9386 | |
|
|
2d6fa30bb8 | |
|
|
508ad89c82 | |
|
|
fb843668fb | |
|
|
72222cd467 | |
|
|
7ad5505bb5 | |
|
|
061da2e222 | |
|
|
60dcd5c318 | |
|
|
0e4cfa0370 | |
|
|
ebcee09ca1 | |
|
|
3ae784f589 | |
|
|
2b6cc38d52 | |
|
|
7cc7dbf447 | |
|
|
3399c0759f | |
|
|
a8d7212a4f | |
|
|
29fada0f41 | |
|
|
1f608d590c | |
|
|
dee5eb05e5 | |
|
|
ecf6d8b4a1 | |
|
|
720f8613bd | |
|
|
d3a961a9b1 | |
|
|
312e22fe79 | |
|
|
d2eecb9d1d | |
|
|
169f36a0c9 | |
|
|
85b0e73c77 | |
|
|
1afde09498 | |
|
|
10ecd12690 | |
|
|
057d3c6d37 | |
|
|
82149efee9 | |
|
|
3a09567f7d | |
|
|
355c49ffa5 | |
|
|
ebaa603b30 | |
|
|
8d6134b204 | |
|
|
51d8fc708c | |
|
|
71ba9c18e0 | |
|
|
9b7ea92b9e | |
|
|
d1eacf12b5 | |
|
|
50a4127022 | |
|
|
954a0077c8 | |
|
|
be99929d60 | |
|
|
e78411948d | |
|
|
09d8ce3db1 | |
|
|
e8763fc9ab | |
|
|
78832863ef | |
|
|
32f4969d44 | |
|
|
2909812583 | |
|
|
e53f4cd504 | |
|
|
236696e52c | |
|
|
cf866f0a5a | |
|
|
c06d313d86 | |
|
|
71d36000dc | |
|
|
f760bff328 | |
|
|
7a7e9ed98f | |
|
|
1f2c908d53 | |
|
|
115e987035 | |
|
|
0015ada629 | |
|
|
459ce6e3d7 | |
|
|
8f85d085fe | |
|
|
83d4d61bc9 | |
|
|
02c06ffc13 | |
|
|
fc3511962d | |
|
|
2ff4761db4 | |
|
|
bc5e8473aa | |
|
|
6acccd52a2 | |
|
|
362da458a4 | |
|
|
083e2706e1 | |
|
|
3e26254f31 | |
|
|
1d11326a57 | |
|
|
f8879e85f0 | |
|
|
d8b3b9d32d | |
|
|
dedf895184 | |
|
|
6c70aca76e | |
|
|
95339955c5 | |
|
|
85903c9a29 | |
|
|
fbd4b581cb | |
|
|
0d5cf51e0d | |
|
|
52f136f640 | |
|
|
7ae2585b86 | |
|
|
a9c3d70d90 | |
|
|
825bd5dacb | |
|
|
7fda6c588a | |
|
|
c5b72cc56b | |
|
|
62c88ed940 | |
|
|
49437375b6 | |
|
|
02ca3aabe9 | |
|
|
e44786b269 | |
|
|
28ee49e515 | |
|
|
93c267bfb4 | |
|
|
459f280813 | |
|
|
0d95472a4b | |
|
|
2d212aae55 | |
|
|
cfd89a6f8b | |
|
|
3296d4fe77 | |
|
|
a2f1f66075 | |
|
|
570d2cf0ec | |
|
|
c3f852754f | |
|
|
c79fcefaaf | |
|
|
bce4247869 | |
|
|
212e2c1d0c | |
|
|
7f1d58d1a1 | |
|
|
e1e089d1f2 | |
|
|
d56dcd3549 | |
|
|
e5f1505e53 | |
|
|
9b272e138d | |
|
|
4278941285 | |
|
|
4c61b5b9df | |
|
|
a5ea744ca2 |
16
Makefile
16
Makefile
|
|
@ -1,6 +1,8 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Top level Makefile for iproute2
|
||||
|
||||
-include config.mk
|
||||
|
||||
ifeq ("$(origin V)", "command line")
|
||||
VERBOSE = $(V)
|
||||
endif
|
||||
|
|
@ -13,7 +15,6 @@ MAKEFLAGS += --no-print-directory
|
|||
endif
|
||||
|
||||
PREFIX?=/usr
|
||||
LIBDIR?=$(PREFIX)/lib
|
||||
SBINDIR?=/sbin
|
||||
CONFDIR?=/etc/iproute2
|
||||
NETNS_RUN_DIR?=/var/run/netns
|
||||
|
|
@ -40,9 +41,18 @@ DEFINES+=-DCONFDIR=\"$(CONFDIR)\" \
|
|||
-DNETNS_RUN_DIR=\"$(NETNS_RUN_DIR)\" \
|
||||
-DNETNS_ETC_DIR=\"$(NETNS_ETC_DIR)\"
|
||||
|
||||
#options for AX.25
|
||||
ADDLIB+=ax25_ntop.o
|
||||
|
||||
#options for AX.25
|
||||
ADDLIB+=rose_ntop.o
|
||||
|
||||
#options for mpls
|
||||
ADDLIB+=mpls_ntop.o mpls_pton.o
|
||||
|
||||
#options for NETROM
|
||||
ADDLIB+=netrom_ntop.o
|
||||
|
||||
CC := gcc
|
||||
HOSTCC ?= $(CC)
|
||||
DEFINES += -D_GNU_SOURCE
|
||||
|
|
@ -81,7 +91,9 @@ help:
|
|||
@echo " V=[0|1] - set build verbosity level"
|
||||
|
||||
config.mk:
|
||||
sh configure $(KERNEL_INCLUDE)
|
||||
@if [ ! -f config.mk -o configure -nt config.mk ]; then \
|
||||
sh configure $(KERNEL_INCLUDE); \
|
||||
fi
|
||||
|
||||
install: all
|
||||
install -m 0755 -d $(DESTDIR)$(SBINDIR)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,9 @@ int print_mdb_mon(struct nlmsghdr *n, void *arg);
|
|||
int print_fdb(struct nlmsghdr *n, void *arg);
|
||||
void print_stp_state(__u8 state);
|
||||
int parse_stp_state(const char *arg);
|
||||
int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor);
|
||||
int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor,
|
||||
bool global_only);
|
||||
void br_print_router_port_stats(struct rtattr *pattr);
|
||||
|
||||
int do_fdb(int argc, char **argv);
|
||||
int do_mdb(int argc, char **argv);
|
||||
|
|
|
|||
|
|
@ -37,10 +37,10 @@ static void usage(void)
|
|||
fprintf(stderr,
|
||||
"Usage: bridge [ OPTIONS ] OBJECT { COMMAND | help }\n"
|
||||
" bridge [ -force ] -batch filename\n"
|
||||
"where OBJECT := { link | fdb | mdb | vlan | monitor }\n"
|
||||
" OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n"
|
||||
" -o[neline] | -t[imestamp] | -n[etns] name |\n"
|
||||
" -c[ompressvlans] -color -p[retty] -j[son] }\n");
|
||||
"where OBJECT := { link | fdb | mdb | vlan | monitor }\n"
|
||||
" OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] |\n"
|
||||
" -o[neline] | -t[imestamp] | -n[etns] name |\n"
|
||||
" -c[ompressvlans] -color -p[retty] -j[son] }\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
|
@ -149,9 +149,9 @@ main(int argc, char **argv)
|
|||
NEXT_ARG();
|
||||
if (netns_switch(argv[1]))
|
||||
exit(-1);
|
||||
} else if (matches_color(opt, &color)) {
|
||||
} else if (matches(opt, "-compressvlans") == 0) {
|
||||
++compress_vlans;
|
||||
} else if (matches_color(opt, &color)) {
|
||||
} else if (matches(opt, "-force") == 0) {
|
||||
++force;
|
||||
} else if (matches(opt, "-json") == 0) {
|
||||
|
|
|
|||
11
bridge/fdb.c
11
bridge/fdb.c
|
|
@ -192,10 +192,13 @@ int print_fdb(struct nlmsghdr *n, void *arg)
|
|||
"mac", "%s ", lladdr);
|
||||
}
|
||||
|
||||
if (!filter_index && r->ndm_ifindex)
|
||||
if (!filter_index && r->ndm_ifindex) {
|
||||
print_string(PRINT_FP, NULL, "dev ", NULL);
|
||||
|
||||
print_color_string(PRINT_ANY, COLOR_IFNAME,
|
||||
"ifname", "dev %s ",
|
||||
"ifname", "%s ",
|
||||
ll_index_to_name(r->ndm_ifindex));
|
||||
}
|
||||
|
||||
if (tb[NDA_DST]) {
|
||||
int family = AF_INET;
|
||||
|
|
@ -208,9 +211,11 @@ int print_fdb(struct nlmsghdr *n, void *arg)
|
|||
RTA_PAYLOAD(tb[NDA_DST]),
|
||||
RTA_DATA(tb[NDA_DST]));
|
||||
|
||||
print_string(PRINT_FP, NULL, "dst ", NULL);
|
||||
|
||||
print_color_string(PRINT_ANY,
|
||||
ifa_family_color(family),
|
||||
"dst", "dst %s ", dst);
|
||||
"dst", "%s ", dst);
|
||||
}
|
||||
|
||||
if (vid)
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ static const char *format_timer(__u32 ticks, int align)
|
|||
return tbuf;
|
||||
}
|
||||
|
||||
static void __print_router_port_stats(FILE *f, struct rtattr *pattr)
|
||||
void br_print_router_port_stats(struct rtattr *pattr)
|
||||
{
|
||||
struct rtattr *tb[MDBA_ROUTER_PATTR_MAX + 1];
|
||||
|
||||
|
|
@ -101,13 +101,13 @@ static void br_print_router_ports(FILE *f, struct rtattr *attr,
|
|||
print_string(PRINT_JSON, "port", NULL, port_ifname);
|
||||
|
||||
if (show_stats)
|
||||
__print_router_port_stats(f, i);
|
||||
br_print_router_port_stats(i);
|
||||
close_json_object();
|
||||
} else if (show_stats) {
|
||||
fprintf(f, "router ports on %s: %s",
|
||||
brifname, port_ifname);
|
||||
|
||||
__print_router_port_stats(f, i);
|
||||
br_print_router_port_stats(i);
|
||||
fprintf(f, "\n");
|
||||
} else {
|
||||
fprintf(f, "%s ", port_ifname);
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ static int accept_msg(struct rtnl_ctrl_data *ctrl,
|
|||
case RTM_DELVLAN:
|
||||
if (prefix_banner)
|
||||
fprintf(fp, "[VLAN]");
|
||||
return print_vlan_rtm(n, arg, true);
|
||||
return print_vlan_rtm(n, arg, true, false);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
|
|
|
|||
635
bridge/vlan.c
635
bridge/vlan.c
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/if_bridge.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "json_print.h"
|
||||
#include "libnetlink.h"
|
||||
|
|
@ -35,8 +36,23 @@ static void usage(void)
|
|||
" [ pvid ] [ untagged ]\n"
|
||||
" [ self ] [ master ]\n"
|
||||
" bridge vlan { set } vid VLAN_ID dev DEV [ state STP_STATE ]\n"
|
||||
" [ mcast_router MULTICAST_ROUTER ]\n"
|
||||
" bridge vlan { show } [ dev DEV ] [ vid VLAN_ID ]\n"
|
||||
" bridge vlan { tunnelshow } [ 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"
|
||||
" [ mcast_snooping MULTICAST_SNOOPING ]\n"
|
||||
" [ mcast_querier MULTICAST_QUERIER ]\n"
|
||||
" [ mcast_igmp_version IGMP_VERSION ]\n"
|
||||
" [ mcast_mld_version MLD_VERSION ]\n"
|
||||
" [ mcast_last_member_count LAST_MEMBER_COUNT ]\n"
|
||||
" [ mcast_last_member_interval LAST_MEMBER_INTERVAL ]\n"
|
||||
" [ mcast_startup_query_count STARTUP_QUERY_COUNT ]\n"
|
||||
" [ mcast_startup_query_interval STARTUP_QUERY_INTERVAL ]\n"
|
||||
" [ mcast_membership_interval MEMBERSHIP_INTERVAL ]\n"
|
||||
" [ mcast_querier_interval QUERIER_INTERVAL ]\n"
|
||||
" [ mcast_query_interval QUERY_INTERVAL ]\n"
|
||||
" [ mcast_query_response_interval QUERY_RESPONSE_INTERVAL ]\n"
|
||||
" bridge vlan global { show } [ dev DEV ] [ vid VLAN_ID ]\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
|
@ -257,15 +273,129 @@ static int vlan_option_set(int argc, char **argv)
|
|||
};
|
||||
struct bridge_vlan_info vinfo = {};
|
||||
struct rtattr *afspec;
|
||||
short vid_end = -1;
|
||||
char *d = NULL;
|
||||
short vid = -1;
|
||||
int state = -1;
|
||||
|
||||
afspec = addattr_nest(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY);
|
||||
afspec->rta_type |= NLA_F_NESTED;
|
||||
while (argc > 0) {
|
||||
if (strcmp(*argv, "dev") == 0) {
|
||||
NEXT_ARG();
|
||||
d = *argv;
|
||||
req.bvm.ifindex = ll_name_to_index(d);
|
||||
if (req.bvm.ifindex == 0) {
|
||||
fprintf(stderr,
|
||||
"Cannot find network device \"%s\"\n",
|
||||
d);
|
||||
return -1;
|
||||
}
|
||||
} else if (strcmp(*argv, "vid") == 0) {
|
||||
short vid_end = -1;
|
||||
char *p;
|
||||
|
||||
NEXT_ARG();
|
||||
p = strchr(*argv, '-');
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
p++;
|
||||
vid = atoi(*argv);
|
||||
vid_end = atoi(p);
|
||||
if (vid >= vid_end || vid_end >= 4096) {
|
||||
fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n",
|
||||
vid, vid_end);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
vid = atoi(*argv);
|
||||
}
|
||||
if (vid >= 4096) {
|
||||
fprintf(stderr, "Invalid VLAN ID \"%hu\"\n",
|
||||
vid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
vinfo.flags = BRIDGE_VLAN_INFO_ONLY_OPTS;
|
||||
vinfo.vid = vid;
|
||||
addattr_l(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_INFO,
|
||||
&vinfo, sizeof(vinfo));
|
||||
if (vid_end != -1)
|
||||
addattr16(&req.n, sizeof(req),
|
||||
BRIDGE_VLANDB_ENTRY_RANGE, vid_end);
|
||||
} else if (strcmp(*argv, "state") == 0) {
|
||||
char *endptr;
|
||||
int state;
|
||||
|
||||
NEXT_ARG();
|
||||
state = strtol(*argv, &endptr, 10);
|
||||
if (!(**argv != '\0' && *endptr == '\0'))
|
||||
state = parse_stp_state(*argv);
|
||||
if (state == -1) {
|
||||
fprintf(stderr, "Error: invalid STP state\n");
|
||||
return -1;
|
||||
}
|
||||
addattr8(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_STATE,
|
||||
state);
|
||||
} else if (strcmp(*argv, "mcast_router") == 0) {
|
||||
__u8 mcast_router;
|
||||
|
||||
NEXT_ARG();
|
||||
if (get_u8(&mcast_router, *argv, 0))
|
||||
invarg("invalid mcast_router", *argv);
|
||||
addattr8(&req.n, sizeof(req),
|
||||
BRIDGE_VLANDB_ENTRY_MCAST_ROUTER,
|
||||
mcast_router);
|
||||
} else {
|
||||
if (matches(*argv, "help") == 0)
|
||||
NEXT_ARG();
|
||||
}
|
||||
argc--; argv++;
|
||||
}
|
||||
addattr_nest_end(&req.n, afspec);
|
||||
|
||||
if (d == NULL || vid == -1) {
|
||||
fprintf(stderr, "Device and VLAN ID are required arguments.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rtnl_talk(&rth, &req.n, NULL) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vlan_global_option_set(int argc, char **argv)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct br_vlan_msg bvm;
|
||||
char buf[1024];
|
||||
} req = {
|
||||
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_vlan_msg)),
|
||||
.n.nlmsg_flags = NLM_F_REQUEST,
|
||||
.n.nlmsg_type = RTM_NEWVLAN,
|
||||
.bvm.family = PF_BRIDGE,
|
||||
};
|
||||
struct rtattr *afspec;
|
||||
short vid_end = -1;
|
||||
char *d = NULL;
|
||||
short vid = -1;
|
||||
__u64 val64;
|
||||
__u32 val32;
|
||||
__u8 val8;
|
||||
|
||||
afspec = addattr_nest(&req.n, sizeof(req),
|
||||
BRIDGE_VLANDB_GLOBAL_OPTIONS);
|
||||
afspec->rta_type |= NLA_F_NESTED;
|
||||
while (argc > 0) {
|
||||
if (strcmp(*argv, "dev") == 0) {
|
||||
NEXT_ARG();
|
||||
d = *argv;
|
||||
req.bvm.ifindex = ll_name_to_index(d);
|
||||
if (req.bvm.ifindex == 0) {
|
||||
fprintf(stderr, "Cannot find network device \"%s\"\n",
|
||||
d);
|
||||
return -1;
|
||||
}
|
||||
} else if (strcmp(*argv, "vid") == 0) {
|
||||
char *p;
|
||||
|
||||
|
|
@ -284,53 +414,116 @@ static int vlan_option_set(int argc, char **argv)
|
|||
} else {
|
||||
vid = atoi(*argv);
|
||||
}
|
||||
} else if (strcmp(*argv, "state") == 0) {
|
||||
char *endptr;
|
||||
|
||||
NEXT_ARG();
|
||||
state = strtol(*argv, &endptr, 10);
|
||||
if (!(**argv != '\0' && *endptr == '\0'))
|
||||
state = parse_stp_state(*argv);
|
||||
if (state == -1) {
|
||||
fprintf(stderr, "Error: invalid STP state\n");
|
||||
if (vid >= 4096) {
|
||||
fprintf(stderr, "Invalid VLAN ID \"%hu\"\n",
|
||||
vid);
|
||||
return -1;
|
||||
}
|
||||
addattr16(&req.n, sizeof(req), BRIDGE_VLANDB_GOPTS_ID,
|
||||
vid);
|
||||
if (vid_end != -1)
|
||||
addattr16(&req.n, sizeof(req),
|
||||
BRIDGE_VLANDB_GOPTS_RANGE, vid_end);
|
||||
} else if (strcmp(*argv, "mcast_snooping") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_u8(&val8, *argv, 0))
|
||||
invarg("invalid mcast_snooping", *argv);
|
||||
addattr8(&req.n, 1024,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_SNOOPING, val8);
|
||||
} else if (strcmp(*argv, "mcast_querier") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_u8(&val8, *argv, 0))
|
||||
invarg("invalid mcast_querier", *argv);
|
||||
addattr8(&req.n, 1024,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_QUERIER, val8);
|
||||
} else if (strcmp(*argv, "mcast_igmp_version") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_u8(&val8, *argv, 0))
|
||||
invarg("invalid mcast_igmp_version", *argv);
|
||||
addattr8(&req.n, 1024,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_IGMP_VERSION, val8);
|
||||
} else if (strcmp(*argv, "mcast_mld_version") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_u8(&val8, *argv, 0))
|
||||
invarg("invalid mcast_mld_version", *argv);
|
||||
addattr8(&req.n, 1024,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_MLD_VERSION, val8);
|
||||
} else if (strcmp(*argv, "mcast_last_member_count") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_u32(&val32, *argv, 0))
|
||||
invarg("invalid mcast_last_member_count", *argv);
|
||||
addattr32(&req.n, 1024,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_LAST_MEMBER_CNT,
|
||||
val32);
|
||||
} else if (strcmp(*argv, "mcast_startup_query_count") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_u32(&val32, *argv, 0))
|
||||
invarg("invalid mcast_startup_query_count",
|
||||
*argv);
|
||||
addattr32(&req.n, 1024,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_CNT,
|
||||
val32);
|
||||
} else if (strcmp(*argv, "mcast_last_member_interval") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_u64(&val64, *argv, 0))
|
||||
invarg("invalid mcast_last_member_interval",
|
||||
*argv);
|
||||
addattr64(&req.n, 1024,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_LAST_MEMBER_INTVL,
|
||||
val64);
|
||||
} else if (strcmp(*argv, "mcast_membership_interval") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_u64(&val64, *argv, 0))
|
||||
invarg("invalid mcast_membership_interval",
|
||||
*argv);
|
||||
addattr64(&req.n, 1024,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_MEMBERSHIP_INTVL,
|
||||
val64);
|
||||
} else if (strcmp(*argv, "mcast_querier_interval") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_u64(&val64, *argv, 0))
|
||||
invarg("invalid mcast_querier_interval",
|
||||
*argv);
|
||||
addattr64(&req.n, 1024,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_INTVL,
|
||||
val64);
|
||||
} else if (strcmp(*argv, "mcast_query_interval") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_u64(&val64, *argv, 0))
|
||||
invarg("invalid mcast_query_interval",
|
||||
*argv);
|
||||
addattr64(&req.n, 1024,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_QUERY_INTVL,
|
||||
val64);
|
||||
} else if (strcmp(*argv, "mcast_query_response_interval") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_u64(&val64, *argv, 0))
|
||||
invarg("invalid mcast_query_response_interval",
|
||||
*argv);
|
||||
addattr64(&req.n, 1024,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_QUERY_RESPONSE_INTVL,
|
||||
val64);
|
||||
} else if (strcmp(*argv, "mcast_startup_query_interval") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_u64(&val64, *argv, 0))
|
||||
invarg("invalid mcast_startup_query_interval",
|
||||
*argv);
|
||||
addattr64(&req.n, 1024,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL,
|
||||
val64);
|
||||
} else {
|
||||
if (matches(*argv, "help") == 0)
|
||||
if (strcmp(*argv, "help") == 0)
|
||||
NEXT_ARG();
|
||||
}
|
||||
argc--; argv++;
|
||||
}
|
||||
addattr_nest_end(&req.n, afspec);
|
||||
|
||||
if (d == NULL || vid == -1) {
|
||||
fprintf(stderr, "Device and VLAN ID are required arguments.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
req.bvm.ifindex = ll_name_to_index(d);
|
||||
if (req.bvm.ifindex == 0) {
|
||||
fprintf(stderr, "Cannot find network device \"%s\"\n", d);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vid >= 4096) {
|
||||
fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid);
|
||||
return -1;
|
||||
}
|
||||
afspec = addattr_nest(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY);
|
||||
afspec->rta_type |= NLA_F_NESTED;
|
||||
|
||||
vinfo.flags = BRIDGE_VLAN_INFO_ONLY_OPTS;
|
||||
vinfo.vid = vid;
|
||||
addattr_l(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_INFO, &vinfo,
|
||||
sizeof(vinfo));
|
||||
if (vid_end != -1)
|
||||
addattr16(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_RANGE,
|
||||
vid_end);
|
||||
if (state >= 0)
|
||||
addattr8(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_STATE, state);
|
||||
addattr_nest_end(&req.n, afspec);
|
||||
|
||||
if (rtnl_talk(&rth, &req.n, NULL) < 0)
|
||||
return -1;
|
||||
|
||||
|
|
@ -621,11 +814,224 @@ static int print_vlan_stats(struct nlmsghdr *n, void *arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor)
|
||||
static void print_vlan_router_ports(struct rtattr *rattr)
|
||||
{
|
||||
int rem = RTA_PAYLOAD(rattr);
|
||||
struct rtattr *i;
|
||||
|
||||
print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
|
||||
open_json_array(PRINT_ANY, is_json_context() ? "router_ports" :
|
||||
"router ports: ");
|
||||
for (i = RTA_DATA(rattr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
|
||||
uint32_t *port_ifindex = RTA_DATA(i);
|
||||
const char *port_ifname = ll_index_to_name(*port_ifindex);
|
||||
|
||||
open_json_object(NULL);
|
||||
if (show_stats && i != RTA_DATA(rattr)) {
|
||||
print_nl();
|
||||
/* start: IFNAMSIZ + 4 + strlen("router ports: ") */
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-" __stringify(IFNAMSIZ) "s "
|
||||
" ",
|
||||
"");
|
||||
}
|
||||
print_string(PRINT_ANY, "port", "%s ", port_ifname);
|
||||
if (show_stats)
|
||||
br_print_router_port_stats(i);
|
||||
close_json_object();
|
||||
}
|
||||
close_json_array(PRINT_JSON, NULL);
|
||||
print_nl();
|
||||
}
|
||||
|
||||
static void print_vlan_global_opts(struct rtattr *a, int ifindex)
|
||||
{
|
||||
struct rtattr *vtb[BRIDGE_VLANDB_GOPTS_MAX + 1], *vattr;
|
||||
__u16 vid, vrange = 0;
|
||||
|
||||
if ((a->rta_type & NLA_TYPE_MASK) != BRIDGE_VLANDB_GLOBAL_OPTIONS)
|
||||
return;
|
||||
|
||||
parse_rtattr_flags(vtb, BRIDGE_VLANDB_GOPTS_MAX, RTA_DATA(a),
|
||||
RTA_PAYLOAD(a), NLA_F_NESTED);
|
||||
vid = rta_getattr_u16(vtb[BRIDGE_VLANDB_GOPTS_ID]);
|
||||
if (vtb[BRIDGE_VLANDB_GOPTS_RANGE])
|
||||
vrange = rta_getattr_u16(vtb[BRIDGE_VLANDB_GOPTS_RANGE]);
|
||||
else
|
||||
vrange = vid;
|
||||
|
||||
if (filter_vlan && (filter_vlan < vid || filter_vlan > vrange))
|
||||
return;
|
||||
|
||||
if (vlan_rtm_cur_ifidx != ifindex) {
|
||||
open_vlan_port(ifindex, VLAN_SHOW_VLAN);
|
||||
open_json_object(NULL);
|
||||
vlan_rtm_cur_ifidx = ifindex;
|
||||
} else {
|
||||
open_json_object(NULL);
|
||||
print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
|
||||
}
|
||||
print_range("vlan", vid, vrange);
|
||||
print_nl();
|
||||
print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
|
||||
if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_SNOOPING]) {
|
||||
vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_SNOOPING];
|
||||
print_uint(PRINT_ANY, "mcast_snooping", "mcast_snooping %u ",
|
||||
rta_getattr_u8(vattr));
|
||||
}
|
||||
if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERIER]) {
|
||||
vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERIER];
|
||||
print_uint(PRINT_ANY, "mcast_querier", "mcast_querier %u ",
|
||||
rta_getattr_u8(vattr));
|
||||
}
|
||||
if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_IGMP_VERSION]) {
|
||||
vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_IGMP_VERSION];
|
||||
print_uint(PRINT_ANY, "mcast_igmp_version",
|
||||
"mcast_igmp_version %u ", rta_getattr_u8(vattr));
|
||||
}
|
||||
if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_MLD_VERSION]) {
|
||||
vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_MLD_VERSION];
|
||||
print_uint(PRINT_ANY, "mcast_mld_version",
|
||||
"mcast_mld_version %u ", rta_getattr_u8(vattr));
|
||||
}
|
||||
if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_MLD_VERSION]) {
|
||||
vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_LAST_MEMBER_CNT];
|
||||
print_uint(PRINT_ANY, "mcast_last_member_count",
|
||||
"mcast_last_member_count %u ",
|
||||
rta_getattr_u32(vattr));
|
||||
}
|
||||
if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_LAST_MEMBER_INTVL]) {
|
||||
vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_LAST_MEMBER_INTVL];
|
||||
print_lluint(PRINT_ANY, "mcast_last_member_interval",
|
||||
"mcast_last_member_interval %llu ",
|
||||
rta_getattr_u64(vattr));
|
||||
}
|
||||
if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_CNT]) {
|
||||
vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_CNT];
|
||||
print_uint(PRINT_ANY, "mcast_startup_query_count",
|
||||
"mcast_startup_query_count %u ",
|
||||
rta_getattr_u32(vattr));
|
||||
}
|
||||
if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL]) {
|
||||
vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL];
|
||||
print_lluint(PRINT_ANY, "mcast_startup_query_interval",
|
||||
"mcast_startup_query_interval %llu ",
|
||||
rta_getattr_u64(vattr));
|
||||
}
|
||||
if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_MEMBERSHIP_INTVL]) {
|
||||
vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_MEMBERSHIP_INTVL];
|
||||
print_lluint(PRINT_ANY, "mcast_membership_interval",
|
||||
"mcast_membership_interval %llu ",
|
||||
rta_getattr_u64(vattr));
|
||||
}
|
||||
if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_INTVL]) {
|
||||
vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_INTVL];
|
||||
print_lluint(PRINT_ANY, "mcast_querier_interval",
|
||||
"mcast_querier_interval %llu ",
|
||||
rta_getattr_u64(vattr));
|
||||
}
|
||||
if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_INTVL]) {
|
||||
vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_INTVL];
|
||||
print_lluint(PRINT_ANY, "mcast_query_interval",
|
||||
"mcast_query_interval %llu ",
|
||||
rta_getattr_u64(vattr));
|
||||
}
|
||||
if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_RESPONSE_INTVL]) {
|
||||
vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_RESPONSE_INTVL];
|
||||
print_lluint(PRINT_ANY, "mcast_query_response_interval",
|
||||
"mcast_query_response_interval %llu ",
|
||||
rta_getattr_u64(vattr));
|
||||
}
|
||||
print_nl();
|
||||
if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS]) {
|
||||
vattr = RTA_DATA(vtb[BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS]);
|
||||
print_vlan_router_ports(vattr);
|
||||
}
|
||||
close_json_object();
|
||||
}
|
||||
|
||||
static void print_vlan_opts(struct rtattr *a, int ifindex)
|
||||
{
|
||||
struct rtattr *vtb[BRIDGE_VLANDB_ENTRY_MAX + 1], *vattr;
|
||||
struct bridge_vlan_xstats vstats;
|
||||
struct bridge_vlan_info *vinfo;
|
||||
__u16 vrange = 0;
|
||||
__u8 state = 0;
|
||||
|
||||
if ((a->rta_type & NLA_TYPE_MASK) != BRIDGE_VLANDB_ENTRY)
|
||||
return;
|
||||
|
||||
parse_rtattr_flags(vtb, BRIDGE_VLANDB_ENTRY_MAX, RTA_DATA(a),
|
||||
RTA_PAYLOAD(a), NLA_F_NESTED);
|
||||
vinfo = RTA_DATA(vtb[BRIDGE_VLANDB_ENTRY_INFO]);
|
||||
|
||||
memset(&vstats, 0, sizeof(vstats));
|
||||
if (vtb[BRIDGE_VLANDB_ENTRY_RANGE])
|
||||
vrange = rta_getattr_u16(vtb[BRIDGE_VLANDB_ENTRY_RANGE]);
|
||||
else
|
||||
vrange = vinfo->vid;
|
||||
|
||||
if (filter_vlan && (filter_vlan < vinfo->vid || filter_vlan > vrange))
|
||||
return;
|
||||
|
||||
if (vtb[BRIDGE_VLANDB_ENTRY_STATE])
|
||||
state = rta_getattr_u8(vtb[BRIDGE_VLANDB_ENTRY_STATE]);
|
||||
|
||||
if (vtb[BRIDGE_VLANDB_ENTRY_STATS]) {
|
||||
struct rtattr *stb[BRIDGE_VLANDB_STATS_MAX+1];
|
||||
struct rtattr *attr;
|
||||
|
||||
attr = vtb[BRIDGE_VLANDB_ENTRY_STATS];
|
||||
parse_rtattr(stb, BRIDGE_VLANDB_STATS_MAX, RTA_DATA(attr),
|
||||
RTA_PAYLOAD(attr));
|
||||
|
||||
if (stb[BRIDGE_VLANDB_STATS_RX_BYTES]) {
|
||||
attr = stb[BRIDGE_VLANDB_STATS_RX_BYTES];
|
||||
vstats.rx_bytes = rta_getattr_u64(attr);
|
||||
}
|
||||
if (stb[BRIDGE_VLANDB_STATS_RX_PACKETS]) {
|
||||
attr = stb[BRIDGE_VLANDB_STATS_RX_PACKETS];
|
||||
vstats.rx_packets = rta_getattr_u64(attr);
|
||||
}
|
||||
if (stb[BRIDGE_VLANDB_STATS_TX_PACKETS]) {
|
||||
attr = stb[BRIDGE_VLANDB_STATS_TX_PACKETS];
|
||||
vstats.tx_packets = rta_getattr_u64(attr);
|
||||
}
|
||||
if (stb[BRIDGE_VLANDB_STATS_TX_BYTES]) {
|
||||
attr = stb[BRIDGE_VLANDB_STATS_TX_BYTES];
|
||||
vstats.tx_bytes = rta_getattr_u64(attr);
|
||||
}
|
||||
}
|
||||
|
||||
if (vlan_rtm_cur_ifidx != ifindex) {
|
||||
open_vlan_port(ifindex, VLAN_SHOW_VLAN);
|
||||
open_json_object(NULL);
|
||||
vlan_rtm_cur_ifidx = ifindex;
|
||||
} else {
|
||||
open_json_object(NULL);
|
||||
print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
|
||||
}
|
||||
print_range("vlan", vinfo->vid, vrange);
|
||||
print_vlan_flags(vinfo->flags);
|
||||
print_nl();
|
||||
print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
|
||||
print_stp_state(state);
|
||||
if (vtb[BRIDGE_VLANDB_ENTRY_MCAST_ROUTER]) {
|
||||
vattr = vtb[BRIDGE_VLANDB_ENTRY_MCAST_ROUTER];
|
||||
print_uint(PRINT_ANY, "mcast_router", "mcast_router %u ",
|
||||
rta_getattr_u8(vattr));
|
||||
}
|
||||
print_nl();
|
||||
if (show_stats)
|
||||
__print_one_vlan_stats(&vstats);
|
||||
close_json_object();
|
||||
}
|
||||
|
||||
int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor, bool global_only)
|
||||
{
|
||||
struct rtattr *vtb[BRIDGE_VLANDB_ENTRY_MAX + 1], *a;
|
||||
struct br_vlan_msg *bvm = NLMSG_DATA(n);
|
||||
int len = n->nlmsg_len;
|
||||
struct rtattr *a;
|
||||
int rem;
|
||||
|
||||
if (n->nlmsg_type != RTM_NEWVLAN && n->nlmsg_type != RTM_DELVLAN &&
|
||||
|
|
@ -660,66 +1066,21 @@ int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor)
|
|||
|
||||
rem = len;
|
||||
for (a = BRVLAN_RTA(bvm); RTA_OK(a, rem); a = RTA_NEXT(a, rem)) {
|
||||
struct bridge_vlan_xstats vstats;
|
||||
struct bridge_vlan_info *vinfo;
|
||||
__u32 vrange = 0;
|
||||
__u8 state = 0;
|
||||
unsigned short rta_type = a->rta_type & NLA_TYPE_MASK;
|
||||
|
||||
parse_rtattr_flags(vtb, BRIDGE_VLANDB_ENTRY_MAX, RTA_DATA(a),
|
||||
RTA_PAYLOAD(a), NLA_F_NESTED);
|
||||
vinfo = RTA_DATA(vtb[BRIDGE_VLANDB_ENTRY_INFO]);
|
||||
/* skip unknown attributes */
|
||||
if (rta_type > BRIDGE_VLANDB_MAX ||
|
||||
(global_only && rta_type != BRIDGE_VLANDB_GLOBAL_OPTIONS))
|
||||
continue;
|
||||
|
||||
memset(&vstats, 0, sizeof(vstats));
|
||||
if (vtb[BRIDGE_VLANDB_ENTRY_RANGE])
|
||||
vrange = rta_getattr_u16(vtb[BRIDGE_VLANDB_ENTRY_RANGE]);
|
||||
else
|
||||
vrange = vinfo->vid;
|
||||
|
||||
if (vtb[BRIDGE_VLANDB_ENTRY_STATE])
|
||||
state = rta_getattr_u8(vtb[BRIDGE_VLANDB_ENTRY_STATE]);
|
||||
|
||||
if (vtb[BRIDGE_VLANDB_ENTRY_STATS]) {
|
||||
struct rtattr *stb[BRIDGE_VLANDB_STATS_MAX+1];
|
||||
struct rtattr *attr;
|
||||
|
||||
attr = vtb[BRIDGE_VLANDB_ENTRY_STATS];
|
||||
parse_rtattr(stb, BRIDGE_VLANDB_STATS_MAX, RTA_DATA(attr),
|
||||
RTA_PAYLOAD(attr));
|
||||
|
||||
if (stb[BRIDGE_VLANDB_STATS_RX_BYTES]) {
|
||||
attr = stb[BRIDGE_VLANDB_STATS_RX_BYTES];
|
||||
vstats.rx_bytes = rta_getattr_u64(attr);
|
||||
}
|
||||
if (stb[BRIDGE_VLANDB_STATS_RX_PACKETS]) {
|
||||
attr = stb[BRIDGE_VLANDB_STATS_RX_PACKETS];
|
||||
vstats.rx_packets = rta_getattr_u64(attr);
|
||||
}
|
||||
if (stb[BRIDGE_VLANDB_STATS_TX_PACKETS]) {
|
||||
attr = stb[BRIDGE_VLANDB_STATS_TX_PACKETS];
|
||||
vstats.tx_packets = rta_getattr_u64(attr);
|
||||
}
|
||||
if (stb[BRIDGE_VLANDB_STATS_TX_BYTES]) {
|
||||
attr = stb[BRIDGE_VLANDB_STATS_TX_BYTES];
|
||||
vstats.tx_bytes = rta_getattr_u64(attr);
|
||||
}
|
||||
switch (rta_type) {
|
||||
case BRIDGE_VLANDB_ENTRY:
|
||||
print_vlan_opts(a, bvm->ifindex);
|
||||
break;
|
||||
case BRIDGE_VLANDB_GLOBAL_OPTIONS:
|
||||
print_vlan_global_opts(a, bvm->ifindex);
|
||||
break;
|
||||
}
|
||||
if (vlan_rtm_cur_ifidx != bvm->ifindex) {
|
||||
open_vlan_port(bvm->ifindex, VLAN_SHOW_VLAN);
|
||||
open_json_object(NULL);
|
||||
vlan_rtm_cur_ifidx = bvm->ifindex;
|
||||
} else {
|
||||
open_json_object(NULL);
|
||||
print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
|
||||
}
|
||||
print_range("vlan", vinfo->vid, vrange);
|
||||
print_vlan_flags(vinfo->flags);
|
||||
print_nl();
|
||||
print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
|
||||
print_stp_state(state);
|
||||
print_nl();
|
||||
if (show_stats)
|
||||
__print_one_vlan_stats(&vstats);
|
||||
close_json_object();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -727,7 +1088,12 @@ int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor)
|
|||
|
||||
static int print_vlan_rtm_filter(struct nlmsghdr *n, void *arg)
|
||||
{
|
||||
return print_vlan_rtm(n, arg, false);
|
||||
return print_vlan_rtm(n, arg, false, false);
|
||||
}
|
||||
|
||||
static int print_vlan_rtm_global_filter(struct nlmsghdr *n, void *arg)
|
||||
{
|
||||
return print_vlan_rtm(n, arg, false, true);
|
||||
}
|
||||
|
||||
static int vlan_show(int argc, char **argv, int subject)
|
||||
|
|
@ -845,6 +1211,61 @@ out:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int vlan_global_show(int argc, char **argv)
|
||||
{
|
||||
__u32 dump_flags = BRIDGE_VLANDB_DUMPF_GLOBAL;
|
||||
int ret = 0, subject = VLAN_SHOW_VLAN;
|
||||
char *filter_dev = NULL;
|
||||
|
||||
while (argc > 0) {
|
||||
if (strcmp(*argv, "dev") == 0) {
|
||||
NEXT_ARG();
|
||||
if (filter_dev)
|
||||
duparg("dev", *argv);
|
||||
filter_dev = *argv;
|
||||
} else if (strcmp(*argv, "vid") == 0) {
|
||||
NEXT_ARG();
|
||||
if (filter_vlan)
|
||||
duparg("vid", *argv);
|
||||
filter_vlan = atoi(*argv);
|
||||
}
|
||||
argc--; argv++;
|
||||
}
|
||||
|
||||
if (filter_dev) {
|
||||
filter_index = ll_name_to_index(filter_dev);
|
||||
if (!filter_index)
|
||||
return nodev(filter_dev);
|
||||
}
|
||||
|
||||
new_json_obj(json);
|
||||
|
||||
if (rtnl_brvlandump_req(&rth, PF_BRIDGE, dump_flags) < 0) {
|
||||
perror("Cannot send dump request");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!is_json_context()) {
|
||||
printf("%-" __stringify(IFNAMSIZ) "s %-"
|
||||
__stringify(VLAN_ID_LEN) "s", "port",
|
||||
"vlan-id");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
ret = rtnl_dump_filter(&rth, print_vlan_rtm_global_filter, &subject);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Dump terminated\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (vlan_rtm_cur_ifidx != -1)
|
||||
close_vlan_port();
|
||||
|
||||
delete_json_obj();
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_vlan_info(struct rtattr *tb, int ifindex)
|
||||
{
|
||||
struct rtattr *i, *list = tb;
|
||||
|
|
@ -889,6 +1310,24 @@ void print_vlan_info(struct rtattr *tb, int ifindex)
|
|||
close_vlan_port();
|
||||
}
|
||||
|
||||
static int vlan_global(int argc, char **argv)
|
||||
{
|
||||
if (argc > 0) {
|
||||
if (strcmp(*argv, "show") == 0 ||
|
||||
strcmp(*argv, "lst") == 0 ||
|
||||
strcmp(*argv, "list") == 0)
|
||||
return vlan_global_show(argc-1, argv+1);
|
||||
else if (strcmp(*argv, "set") == 0)
|
||||
return vlan_global_option_set(argc-1, argv+1);
|
||||
else
|
||||
usage();
|
||||
} else {
|
||||
return vlan_global_show(0, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_vlan(int argc, char **argv)
|
||||
{
|
||||
ll_init_map(&rth);
|
||||
|
|
@ -907,6 +1346,8 @@ int do_vlan(int argc, char **argv)
|
|||
}
|
||||
if (matches(*argv, "set") == 0)
|
||||
return vlan_option_set(argc-1, argv+1);
|
||||
if (strcmp(*argv, "global") == 0)
|
||||
return vlan_global(argc-1, argv+1);
|
||||
if (matches(*argv, "help") == 0)
|
||||
usage();
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# This is not an autoconf generated configure
|
||||
#
|
||||
# Influential LIBBPF environment variables:
|
||||
# LIBBPF_FORCE={on,off} on: require link against libbpf;
|
||||
# off: disable libbpf probing
|
||||
# LIBBPF_DIR Path to libbpf DESTDIR to use
|
||||
|
||||
INCLUDE=${1:-"$PWD/include"}
|
||||
INCLUDE="$PWD/include"
|
||||
PREFIX="/usr"
|
||||
LIBDIR="\${prefix}/lib"
|
||||
|
||||
# Output file which is input to Makefile
|
||||
CONFIG=config.mk
|
||||
|
|
@ -153,6 +150,15 @@ EOF
|
|||
rm -f $TMPDIR/ipttest.c $TMPDIR/ipttest
|
||||
}
|
||||
|
||||
check_lib_dir()
|
||||
{
|
||||
LIBDIR=$(echo $LIBDIR | sed "s|\${prefix}|$PREFIX|")
|
||||
|
||||
echo -n "lib directory: "
|
||||
echo "$LIBDIR"
|
||||
echo "LIBDIR:=$LIBDIR" >> $CONFIG
|
||||
}
|
||||
|
||||
check_ipt()
|
||||
{
|
||||
if ! grep TC_CONFIG_XT $CONFIG > /dev/null; then
|
||||
|
|
@ -202,6 +208,31 @@ EOF
|
|||
rm -f $TMPDIR/setnstest.c $TMPDIR/setnstest
|
||||
}
|
||||
|
||||
check_name_to_handle_at()
|
||||
{
|
||||
cat >$TMPDIR/name_to_handle_at_test.c <<EOF
|
||||
#define _GNU_SOURCE
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct file_handle *fhp;
|
||||
int mount_id, flags, dirfd;
|
||||
char *pathname;
|
||||
name_to_handle_at(dirfd, pathname, fhp, &mount_id, flags);
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if $CC -I$INCLUDE -o $TMPDIR/name_to_handle_at_test $TMPDIR/name_to_handle_at_test.c >/dev/null 2>&1; then
|
||||
echo "yes"
|
||||
echo "CFLAGS += -DHAVE_HANDLE_AT" >>$CONFIG
|
||||
else
|
||||
echo "no"
|
||||
fi
|
||||
rm -f $TMPDIR/name_to_handle_at_test.c $TMPDIR/name_to_handle_at_test
|
||||
}
|
||||
|
||||
check_ipset()
|
||||
{
|
||||
cat >$TMPDIR/ipsettest.c <<EOF
|
||||
|
|
@ -461,6 +492,76 @@ endif
|
|||
EOF
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
cat <<EOF
|
||||
Usage: $0 [OPTIONS]
|
||||
--include_dir <dir> Path to iproute2 include dir
|
||||
--libdir <dir> Path to iproute2 lib dir
|
||||
--libbpf_dir <dir> Path to libbpf DESTDIR
|
||||
--libbpf_force <on|off> Enable/disable libbpf by force. Available options:
|
||||
on: require link against libbpf, quit config if no libbpf support
|
||||
off: disable libbpf probing
|
||||
--prefix <dir> Path prefix of the lib files to install
|
||||
-h | --help Show this usage info
|
||||
EOF
|
||||
exit $1
|
||||
}
|
||||
|
||||
# Compat with the old INCLUDE path setting method.
|
||||
if [ $# -eq 1 ] && [ "$(echo $1 | cut -c 1)" != '-' ]; then
|
||||
INCLUDE="$1"
|
||||
else
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--include_dir)
|
||||
shift
|
||||
INCLUDE="$1" ;;
|
||||
--include_dir=*)
|
||||
INCLUDE="${1#*=}" ;;
|
||||
--libdir)
|
||||
shift
|
||||
LIBDIR="$1" ;;
|
||||
--libdir=*)
|
||||
LIBDIR="${1#*=}" ;;
|
||||
--libbpf_dir)
|
||||
shift
|
||||
LIBBPF_DIR="$1" ;;
|
||||
--libbpf_dir=*)
|
||||
LIBBPF_DIR="${1#*=}" ;;
|
||||
--libbpf_force)
|
||||
shift
|
||||
LIBBPF_FORCE="$1" ;;
|
||||
--libbpf_force=*)
|
||||
LIBBPF_FORCE="${1#*=}" ;;
|
||||
--prefix)
|
||||
shift
|
||||
PREFIX="$1" ;;
|
||||
--prefix=*)
|
||||
PREFIX="${1#*=}" ;;
|
||||
-h | --help)
|
||||
usage 0 ;;
|
||||
--*)
|
||||
;;
|
||||
*)
|
||||
usage 1 ;;
|
||||
esac
|
||||
[ "$#" -gt 0 ] && shift
|
||||
done
|
||||
fi
|
||||
|
||||
[ -d "$INCLUDE" ] || usage 1
|
||||
if [ "${LIBBPF_DIR-unused}" != "unused" ]; then
|
||||
[ -d "$LIBBPF_DIR" ] || usage 1
|
||||
fi
|
||||
if [ "${LIBBPF_FORCE-unused}" != "unused" ]; then
|
||||
if [ "$LIBBPF_FORCE" != 'on' ] && [ "$LIBBPF_FORCE" != 'off' ]; then
|
||||
usage 1
|
||||
fi
|
||||
fi
|
||||
[ -z "$PREFIX" ] && usage 1
|
||||
[ -z "$LIBDIR" ] && usage 1
|
||||
|
||||
echo "# Generated config based on" $INCLUDE >$CONFIG
|
||||
quiet_config >> $CONFIG
|
||||
|
||||
|
|
@ -484,6 +585,7 @@ if ! grep -q TC_CONFIG_NO_XT $CONFIG; then
|
|||
fi
|
||||
|
||||
echo
|
||||
check_lib_dir
|
||||
if ! grep -q TC_CONFIG_NO_XT $CONFIG; then
|
||||
echo -n "iptables modules directory: "
|
||||
check_ipt_lib_dir
|
||||
|
|
@ -492,6 +594,9 @@ fi
|
|||
echo -n "libc has setns: "
|
||||
check_setns
|
||||
|
||||
echo -n "libc has name_to_handle_at: "
|
||||
check_name_to_handle_at
|
||||
|
||||
echo -n "SELinux support: "
|
||||
check_selinux
|
||||
|
||||
|
|
|
|||
|
|
@ -571,7 +571,8 @@ int main(int argc, char **argv)
|
|||
break;
|
||||
case 'h':
|
||||
dcb_help();
|
||||
return 0;
|
||||
ret = EXIT_SUCCESS;
|
||||
goto dcb_free;
|
||||
default:
|
||||
fprintf(stderr, "Unknown option.\n");
|
||||
dcb_help();
|
||||
|
|
|
|||
|
|
@ -667,7 +667,7 @@ static int dcb_cmd_app_show(struct dcb *dcb, const char *dev, int argc, char **a
|
|||
out:
|
||||
close_json_object();
|
||||
dcb_app_table_fini(&tab);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dcb_cmd_app_flush(struct dcb *dcb, const char *dev, int argc, char **argv)
|
||||
|
|
|
|||
|
|
@ -71,6 +71,8 @@ static bool g_indent_newline;
|
|||
#define INDENT_STR_MAXLEN 32
|
||||
static char g_indent_str[INDENT_STR_MAXLEN + 1] = "";
|
||||
|
||||
static bool use_iec = false;
|
||||
|
||||
static void __attribute__((format(printf, 1, 2)))
|
||||
pr_err(const char *fmt, ...)
|
||||
{
|
||||
|
|
@ -286,6 +288,12 @@ static void ifname_map_free(struct ifname_map *ifname_map)
|
|||
#define DL_OPT_PORT_PFNUMBER BIT(43)
|
||||
#define DL_OPT_PORT_SFNUMBER BIT(44)
|
||||
#define DL_OPT_PORT_FUNCTION_STATE BIT(45)
|
||||
#define DL_OPT_PORT_CONTROLLER BIT(46)
|
||||
#define DL_OPT_PORT_FN_RATE_TYPE BIT(47)
|
||||
#define DL_OPT_PORT_FN_RATE_TX_SHARE BIT(48)
|
||||
#define DL_OPT_PORT_FN_RATE_TX_MAX BIT(49)
|
||||
#define DL_OPT_PORT_FN_RATE_NODE_NAME BIT(50)
|
||||
#define DL_OPT_PORT_FN_RATE_PARENT BIT(51)
|
||||
|
||||
struct dl_opts {
|
||||
uint64_t present; /* flags of present items */
|
||||
|
|
@ -336,10 +344,16 @@ struct dl_opts {
|
|||
uint32_t overwrite_mask;
|
||||
enum devlink_reload_action reload_action;
|
||||
enum devlink_reload_limit reload_limit;
|
||||
uint32_t port_controller;
|
||||
uint32_t port_sfnumber;
|
||||
uint16_t port_flavour;
|
||||
uint16_t port_pfnumber;
|
||||
uint8_t port_fn_state;
|
||||
uint16_t rate_type;
|
||||
uint64_t rate_tx_share;
|
||||
uint64_t rate_tx_max;
|
||||
char *rate_node_name;
|
||||
const char *rate_parent_node;
|
||||
};
|
||||
|
||||
struct dl {
|
||||
|
|
@ -915,6 +929,19 @@ static int strtobool(const char *str, bool *p_val)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ident_str_validate(char *str, unsigned int expected)
|
||||
{
|
||||
if (!str)
|
||||
return -EINVAL;
|
||||
|
||||
if (get_str_char_count(str, '/') != expected) {
|
||||
pr_err("Wrong identification string format.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name)
|
||||
{
|
||||
int err;
|
||||
|
|
@ -930,15 +957,12 @@ static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name)
|
|||
static int dl_argv_handle(struct dl *dl, char **p_bus_name, char **p_dev_name)
|
||||
{
|
||||
char *str = dl_argv_next(dl);
|
||||
int err;
|
||||
|
||||
if (!str) {
|
||||
err = ident_str_validate(str, 1);
|
||||
if (err) {
|
||||
pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (get_str_char_count(str, '/') != 1) {
|
||||
pr_err("Wrong devlink identification string format.\n");
|
||||
pr_err("Expected \"bus_name/dev_name\".\n");
|
||||
return -EINVAL;
|
||||
return err;
|
||||
}
|
||||
return __dl_argv_handle(str, p_bus_name, p_dev_name);
|
||||
}
|
||||
|
|
@ -1050,44 +1074,103 @@ static int dl_argv_handle_both(struct dl *dl, char **p_bus_name,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __dl_argv_handle_region(char *str, char **p_bus_name,
|
||||
char **p_dev_name, char **p_region)
|
||||
static int __dl_argv_handle_name(char *str, char **p_bus_name,
|
||||
char **p_dev_name, char **p_name)
|
||||
{
|
||||
char *handlestr;
|
||||
int err;
|
||||
|
||||
err = str_split_by_char(str, &handlestr, p_region, '/');
|
||||
if (err) {
|
||||
pr_err("Region identification \"%s\" is invalid\n", str);
|
||||
err = str_split_by_char(str, &handlestr, p_name, '/');
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
err = str_split_by_char(handlestr, p_bus_name, p_dev_name, '/');
|
||||
if (err) {
|
||||
pr_err("Region identification \"%s\" is invalid\n", str);
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
|
||||
return str_split_by_char(handlestr, p_bus_name, p_dev_name, '/');
|
||||
}
|
||||
|
||||
static int dl_argv_handle_region(struct dl *dl, char **p_bus_name,
|
||||
char **p_dev_name, char **p_region)
|
||||
char **p_dev_name, char **p_region)
|
||||
{
|
||||
char *str = dl_argv_next(dl);
|
||||
unsigned int slash_count;
|
||||
int err;
|
||||
|
||||
if (!str) {
|
||||
err = ident_str_validate(str, 2);
|
||||
if (err) {
|
||||
pr_err("Expected \"bus_name/dev_name/region\" identification.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = __dl_argv_handle_name(str, p_bus_name, p_dev_name, p_region);
|
||||
if (err)
|
||||
pr_err("Region identification \"%s\" is invalid\n", str);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int dl_argv_handle_rate_node(struct dl *dl, char **p_bus_name,
|
||||
char **p_dev_name, char **p_node)
|
||||
{
|
||||
char *str = dl_argv_next(dl);
|
||||
int err;
|
||||
|
||||
err = ident_str_validate(str, 2);
|
||||
if (err) {
|
||||
pr_err("Expected \"bus_name/dev_name/node\" identification.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = __dl_argv_handle_name(str, p_bus_name, p_dev_name, p_node);
|
||||
if (err) {
|
||||
pr_err("Node identification \"%s\" is invalid\n", str);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!**p_node || strspn(*p_node, "0123456789") == strlen(*p_node)) {
|
||||
err = -EINVAL;
|
||||
pr_err("Node name cannot be a devlink port index or empty.\n");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int dl_argv_handle_rate(struct dl *dl, char **p_bus_name,
|
||||
char **p_dev_name, uint32_t *p_port_index,
|
||||
char **p_node_name, uint64_t *p_handle_bit)
|
||||
{
|
||||
char *str = dl_argv_next(dl);
|
||||
char *identifier;
|
||||
int err;
|
||||
|
||||
err = ident_str_validate(str, 2);
|
||||
if (err) {
|
||||
pr_err("Expected \"bus_name/dev_name/node\" or "
|
||||
"\"bus_name/dev_name/port_index\" identification.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = __dl_argv_handle_name(str, p_bus_name, p_dev_name, &identifier);
|
||||
if (err) {
|
||||
pr_err("Identification \"%s\" is invalid\n", str);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!*identifier) {
|
||||
pr_err("Identifier cannot be empty");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
slash_count = get_str_char_count(str, '/');
|
||||
if (slash_count != 2) {
|
||||
pr_err("Wrong region identification string format.\n");
|
||||
pr_err("Expected \"bus_name/dev_name/region\" identification.\n"".\n");
|
||||
return -EINVAL;
|
||||
if (strspn(identifier, "0123456789") == strlen(identifier)) {
|
||||
err = strtouint32_t(identifier, p_port_index);
|
||||
if (err) {
|
||||
pr_err("Port index \"%s\" is not a number"
|
||||
" or not within range\n", identifier);
|
||||
return err;
|
||||
}
|
||||
*p_handle_bit = DL_OPT_HANDLEP;
|
||||
} else {
|
||||
*p_handle_bit = DL_OPT_PORT_FN_RATE_NODE_NAME;
|
||||
*p_node_name = identifier;
|
||||
}
|
||||
|
||||
return __dl_argv_handle_region(str, p_bus_name, p_dev_name, p_region);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dl_argv_uint64_t(struct dl *dl, uint64_t *p_val)
|
||||
|
|
@ -1399,6 +1482,36 @@ static int port_fn_state_parse(const char *statestr, uint8_t *state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int port_fn_rate_type_get(const char *typestr, uint16_t *type)
|
||||
{
|
||||
if (!strcmp(typestr, "leaf"))
|
||||
*type = DEVLINK_RATE_TYPE_LEAF;
|
||||
else if (!strcmp(typestr, "node"))
|
||||
*type = DEVLINK_RATE_TYPE_NODE;
|
||||
else
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int port_fn_rate_value_get(struct dl *dl, uint64_t *rate)
|
||||
{
|
||||
const char *ratestr;
|
||||
__u64 rate64;
|
||||
int err;
|
||||
|
||||
err = dl_argv_str(dl, &ratestr);
|
||||
if (err)
|
||||
return err;
|
||||
err = get_rate64(&rate64, ratestr);
|
||||
if (err) {
|
||||
pr_err("Invalid rate value: \"%s\"\n", ratestr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*rate = rate64;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dl_args_metadata {
|
||||
uint64_t o_flag;
|
||||
char err_msg[DL_ARGS_REQUIRED_MAX_ERR_LEN];
|
||||
|
|
@ -1471,6 +1584,19 @@ static int dl_argv_parse(struct dl *dl, uint64_t o_required,
|
|||
return err;
|
||||
o_required &= ~(DL_OPT_HANDLE | DL_OPT_HANDLEP) | handle_bit;
|
||||
o_found |= handle_bit;
|
||||
} else if (o_required & DL_OPT_HANDLEP &&
|
||||
o_required & DL_OPT_PORT_FN_RATE_NODE_NAME) {
|
||||
uint64_t handle_bit;
|
||||
|
||||
err = dl_argv_handle_rate(dl, &opts->bus_name, &opts->dev_name,
|
||||
&opts->port_index,
|
||||
&opts->rate_node_name,
|
||||
&handle_bit);
|
||||
if (err)
|
||||
return err;
|
||||
o_required &= ~(DL_OPT_HANDLEP | DL_OPT_PORT_FN_RATE_NODE_NAME) |
|
||||
handle_bit;
|
||||
o_found |= handle_bit;
|
||||
} else if (o_required & DL_OPT_HANDLE) {
|
||||
err = dl_argv_handle(dl, &opts->bus_name, &opts->dev_name);
|
||||
if (err)
|
||||
|
|
@ -1489,6 +1615,13 @@ static int dl_argv_parse(struct dl *dl, uint64_t o_required,
|
|||
if (err)
|
||||
return err;
|
||||
o_found |= DL_OPT_HANDLE_REGION;
|
||||
} else if (o_required & DL_OPT_PORT_FN_RATE_NODE_NAME) {
|
||||
err = dl_argv_handle_rate_node(dl, &opts->bus_name,
|
||||
&opts->dev_name,
|
||||
&opts->rate_node_name);
|
||||
if (err)
|
||||
return err;
|
||||
o_found |= DL_OPT_PORT_FN_RATE_NODE_NAME;
|
||||
}
|
||||
|
||||
while (dl_argc(dl)) {
|
||||
|
|
@ -1886,6 +2019,50 @@ static int dl_argv_parse(struct dl *dl, uint64_t o_required,
|
|||
if (err)
|
||||
return err;
|
||||
o_found |= DL_OPT_PORT_SFNUMBER;
|
||||
} else if (dl_argv_match(dl, "controller") && (o_all & DL_OPT_PORT_CONTROLLER)) {
|
||||
dl_arg_inc(dl);
|
||||
err = dl_argv_uint32_t(dl, &opts->port_controller);
|
||||
if (err)
|
||||
return err;
|
||||
o_found |= DL_OPT_PORT_CONTROLLER;
|
||||
} else if (dl_argv_match(dl, "type") &&
|
||||
(o_all & DL_OPT_PORT_FN_RATE_TYPE)) {
|
||||
const char *typestr;
|
||||
|
||||
dl_arg_inc(dl);
|
||||
err = dl_argv_str(dl, &typestr);
|
||||
if (err)
|
||||
return err;
|
||||
err = port_fn_rate_type_get(typestr, &opts->rate_type);
|
||||
if (err)
|
||||
return err;
|
||||
o_found |= DL_OPT_PORT_FN_RATE_TYPE;
|
||||
} else if (dl_argv_match(dl, "tx_share") &&
|
||||
(o_all & DL_OPT_PORT_FN_RATE_TX_SHARE)) {
|
||||
dl_arg_inc(dl);
|
||||
err = port_fn_rate_value_get(dl, &opts->rate_tx_share);
|
||||
if (err)
|
||||
return err;
|
||||
o_found |= DL_OPT_PORT_FN_RATE_TX_SHARE;
|
||||
} else if (dl_argv_match(dl, "tx_max") &&
|
||||
(o_all & DL_OPT_PORT_FN_RATE_TX_MAX)) {
|
||||
dl_arg_inc(dl);
|
||||
err = port_fn_rate_value_get(dl, &opts->rate_tx_max);
|
||||
if (err)
|
||||
return err;
|
||||
o_found |= DL_OPT_PORT_FN_RATE_TX_MAX;
|
||||
} else if (dl_argv_match(dl, "parent") &&
|
||||
(o_all & DL_OPT_PORT_FN_RATE_PARENT)) {
|
||||
dl_arg_inc(dl);
|
||||
err = dl_argv_str(dl, &opts->rate_parent_node);
|
||||
if (err)
|
||||
return err;
|
||||
o_found |= DL_OPT_PORT_FN_RATE_PARENT;
|
||||
} else if (dl_argv_match(dl, "noparent") &&
|
||||
(o_all & DL_OPT_PORT_FN_RATE_PARENT)) {
|
||||
dl_arg_inc(dl);
|
||||
opts->rate_parent_node = "";
|
||||
o_found |= DL_OPT_PORT_FN_RATE_PARENT;
|
||||
} else {
|
||||
pr_err("Unknown option \"%s\"\n", dl_argv(dl));
|
||||
return -EINVAL;
|
||||
|
|
@ -1958,6 +2135,11 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
|
|||
mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
|
||||
mnl_attr_put_strz(nlh, DEVLINK_ATTR_REGION_NAME,
|
||||
opts->region_name);
|
||||
} else if (opts->present & DL_OPT_PORT_FN_RATE_NODE_NAME) {
|
||||
mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
|
||||
mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
|
||||
mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_NODE_NAME,
|
||||
opts->rate_node_name);
|
||||
}
|
||||
if (opts->present & DL_OPT_PORT_TYPE)
|
||||
mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_TYPE,
|
||||
|
|
@ -2079,6 +2261,21 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
|
|||
mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, opts->port_pfnumber);
|
||||
if (opts->present & DL_OPT_PORT_SFNUMBER)
|
||||
mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_PCI_SF_NUMBER, opts->port_sfnumber);
|
||||
if (opts->present & DL_OPT_PORT_CONTROLLER)
|
||||
mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER,
|
||||
opts->port_controller);
|
||||
if (opts->present & DL_OPT_PORT_FN_RATE_TYPE)
|
||||
mnl_attr_put_u16(nlh, DEVLINK_ATTR_RATE_TYPE,
|
||||
opts->rate_type);
|
||||
if (opts->present & DL_OPT_PORT_FN_RATE_TX_SHARE)
|
||||
mnl_attr_put_u64(nlh, DEVLINK_ATTR_RATE_TX_SHARE,
|
||||
opts->rate_tx_share);
|
||||
if (opts->present & DL_OPT_PORT_FN_RATE_TX_MAX)
|
||||
mnl_attr_put_u64(nlh, DEVLINK_ATTR_RATE_TX_MAX,
|
||||
opts->rate_tx_max);
|
||||
if (opts->present & DL_OPT_PORT_FN_RATE_PARENT)
|
||||
mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_PARENT_NODE_NAME,
|
||||
opts->rate_parent_node);
|
||||
}
|
||||
|
||||
static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl,
|
||||
|
|
@ -2839,6 +3036,7 @@ static int cmd_dev_param_show_cb(const struct nlmsghdr *nlh, void *data)
|
|||
struct param_ctx {
|
||||
struct dl *dl;
|
||||
int nla_type;
|
||||
bool cmode_found;
|
||||
union {
|
||||
uint8_t vu8;
|
||||
uint16_t vu16;
|
||||
|
|
@ -2891,6 +3089,7 @@ static int cmd_dev_param_set_cb(const struct nlmsghdr *nlh, void *data)
|
|||
|
||||
cmode = mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
|
||||
if (cmode == dl->opts.cmode) {
|
||||
ctx->cmode_found = true;
|
||||
val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
|
||||
switch (nla_type) {
|
||||
case MNL_TYPE_U8:
|
||||
|
|
@ -2943,6 +3142,10 @@ static int cmd_dev_param_set(struct dl *dl)
|
|||
err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dev_param_set_cb, &ctx);
|
||||
if (err)
|
||||
return err;
|
||||
if (!ctx.cmode_found) {
|
||||
pr_err("Configuration mode not supported\n");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PARAM_SET,
|
||||
NLM_F_REQUEST | NLM_F_ACK);
|
||||
|
|
@ -3503,7 +3706,7 @@ static int cmd_dev_flash_status_cb(const struct nlmsghdr *nlh, void *data)
|
|||
strcmp(dev_name, opts->dev_name))
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
if (genl->cmd == DEVLINK_CMD_FLASH_UPDATE_END && ctx->not_first) {
|
||||
if (genl->cmd == DEVLINK_CMD_FLASH_UPDATE_END) {
|
||||
pr_out("\n");
|
||||
free(ctx->last_msg);
|
||||
free(ctx->last_component);
|
||||
|
|
@ -3791,11 +3994,13 @@ static void cmd_port_help(void)
|
|||
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");
|
||||
pr_err(" devlink port function set DEV/PORT_INDEX [ hw_addr ADDR ] [ state STATE ]\n");
|
||||
pr_err(" devlink port function set DEV/PORT_INDEX [ hw_addr ADDR ] [ state { active | inactive } ]\n");
|
||||
pr_err(" devlink port function rate { help | show | add | del | set }\n");
|
||||
pr_err(" devlink port param set DEV/PORT_INDEX name PARAMETER value VALUE cmode { permanent | driverinit | runtime }\n");
|
||||
pr_err(" devlink port param show [DEV/PORT_INDEX name PARAMETER]\n");
|
||||
pr_err(" devlink port health show [ DEV/PORT_INDEX reporter REPORTER_NAME ]\n");
|
||||
pr_err(" devlink port add DEV/PORT_INDEX flavour FLAVOUR pfnum PFNUM [ sfnum SFNUM ]\n");
|
||||
pr_err(" devlink port add DEV/PORT_INDEX flavour FLAVOUR pfnum PFNUM\n"
|
||||
" [ sfnum SFNUM ][ controller CNUM ]\n");
|
||||
pr_err(" devlink port del DEV/PORT_INDEX\n");
|
||||
}
|
||||
|
||||
|
|
@ -4085,6 +4290,7 @@ static int cmd_port_param_show(struct dl *dl)
|
|||
static void cmd_port_function_help(void)
|
||||
{
|
||||
pr_err("Usage: devlink port function set DEV/PORT_INDEX [ hw_addr ADDR ] [ state STATE ]\n");
|
||||
pr_err(" devlink port function rate { help | show | add | del | set }\n");
|
||||
}
|
||||
|
||||
static int cmd_port_function_set(struct dl *dl)
|
||||
|
|
@ -4306,6 +4512,280 @@ static int cmd_port_param(struct dl *dl)
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
static void
|
||||
pr_out_port_rate_handle_start(struct dl *dl, struct nlattr **tb, bool try_nice)
|
||||
{
|
||||
const char *bus_name;
|
||||
const char *dev_name;
|
||||
const char *node_name;
|
||||
static char buf[64];
|
||||
|
||||
bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
|
||||
dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
|
||||
node_name = mnl_attr_get_str(tb[DEVLINK_ATTR_RATE_NODE_NAME]);
|
||||
sprintf(buf, "%s/%s/%s", bus_name, dev_name, node_name);
|
||||
if (dl->json_output)
|
||||
open_json_object(buf);
|
||||
else
|
||||
pr_out("%s:", buf);
|
||||
}
|
||||
|
||||
static char *port_rate_type_name(uint16_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case DEVLINK_RATE_TYPE_LEAF:
|
||||
return "leaf";
|
||||
case DEVLINK_RATE_TYPE_NODE:
|
||||
return "node";
|
||||
default:
|
||||
return "<unknown type>";
|
||||
}
|
||||
}
|
||||
|
||||
static void pr_out_port_fn_rate(struct dl *dl, struct nlattr **tb)
|
||||
{
|
||||
|
||||
if (!tb[DEVLINK_ATTR_RATE_NODE_NAME])
|
||||
pr_out_port_handle_start(dl, tb, false);
|
||||
else
|
||||
pr_out_port_rate_handle_start(dl, tb, false);
|
||||
check_indent_newline(dl);
|
||||
|
||||
if (tb[DEVLINK_ATTR_RATE_TYPE]) {
|
||||
uint16_t type =
|
||||
mnl_attr_get_u16(tb[DEVLINK_ATTR_RATE_TYPE]);
|
||||
|
||||
print_string(PRINT_ANY, "type", "type %s",
|
||||
port_rate_type_name(type));
|
||||
}
|
||||
if (tb[DEVLINK_ATTR_RATE_TX_SHARE]) {
|
||||
uint64_t rate =
|
||||
mnl_attr_get_u64(tb[DEVLINK_ATTR_RATE_TX_SHARE]);
|
||||
|
||||
if (rate)
|
||||
print_rate(use_iec, PRINT_ANY, "tx_share",
|
||||
" tx_share %s", rate);
|
||||
}
|
||||
if (tb[DEVLINK_ATTR_RATE_TX_MAX]) {
|
||||
uint64_t rate =
|
||||
mnl_attr_get_u64(tb[DEVLINK_ATTR_RATE_TX_MAX]);
|
||||
|
||||
if (rate)
|
||||
print_rate(use_iec, PRINT_ANY, "tx_max",
|
||||
" tx_max %s", rate);
|
||||
}
|
||||
if (tb[DEVLINK_ATTR_RATE_PARENT_NODE_NAME]) {
|
||||
const char *parent =
|
||||
mnl_attr_get_str(tb[DEVLINK_ATTR_RATE_PARENT_NODE_NAME]);
|
||||
|
||||
print_string(PRINT_ANY, "parent", " parent %s", parent);
|
||||
}
|
||||
|
||||
pr_out_port_handle_end(dl);
|
||||
}
|
||||
|
||||
static int cmd_port_fn_rate_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_RATE_NODE_NAME]) {
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
pr_out_port_fn_rate(dl, tb);
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static void cmd_port_fn_rate_help(void)
|
||||
{
|
||||
pr_err("Usage: devlink port function rate help\n");
|
||||
pr_err(" devlink port function rate show [ DEV/{ PORT_INDEX | NODE_NAME } ]\n");
|
||||
pr_err(" devlink port function rate add DEV/NODE_NAME\n");
|
||||
pr_err(" [ tx_share VAL ][ tx_max VAL ][ { parent NODE_NAME | noparent } ]\n");
|
||||
pr_err(" devlink port function rate del DEV/NODE_NAME\n");
|
||||
pr_err(" devlink port function rate set DEV/{ PORT_INDEX | NODE_NAME }\n");
|
||||
pr_err(" [ tx_share VAL ][ tx_max VAL ][ { parent NODE_NAME | noparent } ]\n\n");
|
||||
pr_err(" VAL - float or integer value in units of bits or bytes per second (bit|bps)\n");
|
||||
pr_err(" and SI (k-, m-, g-, t-) or IEC (ki-, mi-, gi-, ti-) case-insensitive prefix.\n");
|
||||
pr_err(" Bare number, means bits per second, is possible.\n\n");
|
||||
pr_err(" For details refer to devlink-rate(8) man page.\n");
|
||||
}
|
||||
|
||||
static int cmd_port_fn_rate_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 = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_GET, flags);
|
||||
|
||||
if (dl_argc(dl) > 0) {
|
||||
err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP |
|
||||
DL_OPT_PORT_FN_RATE_NODE_NAME, 0);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
pr_out_section_start(dl, "rate");
|
||||
err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_fn_rate_show_cb, dl);
|
||||
pr_out_section_end(dl);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int port_fn_check_tx_rates(uint64_t min_rate, uint64_t max_rate)
|
||||
{
|
||||
if (max_rate && min_rate > max_rate) {
|
||||
pr_err("Invalid. Expected tx_share <= tx_max or tx_share == 0.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int port_fn_get_and_check_tx_rates(struct dl_opts *reply,
|
||||
struct dl_opts *request)
|
||||
{
|
||||
uint64_t min = reply->rate_tx_share;
|
||||
uint64_t max = reply->rate_tx_max;
|
||||
|
||||
if (request->present & DL_OPT_PORT_FN_RATE_TX_SHARE)
|
||||
return port_fn_check_tx_rates(request->rate_tx_share, max);
|
||||
return port_fn_check_tx_rates(min, request->rate_tx_max);
|
||||
}
|
||||
|
||||
static int cmd_port_fn_rate_add(struct dl *dl)
|
||||
{
|
||||
struct nlmsghdr *nlh;
|
||||
int err;
|
||||
|
||||
nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_NEW,
|
||||
NLM_F_REQUEST | NLM_F_ACK);
|
||||
err = dl_argv_parse_put(nlh, dl, DL_OPT_PORT_FN_RATE_NODE_NAME,
|
||||
DL_OPT_PORT_FN_RATE_TX_SHARE |
|
||||
DL_OPT_PORT_FN_RATE_TX_MAX);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if ((dl->opts.present & DL_OPT_PORT_FN_RATE_TX_SHARE) &&
|
||||
(dl->opts.present & DL_OPT_PORT_FN_RATE_TX_MAX)) {
|
||||
err = port_fn_check_tx_rates(dl->opts.rate_tx_share,
|
||||
dl->opts.rate_tx_max);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
|
||||
}
|
||||
|
||||
static int cmd_port_fn_rate_del(struct dl *dl)
|
||||
{
|
||||
struct nlmsghdr *nlh;
|
||||
int err;
|
||||
|
||||
nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_DEL,
|
||||
NLM_F_REQUEST | NLM_F_ACK);
|
||||
err = dl_argv_parse_put(nlh, dl, DL_OPT_PORT_FN_RATE_NODE_NAME, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
|
||||
}
|
||||
|
||||
static int port_fn_get_rates_cb(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
struct dl_opts *opts = 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_RATE_NODE_NAME]) {
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
|
||||
if (tb[DEVLINK_ATTR_RATE_TX_SHARE])
|
||||
opts->rate_tx_share =
|
||||
mnl_attr_get_u64(tb[DEVLINK_ATTR_RATE_TX_SHARE]);
|
||||
if (tb[DEVLINK_ATTR_RATE_TX_MAX])
|
||||
opts->rate_tx_max =
|
||||
mnl_attr_get_u64(tb[DEVLINK_ATTR_RATE_TX_MAX]);
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int cmd_port_fn_rate_set(struct dl *dl)
|
||||
{
|
||||
struct dl_opts tmp_opts = {0};
|
||||
struct nlmsghdr *nlh;
|
||||
int err;
|
||||
|
||||
err = dl_argv_parse(dl, DL_OPT_HANDLEP |
|
||||
DL_OPT_PORT_FN_RATE_NODE_NAME,
|
||||
DL_OPT_PORT_FN_RATE_TX_SHARE |
|
||||
DL_OPT_PORT_FN_RATE_TX_MAX |
|
||||
DL_OPT_PORT_FN_RATE_PARENT);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if ((dl->opts.present & DL_OPT_PORT_FN_RATE_TX_SHARE) &&
|
||||
(dl->opts.present & DL_OPT_PORT_FN_RATE_TX_MAX)) {
|
||||
err = port_fn_check_tx_rates(dl->opts.rate_tx_share,
|
||||
dl->opts.rate_tx_max);
|
||||
if (err)
|
||||
return err;
|
||||
} else if (dl->opts.present &
|
||||
(DL_OPT_PORT_FN_RATE_TX_SHARE | DL_OPT_PORT_FN_RATE_TX_MAX)) {
|
||||
nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_GET,
|
||||
NLM_F_REQUEST | NLM_F_ACK);
|
||||
tmp_opts = dl->opts;
|
||||
dl->opts.present &= ~(DL_OPT_PORT_FN_RATE_TX_SHARE |
|
||||
DL_OPT_PORT_FN_RATE_TX_MAX |
|
||||
DL_OPT_PORT_FN_RATE_PARENT);
|
||||
dl_opts_put(nlh, dl);
|
||||
err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, port_fn_get_rates_cb,
|
||||
&dl->opts);
|
||||
if (err)
|
||||
return err;
|
||||
err = port_fn_get_and_check_tx_rates(&dl->opts, &tmp_opts);
|
||||
if (err)
|
||||
return err;
|
||||
dl->opts = tmp_opts;
|
||||
}
|
||||
|
||||
nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_SET,
|
||||
NLM_F_REQUEST | NLM_F_ACK);
|
||||
dl_opts_put(nlh, dl);
|
||||
return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
|
||||
}
|
||||
|
||||
static int cmd_port_function_rate(struct dl *dl)
|
||||
{
|
||||
if (dl_argv_match(dl, "help")) {
|
||||
cmd_port_fn_rate_help();
|
||||
return 0;
|
||||
} else if (dl_argv_match(dl, "show") || dl_no_arg(dl)) {
|
||||
dl_arg_inc(dl);
|
||||
return cmd_port_fn_rate_show(dl);
|
||||
} else if (dl_argv_match(dl, "add")) {
|
||||
dl_arg_inc(dl);
|
||||
return cmd_port_fn_rate_add(dl);
|
||||
} else if (dl_argv_match(dl, "del")) {
|
||||
dl_arg_inc(dl);
|
||||
return cmd_port_fn_rate_del(dl);
|
||||
} else if (dl_argv_match(dl, "set")) {
|
||||
dl_arg_inc(dl);
|
||||
return cmd_port_fn_rate_set(dl);
|
||||
}
|
||||
pr_err("Command \"%s\" not found\n", dl_argv(dl));
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int cmd_port_function(struct dl *dl)
|
||||
{
|
||||
if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
|
||||
|
|
@ -4314,6 +4794,9 @@ static int cmd_port_function(struct dl *dl)
|
|||
} else if (dl_argv_match(dl, "set")) {
|
||||
dl_arg_inc(dl);
|
||||
return cmd_port_function_set(dl);
|
||||
} else if (dl_argv_match(dl, "rate")) {
|
||||
dl_arg_inc(dl);
|
||||
return cmd_port_function_rate(dl);
|
||||
}
|
||||
pr_err("Command \"%s\" not found\n", dl_argv(dl));
|
||||
return -ENOENT;
|
||||
|
|
@ -4324,7 +4807,8 @@ static int __cmd_health_show(struct dl *dl, bool show_device, bool show_port);
|
|||
|
||||
static void cmd_port_add_help(void)
|
||||
{
|
||||
pr_err(" devlink port add { DEV | DEV/PORT_INDEX } flavour FLAVOUR pfnum PFNUM [ sfnum SFNUM ]\n");
|
||||
pr_err(" devlink port add DEV/PORT_INDEX flavour FLAVOUR pfnum PFNUM\n"
|
||||
" [ sfnum SFNUM ][ controller CNUM ]\n");
|
||||
}
|
||||
|
||||
static int cmd_port_add(struct dl *dl)
|
||||
|
|
@ -4342,7 +4826,7 @@ static int cmd_port_add(struct dl *dl)
|
|||
|
||||
err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_HANDLEP |
|
||||
DL_OPT_PORT_FLAVOUR | DL_OPT_PORT_PFNUMBER,
|
||||
DL_OPT_PORT_SFNUMBER);
|
||||
DL_OPT_PORT_SFNUMBER | DL_OPT_PORT_CONTROLLER);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
@ -7367,6 +7851,10 @@ static void pr_out_region(struct dl *dl, struct nlattr **tb)
|
|||
if (tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
|
||||
pr_out_snapshot(dl, tb);
|
||||
|
||||
if (tb[DEVLINK_ATTR_REGION_MAX_SNAPSHOTS])
|
||||
pr_out_u64(dl, "max",
|
||||
mnl_attr_get_u32(tb[DEVLINK_ATTR_REGION_MAX_SNAPSHOTS]));
|
||||
|
||||
pr_out_region_handle_end(dl);
|
||||
}
|
||||
|
||||
|
|
@ -8609,6 +9097,7 @@ int main(int argc, char **argv)
|
|||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ "statistics", no_argument, NULL, 's' },
|
||||
{ "Netns", required_argument, NULL, 'N' },
|
||||
{ "iec", no_argument, NULL, 'i' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
const char *batch_file = NULL;
|
||||
|
|
@ -8624,7 +9113,7 @@ int main(int argc, char **argv)
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "Vfb:njpvsN:",
|
||||
while ((opt = getopt_long(argc, argv, "Vfb:njpvsN:i",
|
||||
long_options, NULL)) >= 0) {
|
||||
|
||||
switch (opt) {
|
||||
|
|
@ -8659,6 +9148,9 @@ int main(int argc, char **argv)
|
|||
goto dl_free;
|
||||
}
|
||||
break;
|
||||
case 'i':
|
||||
use_iec = true;
|
||||
break;
|
||||
default:
|
||||
pr_err("Unknown option.\n");
|
||||
help();
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ Where:
|
|||
|
||||
ACTION semantics
|
||||
- pass and ok are equivalent to accept
|
||||
- continue allows to restart classification lookup
|
||||
- continue allows one to restart classification lookup
|
||||
- drop drops packets
|
||||
- reclassify implies continue classification where we left off
|
||||
|
||||
|
|
|
|||
|
|
@ -109,6 +109,27 @@ struct rtnl_ctrl_data {
|
|||
|
||||
typedef int (*rtnl_filter_t)(struct nlmsghdr *n, void *);
|
||||
|
||||
/**
|
||||
* rtnl error handler called from
|
||||
* rtnl_dump_done()
|
||||
* rtnl_dump_error()
|
||||
*
|
||||
* Return value is a bitmask of the following values:
|
||||
* RTNL_LET_NLERR
|
||||
* error handled as usual
|
||||
* RTNL_SUPPRESS_NLMSG_DONE_NLERR
|
||||
* error in nlmsg_type == NLMSG_DONE will be suppressed
|
||||
* RTNL_SUPPRESS_NLMSG_ERROR_NLERR
|
||||
* error in nlmsg_type == NLMSG_ERROR will be suppressed
|
||||
* and nlmsg will be skipped
|
||||
* RTNL_SUPPRESS_NLERR - suppress error in both previous cases
|
||||
*/
|
||||
#define RTNL_LET_NLERR 0x01
|
||||
#define RTNL_SUPPRESS_NLMSG_DONE_NLERR 0x02
|
||||
#define RTNL_SUPPRESS_NLMSG_ERROR_NLERR 0x04
|
||||
#define RTNL_SUPPRESS_NLERR 0x06
|
||||
typedef int (*rtnl_err_hndlr_t)(struct nlmsghdr *n, void *);
|
||||
|
||||
typedef int (*rtnl_listen_filter_t)(struct rtnl_ctrl_data *,
|
||||
struct nlmsghdr *n, void *);
|
||||
|
||||
|
|
@ -118,6 +139,8 @@ typedef int (*nl_ext_ack_fn_t)(const char *errmsg, uint32_t off,
|
|||
struct rtnl_dump_filter_arg {
|
||||
rtnl_filter_t filter;
|
||||
void *arg1;
|
||||
rtnl_err_hndlr_t errhndlr;
|
||||
void *arg2;
|
||||
__u16 nc_flags;
|
||||
};
|
||||
|
||||
|
|
@ -126,6 +149,15 @@ int rtnl_dump_filter_nc(struct rtnl_handle *rth,
|
|||
void *arg, __u16 nc_flags);
|
||||
#define rtnl_dump_filter(rth, filter, arg) \
|
||||
rtnl_dump_filter_nc(rth, filter, arg, 0)
|
||||
int rtnl_dump_filter_errhndlr_nc(struct rtnl_handle *rth,
|
||||
rtnl_filter_t filter,
|
||||
void *arg1,
|
||||
rtnl_err_hndlr_t errhndlr,
|
||||
void *arg2,
|
||||
__u16 nc_flags);
|
||||
#define rtnl_dump_filter_errhndlr(rth, filter, farg, errhndlr, earg) \
|
||||
rtnl_dump_filter_errhndlr_nc(rth, filter, farg, errhndlr, earg, 0)
|
||||
|
||||
int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
|
||||
struct nlmsghdr **answer)
|
||||
__attribute__((warn_unused_result));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2021 Taehee Yoo <ap420073@gmail.com>
|
||||
*/
|
||||
#ifndef _AMT_H_
|
||||
#define _AMT_H_
|
||||
|
||||
enum ifla_amt_mode {
|
||||
/* AMT interface works as Gateway mode.
|
||||
* The Gateway mode encapsulates IGMP/MLD traffic and decapsulates
|
||||
* multicast traffic.
|
||||
*/
|
||||
AMT_MODE_GATEWAY = 0,
|
||||
/* AMT interface works as Relay mode.
|
||||
* The Relay mode encapsulates multicast traffic and decapsulates
|
||||
* IGMP/MLD traffic.
|
||||
*/
|
||||
AMT_MODE_RELAY,
|
||||
__AMT_MODE_MAX,
|
||||
};
|
||||
|
||||
#define AMT_MODE_MAX (__AMT_MODE_MAX - 1)
|
||||
|
||||
enum {
|
||||
IFLA_AMT_UNSPEC,
|
||||
/* This attribute specify mode etier Gateway or Relay. */
|
||||
IFLA_AMT_MODE,
|
||||
/* This attribute specify Relay port.
|
||||
* AMT interface is created as Gateway mode, this attribute is used
|
||||
* to specify relay(remote) port.
|
||||
* AMT interface is created as Relay mode, this attribute is used
|
||||
* as local port.
|
||||
*/
|
||||
IFLA_AMT_RELAY_PORT,
|
||||
/* This attribute specify Gateway port.
|
||||
* AMT interface is created as Gateway mode, this attribute is used
|
||||
* as local port.
|
||||
* AMT interface is created as Relay mode, this attribute is not used.
|
||||
*/
|
||||
IFLA_AMT_GATEWAY_PORT,
|
||||
/* This attribute specify physical device */
|
||||
IFLA_AMT_LINK,
|
||||
/* This attribute specify local ip address */
|
||||
IFLA_AMT_LOCAL_IP,
|
||||
/* This attribute specify Relay ip address.
|
||||
* So, this is not used by Relay.
|
||||
*/
|
||||
IFLA_AMT_REMOTE_IP,
|
||||
/* This attribute specify Discovery ip address.
|
||||
* When Gateway get started, it send discovery message to find the
|
||||
* Relay's ip address.
|
||||
* So, this is not used by Relay.
|
||||
*/
|
||||
IFLA_AMT_DISCOVERY_IP,
|
||||
/* This attribute specify number of maximum tunnel. */
|
||||
IFLA_AMT_MAX_TUNNELS,
|
||||
__IFLA_AMT_MAX,
|
||||
};
|
||||
|
||||
#define IFLA_AMT_MAX (__IFLA_AMT_MAX - 1)
|
||||
|
||||
#endif /* _AMT_H_ */
|
||||
|
|
@ -84,7 +84,7 @@ struct bpf_lpm_trie_key {
|
|||
|
||||
struct bpf_cgroup_storage_key {
|
||||
__u64 cgroup_inode_id; /* cgroup inode id */
|
||||
__u32 attach_type; /* program attach type */
|
||||
__u32 attach_type; /* program attach type (enum bpf_attach_type) */
|
||||
};
|
||||
|
||||
union bpf_iter_link_info {
|
||||
|
|
@ -324,9 +324,6 @@ union bpf_iter_link_info {
|
|||
* **BPF_PROG_TYPE_SK_LOOKUP**
|
||||
* *data_in* and *data_out* must be NULL.
|
||||
*
|
||||
* **BPF_PROG_TYPE_XDP**
|
||||
* *ctx_in* and *ctx_out* must be NULL.
|
||||
*
|
||||
* **BPF_PROG_TYPE_RAW_TRACEPOINT**,
|
||||
* **BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE**
|
||||
*
|
||||
|
|
@ -527,6 +524,15 @@ union bpf_iter_link_info {
|
|||
* Look up an element with the given *key* in the map referred to
|
||||
* by the file descriptor *fd*, and if found, delete the element.
|
||||
*
|
||||
* For **BPF_MAP_TYPE_QUEUE** and **BPF_MAP_TYPE_STACK** map
|
||||
* types, the *flags* argument needs to be set to 0, but for other
|
||||
* map types, it may be specified as:
|
||||
*
|
||||
* **BPF_F_LOCK**
|
||||
* Look up and delete the value of a spin-locked map
|
||||
* without returning the lock. This must be specified if
|
||||
* the elements contain a spinlock.
|
||||
*
|
||||
* The **BPF_MAP_TYPE_QUEUE** and **BPF_MAP_TYPE_STACK** map types
|
||||
* implement this command as a "pop" operation, deleting the top
|
||||
* element rather than one corresponding to *key*.
|
||||
|
|
@ -536,6 +542,10 @@ union bpf_iter_link_info {
|
|||
* This command is only valid for the following map types:
|
||||
* * **BPF_MAP_TYPE_QUEUE**
|
||||
* * **BPF_MAP_TYPE_STACK**
|
||||
* * **BPF_MAP_TYPE_HASH**
|
||||
* * **BPF_MAP_TYPE_PERCPU_HASH**
|
||||
* * **BPF_MAP_TYPE_LRU_HASH**
|
||||
* * **BPF_MAP_TYPE_LRU_PERCPU_HASH**
|
||||
*
|
||||
* Return
|
||||
* Returns zero on success. On error, -1 is returned and *errno*
|
||||
|
|
@ -837,6 +847,7 @@ enum bpf_cmd {
|
|||
BPF_PROG_ATTACH,
|
||||
BPF_PROG_DETACH,
|
||||
BPF_PROG_TEST_RUN,
|
||||
BPF_PROG_RUN = BPF_PROG_TEST_RUN,
|
||||
BPF_PROG_GET_NEXT_ID,
|
||||
BPF_MAP_GET_NEXT_ID,
|
||||
BPF_PROG_GET_FD_BY_ID,
|
||||
|
|
@ -895,6 +906,7 @@ enum bpf_map_type {
|
|||
BPF_MAP_TYPE_RINGBUF,
|
||||
BPF_MAP_TYPE_INODE_STORAGE,
|
||||
BPF_MAP_TYPE_TASK_STORAGE,
|
||||
BPF_MAP_TYPE_BLOOM_FILTER,
|
||||
};
|
||||
|
||||
/* Note that tracing related programs such as
|
||||
|
|
@ -937,6 +949,7 @@ enum bpf_prog_type {
|
|||
BPF_PROG_TYPE_EXT,
|
||||
BPF_PROG_TYPE_LSM,
|
||||
BPF_PROG_TYPE_SK_LOOKUP,
|
||||
BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */
|
||||
};
|
||||
|
||||
enum bpf_attach_type {
|
||||
|
|
@ -979,6 +992,9 @@ enum bpf_attach_type {
|
|||
BPF_SK_LOOKUP,
|
||||
BPF_XDP,
|
||||
BPF_SK_SKB_VERDICT,
|
||||
BPF_SK_REUSEPORT_SELECT,
|
||||
BPF_SK_REUSEPORT_SELECT_OR_MIGRATE,
|
||||
BPF_PERF_EVENT,
|
||||
__MAX_BPF_ATTACH_TYPE
|
||||
};
|
||||
|
||||
|
|
@ -992,6 +1008,7 @@ enum bpf_link_type {
|
|||
BPF_LINK_TYPE_ITER = 4,
|
||||
BPF_LINK_TYPE_NETNS = 5,
|
||||
BPF_LINK_TYPE_XDP = 6,
|
||||
BPF_LINK_TYPE_PERF_EVENT = 7,
|
||||
|
||||
MAX_BPF_LINK_TYPE,
|
||||
};
|
||||
|
|
@ -1097,8 +1114,8 @@ enum bpf_link_type {
|
|||
/* When BPF ldimm64's insn[0].src_reg != 0 then this can have
|
||||
* the following extensions:
|
||||
*
|
||||
* insn[0].src_reg: BPF_PSEUDO_MAP_FD
|
||||
* insn[0].imm: map fd
|
||||
* insn[0].src_reg: BPF_PSEUDO_MAP_[FD|IDX]
|
||||
* insn[0].imm: map fd or fd_idx
|
||||
* insn[1].imm: 0
|
||||
* insn[0].off: 0
|
||||
* insn[1].off: 0
|
||||
|
|
@ -1106,15 +1123,19 @@ enum bpf_link_type {
|
|||
* verifier type: CONST_PTR_TO_MAP
|
||||
*/
|
||||
#define BPF_PSEUDO_MAP_FD 1
|
||||
/* insn[0].src_reg: BPF_PSEUDO_MAP_VALUE
|
||||
* insn[0].imm: map fd
|
||||
#define BPF_PSEUDO_MAP_IDX 5
|
||||
|
||||
/* insn[0].src_reg: BPF_PSEUDO_MAP_[IDX_]VALUE
|
||||
* insn[0].imm: map fd or fd_idx
|
||||
* insn[1].imm: offset into value
|
||||
* insn[0].off: 0
|
||||
* insn[1].off: 0
|
||||
* ldimm64 rewrite: address of map[0]+offset
|
||||
* verifier type: PTR_TO_MAP_VALUE
|
||||
*/
|
||||
#define BPF_PSEUDO_MAP_VALUE 2
|
||||
#define BPF_PSEUDO_MAP_VALUE 2
|
||||
#define BPF_PSEUDO_MAP_IDX_VALUE 6
|
||||
|
||||
/* insn[0].src_reg: BPF_PSEUDO_BTF_ID
|
||||
* insn[0].imm: kernel btd id of VAR
|
||||
* insn[1].imm: 0
|
||||
|
|
@ -1254,6 +1275,13 @@ union bpf_attr {
|
|||
* struct stored as the
|
||||
* map value
|
||||
*/
|
||||
/* Any per-map-type extra fields
|
||||
*
|
||||
* BPF_MAP_TYPE_BLOOM_FILTER - the lowest 4 bits indicate the
|
||||
* number of hash functions (if 0, the bloom filter will default
|
||||
* to using 5 hash functions).
|
||||
*/
|
||||
__u64 map_extra;
|
||||
};
|
||||
|
||||
struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
|
||||
|
|
@ -1314,6 +1342,8 @@ union bpf_attr {
|
|||
/* or valid module BTF object fd or 0 to attach to vmlinux */
|
||||
__u32 attach_btf_obj_fd;
|
||||
};
|
||||
__u32 :32; /* pad */
|
||||
__aligned_u64 fd_array; /* array of FDs */
|
||||
};
|
||||
|
||||
struct { /* anonymous struct used by BPF_OBJ_* commands */
|
||||
|
|
@ -1426,6 +1456,13 @@ union bpf_attr {
|
|||
__aligned_u64 iter_info; /* extra bpf_iter_link_info */
|
||||
__u32 iter_info_len; /* iter_info length */
|
||||
};
|
||||
struct {
|
||||
/* black box user-provided value passed through
|
||||
* to BPF program at the execution time and
|
||||
* accessible through bpf_get_attach_cookie() BPF helper
|
||||
*/
|
||||
__u64 bpf_cookie;
|
||||
} perf_event;
|
||||
};
|
||||
} link_create;
|
||||
|
||||
|
|
@ -1600,7 +1637,7 @@ union bpf_attr {
|
|||
* u32 bpf_get_smp_processor_id(void)
|
||||
* Description
|
||||
* Get the SMP (symmetric multiprocessing) processor id. Note that
|
||||
* all programs run with preemption disabled, which means that the
|
||||
* all programs run with migration disabled, which means that the
|
||||
* SMP processor id is stable during all the execution of the
|
||||
* program.
|
||||
* Return
|
||||
|
|
@ -2534,8 +2571,12 @@ union bpf_attr {
|
|||
* The lower two bits of *flags* are used as the return code if
|
||||
* the map lookup fails. This is so that the return value can be
|
||||
* one of the XDP program return codes up to **XDP_TX**, as chosen
|
||||
* by the caller. Any higher bits in the *flags* argument must be
|
||||
* unset.
|
||||
* by the caller. The higher bits of *flags* can be set to
|
||||
* BPF_F_BROADCAST or BPF_F_EXCLUDE_INGRESS as defined below.
|
||||
*
|
||||
* With BPF_F_BROADCAST the packet will be broadcasted to all the
|
||||
* interfaces in the map, with BPF_F_EXCLUDE_INGRESS the ingress
|
||||
* interface will be excluded when do broadcasting.
|
||||
*
|
||||
* See also **bpf_redirect**\ (), which only supports redirecting
|
||||
* to an ifindex, but doesn't require a map to do so.
|
||||
|
|
@ -3222,7 +3263,7 @@ union bpf_attr {
|
|||
* long bpf_sk_select_reuseport(struct sk_reuseport_md *reuse, struct bpf_map *map, void *key, u64 flags)
|
||||
* Description
|
||||
* Select a **SO_REUSEPORT** socket from a
|
||||
* **BPF_MAP_TYPE_REUSEPORT_ARRAY** *map*.
|
||||
* **BPF_MAP_TYPE_REUSEPORT_SOCKARRAY** *map*.
|
||||
* It checks the selected socket is matching the incoming
|
||||
* request in the socket buffer.
|
||||
* Return
|
||||
|
|
@ -4013,7 +4054,7 @@ union bpf_attr {
|
|||
* arguments. The *data* are a **u64** array and corresponding format string
|
||||
* values are stored in the array. For strings and pointers where pointees
|
||||
* are accessed, only the pointer values are stored in the *data* array.
|
||||
* The *data_len* is the size of *data* in bytes.
|
||||
* The *data_len* is the size of *data* in bytes - must be a multiple of 8.
|
||||
*
|
||||
* Formats **%s**, **%p{i,I}{4,6}** requires to read kernel memory.
|
||||
* Reading kernel memory may fail due to either invalid address or
|
||||
|
|
@ -4718,7 +4759,8 @@ union bpf_attr {
|
|||
* Each format specifier in **fmt** corresponds to one u64 element
|
||||
* in the **data** array. For strings and pointers where pointees
|
||||
* are accessed, only the pointer values are stored in the *data*
|
||||
* array. The *data_len* is the size of *data* in bytes.
|
||||
* array. The *data_len* is the size of *data* in bytes - must be
|
||||
* a multiple of 8.
|
||||
*
|
||||
* Formats **%s** and **%p{i,I}{4,6}** require to read kernel
|
||||
* memory. Reading kernel memory may fail due to either invalid
|
||||
|
|
@ -4735,6 +4777,167 @@ union bpf_attr {
|
|||
* be zero-terminated except when **str_size** is 0.
|
||||
*
|
||||
* Or **-EBUSY** if the per-CPU memory copy buffer is busy.
|
||||
*
|
||||
* long bpf_sys_bpf(u32 cmd, void *attr, u32 attr_size)
|
||||
* Description
|
||||
* Execute bpf syscall with given arguments.
|
||||
* Return
|
||||
* A syscall result.
|
||||
*
|
||||
* long bpf_btf_find_by_name_kind(char *name, int name_sz, u32 kind, int flags)
|
||||
* Description
|
||||
* Find BTF type with given name and kind in vmlinux BTF or in module's BTFs.
|
||||
* Return
|
||||
* Returns btf_id and btf_obj_fd in lower and upper 32 bits.
|
||||
*
|
||||
* long bpf_sys_close(u32 fd)
|
||||
* Description
|
||||
* Execute close syscall for given FD.
|
||||
* Return
|
||||
* A syscall result.
|
||||
*
|
||||
* long bpf_timer_init(struct bpf_timer *timer, struct bpf_map *map, u64 flags)
|
||||
* Description
|
||||
* Initialize the timer.
|
||||
* First 4 bits of *flags* specify clockid.
|
||||
* Only CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_BOOTTIME are allowed.
|
||||
* All other bits of *flags* are reserved.
|
||||
* The verifier will reject the program if *timer* is not from
|
||||
* the same *map*.
|
||||
* Return
|
||||
* 0 on success.
|
||||
* **-EBUSY** if *timer* is already initialized.
|
||||
* **-EINVAL** if invalid *flags* are passed.
|
||||
* **-EPERM** if *timer* is in a map that doesn't have any user references.
|
||||
* The user space should either hold a file descriptor to a map with timers
|
||||
* or pin such map in bpffs. When map is unpinned or file descriptor is
|
||||
* closed all timers in the map will be cancelled and freed.
|
||||
*
|
||||
* long bpf_timer_set_callback(struct bpf_timer *timer, void *callback_fn)
|
||||
* Description
|
||||
* Configure the timer to call *callback_fn* static function.
|
||||
* Return
|
||||
* 0 on success.
|
||||
* **-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier.
|
||||
* **-EPERM** if *timer* is in a map that doesn't have any user references.
|
||||
* The user space should either hold a file descriptor to a map with timers
|
||||
* or pin such map in bpffs. When map is unpinned or file descriptor is
|
||||
* closed all timers in the map will be cancelled and freed.
|
||||
*
|
||||
* long bpf_timer_start(struct bpf_timer *timer, u64 nsecs, u64 flags)
|
||||
* Description
|
||||
* Set timer expiration N nanoseconds from the current time. The
|
||||
* configured callback will be invoked in soft irq context on some cpu
|
||||
* and will not repeat unless another bpf_timer_start() is made.
|
||||
* In such case the next invocation can migrate to a different cpu.
|
||||
* Since struct bpf_timer is a field inside map element the map
|
||||
* owns the timer. The bpf_timer_set_callback() will increment refcnt
|
||||
* of BPF program to make sure that callback_fn code stays valid.
|
||||
* When user space reference to a map reaches zero all timers
|
||||
* in a map are cancelled and corresponding program's refcnts are
|
||||
* decremented. This is done to make sure that Ctrl-C of a user
|
||||
* process doesn't leave any timers running. If map is pinned in
|
||||
* bpffs the callback_fn can re-arm itself indefinitely.
|
||||
* bpf_map_update/delete_elem() helpers and user space sys_bpf commands
|
||||
* cancel and free the timer in the given map element.
|
||||
* The map can contain timers that invoke callback_fn-s from different
|
||||
* programs. The same callback_fn can serve different timers from
|
||||
* different maps if key/value layout matches across maps.
|
||||
* Every bpf_timer_set_callback() can have different callback_fn.
|
||||
*
|
||||
* Return
|
||||
* 0 on success.
|
||||
* **-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier
|
||||
* or invalid *flags* are passed.
|
||||
*
|
||||
* long bpf_timer_cancel(struct bpf_timer *timer)
|
||||
* Description
|
||||
* Cancel the timer and wait for callback_fn to finish if it was running.
|
||||
* Return
|
||||
* 0 if the timer was not active.
|
||||
* 1 if the timer was active.
|
||||
* **-EINVAL** if *timer* was not initialized with bpf_timer_init() earlier.
|
||||
* **-EDEADLK** if callback_fn tried to call bpf_timer_cancel() on its
|
||||
* own timer which would have led to a deadlock otherwise.
|
||||
*
|
||||
* u64 bpf_get_func_ip(void *ctx)
|
||||
* Description
|
||||
* Get address of the traced function (for tracing and kprobe programs).
|
||||
* Return
|
||||
* Address of the traced function.
|
||||
*
|
||||
* u64 bpf_get_attach_cookie(void *ctx)
|
||||
* Description
|
||||
* Get bpf_cookie value provided (optionally) during the program
|
||||
* attachment. It might be different for each individual
|
||||
* attachment, even if BPF program itself is the same.
|
||||
* Expects BPF program context *ctx* as a first argument.
|
||||
*
|
||||
* Supported for the following program types:
|
||||
* - kprobe/uprobe;
|
||||
* - tracepoint;
|
||||
* - perf_event.
|
||||
* Return
|
||||
* Value specified by user at BPF link creation/attachment time
|
||||
* or 0, if it was not specified.
|
||||
*
|
||||
* long bpf_task_pt_regs(struct task_struct *task)
|
||||
* Description
|
||||
* Get the struct pt_regs associated with **task**.
|
||||
* Return
|
||||
* A pointer to struct pt_regs.
|
||||
*
|
||||
* long bpf_get_branch_snapshot(void *entries, u32 size, u64 flags)
|
||||
* Description
|
||||
* Get branch trace from hardware engines like Intel LBR. The
|
||||
* hardware engine is stopped shortly after the helper is
|
||||
* called. Therefore, the user need to filter branch entries
|
||||
* based on the actual use case. To capture branch trace
|
||||
* before the trigger point of the BPF program, the helper
|
||||
* should be called at the beginning of the BPF program.
|
||||
*
|
||||
* The data is stored as struct perf_branch_entry into output
|
||||
* buffer *entries*. *size* is the size of *entries* in bytes.
|
||||
* *flags* is reserved for now and must be zero.
|
||||
*
|
||||
* Return
|
||||
* On success, number of bytes written to *buf*. On error, a
|
||||
* negative value.
|
||||
*
|
||||
* **-EINVAL** if *flags* is not zero.
|
||||
*
|
||||
* **-ENOENT** if architecture does not support branch records.
|
||||
*
|
||||
* long bpf_trace_vprintk(const char *fmt, u32 fmt_size, const void *data, u32 data_len)
|
||||
* Description
|
||||
* Behaves like **bpf_trace_printk**\ () helper, but takes an array of u64
|
||||
* to format and can handle more format args as a result.
|
||||
*
|
||||
* Arguments are to be used as in **bpf_seq_printf**\ () helper.
|
||||
* Return
|
||||
* The number of bytes written to the buffer, or a negative error
|
||||
* in case of failure.
|
||||
*
|
||||
* struct unix_sock *bpf_skc_to_unix_sock(void *sk)
|
||||
* Description
|
||||
* Dynamically cast a *sk* pointer to a *unix_sock* pointer.
|
||||
* Return
|
||||
* *sk* if casting is valid, or **NULL** otherwise.
|
||||
*
|
||||
* long bpf_kallsyms_lookup_name(const char *name, int name_sz, int flags, u64 *res)
|
||||
* Description
|
||||
* Get the address of a kernel symbol, returned in *res*. *res* is
|
||||
* set to 0 if the symbol is not found.
|
||||
* Return
|
||||
* On success, zero. On error, a negative value.
|
||||
*
|
||||
* **-EINVAL** if *flags* is not zero.
|
||||
*
|
||||
* **-EINVAL** if string *name* is not the same size as *name_sz*.
|
||||
*
|
||||
* **-ENOENT** if symbol is not found.
|
||||
*
|
||||
* **-EPERM** if caller does not have permission to obtain kernel address.
|
||||
*/
|
||||
#define __BPF_FUNC_MAPPER(FN) \
|
||||
FN(unspec), \
|
||||
|
|
@ -4903,6 +5106,20 @@ union bpf_attr {
|
|||
FN(check_mtu), \
|
||||
FN(for_each_map_elem), \
|
||||
FN(snprintf), \
|
||||
FN(sys_bpf), \
|
||||
FN(btf_find_by_name_kind), \
|
||||
FN(sys_close), \
|
||||
FN(timer_init), \
|
||||
FN(timer_set_callback), \
|
||||
FN(timer_start), \
|
||||
FN(timer_cancel), \
|
||||
FN(get_func_ip), \
|
||||
FN(get_attach_cookie), \
|
||||
FN(task_pt_regs), \
|
||||
FN(get_branch_snapshot), \
|
||||
FN(trace_vprintk), \
|
||||
FN(skc_to_unix_sock), \
|
||||
FN(kallsyms_lookup_name), \
|
||||
/* */
|
||||
|
||||
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
|
||||
|
|
@ -5080,6 +5297,12 @@ enum {
|
|||
BPF_F_BPRM_SECUREEXEC = (1ULL << 0),
|
||||
};
|
||||
|
||||
/* Flags for bpf_redirect_map helper */
|
||||
enum {
|
||||
BPF_F_BROADCAST = (1ULL << 3),
|
||||
BPF_F_EXCLUDE_INGRESS = (1ULL << 4),
|
||||
};
|
||||
|
||||
#define __bpf_md_ptr(type, name) \
|
||||
union { \
|
||||
type name; \
|
||||
|
|
@ -5126,6 +5349,8 @@ struct __sk_buff {
|
|||
__u32 gso_segs;
|
||||
__bpf_md_ptr(struct bpf_sock *, sk);
|
||||
__u32 gso_size;
|
||||
__u32 :32; /* Padding, future use. */
|
||||
__u64 hwtstamp;
|
||||
};
|
||||
|
||||
struct bpf_tunnel_key {
|
||||
|
|
@ -5364,6 +5589,20 @@ struct sk_reuseport_md {
|
|||
__u32 ip_protocol; /* IP protocol. e.g. IPPROTO_TCP, IPPROTO_UDP */
|
||||
__u32 bind_inany; /* Is sock bound to an INANY address? */
|
||||
__u32 hash; /* A hash of the packet 4 tuples */
|
||||
/* When reuse->migrating_sk is NULL, it is selecting a sk for the
|
||||
* new incoming connection request (e.g. selecting a listen sk for
|
||||
* the received SYN in the TCP case). reuse->sk is one of the sk
|
||||
* in the reuseport group. The bpf prog can use reuse->sk to learn
|
||||
* the local listening ip/port without looking into the skb.
|
||||
*
|
||||
* When reuse->migrating_sk is not NULL, reuse->sk is closed and
|
||||
* reuse->migrating_sk is the socket that needs to be migrated
|
||||
* to another listening socket. migrating_sk could be a fullsock
|
||||
* sk that is fully established or a reqsk that is in-the-middle
|
||||
* of 3-way handshake.
|
||||
*/
|
||||
__bpf_md_ptr(struct bpf_sock *, sk);
|
||||
__bpf_md_ptr(struct bpf_sock *, migrating_sk);
|
||||
};
|
||||
|
||||
#define BPF_TAG_SIZE 8
|
||||
|
|
@ -5405,6 +5644,7 @@ struct bpf_prog_info {
|
|||
__u64 run_time_ns;
|
||||
__u64 run_cnt;
|
||||
__u64 recursion_misses;
|
||||
__u32 verified_insns;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
struct bpf_map_info {
|
||||
|
|
@ -5422,6 +5662,8 @@ struct bpf_map_info {
|
|||
__u32 btf_id;
|
||||
__u32 btf_key_type_id;
|
||||
__u32 btf_value_type_id;
|
||||
__u32 :32; /* alignment pad */
|
||||
__u64 map_extra;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
struct bpf_btf_info {
|
||||
|
|
@ -6009,6 +6251,11 @@ struct bpf_spin_lock {
|
|||
__u32 val;
|
||||
};
|
||||
|
||||
struct bpf_timer {
|
||||
__u64 :64;
|
||||
__u64 :64;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
struct bpf_sysctl {
|
||||
__u32 write; /* Sysctl is being read (= 0) or written (= 1).
|
||||
* Allows 1,2,4-byte read, but no write.
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ struct btf_type {
|
|||
* "size" tells the size of the type it is describing.
|
||||
*
|
||||
* "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
|
||||
* FUNC, FUNC_PROTO and VAR.
|
||||
* FUNC, FUNC_PROTO, VAR and DECL_TAG.
|
||||
* "type" is a type_id referring to another type.
|
||||
*/
|
||||
union {
|
||||
|
|
@ -56,25 +56,29 @@ struct btf_type {
|
|||
#define BTF_INFO_VLEN(info) ((info) & 0xffff)
|
||||
#define BTF_INFO_KFLAG(info) ((info) >> 31)
|
||||
|
||||
#define BTF_KIND_UNKN 0 /* Unknown */
|
||||
#define BTF_KIND_INT 1 /* Integer */
|
||||
#define BTF_KIND_PTR 2 /* Pointer */
|
||||
#define BTF_KIND_ARRAY 3 /* Array */
|
||||
#define BTF_KIND_STRUCT 4 /* Struct */
|
||||
#define BTF_KIND_UNION 5 /* Union */
|
||||
#define BTF_KIND_ENUM 6 /* Enumeration */
|
||||
#define BTF_KIND_FWD 7 /* Forward */
|
||||
#define BTF_KIND_TYPEDEF 8 /* Typedef */
|
||||
#define BTF_KIND_VOLATILE 9 /* Volatile */
|
||||
#define BTF_KIND_CONST 10 /* Const */
|
||||
#define BTF_KIND_RESTRICT 11 /* Restrict */
|
||||
#define BTF_KIND_FUNC 12 /* Function */
|
||||
#define BTF_KIND_FUNC_PROTO 13 /* Function Proto */
|
||||
#define BTF_KIND_VAR 14 /* Variable */
|
||||
#define BTF_KIND_DATASEC 15 /* Section */
|
||||
#define BTF_KIND_FLOAT 16 /* Floating point */
|
||||
#define BTF_KIND_MAX BTF_KIND_FLOAT
|
||||
#define NR_BTF_KINDS (BTF_KIND_MAX + 1)
|
||||
enum {
|
||||
BTF_KIND_UNKN = 0, /* Unknown */
|
||||
BTF_KIND_INT = 1, /* Integer */
|
||||
BTF_KIND_PTR = 2, /* Pointer */
|
||||
BTF_KIND_ARRAY = 3, /* Array */
|
||||
BTF_KIND_STRUCT = 4, /* Struct */
|
||||
BTF_KIND_UNION = 5, /* Union */
|
||||
BTF_KIND_ENUM = 6, /* Enumeration */
|
||||
BTF_KIND_FWD = 7, /* Forward */
|
||||
BTF_KIND_TYPEDEF = 8, /* Typedef */
|
||||
BTF_KIND_VOLATILE = 9, /* Volatile */
|
||||
BTF_KIND_CONST = 10, /* Const */
|
||||
BTF_KIND_RESTRICT = 11, /* Restrict */
|
||||
BTF_KIND_FUNC = 12, /* Function */
|
||||
BTF_KIND_FUNC_PROTO = 13, /* Function Proto */
|
||||
BTF_KIND_VAR = 14, /* Variable */
|
||||
BTF_KIND_DATASEC = 15, /* Section */
|
||||
BTF_KIND_FLOAT = 16, /* Floating point */
|
||||
BTF_KIND_DECL_TAG = 17, /* Decl Tag */
|
||||
|
||||
NR_BTF_KINDS,
|
||||
BTF_KIND_MAX = NR_BTF_KINDS - 1,
|
||||
};
|
||||
|
||||
/* For some specific BTF_KIND, "struct btf_type" is immediately
|
||||
* followed by extra data.
|
||||
|
|
@ -170,4 +174,15 @@ struct btf_var_secinfo {
|
|||
__u32 size;
|
||||
};
|
||||
|
||||
/* BTF_KIND_DECL_TAG is followed by a single "struct btf_decl_tag" to describe
|
||||
* additional information related to the tag applied location.
|
||||
* If component_idx == -1, the tag is applied to a struct, union,
|
||||
* variable or function. Otherwise, it is applied to a struct/union
|
||||
* member or a func argument, and component_idx indicates which member
|
||||
* or argument (0 ... vlen-1).
|
||||
*/
|
||||
struct btf_decl_tag {
|
||||
__s32 component_idx;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_BTF_H__ */
|
||||
|
|
|
|||
|
|
@ -123,8 +123,8 @@ struct can_frame {
|
|||
/*
|
||||
* defined bits for canfd_frame.flags
|
||||
*
|
||||
* The use of struct canfd_frame implies the Extended Data Length (EDL) bit to
|
||||
* be set in the CAN frame bitstream on the wire. The EDL bit switch turns
|
||||
* The use of struct canfd_frame implies the FD Frame (FDF) bit to
|
||||
* be set in the CAN frame bitstream on the wire. The FDF bit switch turns
|
||||
* the CAN controllers bitstream processor into the CAN FD mode which creates
|
||||
* two new options within the CAN FD frame specification:
|
||||
*
|
||||
|
|
@ -135,9 +135,18 @@ struct can_frame {
|
|||
* controller only the CANFD_BRS bit is relevant for real CAN controllers when
|
||||
* building a CAN FD frame for transmission. Setting the CANFD_ESI bit can make
|
||||
* sense for virtual CAN interfaces to test applications with echoed frames.
|
||||
*
|
||||
* The struct can_frame and struct canfd_frame intentionally share the same
|
||||
* layout to be able to write CAN frame content into a CAN FD frame structure.
|
||||
* When this is done the former differentiation via CAN_MTU / CANFD_MTU gets
|
||||
* lost. CANFD_FDF allows programmers to mark CAN FD frames in the case of
|
||||
* using struct canfd_frame for mixed CAN / CAN FD content (dual use).
|
||||
* N.B. the Kernel APIs do NOT provide mixed CAN / CAN FD content inside of
|
||||
* struct canfd_frame therefore the CANFD_FDF flag is disregarded by Linux.
|
||||
*/
|
||||
#define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */
|
||||
#define CANFD_ESI 0x02 /* error state indicator of the transmitting node */
|
||||
#define CANFD_FDF 0x04 /* mark CAN FD for dual use of struct canfd_frame */
|
||||
|
||||
/**
|
||||
* struct canfd_frame - CAN flexible data rate frame structure
|
||||
|
|
|
|||
|
|
@ -101,6 +101,8 @@ struct can_ctrlmode {
|
|||
#define CAN_CTRLMODE_PRESUME_ACK 0x40 /* Ignore missing CAN ACKs */
|
||||
#define CAN_CTRLMODE_FD_NON_ISO 0x80 /* CAN FD in non-ISO mode */
|
||||
#define CAN_CTRLMODE_CC_LEN8_DLC 0x100 /* Classic CAN DLC option */
|
||||
#define CAN_CTRLMODE_TDC_AUTO 0x200 /* CAN transiver automatically calculates TDCV */
|
||||
#define CAN_CTRLMODE_TDC_MANUAL 0x400 /* TDCV is manually set up by user */
|
||||
|
||||
/*
|
||||
* CAN device statistics
|
||||
|
|
@ -134,10 +136,35 @@ enum {
|
|||
IFLA_CAN_BITRATE_CONST,
|
||||
IFLA_CAN_DATA_BITRATE_CONST,
|
||||
IFLA_CAN_BITRATE_MAX,
|
||||
__IFLA_CAN_MAX
|
||||
IFLA_CAN_TDC,
|
||||
|
||||
/* add new constants above here */
|
||||
__IFLA_CAN_MAX,
|
||||
IFLA_CAN_MAX = __IFLA_CAN_MAX - 1
|
||||
};
|
||||
|
||||
#define IFLA_CAN_MAX (__IFLA_CAN_MAX - 1)
|
||||
/*
|
||||
* CAN FD Transmitter Delay Compensation (TDC)
|
||||
*
|
||||
* Please refer to struct can_tdc_const and can_tdc in
|
||||
* include/linux/can/bittiming.h for further details.
|
||||
*/
|
||||
enum {
|
||||
IFLA_CAN_TDC_UNSPEC,
|
||||
IFLA_CAN_TDC_TDCV_MIN, /* u32 */
|
||||
IFLA_CAN_TDC_TDCV_MAX, /* u32 */
|
||||
IFLA_CAN_TDC_TDCO_MIN, /* u32 */
|
||||
IFLA_CAN_TDC_TDCO_MAX, /* u32 */
|
||||
IFLA_CAN_TDC_TDCF_MIN, /* u32 */
|
||||
IFLA_CAN_TDC_TDCF_MAX, /* u32 */
|
||||
IFLA_CAN_TDC_TDCV, /* u32 */
|
||||
IFLA_CAN_TDC_TDCO, /* u32 */
|
||||
IFLA_CAN_TDC_TDCF, /* u32 */
|
||||
|
||||
/* add new constants above here */
|
||||
__IFLA_CAN_TDC,
|
||||
IFLA_CAN_TDC_MAX = __IFLA_CAN_TDC - 1
|
||||
};
|
||||
|
||||
/* u16 termination range: 1..65535 Ohms */
|
||||
#define CAN_TERMINATION_DISABLED 0
|
||||
|
|
|
|||
|
|
@ -126,6 +126,11 @@ enum devlink_command {
|
|||
|
||||
DEVLINK_CMD_HEALTH_REPORTER_TEST,
|
||||
|
||||
DEVLINK_CMD_RATE_GET, /* can dump */
|
||||
DEVLINK_CMD_RATE_SET,
|
||||
DEVLINK_CMD_RATE_NEW,
|
||||
DEVLINK_CMD_RATE_DEL,
|
||||
|
||||
/* add new commands above here */
|
||||
__DEVLINK_CMD_MAX,
|
||||
DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1
|
||||
|
|
@ -206,6 +211,11 @@ enum devlink_port_flavour {
|
|||
*/
|
||||
};
|
||||
|
||||
enum devlink_rate_type {
|
||||
DEVLINK_RATE_TYPE_LEAF,
|
||||
DEVLINK_RATE_TYPE_NODE,
|
||||
};
|
||||
|
||||
enum devlink_param_cmode {
|
||||
DEVLINK_PARAM_CMODE_RUNTIME,
|
||||
DEVLINK_PARAM_CMODE_DRIVERINIT,
|
||||
|
|
@ -534,6 +544,15 @@ enum devlink_attr {
|
|||
DEVLINK_ATTR_RELOAD_ACTION_STATS, /* nested */
|
||||
|
||||
DEVLINK_ATTR_PORT_PCI_SF_NUMBER, /* u32 */
|
||||
|
||||
DEVLINK_ATTR_RATE_TYPE, /* u16 */
|
||||
DEVLINK_ATTR_RATE_TX_SHARE, /* u64 */
|
||||
DEVLINK_ATTR_RATE_TX_MAX, /* u64 */
|
||||
DEVLINK_ATTR_RATE_NODE_NAME, /* string */
|
||||
DEVLINK_ATTR_RATE_PARENT_NODE_NAME, /* string */
|
||||
|
||||
DEVLINK_ATTR_REGION_MAX_SNAPSHOTS, /* u32 */
|
||||
|
||||
/* add new attributes above here, update the policy in devlink.c */
|
||||
|
||||
__DEVLINK_ATTR_MAX,
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@
|
|||
#define ARPHRD_X25 271 /* CCITT X.25 */
|
||||
#define ARPHRD_HWX25 272 /* Boards with X.25 in firmware */
|
||||
#define ARPHRD_CAN 280 /* Controller Area Network */
|
||||
#define ARPHRD_MCTP 290
|
||||
#define ARPHRD_PPP 512
|
||||
#define ARPHRD_CISCO 513 /* Cisco HDLC */
|
||||
#define ARPHRD_HDLC ARPHRD_CISCO
|
||||
|
|
|
|||
|
|
@ -479,16 +479,22 @@ enum {
|
|||
|
||||
/* flags used in BRIDGE_VLANDB_DUMP_FLAGS attribute to affect dumps */
|
||||
#define BRIDGE_VLANDB_DUMPF_STATS (1 << 0) /* Include stats in the dump */
|
||||
#define BRIDGE_VLANDB_DUMPF_GLOBAL (1 << 1) /* Dump global vlan options only */
|
||||
|
||||
/* Bridge vlan RTM attributes
|
||||
* [BRIDGE_VLANDB_ENTRY] = {
|
||||
* [BRIDGE_VLANDB_ENTRY_INFO]
|
||||
* ...
|
||||
* }
|
||||
* [BRIDGE_VLANDB_GLOBAL_OPTIONS] = {
|
||||
* [BRIDGE_VLANDB_GOPTS_ID]
|
||||
* ...
|
||||
* }
|
||||
*/
|
||||
enum {
|
||||
BRIDGE_VLANDB_UNSPEC,
|
||||
BRIDGE_VLANDB_ENTRY,
|
||||
BRIDGE_VLANDB_GLOBAL_OPTIONS,
|
||||
__BRIDGE_VLANDB_MAX,
|
||||
};
|
||||
#define BRIDGE_VLANDB_MAX (__BRIDGE_VLANDB_MAX - 1)
|
||||
|
|
@ -500,6 +506,7 @@ enum {
|
|||
BRIDGE_VLANDB_ENTRY_STATE,
|
||||
BRIDGE_VLANDB_ENTRY_TUNNEL_INFO,
|
||||
BRIDGE_VLANDB_ENTRY_STATS,
|
||||
BRIDGE_VLANDB_ENTRY_MCAST_ROUTER,
|
||||
__BRIDGE_VLANDB_ENTRY_MAX,
|
||||
};
|
||||
#define BRIDGE_VLANDB_ENTRY_MAX (__BRIDGE_VLANDB_ENTRY_MAX - 1)
|
||||
|
|
@ -538,6 +545,29 @@ enum {
|
|||
};
|
||||
#define BRIDGE_VLANDB_STATS_MAX (__BRIDGE_VLANDB_STATS_MAX - 1)
|
||||
|
||||
enum {
|
||||
BRIDGE_VLANDB_GOPTS_UNSPEC,
|
||||
BRIDGE_VLANDB_GOPTS_ID,
|
||||
BRIDGE_VLANDB_GOPTS_RANGE,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_SNOOPING,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_IGMP_VERSION,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_MLD_VERSION,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_LAST_MEMBER_CNT,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_CNT,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_LAST_MEMBER_INTVL,
|
||||
BRIDGE_VLANDB_GOPTS_PAD,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_MEMBERSHIP_INTVL,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_INTVL,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_QUERY_INTVL,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_QUERY_RESPONSE_INTVL,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_QUERIER,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS,
|
||||
BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_STATE,
|
||||
__BRIDGE_VLANDB_GOPTS_MAX
|
||||
};
|
||||
#define BRIDGE_VLANDB_GOPTS_MAX (__BRIDGE_VLANDB_GOPTS_MAX - 1)
|
||||
|
||||
/* Bridge multicast database attributes
|
||||
* [MDBA_MDB] = {
|
||||
* [MDBA_MDB_ENTRY] = {
|
||||
|
|
@ -627,6 +657,9 @@ enum {
|
|||
MDBA_ROUTER_PATTR_UNSPEC,
|
||||
MDBA_ROUTER_PATTR_TIMER,
|
||||
MDBA_ROUTER_PATTR_TYPE,
|
||||
MDBA_ROUTER_PATTR_INET_TIMER,
|
||||
MDBA_ROUTER_PATTR_INET6_TIMER,
|
||||
MDBA_ROUTER_PATTR_VID,
|
||||
__MDBA_ROUTER_PATTR_MAX
|
||||
};
|
||||
#define MDBA_ROUTER_PATTR_MAX (__MDBA_ROUTER_PATTR_MAX - 1)
|
||||
|
|
@ -718,12 +751,14 @@ struct br_mcast_stats {
|
|||
|
||||
/* bridge boolean options
|
||||
* BR_BOOLOPT_NO_LL_LEARN - disable learning from link-local packets
|
||||
* BR_BOOLOPT_MCAST_VLAN_SNOOPING - control vlan multicast snooping
|
||||
*
|
||||
* IMPORTANT: if adding a new option do not forget to handle
|
||||
* it in br_boolopt_toggle/get and bridge sysfs
|
||||
*/
|
||||
enum br_boolopt_id {
|
||||
BR_BOOLOPT_NO_LL_LEARN,
|
||||
BR_BOOLOPT_MCAST_VLAN_SNOOPING,
|
||||
BR_BOOLOPT_MAX
|
||||
};
|
||||
|
||||
|
|
@ -736,4 +771,17 @@ struct br_boolopt_multi {
|
|||
__u32 optval;
|
||||
__u32 optmask;
|
||||
};
|
||||
|
||||
enum {
|
||||
BRIDGE_QUERIER_UNSPEC,
|
||||
BRIDGE_QUERIER_IP_ADDRESS,
|
||||
BRIDGE_QUERIER_IP_PORT,
|
||||
BRIDGE_QUERIER_IP_OTHER_TIMER,
|
||||
BRIDGE_QUERIER_PAD,
|
||||
BRIDGE_QUERIER_IPV6_ADDRESS,
|
||||
BRIDGE_QUERIER_IPV6_PORT,
|
||||
BRIDGE_QUERIER_IPV6_OTHER_TIMER,
|
||||
__BRIDGE_QUERIER_MAX
|
||||
};
|
||||
#define BRIDGE_QUERIER_MAX (__BRIDGE_QUERIER_MAX - 1)
|
||||
#endif /* _LINUX_IF_BRIDGE_H */
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@
|
|||
* over Ethernet
|
||||
*/
|
||||
#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
|
||||
#define ETH_P_REALTEK 0x8899 /* Multiple proprietary protocols */
|
||||
#define ETH_P_AOE 0x88A2 /* ATA over Ethernet */
|
||||
#define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */
|
||||
#define ETH_P_802_EX1 0x88B5 /* 802.1 Local Experimental 1. */
|
||||
|
|
@ -116,7 +117,7 @@
|
|||
#define ETH_P_IFE 0xED3E /* ForCES inter-FE LFB type */
|
||||
#define ETH_P_AF_IUCV 0xFBFB /* IBM af_iucv [ NOT AN OFFICIALLY REGISTERED ID ] */
|
||||
|
||||
#define ETH_P_802_3_MIN 0x0600 /* If the value in the ethernet type is less than this value
|
||||
#define ETH_P_802_3_MIN 0x0600 /* If the value in the ethernet type is more than this value
|
||||
* then the frame is Ethernet II. Else it is 802.3 */
|
||||
|
||||
/*
|
||||
|
|
@ -151,6 +152,9 @@
|
|||
#define ETH_P_MAP 0x00F9 /* Qualcomm multiplexing and
|
||||
* aggregation protocol
|
||||
*/
|
||||
#define ETH_P_MCTP 0x00FA /* Management component transport
|
||||
* protocol packets
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is an Ethernet frame header.
|
||||
|
|
|
|||
|
|
@ -341,6 +341,13 @@ enum {
|
|||
IFLA_ALT_IFNAME, /* Alternative ifname */
|
||||
IFLA_PERM_ADDRESS,
|
||||
IFLA_PROTO_DOWN_REASON,
|
||||
|
||||
/* device (sysfs) name as parent, used instead
|
||||
* of IFLA_LINK where there's no parent netdev
|
||||
*/
|
||||
IFLA_PARENT_DEV_NAME,
|
||||
IFLA_PARENT_DEV_BUS_NAME,
|
||||
|
||||
__IFLA_MAX
|
||||
};
|
||||
|
||||
|
|
@ -408,6 +415,7 @@ enum {
|
|||
IFLA_INET6_ICMP6STATS, /* statistics (icmpv6) */
|
||||
IFLA_INET6_TOKEN, /* device token */
|
||||
IFLA_INET6_ADDR_GEN_MODE, /* implicit address generator mode */
|
||||
IFLA_INET6_RA_MTU, /* mtu carried in the RA message */
|
||||
__IFLA_INET6_MAX
|
||||
};
|
||||
|
||||
|
|
@ -470,6 +478,7 @@ enum {
|
|||
IFLA_BR_MCAST_MLD_VERSION,
|
||||
IFLA_BR_VLAN_STATS_PER_PORT,
|
||||
IFLA_BR_MULTI_BOOLOPT,
|
||||
IFLA_BR_MCAST_QUERIER_STATE,
|
||||
__IFLA_BR_MAX,
|
||||
};
|
||||
|
||||
|
|
@ -846,6 +855,7 @@ enum {
|
|||
IFLA_BOND_AD_ACTOR_SYSTEM,
|
||||
IFLA_BOND_TLB_DYNAMIC_LB,
|
||||
IFLA_BOND_PEER_NOTIF_DELAY,
|
||||
IFLA_BOND_AD_LACP_ACTIVE,
|
||||
__IFLA_BOND_MAX,
|
||||
};
|
||||
|
||||
|
|
@ -1234,6 +1244,8 @@ enum {
|
|||
#define RMNET_FLAGS_INGRESS_MAP_COMMANDS (1U << 1)
|
||||
#define RMNET_FLAGS_INGRESS_MAP_CKSUMV4 (1U << 2)
|
||||
#define RMNET_FLAGS_EGRESS_MAP_CKSUMV4 (1U << 3)
|
||||
#define RMNET_FLAGS_INGRESS_MAP_CKSUMV5 (1U << 4)
|
||||
#define RMNET_FLAGS_EGRESS_MAP_CKSUMV5 (1U << 5)
|
||||
|
||||
enum {
|
||||
IFLA_RMNET_UNSPEC,
|
||||
|
|
@ -1249,4 +1261,14 @@ struct ifla_rmnet_flags {
|
|||
__u32 mask;
|
||||
};
|
||||
|
||||
/* MCTP section */
|
||||
|
||||
enum {
|
||||
IFLA_MCTP_UNSPEC,
|
||||
IFLA_MCTP_NET,
|
||||
__IFLA_MCTP_MAX,
|
||||
};
|
||||
|
||||
#define IFLA_MCTP_MAX (__IFLA_MCTP_MAX - 1)
|
||||
|
||||
#endif /* _LINUX_IF_LINK_H */
|
||||
|
|
|
|||
|
|
@ -188,11 +188,22 @@ struct ip_mreq_source {
|
|||
};
|
||||
|
||||
struct ip_msfilter {
|
||||
__be32 imsf_multiaddr;
|
||||
__be32 imsf_interface;
|
||||
__u32 imsf_fmode;
|
||||
__u32 imsf_numsrc;
|
||||
__be32 imsf_slist[1];
|
||||
union {
|
||||
struct {
|
||||
__be32 imsf_multiaddr_aux;
|
||||
__be32 imsf_interface_aux;
|
||||
__u32 imsf_fmode_aux;
|
||||
__u32 imsf_numsrc_aux;
|
||||
__be32 imsf_slist[1];
|
||||
};
|
||||
struct {
|
||||
__be32 imsf_multiaddr;
|
||||
__be32 imsf_interface;
|
||||
__u32 imsf_fmode;
|
||||
__u32 imsf_numsrc;
|
||||
__be32 imsf_slist_flex[];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#define IP_MSFILTER_SIZE(numsrc) \
|
||||
|
|
@ -211,11 +222,22 @@ struct group_source_req {
|
|||
};
|
||||
|
||||
struct group_filter {
|
||||
__u32 gf_interface; /* interface index */
|
||||
struct __kernel_sockaddr_storage gf_group; /* multicast address */
|
||||
__u32 gf_fmode; /* filter mode */
|
||||
__u32 gf_numsrc; /* number of sources */
|
||||
struct __kernel_sockaddr_storage gf_slist[1]; /* interface index */
|
||||
union {
|
||||
struct {
|
||||
__u32 gf_interface_aux; /* interface index */
|
||||
struct __kernel_sockaddr_storage gf_group_aux; /* multicast address */
|
||||
__u32 gf_fmode_aux; /* filter mode */
|
||||
__u32 gf_numsrc_aux; /* number of sources */
|
||||
struct __kernel_sockaddr_storage gf_slist[1]; /* interface index */
|
||||
};
|
||||
struct {
|
||||
__u32 gf_interface; /* interface index */
|
||||
struct __kernel_sockaddr_storage gf_group; /* multicast address */
|
||||
__u32 gf_fmode; /* filter mode */
|
||||
__u32 gf_numsrc; /* number of sources */
|
||||
struct __kernel_sockaddr_storage gf_slist_flex[]; /* interface index */
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
#define GROUP_FILTER_SIZE(numsrc) \
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ struct in6_flowlabel_req {
|
|||
#define IPV6_TLV_PADN 1
|
||||
#define IPV6_TLV_ROUTERALERT 5
|
||||
#define IPV6_TLV_CALIPSO 7 /* RFC 5570 */
|
||||
#define IPV6_TLV_IOAM 49 /* TEMPORARY IANA allocation for IOAM */
|
||||
#define IPV6_TLV_JUMBO 194
|
||||
#define IPV6_TLV_HAO 201 /* home address option */
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,133 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
|
||||
/*
|
||||
* IPv6 IOAM implementation
|
||||
*
|
||||
* Author:
|
||||
* Justin Iurman <justin.iurman@uliege.be>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_IOAM6_H
|
||||
#define _LINUX_IOAM6_H
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define IOAM6_U16_UNAVAILABLE U16_MAX
|
||||
#define IOAM6_U32_UNAVAILABLE U32_MAX
|
||||
#define IOAM6_U64_UNAVAILABLE U64_MAX
|
||||
|
||||
#define IOAM6_DEFAULT_ID (IOAM6_U32_UNAVAILABLE >> 8)
|
||||
#define IOAM6_DEFAULT_ID_WIDE (IOAM6_U64_UNAVAILABLE >> 8)
|
||||
#define IOAM6_DEFAULT_IF_ID IOAM6_U16_UNAVAILABLE
|
||||
#define IOAM6_DEFAULT_IF_ID_WIDE IOAM6_U32_UNAVAILABLE
|
||||
|
||||
/*
|
||||
* IPv6 IOAM Option Header
|
||||
*/
|
||||
struct ioam6_hdr {
|
||||
__u8 opt_type;
|
||||
__u8 opt_len;
|
||||
__u8 :8; /* reserved */
|
||||
#define IOAM6_TYPE_PREALLOC 0
|
||||
__u8 type;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* IOAM Trace Header
|
||||
*/
|
||||
struct ioam6_trace_hdr {
|
||||
__be16 namespace_id;
|
||||
|
||||
#if defined(__LITTLE_ENDIAN_BITFIELD)
|
||||
|
||||
__u8 :1, /* unused */
|
||||
:1, /* unused */
|
||||
overflow:1,
|
||||
nodelen:5;
|
||||
|
||||
__u8 remlen:7,
|
||||
:1; /* unused */
|
||||
|
||||
union {
|
||||
__be32 type_be32;
|
||||
|
||||
struct {
|
||||
__u32 bit7:1,
|
||||
bit6:1,
|
||||
bit5:1,
|
||||
bit4:1,
|
||||
bit3:1,
|
||||
bit2:1,
|
||||
bit1:1,
|
||||
bit0:1,
|
||||
bit15:1, /* unused */
|
||||
bit14:1, /* unused */
|
||||
bit13:1, /* unused */
|
||||
bit12:1, /* unused */
|
||||
bit11:1,
|
||||
bit10:1,
|
||||
bit9:1,
|
||||
bit8:1,
|
||||
bit23:1, /* reserved */
|
||||
bit22:1,
|
||||
bit21:1, /* unused */
|
||||
bit20:1, /* unused */
|
||||
bit19:1, /* unused */
|
||||
bit18:1, /* unused */
|
||||
bit17:1, /* unused */
|
||||
bit16:1, /* unused */
|
||||
:8; /* reserved */
|
||||
} type;
|
||||
};
|
||||
|
||||
#elif defined(__BIG_ENDIAN_BITFIELD)
|
||||
|
||||
__u8 nodelen:5,
|
||||
overflow:1,
|
||||
:1, /* unused */
|
||||
:1; /* unused */
|
||||
|
||||
__u8 :1, /* unused */
|
||||
remlen:7;
|
||||
|
||||
union {
|
||||
__be32 type_be32;
|
||||
|
||||
struct {
|
||||
__u32 bit0:1,
|
||||
bit1:1,
|
||||
bit2:1,
|
||||
bit3:1,
|
||||
bit4:1,
|
||||
bit5:1,
|
||||
bit6:1,
|
||||
bit7:1,
|
||||
bit8:1,
|
||||
bit9:1,
|
||||
bit10:1,
|
||||
bit11:1,
|
||||
bit12:1, /* unused */
|
||||
bit13:1, /* unused */
|
||||
bit14:1, /* unused */
|
||||
bit15:1, /* unused */
|
||||
bit16:1, /* unused */
|
||||
bit17:1, /* unused */
|
||||
bit18:1, /* unused */
|
||||
bit19:1, /* unused */
|
||||
bit20:1, /* unused */
|
||||
bit21:1, /* unused */
|
||||
bit22:1,
|
||||
bit23:1, /* reserved */
|
||||
:8; /* reserved */
|
||||
} type;
|
||||
};
|
||||
|
||||
#else
|
||||
#error "Please fix <asm/byteorder.h>"
|
||||
#endif
|
||||
|
||||
#define IOAM6_TRACE_DATA_SIZE_MAX 244
|
||||
__u8 data[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
#endif /* _LINUX_IOAM6_H */
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
|
||||
/*
|
||||
* IPv6 IOAM Generic Netlink API
|
||||
*
|
||||
* Author:
|
||||
* Justin Iurman <justin.iurman@uliege.be>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_IOAM6_GENL_H
|
||||
#define _LINUX_IOAM6_GENL_H
|
||||
|
||||
#define IOAM6_GENL_NAME "IOAM6"
|
||||
#define IOAM6_GENL_VERSION 0x1
|
||||
|
||||
enum {
|
||||
IOAM6_ATTR_UNSPEC,
|
||||
|
||||
IOAM6_ATTR_NS_ID, /* u16 */
|
||||
IOAM6_ATTR_NS_DATA, /* u32 */
|
||||
IOAM6_ATTR_NS_DATA_WIDE,/* u64 */
|
||||
|
||||
#define IOAM6_MAX_SCHEMA_DATA_LEN (255 * 4)
|
||||
IOAM6_ATTR_SC_ID, /* u32 */
|
||||
IOAM6_ATTR_SC_DATA, /* Binary */
|
||||
IOAM6_ATTR_SC_NONE, /* Flag */
|
||||
|
||||
IOAM6_ATTR_PAD,
|
||||
|
||||
__IOAM6_ATTR_MAX,
|
||||
};
|
||||
|
||||
#define IOAM6_ATTR_MAX (__IOAM6_ATTR_MAX - 1)
|
||||
|
||||
enum {
|
||||
IOAM6_CMD_UNSPEC,
|
||||
|
||||
IOAM6_CMD_ADD_NAMESPACE,
|
||||
IOAM6_CMD_DEL_NAMESPACE,
|
||||
IOAM6_CMD_DUMP_NAMESPACES,
|
||||
|
||||
IOAM6_CMD_ADD_SCHEMA,
|
||||
IOAM6_CMD_DEL_SCHEMA,
|
||||
IOAM6_CMD_DUMP_SCHEMAS,
|
||||
|
||||
IOAM6_CMD_NS_SET_SCHEMA,
|
||||
|
||||
__IOAM6_CMD_MAX,
|
||||
};
|
||||
|
||||
#define IOAM6_CMD_MAX (__IOAM6_CMD_MAX - 1)
|
||||
|
||||
#endif /* _LINUX_IOAM6_GENL_H */
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
|
||||
/*
|
||||
* IPv6 IOAM Lightweight Tunnel API
|
||||
*
|
||||
* Author:
|
||||
* Justin Iurman <justin.iurman@uliege.be>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_IOAM6_IPTUNNEL_H
|
||||
#define _LINUX_IOAM6_IPTUNNEL_H
|
||||
|
||||
/* Encap modes:
|
||||
* - inline: direct insertion
|
||||
* - encap: ip6ip6 encapsulation
|
||||
* - auto: __inline__ for local packets, encap for in-transit packets
|
||||
*/
|
||||
enum {
|
||||
__IOAM6_IPTUNNEL_MODE_MIN,
|
||||
|
||||
IOAM6_IPTUNNEL_MODE_INLINE,
|
||||
IOAM6_IPTUNNEL_MODE_ENCAP,
|
||||
IOAM6_IPTUNNEL_MODE_AUTO,
|
||||
|
||||
__IOAM6_IPTUNNEL_MODE_MAX,
|
||||
};
|
||||
|
||||
#define IOAM6_IPTUNNEL_MODE_MIN (__IOAM6_IPTUNNEL_MODE_MIN + 1)
|
||||
#define IOAM6_IPTUNNEL_MODE_MAX (__IOAM6_IPTUNNEL_MODE_MAX - 1)
|
||||
|
||||
enum {
|
||||
IOAM6_IPTUNNEL_UNSPEC,
|
||||
|
||||
/* Encap mode */
|
||||
IOAM6_IPTUNNEL_MODE, /* u8 */
|
||||
|
||||
/* Tunnel dst address.
|
||||
* For encap,auto modes.
|
||||
*/
|
||||
IOAM6_IPTUNNEL_DST, /* struct in6_addr */
|
||||
|
||||
/* IOAM Trace Header */
|
||||
IOAM6_IPTUNNEL_TRACE, /* struct ioam6_trace_hdr */
|
||||
|
||||
__IOAM6_IPTUNNEL_MAX,
|
||||
};
|
||||
|
||||
#define IOAM6_IPTUNNEL_MAX (__IOAM6_IPTUNNEL_MAX - 1)
|
||||
|
||||
#endif /* _LINUX_IOAM6_IPTUNNEL_H */
|
||||
|
|
@ -169,6 +169,7 @@ enum
|
|||
IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST,
|
||||
IPV4_DEVCONF_DROP_GRATUITOUS_ARP,
|
||||
IPV4_DEVCONF_BC_FORWARDING,
|
||||
IPV4_DEVCONF_ARP_EVICT_NOCARRIER,
|
||||
__IPV4_DEVCONF_MAX
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ enum lwtunnel_encap_types {
|
|||
LWTUNNEL_ENCAP_BPF,
|
||||
LWTUNNEL_ENCAP_SEG6_LOCAL,
|
||||
LWTUNNEL_ENCAP_RPL,
|
||||
LWTUNNEL_ENCAP_IOAM6,
|
||||
__LWTUNNEL_ENCAP_MAX,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -97,5 +97,6 @@
|
|||
#define DEVMEM_MAGIC 0x454d444d /* "DMEM" */
|
||||
#define Z3FOLD_MAGIC 0x33
|
||||
#define PPC_CMM_MAGIC 0xc7571590
|
||||
#define SECRETMEM_MAGIC 0x5345434d /* "SECM" */
|
||||
|
||||
#endif /* __LINUX_MAGIC_H__ */
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@
|
|||
|
||||
#include <linux/const.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/in.h> /* for sockaddr_in */
|
||||
#include <linux/in6.h> /* for sockaddr_in6 */
|
||||
#include <linux/socket.h> /* for sockaddr_storage and sa_family */
|
||||
|
||||
#include <sys/socket.h> /* for struct sockaddr */
|
||||
|
||||
#define MPTCP_SUBFLOW_FLAG_MCAP_REM _BITUL(0)
|
||||
#define MPTCP_SUBFLOW_FLAG_MCAP_LOC _BITUL(1)
|
||||
|
|
@ -73,6 +78,7 @@ enum {
|
|||
#define MPTCP_PM_ADDR_FLAG_SIGNAL (1 << 0)
|
||||
#define MPTCP_PM_ADDR_FLAG_SUBFLOW (1 << 1)
|
||||
#define MPTCP_PM_ADDR_FLAG_BACKUP (1 << 2)
|
||||
#define MPTCP_PM_ADDR_FLAG_FULLMESH (1 << 3)
|
||||
|
||||
enum {
|
||||
MPTCP_PM_CMD_UNSPEC,
|
||||
|
|
@ -105,6 +111,7 @@ struct mptcp_info {
|
|||
__u64 mptcpi_rcv_nxt;
|
||||
__u8 mptcpi_local_addr_used;
|
||||
__u8 mptcpi_local_addr_max;
|
||||
__u8 mptcpi_csum_enabled;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -191,4 +198,32 @@ enum mptcp_event_attr {
|
|||
#define MPTCP_RST_EBADPERF 5
|
||||
#define MPTCP_RST_EMIDDLEBOX 6
|
||||
|
||||
struct mptcp_subflow_data {
|
||||
__u32 size_subflow_data; /* size of this structure in userspace */
|
||||
__u32 num_subflows; /* must be 0, set by kernel */
|
||||
__u32 size_kernel; /* must be 0, set by kernel */
|
||||
__u32 size_user; /* size of one element in data[] */
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
struct mptcp_subflow_addrs {
|
||||
union {
|
||||
__kernel_sa_family_t sa_family;
|
||||
struct sockaddr sa_local;
|
||||
struct sockaddr_in sin_local;
|
||||
struct sockaddr_in6 sin6_local;
|
||||
struct __kernel_sockaddr_storage ss_local;
|
||||
};
|
||||
union {
|
||||
struct sockaddr sa_remote;
|
||||
struct sockaddr_in sin_remote;
|
||||
struct sockaddr_in6 sin6_remote;
|
||||
struct __kernel_sockaddr_storage ss_remote;
|
||||
};
|
||||
};
|
||||
|
||||
/* MPTCP socket options */
|
||||
#define MPTCP_INFO 1
|
||||
#define MPTCP_TCPINFO 2
|
||||
#define MPTCP_SUBFLOW_ADDRS 3
|
||||
|
||||
#endif /* _MPTCP_H */
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ enum {
|
|||
NDA_PROTOCOL, /* Originator of entry */
|
||||
NDA_NH_ID,
|
||||
NDA_FDB_EXT_ATTRS,
|
||||
NDA_FLAGS_EXT,
|
||||
__NDA_MAX
|
||||
};
|
||||
|
||||
|
|
@ -40,14 +41,16 @@ enum {
|
|||
* Neighbor Cache Entry Flags
|
||||
*/
|
||||
|
||||
#define NTF_USE 0x01
|
||||
#define NTF_SELF 0x02
|
||||
#define NTF_MASTER 0x04
|
||||
#define NTF_PROXY 0x08 /* == ATF_PUBL */
|
||||
#define NTF_EXT_LEARNED 0x10
|
||||
#define NTF_OFFLOADED 0x20
|
||||
#define NTF_STICKY 0x40
|
||||
#define NTF_ROUTER 0x80
|
||||
#define NTF_USE (1 << 0)
|
||||
#define NTF_SELF (1 << 1)
|
||||
#define NTF_MASTER (1 << 2)
|
||||
#define NTF_PROXY (1 << 3) /* == ATF_PUBL */
|
||||
#define NTF_EXT_LEARNED (1 << 4)
|
||||
#define NTF_OFFLOADED (1 << 5)
|
||||
#define NTF_STICKY (1 << 6)
|
||||
#define NTF_ROUTER (1 << 7)
|
||||
/* Extended flags under NDA_FLAGS_EXT: */
|
||||
#define NTF_EXT_MANAGED (1 << 0)
|
||||
|
||||
/*
|
||||
* Neighbor Cache Entry States.
|
||||
|
|
@ -65,9 +68,22 @@ enum {
|
|||
#define NUD_PERMANENT 0x80
|
||||
#define NUD_NONE 0x00
|
||||
|
||||
/* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change
|
||||
and make no address resolution or NUD.
|
||||
NUD_PERMANENT also cannot be deleted by garbage collectors.
|
||||
/* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change and make no
|
||||
* address resolution or NUD.
|
||||
*
|
||||
* NUD_PERMANENT also cannot be deleted by garbage collectors. This holds true
|
||||
* for dynamic entries with NTF_EXT_LEARNED flag as well. However, upon carrier
|
||||
* down event, NUD_PERMANENT entries are not flushed whereas NTF_EXT_LEARNED
|
||||
* flagged entries explicitly are (which is also consistent with the routing
|
||||
* subsystem).
|
||||
*
|
||||
* When NTF_EXT_LEARNED is set for a bridge fdb entry the different cache entry
|
||||
* states don't make sense and thus are ignored. Such entries don't age and
|
||||
* can roam.
|
||||
*
|
||||
* NTF_EXT_MANAGED flagged neigbor entries are managed by the kernel on behalf
|
||||
* of a user space control plane, and automatically refreshed so that (if
|
||||
* possible) they remain in NUD_REACHABLE state.
|
||||
*/
|
||||
|
||||
struct nda_cacheinfo {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ enum nf_inet_hooks {
|
|||
|
||||
enum nf_dev_hooks {
|
||||
NF_NETDEV_INGRESS,
|
||||
NF_NETDEV_EGRESS,
|
||||
NF_NETDEV_NUMHOOKS
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -91,9 +91,10 @@ struct nlmsghdr {
|
|||
#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
|
||||
#define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN)
|
||||
#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
|
||||
#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
|
||||
#define NLMSG_DATA(nlh) ((void *)(((char *)nlh) + NLMSG_HDRLEN))
|
||||
#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
|
||||
(struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
|
||||
(struct nlmsghdr *)(((char *)(nlh)) + \
|
||||
NLMSG_ALIGN((nlh)->nlmsg_len)))
|
||||
#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \
|
||||
(nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
|
||||
(nlh)->nlmsg_len <= (len))
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ enum {
|
|||
__TCA_ACT_MAX
|
||||
};
|
||||
|
||||
/* See other TCA_ACT_FLAGS_ * flags in include/net/act_api.h. */
|
||||
#define TCA_ACT_FLAGS_NO_PERCPU_STATS 1 /* Don't use percpu allocator for
|
||||
* actions stats.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -827,6 +827,8 @@ struct tc_codel_xstats {
|
|||
|
||||
/* FQ_CODEL */
|
||||
|
||||
#define FQ_CODEL_QUANTUM_MAX (1 << 20)
|
||||
|
||||
enum {
|
||||
TCA_FQ_CODEL_UNSPEC,
|
||||
TCA_FQ_CODEL_TARGET,
|
||||
|
|
@ -838,6 +840,8 @@ enum {
|
|||
TCA_FQ_CODEL_CE_THRESHOLD,
|
||||
TCA_FQ_CODEL_DROP_BATCH_SIZE,
|
||||
TCA_FQ_CODEL_MEMORY_LIMIT,
|
||||
TCA_FQ_CODEL_CE_THRESHOLD_SELECTOR,
|
||||
TCA_FQ_CODEL_CE_THRESHOLD_MASK,
|
||||
__TCA_FQ_CODEL_MAX
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ typedef __s32 sctp_assoc_t;
|
|||
#define SCTP_EXPOSE_POTENTIALLY_FAILED_STATE 131
|
||||
#define SCTP_EXPOSE_PF_STATE SCTP_EXPOSE_POTENTIALLY_FAILED_STATE
|
||||
#define SCTP_REMOTE_UDP_ENCAPS_PORT 132
|
||||
#define SCTP_PLPMTUD_PROBE_INTERVAL 133
|
||||
|
||||
/* PR-SCTP policies */
|
||||
#define SCTP_PR_SCTP_NONE 0x0000
|
||||
|
|
@ -1207,4 +1208,11 @@ enum sctp_sched_type {
|
|||
SCTP_SS_MAX = SCTP_SS_RR
|
||||
};
|
||||
|
||||
/* Probe Interval socket option */
|
||||
struct sctp_probeinterval {
|
||||
sctp_assoc_t spi_assoc_id;
|
||||
struct sockaddr_storage spi_address;
|
||||
__u32 spi_interval;
|
||||
};
|
||||
|
||||
#endif /* _SCTP_H */
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ enum {
|
|||
SEG6_LOCAL_ACTION_END_AM = 14,
|
||||
/* custom BPF action */
|
||||
SEG6_LOCAL_ACTION_END_BPF = 15,
|
||||
/* decap and lookup of DA in v4 or v6 table */
|
||||
SEG6_LOCAL_ACTION_END_DT46 = 16,
|
||||
|
||||
__SEG6_LOCAL_ACTION_MAX,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -290,6 +290,8 @@ enum
|
|||
LINUX_MIB_TCPDUPLICATEDATAREHASH, /* TCPDuplicateDataRehash */
|
||||
LINUX_MIB_TCPDSACKRECVSEGS, /* TCPDSACKRecvSegs */
|
||||
LINUX_MIB_TCPDSACKIGNOREDDUBIOUS, /* TCPDSACKIgnoredDubious */
|
||||
LINUX_MIB_TCPMIGRATEREQSUCCESS, /* TCPMigrateReqSuccess */
|
||||
LINUX_MIB_TCPMIGRATEREQFAILURE, /* TCPMigrateReqFailure */
|
||||
__LINUX_MIB_MAX
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -26,4 +26,9 @@ struct __kernel_sockaddr_storage {
|
|||
};
|
||||
};
|
||||
|
||||
#define SOCK_SNDBUF_LOCK 1
|
||||
#define SOCK_RCVBUF_LOCK 2
|
||||
|
||||
#define SOCK_BUF_LOCK_MASK (SOCK_SNDBUF_LOCK | SOCK_RCVBUF_LOCK)
|
||||
|
||||
#endif /* _LINUX_SOCKET_H */
|
||||
|
|
|
|||
|
|
@ -4,3 +4,40 @@
|
|||
#ifndef __always_inline
|
||||
#define __always_inline __inline__
|
||||
#endif
|
||||
|
||||
/**
|
||||
* __struct_group() - Create a mirrored named and anonyomous struct
|
||||
*
|
||||
* @TAG: The tag name for the named sub-struct (usually empty)
|
||||
* @NAME: The identifier name of the mirrored sub-struct
|
||||
* @ATTRS: Any struct attributes (usually empty)
|
||||
* @MEMBERS: The member declarations for the mirrored structs
|
||||
*
|
||||
* Used to create an anonymous union of two structs with identical layout
|
||||
* and size: one anonymous and one named. The former's members can be used
|
||||
* normally without sub-struct naming, and the latter can be used to
|
||||
* reason about the start, end, and size of the group of struct members.
|
||||
* The named struct can also be explicitly tagged for layer reuse, as well
|
||||
* as both having struct attributes appended.
|
||||
*/
|
||||
#define __struct_group(TAG, NAME, ATTRS, MEMBERS...) \
|
||||
union { \
|
||||
struct { MEMBERS } ATTRS; \
|
||||
struct TAG { MEMBERS } ATTRS NAME; \
|
||||
}
|
||||
|
||||
/**
|
||||
* __DECLARE_FLEX_ARRAY() - Declare a flexible array usable in a union
|
||||
*
|
||||
* @TYPE: The type of each flexible array element
|
||||
* @NAME: The name of the flexible array member
|
||||
*
|
||||
* In order to have a flexible array member in a union or alone in a
|
||||
* struct, it needs to be wrapped in an anonymous struct with at least 1
|
||||
* named member, but that member can be empty.
|
||||
*/
|
||||
#define __DECLARE_FLEX_ARRAY(TYPE, NAME) \
|
||||
struct { \
|
||||
struct { } __empty_ ## NAME; \
|
||||
TYPE NAME[]; \
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#define SKBMOD_F_SMAC 0x2
|
||||
#define SKBMOD_F_ETYPE 0x4
|
||||
#define SKBMOD_F_SWAPMAC 0x8
|
||||
#define SKBMOD_F_ECN 0x10
|
||||
|
||||
struct tc_skbmod {
|
||||
tc_gen;
|
||||
|
|
|
|||
|
|
@ -84,6 +84,20 @@
|
|||
#define TLS_CIPHER_CHACHA20_POLY1305_TAG_SIZE 16
|
||||
#define TLS_CIPHER_CHACHA20_POLY1305_REC_SEQ_SIZE 8
|
||||
|
||||
#define TLS_CIPHER_SM4_GCM 55
|
||||
#define TLS_CIPHER_SM4_GCM_IV_SIZE 8
|
||||
#define TLS_CIPHER_SM4_GCM_KEY_SIZE 16
|
||||
#define TLS_CIPHER_SM4_GCM_SALT_SIZE 4
|
||||
#define TLS_CIPHER_SM4_GCM_TAG_SIZE 16
|
||||
#define TLS_CIPHER_SM4_GCM_REC_SEQ_SIZE 8
|
||||
|
||||
#define TLS_CIPHER_SM4_CCM 56
|
||||
#define TLS_CIPHER_SM4_CCM_IV_SIZE 8
|
||||
#define TLS_CIPHER_SM4_CCM_KEY_SIZE 16
|
||||
#define TLS_CIPHER_SM4_CCM_SALT_SIZE 4
|
||||
#define TLS_CIPHER_SM4_CCM_TAG_SIZE 16
|
||||
#define TLS_CIPHER_SM4_CCM_REC_SEQ_SIZE 8
|
||||
|
||||
#define TLS_SET_RECORD_TYPE 1
|
||||
#define TLS_GET_RECORD_TYPE 2
|
||||
|
||||
|
|
@ -124,6 +138,22 @@ struct tls12_crypto_info_chacha20_poly1305 {
|
|||
unsigned char rec_seq[TLS_CIPHER_CHACHA20_POLY1305_REC_SEQ_SIZE];
|
||||
};
|
||||
|
||||
struct tls12_crypto_info_sm4_gcm {
|
||||
struct tls_crypto_info info;
|
||||
unsigned char iv[TLS_CIPHER_SM4_GCM_IV_SIZE];
|
||||
unsigned char key[TLS_CIPHER_SM4_GCM_KEY_SIZE];
|
||||
unsigned char salt[TLS_CIPHER_SM4_GCM_SALT_SIZE];
|
||||
unsigned char rec_seq[TLS_CIPHER_SM4_GCM_REC_SEQ_SIZE];
|
||||
};
|
||||
|
||||
struct tls12_crypto_info_sm4_ccm {
|
||||
struct tls_crypto_info info;
|
||||
unsigned char iv[TLS_CIPHER_SM4_CCM_IV_SIZE];
|
||||
unsigned char key[TLS_CIPHER_SM4_CCM_KEY_SIZE];
|
||||
unsigned char salt[TLS_CIPHER_SM4_CCM_SALT_SIZE];
|
||||
unsigned char rec_seq[TLS_CIPHER_SM4_CCM_REC_SEQ_SIZE];
|
||||
};
|
||||
|
||||
enum {
|
||||
TLS_INFO_UNSPEC,
|
||||
TLS_INFO_VERSION,
|
||||
|
|
|
|||
|
|
@ -1,40 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
|
||||
/*
|
||||
* vdpa device management interface
|
||||
* Copyright (c) 2020 Mellanox Technologies Ltd. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_VDPA_H_
|
||||
#define _LINUX_VDPA_H_
|
||||
|
||||
#define VDPA_GENL_NAME "vdpa"
|
||||
#define VDPA_GENL_VERSION 0x1
|
||||
|
||||
enum vdpa_command {
|
||||
VDPA_CMD_UNSPEC,
|
||||
VDPA_CMD_MGMTDEV_NEW,
|
||||
VDPA_CMD_MGMTDEV_GET, /* can dump */
|
||||
VDPA_CMD_DEV_NEW,
|
||||
VDPA_CMD_DEV_DEL,
|
||||
VDPA_CMD_DEV_GET, /* can dump */
|
||||
};
|
||||
|
||||
enum vdpa_attr {
|
||||
VDPA_ATTR_UNSPEC,
|
||||
|
||||
/* bus name (optional) + dev name together make the parent device handle */
|
||||
VDPA_ATTR_MGMTDEV_BUS_NAME, /* string */
|
||||
VDPA_ATTR_MGMTDEV_DEV_NAME, /* string */
|
||||
VDPA_ATTR_MGMTDEV_SUPPORTED_CLASSES, /* u64 */
|
||||
|
||||
VDPA_ATTR_DEV_NAME, /* string */
|
||||
VDPA_ATTR_DEV_ID, /* u32 */
|
||||
VDPA_ATTR_DEV_VENDOR_ID, /* u32 */
|
||||
VDPA_ATTR_DEV_MAX_VQS, /* u32 */
|
||||
VDPA_ATTR_DEV_MAX_VQ_SIZE, /* u16 */
|
||||
|
||||
/* new attributes must be added above here */
|
||||
VDPA_ATTR_MAX,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -54,7 +54,31 @@
|
|||
#define VIRTIO_ID_SOUND 25 /* virtio sound */
|
||||
#define VIRTIO_ID_FS 26 /* virtio filesystem */
|
||||
#define VIRTIO_ID_PMEM 27 /* virtio pmem */
|
||||
#define VIRTIO_ID_RPMB 28 /* virtio rpmb */
|
||||
#define VIRTIO_ID_MAC80211_HWSIM 29 /* virtio mac80211-hwsim */
|
||||
#define VIRTIO_ID_VIDEO_ENCODER 30 /* virtio video encoder */
|
||||
#define VIRTIO_ID_VIDEO_DECODER 31 /* virtio video decoder */
|
||||
#define VIRTIO_ID_SCMI 32 /* virtio SCMI */
|
||||
#define VIRTIO_ID_NITRO_SEC_MOD 33 /* virtio nitro secure module*/
|
||||
#define VIRTIO_ID_I2C_ADAPTER 34 /* virtio i2c adapter */
|
||||
#define VIRTIO_ID_WATCHDOG 35 /* virtio watchdog */
|
||||
#define VIRTIO_ID_CAN 36 /* virtio can */
|
||||
#define VIRTIO_ID_DMABUF 37 /* virtio dmabuf */
|
||||
#define VIRTIO_ID_PARAM_SERV 38 /* virtio parameter server */
|
||||
#define VIRTIO_ID_AUDIO_POLICY 39 /* virtio audio policy */
|
||||
#define VIRTIO_ID_BT 40 /* virtio bluetooth */
|
||||
#define VIRTIO_ID_GPIO 41 /* virtio gpio */
|
||||
|
||||
/*
|
||||
* Virtio Transitional IDs
|
||||
*/
|
||||
|
||||
#define VIRTIO_TRANS_ID_NET 1000 /* transitional virtio net */
|
||||
#define VIRTIO_TRANS_ID_BLOCK 1001 /* transitional virtio block */
|
||||
#define VIRTIO_TRANS_ID_BALLOON 1002 /* transitional virtio balloon */
|
||||
#define VIRTIO_TRANS_ID_CONSOLE 1003 /* transitional virtio console */
|
||||
#define VIRTIO_TRANS_ID_SCSI 1004 /* transitional virtio SCSI */
|
||||
#define VIRTIO_TRANS_ID_RNG 1005 /* transitional virtio rng */
|
||||
#define VIRTIO_TRANS_ID_9P 1009 /* transitional virtio 9p console */
|
||||
|
||||
#endif /* _LINUX_VIRTIO_IDS_H */
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (C) 2021 Intel Corporation.
|
||||
*/
|
||||
#ifndef _WWAN_H_
|
||||
#define _WWAN_H_
|
||||
|
||||
enum {
|
||||
IFLA_WWAN_UNSPEC,
|
||||
IFLA_WWAN_LINK_ID, /* u32 */
|
||||
|
||||
__IFLA_WWAN_MAX
|
||||
};
|
||||
#define IFLA_WWAN_MAX (__IFLA_WWAN_MAX - 1)
|
||||
|
||||
#endif /* _WWAN_H_ */
|
||||
|
|
@ -215,6 +215,11 @@ enum {
|
|||
|
||||
XFRM_MSG_MAPPING,
|
||||
#define XFRM_MSG_MAPPING XFRM_MSG_MAPPING
|
||||
|
||||
XFRM_MSG_SETDEFAULT,
|
||||
#define XFRM_MSG_SETDEFAULT XFRM_MSG_SETDEFAULT
|
||||
XFRM_MSG_GETDEFAULT,
|
||||
#define XFRM_MSG_GETDEFAULT XFRM_MSG_GETDEFAULT
|
||||
__XFRM_MSG_MAX
|
||||
};
|
||||
#define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1)
|
||||
|
|
@ -508,6 +513,15 @@ struct xfrm_user_offload {
|
|||
#define XFRM_OFFLOAD_IPV6 1
|
||||
#define XFRM_OFFLOAD_INBOUND 2
|
||||
|
||||
struct xfrm_userpolicy_default {
|
||||
#define XFRM_USERPOLICY_UNSPEC 0
|
||||
#define XFRM_USERPOLICY_BLOCK 1
|
||||
#define XFRM_USERPOLICY_ACCEPT 2
|
||||
__u8 in;
|
||||
__u8 fwd;
|
||||
__u8 out;
|
||||
};
|
||||
|
||||
/* backwards compatibility for userspace */
|
||||
#define XFRMGRP_ACQUIRE 1
|
||||
#define XFRMGRP_EXPIRE 2
|
||||
|
|
|
|||
|
|
@ -51,6 +51,9 @@ void incomplete_command(void) __attribute__((noreturn));
|
|||
#define NEXT_ARG_FWD() do { argv++; argc--; } while(0)
|
||||
#define PREV_ARG() do { argv--; argc++; } while(0)
|
||||
|
||||
/* Upper limit for batch mode */
|
||||
#define MAX_ARGS 512
|
||||
|
||||
#define TIME_UNITS_PER_SEC 1000000
|
||||
#define NSEC_PER_USEC 1000
|
||||
#define NSEC_PER_MSEC 1000000
|
||||
|
|
@ -106,17 +109,6 @@ static inline bool is_addrtype_inet_not_multi(const inet_prefix *p)
|
|||
return (p->flags & ADDRTYPE_INET_MULTI) == ADDRTYPE_INET;
|
||||
}
|
||||
|
||||
#define DN_MAXADDL 20
|
||||
#ifndef AF_DECnet
|
||||
#define AF_DECnet 12
|
||||
#endif
|
||||
|
||||
struct dn_naddr
|
||||
{
|
||||
unsigned short a_len;
|
||||
unsigned char a_addr[DN_MAXADDL];
|
||||
};
|
||||
|
||||
#ifndef AF_MPLS
|
||||
# define AF_MPLS 28
|
||||
#endif
|
||||
|
|
@ -206,9 +198,15 @@ bool matches(const char *prefix, const char *string);
|
|||
int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits);
|
||||
int inet_addr_match_rta(const inet_prefix *m, const struct rtattr *rta);
|
||||
|
||||
const char *ax25_ntop(int af, const void *addr, char *str, socklen_t len);
|
||||
|
||||
const char *rose_ntop(int af, const void *addr, char *buf, socklen_t buflen);
|
||||
|
||||
const char *mpls_ntop(int af, const void *addr, char *str, size_t len);
|
||||
int mpls_pton(int af, const char *src, void *addr, size_t alen);
|
||||
|
||||
const char *netrom_ntop(int af, const void *addr, char *str, socklen_t len);
|
||||
|
||||
extern int __iproute2_hz_internal;
|
||||
int __get_hz(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
static const char version[] = "5.13.0";
|
||||
static const char version[] = "5.15.0";
|
||||
|
|
|
|||
|
|
@ -11,14 +11,15 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \
|
|||
iplink_bridge.o iplink_bridge_slave.o ipfou.o iplink_ipvlan.o \
|
||||
iplink_geneve.o iplink_vrf.o iproute_lwtunnel.o ipmacsec.o ipila.o \
|
||||
ipvrf.o iplink_xstats.o ipseg6.o iplink_netdevsim.o iplink_rmnet.o \
|
||||
ipnexthop.o ipmptcp.o iplink_bareudp.o
|
||||
ipnexthop.o ipmptcp.o iplink_bareudp.o iplink_wwan.o ipioam6.o \
|
||||
iplink_amt.o
|
||||
|
||||
RTMONOBJ=rtmon.o
|
||||
|
||||
include ../config.mk
|
||||
|
||||
ALLOBJ=$(IPOBJ) $(RTMONOBJ)
|
||||
SCRIPTS=ifcfg rtpr routel routef
|
||||
SCRIPTS=routel
|
||||
TARGETS=ip rtmon
|
||||
|
||||
all: $(TARGETS) $(SCRIPTS)
|
||||
|
|
|
|||
150
ip/ifcfg
150
ip/ifcfg
|
|
@ -1,150 +0,0 @@
|
|||
#! /bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
CheckForwarding () {
|
||||
local sbase fwd
|
||||
sbase=/proc/sys/net/ipv4/conf
|
||||
fwd=0
|
||||
if [ -d $sbase ]; then
|
||||
for dir in $sbase/*/forwarding; do
|
||||
fwd=$(( fwd + $(cat "$dir") ))
|
||||
done
|
||||
else
|
||||
fwd=2
|
||||
fi
|
||||
return $fwd
|
||||
}
|
||||
|
||||
RestartRDISC () {
|
||||
killall -HUP rdisc || rdisc -fs
|
||||
}
|
||||
|
||||
ABCMaskLen () {
|
||||
local class;
|
||||
|
||||
class=${1%%.*}
|
||||
if [ "$1" = "" -o $class -eq 0 -o $class -ge 224 ]; then return 0
|
||||
elif [ $class -ge 224 ]; then return 0
|
||||
elif [ $class -ge 192 ]; then return 24
|
||||
elif [ $class -ge 128 ]; then return 16
|
||||
else return 8; fi
|
||||
}
|
||||
|
||||
label="label $1"
|
||||
ldev="$1"
|
||||
dev=${1%:*}
|
||||
if [ "$dev" = "" -o "$1" = "help" ]; then
|
||||
echo "Usage: ifcfg DEV [[add|del [ADDR[/LEN]] [PEER] | stop]" 1>&2
|
||||
echo " add - add new address" 1>&2
|
||||
echo " del - delete address" 1>&2
|
||||
echo " stop - completely disable IP" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
shift
|
||||
|
||||
CheckForwarding
|
||||
fwd=$?
|
||||
if [ $fwd -ne 0 ]; then
|
||||
echo "Forwarding is ON or its state is unknown ($fwd). OK, No RDISC." 1>&2
|
||||
fi
|
||||
|
||||
|
||||
deleting=0
|
||||
case "$1" in
|
||||
add) shift ;;
|
||||
stop)
|
||||
if [ "$ldev" != "$dev" ]; then
|
||||
echo "Cannot stop alias $ldev" 1>&2
|
||||
exit 1;
|
||||
fi
|
||||
ip -4 addr flush dev $dev $label || exit 1
|
||||
if [ $fwd -eq 0 ]; then RestartRDISC; fi
|
||||
exit 0 ;;
|
||||
del*)
|
||||
deleting=1; shift ;;
|
||||
*)
|
||||
esac
|
||||
|
||||
ipaddr=
|
||||
pfxlen=
|
||||
if [ "$1" != "" ]; then
|
||||
ipaddr=${1%/*}
|
||||
if [ "$1" != "$ipaddr" ]; then
|
||||
pfxlen=${1#*/}
|
||||
fi
|
||||
if [ "$ipaddr" = "" ]; then
|
||||
echo "$1 is bad IP address." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
shift
|
||||
|
||||
peer=$1
|
||||
if [ "$peer" != "" ]; then
|
||||
if [ "$pfxlen" != "" -a "$pfxlen" != "32" ]; then
|
||||
echo "Peer address with non-trivial netmask." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
pfx="$ipaddr peer $peer"
|
||||
else
|
||||
if [ "$ipaddr" = "" ]; then
|
||||
echo "Missing IP address argument." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$pfxlen" = "" ]; then
|
||||
ABCMaskLen $ipaddr
|
||||
pfxlen=$?
|
||||
fi
|
||||
pfx="$ipaddr/$pfxlen"
|
||||
fi
|
||||
|
||||
if [ "$ldev" = "$dev" -a "$ipaddr" != "" ]; then
|
||||
label=
|
||||
fi
|
||||
|
||||
if [ $deleting -ne 0 ]; then
|
||||
ip addr del $pfx dev $dev $label || exit 1
|
||||
if [ $fwd -eq 0 ]; then RestartRDISC; fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
if ! ip link set up dev $dev ; then
|
||||
echo "Error: cannot enable interface $dev." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$ipaddr" = "" ]; then exit 0; fi
|
||||
|
||||
if ! arping -q -c 2 -w 3 -D -I $dev $ipaddr ; then
|
||||
echo "Error: some host already uses address $ipaddr on $dev." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! ip address add $pfx brd + dev $dev $label; then
|
||||
echo "Error: failed to add $pfx on $dev." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
arping -q -A -c 1 -I $dev $ipaddr
|
||||
noarp=$?
|
||||
( sleep 2 ;
|
||||
arping -q -U -c 1 -I $dev $ipaddr ) >/dev/null 2>&1 </dev/null &
|
||||
|
||||
ip route add unreachable 224.0.0.0/24 >/dev/null 2>&1
|
||||
ip route add unreachable 255.255.255.255 >/dev/null 2>&1
|
||||
if [ "`ip link ls $dev | grep -c MULTICAST`" -ge 1 ]; then
|
||||
ip route add 224.0.0.0/4 dev $dev scope global >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
if [ $fwd -eq 0 ]; then
|
||||
if [ $noarp -eq 0 ]; then
|
||||
ip ro append default dev $dev metric 30000 scope global
|
||||
elif [ "$peer" != "" ]; then
|
||||
if ping -q -c 2 -w 4 $peer ; then
|
||||
ip ro append default via $peer dev $dev metric 30001
|
||||
fi
|
||||
fi
|
||||
RestartRDISC
|
||||
fi
|
||||
|
||||
exit 0
|
||||
9
ip/ip.c
9
ip/ip.c
|
|
@ -64,15 +64,15 @@ static void usage(void)
|
|||
fprintf(stderr,
|
||||
"Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }\n"
|
||||
" ip [ -force ] -batch filename\n"
|
||||
"where OBJECT := { address | addrlabel | fou | help | ila | l2tp | link |\n"
|
||||
" macsec | maddress | monitor | mptcp | mroute | mrule |\n"
|
||||
"where OBJECT := { address | addrlabel | amt | fou | help | ila | ioam | l2tp |\n"
|
||||
" link | macsec | maddress | monitor | mptcp | mroute | mrule |\n"
|
||||
" neighbor | neighbour | netconf | netns | nexthop | ntable |\n"
|
||||
" ntbl | route | rule | sr | tap | tcpmetrics |\n"
|
||||
" token | tunnel | tuntap | vrf | xfrm }\n"
|
||||
" OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
|
||||
" -h[uman-readable] | -iec | -j[son] | -p[retty] |\n"
|
||||
" -f[amily] { inet | inet6 | mpls | bridge | link } |\n"
|
||||
" -4 | -6 | -I | -D | -M | -B | -0 |\n"
|
||||
" -4 | -6 | -M | -B | -0 |\n"
|
||||
" -l[oops] { maximum-addr-flush-attempts } | -br[ief] |\n"
|
||||
" -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |\n"
|
||||
" -rc[vbuf] [size] | -n[etns] name | -N[umeric] | -a[ll] |\n"
|
||||
|
|
@ -121,6 +121,7 @@ static const struct cmd {
|
|||
{ "sr", do_seg6 },
|
||||
{ "nexthop", do_ipnh },
|
||||
{ "mptcp", do_mptcp },
|
||||
{ "ioam", do_ioam6 },
|
||||
{ "help", do_help },
|
||||
{ 0 }
|
||||
};
|
||||
|
|
@ -223,8 +224,6 @@ int main(int argc, char **argv)
|
|||
preferred_family = AF_INET6;
|
||||
} else if (strcmp(opt, "-0") == 0) {
|
||||
preferred_family = AF_PACKET;
|
||||
} else if (strcmp(opt, "-D") == 0) {
|
||||
preferred_family = AF_DECnet;
|
||||
} else if (strcmp(opt, "-M") == 0) {
|
||||
preferred_family = AF_MPLS;
|
||||
} else if (strcmp(opt, "-B") == 0) {
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ int print_prefix(struct nlmsghdr *n, void *arg);
|
|||
int print_rule(struct nlmsghdr *n, void *arg);
|
||||
int print_netconf(struct rtnl_ctrl_data *ctrl,
|
||||
struct nlmsghdr *n, void *arg);
|
||||
int print_nexthop(struct nlmsghdr *n, void *arg);
|
||||
int print_nexthop_bucket(struct nlmsghdr *n, void *arg);
|
||||
void netns_map_init(void);
|
||||
void netns_nsid_socket_init(void);
|
||||
|
|
@ -90,6 +89,7 @@ int netns_identify_pid(const char *pidstr, char *name, int len);
|
|||
int do_seg6(int argc, char **argv);
|
||||
int do_ipnh(int argc, char **argv);
|
||||
int do_mptcp(int argc, char **argv);
|
||||
int do_ioam6(int argc, char **argv);
|
||||
|
||||
int iplink_get(char *name, __u32 filt_mask);
|
||||
int iplink_ifla_xstats(int argc, char **argv);
|
||||
|
|
@ -167,7 +167,8 @@ int name_is_vrf(const char *name);
|
|||
|
||||
void print_num(FILE *fp, unsigned int width, uint64_t count);
|
||||
void print_rt_flags(FILE *fp, unsigned int flags);
|
||||
void print_rta_if(FILE *fp, const struct rtattr *rta, const char *prefix);
|
||||
void print_rta_ifidx(FILE *fp, __u32 ifidx, const char *prefix);
|
||||
void __print_rta_gateway(FILE *fp, unsigned char family, const char *gateway);
|
||||
void print_rta_gateway(FILE *fp, unsigned char family,
|
||||
const struct rtattr *rta);
|
||||
#endif /* _IP_COMMON_H_ */
|
||||
|
|
|
|||
161
ip/ipaddress.c
161
ip/ipaddress.c
|
|
@ -10,6 +10,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -59,6 +60,7 @@ static void usage(void)
|
|||
" ip address {save|flush} [ dev IFNAME ] [ scope SCOPE-ID ]\n"
|
||||
" [ to PREFIX ] [ FLAG-LIST ] [ label LABEL ] [up]\n"
|
||||
" 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"
|
||||
" ip address {showdump|restore}\n"
|
||||
|
|
@ -544,6 +546,29 @@ static void print_vfinfo(FILE *fp, struct ifinfomsg *ifi, struct rtattr *vfinfo)
|
|||
print_vf_stats64(fp, vf[IFLA_VF_STATS]);
|
||||
}
|
||||
|
||||
static void size_columns(unsigned int cols[], unsigned int n, ...)
|
||||
{
|
||||
unsigned int i, len;
|
||||
uint64_t val, powi;
|
||||
va_list args;
|
||||
|
||||
va_start(args, n);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
val = va_arg(args, unsigned long long);
|
||||
|
||||
if (human_readable)
|
||||
continue;
|
||||
|
||||
for (len = 1, powi = 10; powi < val; len++, powi *= 10)
|
||||
/* nothing */;
|
||||
if (len > cols[i])
|
||||
cols[i] = len;
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void print_num(FILE *fp, unsigned int width, uint64_t count)
|
||||
{
|
||||
const char *prefix = "kMGTPE";
|
||||
|
|
@ -554,7 +579,7 @@ void print_num(FILE *fp, unsigned int width, uint64_t count)
|
|||
char buf[64];
|
||||
|
||||
if (!human_readable || count < base) {
|
||||
fprintf(fp, "%-*"PRIu64" ", width, count);
|
||||
fprintf(fp, "%*"PRIu64" ", width, count);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -581,7 +606,7 @@ void print_num(FILE *fp, unsigned int width, uint64_t count)
|
|||
snprintf(buf, sizeof(buf), "%.*f%c%s", precision,
|
||||
(double) count / powi, *prefix, use_iec ? "i" : "");
|
||||
|
||||
fprintf(fp, "%-*s ", width, buf);
|
||||
fprintf(fp, "%*s ", width, buf);
|
||||
}
|
||||
|
||||
static void print_vf_stats64(FILE *fp, struct rtattr *vfstats)
|
||||
|
|
@ -659,6 +684,15 @@ static void __print_link_stats(FILE *fp, struct rtattr *tb[])
|
|||
{
|
||||
const struct rtattr *carrier_changes = tb[IFLA_CARRIER_CHANGES];
|
||||
struct rtnl_link_stats64 _s, *s = &_s;
|
||||
unsigned int cols[] = {
|
||||
strlen("*X errors:"),
|
||||
strlen("packets"),
|
||||
strlen("errors"),
|
||||
strlen("dropped"),
|
||||
strlen("heartbt"),
|
||||
strlen("overrun"),
|
||||
strlen("compressed"),
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = get_rtnl_link_stats_rta(s, tb);
|
||||
|
|
@ -739,65 +773,98 @@ static void __print_link_stats(FILE *fp, struct rtattr *tb[])
|
|||
close_json_object();
|
||||
close_json_object();
|
||||
} else {
|
||||
size_columns(cols, ARRAY_SIZE(cols),
|
||||
s->rx_bytes, s->rx_packets, s->rx_errors,
|
||||
s->rx_dropped, s->rx_missed_errors,
|
||||
s->multicast, s->rx_compressed);
|
||||
if (show_stats > 1)
|
||||
size_columns(cols, ARRAY_SIZE(cols), 0,
|
||||
s->rx_length_errors, s->rx_crc_errors,
|
||||
s->rx_frame_errors, s->rx_fifo_errors,
|
||||
s->rx_over_errors, s->rx_nohandler);
|
||||
size_columns(cols, ARRAY_SIZE(cols),
|
||||
s->tx_bytes, s->tx_packets, s->tx_errors,
|
||||
s->tx_dropped, s->tx_carrier_errors,
|
||||
s->collisions, s->tx_compressed);
|
||||
if (show_stats > 1)
|
||||
size_columns(cols, ARRAY_SIZE(cols), 0, 0,
|
||||
s->tx_aborted_errors, s->tx_fifo_errors,
|
||||
s->tx_window_errors,
|
||||
s->tx_heartbeat_errors,
|
||||
carrier_changes ?
|
||||
rta_getattr_u32(carrier_changes) : 0);
|
||||
|
||||
/* RX stats */
|
||||
fprintf(fp, " RX: bytes packets errors dropped missed mcast %s%s",
|
||||
s->rx_compressed ? "compressed" : "", _SL_);
|
||||
fprintf(fp, " RX: %*s %*s %*s %*s %*s %*s %*s%s",
|
||||
cols[0] - 4, "bytes", cols[1], "packets",
|
||||
cols[2], "errors", cols[3], "dropped",
|
||||
cols[4], "missed", cols[5], "mcast",
|
||||
cols[6], s->rx_compressed ? "compressed" : "", _SL_);
|
||||
|
||||
fprintf(fp, " ");
|
||||
print_num(fp, 10, s->rx_bytes);
|
||||
print_num(fp, 8, s->rx_packets);
|
||||
print_num(fp, 7, s->rx_errors);
|
||||
print_num(fp, 7, s->rx_dropped);
|
||||
print_num(fp, 7, s->rx_missed_errors);
|
||||
print_num(fp, 7, s->multicast);
|
||||
print_num(fp, cols[0], s->rx_bytes);
|
||||
print_num(fp, cols[1], s->rx_packets);
|
||||
print_num(fp, cols[2], s->rx_errors);
|
||||
print_num(fp, cols[3], s->rx_dropped);
|
||||
print_num(fp, cols[4], s->rx_missed_errors);
|
||||
print_num(fp, cols[5], s->multicast);
|
||||
if (s->rx_compressed)
|
||||
print_num(fp, 7, s->rx_compressed);
|
||||
print_num(fp, cols[6], s->rx_compressed);
|
||||
|
||||
/* RX error stats */
|
||||
if (show_stats > 1) {
|
||||
fprintf(fp, "%s", _SL_);
|
||||
fprintf(fp, " RX errors: length crc frame fifo overrun%s%s",
|
||||
s->rx_nohandler ? " nohandler" : "", _SL_);
|
||||
fprintf(fp, " ");
|
||||
print_num(fp, 8, s->rx_length_errors);
|
||||
print_num(fp, 7, s->rx_crc_errors);
|
||||
print_num(fp, 7, s->rx_frame_errors);
|
||||
print_num(fp, 7, s->rx_fifo_errors);
|
||||
print_num(fp, 7, s->rx_over_errors);
|
||||
fprintf(fp, " RX errors:%*s %*s %*s %*s %*s %*s %*s%s",
|
||||
cols[0] - 10, "", cols[1], "length",
|
||||
cols[2], "crc", cols[3], "frame",
|
||||
cols[4], "fifo", cols[5], "overrun",
|
||||
cols[6], s->rx_nohandler ? "nohandler" : "",
|
||||
_SL_);
|
||||
fprintf(fp, "%*s", cols[0] + 5, "");
|
||||
print_num(fp, cols[1], s->rx_length_errors);
|
||||
print_num(fp, cols[2], s->rx_crc_errors);
|
||||
print_num(fp, cols[3], s->rx_frame_errors);
|
||||
print_num(fp, cols[4], s->rx_fifo_errors);
|
||||
print_num(fp, cols[5], s->rx_over_errors);
|
||||
if (s->rx_nohandler)
|
||||
print_num(fp, 7, s->rx_nohandler);
|
||||
print_num(fp, cols[6], s->rx_nohandler);
|
||||
}
|
||||
fprintf(fp, "%s", _SL_);
|
||||
|
||||
/* TX stats */
|
||||
fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s",
|
||||
s->tx_compressed ? "compressed" : "", _SL_);
|
||||
fprintf(fp, " TX: %*s %*s %*s %*s %*s %*s %*s%s",
|
||||
cols[0] - 4, "bytes", cols[1], "packets",
|
||||
cols[2], "errors", cols[3], "dropped",
|
||||
cols[4], "carrier", cols[5], "collsns",
|
||||
cols[6], s->tx_compressed ? "compressed" : "", _SL_);
|
||||
|
||||
fprintf(fp, " ");
|
||||
print_num(fp, 10, s->tx_bytes);
|
||||
print_num(fp, 8, s->tx_packets);
|
||||
print_num(fp, 7, s->tx_errors);
|
||||
print_num(fp, 7, s->tx_dropped);
|
||||
print_num(fp, 7, s->tx_carrier_errors);
|
||||
print_num(fp, 7, s->collisions);
|
||||
print_num(fp, cols[0], s->tx_bytes);
|
||||
print_num(fp, cols[1], s->tx_packets);
|
||||
print_num(fp, cols[2], s->tx_errors);
|
||||
print_num(fp, cols[3], s->tx_dropped);
|
||||
print_num(fp, cols[4], s->tx_carrier_errors);
|
||||
print_num(fp, cols[5], s->collisions);
|
||||
if (s->tx_compressed)
|
||||
print_num(fp, 7, s->tx_compressed);
|
||||
print_num(fp, cols[6], s->tx_compressed);
|
||||
|
||||
/* TX error stats */
|
||||
if (show_stats > 1) {
|
||||
fprintf(fp, "%s", _SL_);
|
||||
fprintf(fp, " TX errors: aborted fifo window heartbeat");
|
||||
if (carrier_changes)
|
||||
fprintf(fp, " transns");
|
||||
fprintf(fp, "%s", _SL_);
|
||||
fprintf(fp, " TX errors:%*s %*s %*s %*s %*s %*s%s",
|
||||
cols[0] - 10, "", cols[1], "aborted",
|
||||
cols[2], "fifo", cols[3], "window",
|
||||
cols[4], "heartbt",
|
||||
cols[5], carrier_changes ? "transns" : "",
|
||||
_SL_);
|
||||
|
||||
fprintf(fp, " ");
|
||||
print_num(fp, 8, s->tx_aborted_errors);
|
||||
print_num(fp, 7, s->tx_fifo_errors);
|
||||
print_num(fp, 7, s->tx_window_errors);
|
||||
print_num(fp, 7, s->tx_heartbeat_errors);
|
||||
fprintf(fp, "%*s", cols[0] + 5, "");
|
||||
print_num(fp, cols[1], s->tx_aborted_errors);
|
||||
print_num(fp, cols[2], s->tx_fifo_errors);
|
||||
print_num(fp, cols[3], s->tx_window_errors);
|
||||
print_num(fp, cols[4], s->tx_heartbeat_errors);
|
||||
if (carrier_changes)
|
||||
print_num(fp, 7,
|
||||
print_num(fp, cols[5],
|
||||
rta_getattr_u32(carrier_changes));
|
||||
}
|
||||
}
|
||||
|
|
@ -1176,6 +1243,20 @@ int print_linkinfo(struct nlmsghdr *n, void *arg)
|
|||
RTA_PAYLOAD(tb[IFLA_PHYS_SWITCH_ID]),
|
||||
b1, sizeof(b1)));
|
||||
}
|
||||
|
||||
if (tb[IFLA_PARENT_DEV_BUS_NAME]) {
|
||||
print_string(PRINT_ANY,
|
||||
"parentbus",
|
||||
"parentbus %s ",
|
||||
rta_getattr_str(tb[IFLA_PARENT_DEV_BUS_NAME]));
|
||||
}
|
||||
|
||||
if (tb[IFLA_PARENT_DEV_NAME]) {
|
||||
print_string(PRINT_ANY,
|
||||
"parentdev",
|
||||
"parentdev %s ",
|
||||
rta_getattr_str(tb[IFLA_PARENT_DEV_NAME]));
|
||||
}
|
||||
}
|
||||
|
||||
if ((do_link || show_details) && tb[IFLA_IFALIAS]) {
|
||||
|
|
@ -2043,6 +2124,8 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
|
|||
if (!name_is_vrf(*argv))
|
||||
invarg("Not a valid VRF name\n", *argv);
|
||||
filter.master = ifindex;
|
||||
} else if (strcmp(*argv, "nomaster") == 0) {
|
||||
filter.master = -1;
|
||||
} else if (strcmp(*argv, "type") == 0) {
|
||||
int soff;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,333 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* ioam6.c "ip ioam"
|
||||
*
|
||||
* Author: Justin Iurman <justin.iurman@uliege.be>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <linux/genetlink.h>
|
||||
#include <linux/ioam6_genl.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "ip_common.h"
|
||||
#include "libgenl.h"
|
||||
#include "json_print.h"
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: ip ioam { COMMAND | help }\n"
|
||||
" ip ioam namespace show\n"
|
||||
" ip ioam namespace add ID [ data DATA32 ] [ wide DATA64 ]\n"
|
||||
" ip ioam namespace del ID\n"
|
||||
" ip ioam schema show\n"
|
||||
" ip ioam schema add ID DATA\n"
|
||||
" ip ioam schema del ID\n"
|
||||
" ip ioam namespace set ID schema { ID | none }\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
static struct rtnl_handle grth = { .fd = -1 };
|
||||
static int genl_family = -1;
|
||||
|
||||
#define IOAM6_REQUEST(_req, _bufsiz, _cmd, _flags) \
|
||||
GENL_REQUEST(_req, _bufsiz, genl_family, 0, \
|
||||
IOAM6_GENL_VERSION, _cmd, _flags)
|
||||
|
||||
static struct {
|
||||
unsigned int cmd;
|
||||
__u32 sc_id;
|
||||
__u32 ns_data;
|
||||
__u64 ns_data_wide;
|
||||
__u16 ns_id;
|
||||
bool has_ns_data;
|
||||
bool has_ns_data_wide;
|
||||
bool sc_none;
|
||||
__u8 sc_data[IOAM6_MAX_SCHEMA_DATA_LEN];
|
||||
} opts;
|
||||
|
||||
static void print_namespace(struct rtattr *attrs[])
|
||||
{
|
||||
print_uint(PRINT_ANY, "namespace", "namespace %u",
|
||||
rta_getattr_u16(attrs[IOAM6_ATTR_NS_ID]));
|
||||
|
||||
if (attrs[IOAM6_ATTR_SC_ID])
|
||||
print_uint(PRINT_ANY, "schema", " [schema %u]",
|
||||
rta_getattr_u32(attrs[IOAM6_ATTR_SC_ID]));
|
||||
|
||||
if (attrs[IOAM6_ATTR_NS_DATA])
|
||||
print_hex(PRINT_ANY, "data", ", data %#010x",
|
||||
rta_getattr_u32(attrs[IOAM6_ATTR_NS_DATA]));
|
||||
|
||||
if (attrs[IOAM6_ATTR_NS_DATA_WIDE])
|
||||
print_0xhex(PRINT_ANY, "wide", ", wide %#018lx",
|
||||
rta_getattr_u64(attrs[IOAM6_ATTR_NS_DATA_WIDE]));
|
||||
|
||||
print_nl();
|
||||
}
|
||||
|
||||
static void print_schema(struct rtattr *attrs[])
|
||||
{
|
||||
__u8 data[IOAM6_MAX_SCHEMA_DATA_LEN];
|
||||
int len, i = 0;
|
||||
|
||||
print_uint(PRINT_ANY, "schema", "schema %u",
|
||||
rta_getattr_u32(attrs[IOAM6_ATTR_SC_ID]));
|
||||
|
||||
if (attrs[IOAM6_ATTR_NS_ID])
|
||||
print_uint(PRINT_ANY, "namespace", " [namespace %u]",
|
||||
rta_getattr_u16(attrs[IOAM6_ATTR_NS_ID]));
|
||||
|
||||
len = RTA_PAYLOAD(attrs[IOAM6_ATTR_SC_DATA]);
|
||||
memcpy(data, RTA_DATA(attrs[IOAM6_ATTR_SC_DATA]), len);
|
||||
|
||||
print_null(PRINT_ANY, "data", ", data:", NULL);
|
||||
while (i < len) {
|
||||
print_hhu(PRINT_ANY, "", " %02x", data[i]);
|
||||
i++;
|
||||
}
|
||||
print_nl();
|
||||
}
|
||||
|
||||
static int process_msg(struct nlmsghdr *n, void *arg)
|
||||
{
|
||||
struct rtattr *attrs[IOAM6_ATTR_MAX + 1];
|
||||
struct genlmsghdr *ghdr;
|
||||
int len = n->nlmsg_len;
|
||||
|
||||
if (n->nlmsg_type != genl_family)
|
||||
return -1;
|
||||
|
||||
len -= NLMSG_LENGTH(GENL_HDRLEN);
|
||||
if (len < 0)
|
||||
return -1;
|
||||
|
||||
ghdr = NLMSG_DATA(n);
|
||||
parse_rtattr(attrs, IOAM6_ATTR_MAX, (void *)ghdr + GENL_HDRLEN, len);
|
||||
|
||||
open_json_object(NULL);
|
||||
switch (ghdr->cmd) {
|
||||
case IOAM6_CMD_DUMP_NAMESPACES:
|
||||
print_namespace(attrs);
|
||||
break;
|
||||
case IOAM6_CMD_DUMP_SCHEMAS:
|
||||
print_schema(attrs);
|
||||
break;
|
||||
}
|
||||
close_json_object();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ioam6_do_cmd(void)
|
||||
{
|
||||
IOAM6_REQUEST(req, 1056, opts.cmd, NLM_F_REQUEST);
|
||||
int dump = 0;
|
||||
|
||||
if (genl_init_handle(&grth, IOAM6_GENL_NAME, &genl_family))
|
||||
exit(1);
|
||||
|
||||
req.n.nlmsg_type = genl_family;
|
||||
|
||||
switch (opts.cmd) {
|
||||
case IOAM6_CMD_ADD_NAMESPACE:
|
||||
addattr16(&req.n, sizeof(req), IOAM6_ATTR_NS_ID, opts.ns_id);
|
||||
if (opts.has_ns_data)
|
||||
addattr32(&req.n, sizeof(req), IOAM6_ATTR_NS_DATA,
|
||||
opts.ns_data);
|
||||
if (opts.has_ns_data_wide)
|
||||
addattr64(&req.n, sizeof(req), IOAM6_ATTR_NS_DATA_WIDE,
|
||||
opts.ns_data_wide);
|
||||
break;
|
||||
case IOAM6_CMD_DEL_NAMESPACE:
|
||||
addattr16(&req.n, sizeof(req), IOAM6_ATTR_NS_ID, opts.ns_id);
|
||||
break;
|
||||
case IOAM6_CMD_DUMP_NAMESPACES:
|
||||
case IOAM6_CMD_DUMP_SCHEMAS:
|
||||
dump = 1;
|
||||
break;
|
||||
case IOAM6_CMD_ADD_SCHEMA:
|
||||
addattr32(&req.n, sizeof(req), IOAM6_ATTR_SC_ID, opts.sc_id);
|
||||
addattr_l(&req.n, sizeof(req), IOAM6_ATTR_SC_DATA, opts.sc_data,
|
||||
strlen((const char *)opts.sc_data));
|
||||
break;
|
||||
case IOAM6_CMD_DEL_SCHEMA:
|
||||
addattr32(&req.n, sizeof(req), IOAM6_ATTR_SC_ID, opts.sc_id);
|
||||
break;
|
||||
case IOAM6_CMD_NS_SET_SCHEMA:
|
||||
addattr16(&req.n, sizeof(req), IOAM6_ATTR_NS_ID, opts.ns_id);
|
||||
if (opts.sc_none)
|
||||
addattr(&req.n, sizeof(req), IOAM6_ATTR_SC_NONE);
|
||||
else
|
||||
addattr32(&req.n, sizeof(req), IOAM6_ATTR_SC_ID,
|
||||
opts.sc_id);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!dump) {
|
||||
if (rtnl_talk(&grth, &req.n, NULL) < 0)
|
||||
return -1;
|
||||
} else {
|
||||
req.n.nlmsg_flags |= NLM_F_DUMP;
|
||||
req.n.nlmsg_seq = grth.dump = ++grth.seq;
|
||||
if (rtnl_send(&grth, &req, req.n.nlmsg_len) < 0) {
|
||||
perror("Failed to send dump request");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
new_json_obj(json);
|
||||
if (rtnl_dump_filter(&grth, process_msg, stdout) < 0) {
|
||||
fprintf(stderr, "Dump terminated\n");
|
||||
exit(1);
|
||||
}
|
||||
delete_json_obj();
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_ioam6(int argc, char **argv)
|
||||
{
|
||||
bool maybe_wide = false;
|
||||
|
||||
if (argc < 1 || strcmp(*argv, "help") == 0)
|
||||
usage();
|
||||
|
||||
memset(&opts, 0, sizeof(opts));
|
||||
|
||||
if (strcmp(*argv, "namespace") == 0) {
|
||||
NEXT_ARG();
|
||||
|
||||
if (strcmp(*argv, "show") == 0) {
|
||||
opts.cmd = IOAM6_CMD_DUMP_NAMESPACES;
|
||||
|
||||
} else if (strcmp(*argv, "add") == 0) {
|
||||
NEXT_ARG();
|
||||
|
||||
if (get_u16(&opts.ns_id, *argv, 0))
|
||||
invarg("Invalid namespace ID", *argv);
|
||||
|
||||
if (NEXT_ARG_OK()) {
|
||||
NEXT_ARG_FWD();
|
||||
|
||||
if (strcmp(*argv, "data") == 0) {
|
||||
NEXT_ARG();
|
||||
|
||||
if (get_u32(&opts.ns_data, *argv, 0))
|
||||
invarg("Invalid data", *argv);
|
||||
|
||||
maybe_wide = true;
|
||||
opts.has_ns_data = true;
|
||||
|
||||
} else if (strcmp(*argv, "wide") == 0) {
|
||||
NEXT_ARG();
|
||||
|
||||
if (get_u64(&opts.ns_data_wide, *argv, 16))
|
||||
invarg("Invalid wide data", *argv);
|
||||
|
||||
opts.has_ns_data_wide = true;
|
||||
|
||||
} else {
|
||||
invarg("Invalid argument", *argv);
|
||||
}
|
||||
}
|
||||
|
||||
if (NEXT_ARG_OK()) {
|
||||
NEXT_ARG_FWD();
|
||||
|
||||
if (!maybe_wide || strcmp(*argv, "wide") != 0)
|
||||
invarg("Unexpected argument", *argv);
|
||||
|
||||
NEXT_ARG();
|
||||
|
||||
if (get_u64(&opts.ns_data_wide, *argv, 16))
|
||||
invarg("Invalid wide data", *argv);
|
||||
|
||||
opts.has_ns_data_wide = true;
|
||||
}
|
||||
|
||||
opts.cmd = IOAM6_CMD_ADD_NAMESPACE;
|
||||
|
||||
} else if (strcmp(*argv, "del") == 0) {
|
||||
NEXT_ARG();
|
||||
|
||||
if (get_u16(&opts.ns_id, *argv, 0))
|
||||
invarg("Invalid namespace ID", *argv);
|
||||
|
||||
opts.cmd = IOAM6_CMD_DEL_NAMESPACE;
|
||||
|
||||
} else if (strcmp(*argv, "set") == 0) {
|
||||
NEXT_ARG();
|
||||
|
||||
if (get_u16(&opts.ns_id, *argv, 0))
|
||||
invarg("Invalid namespace ID", *argv);
|
||||
|
||||
NEXT_ARG();
|
||||
|
||||
if (strcmp(*argv, "schema") != 0)
|
||||
invarg("Unknown", *argv);
|
||||
|
||||
NEXT_ARG();
|
||||
|
||||
if (strcmp(*argv, "none") == 0) {
|
||||
opts.sc_none = true;
|
||||
|
||||
} else {
|
||||
if (get_u32(&opts.sc_id, *argv, 0))
|
||||
invarg("Invalid schema ID", *argv);
|
||||
|
||||
opts.sc_none = false;
|
||||
}
|
||||
|
||||
opts.cmd = IOAM6_CMD_NS_SET_SCHEMA;
|
||||
|
||||
} else {
|
||||
invarg("Unknown", *argv);
|
||||
}
|
||||
|
||||
} else if (strcmp(*argv, "schema") == 0) {
|
||||
NEXT_ARG();
|
||||
|
||||
if (strcmp(*argv, "show") == 0) {
|
||||
opts.cmd = IOAM6_CMD_DUMP_SCHEMAS;
|
||||
|
||||
} else if (strcmp(*argv, "add") == 0) {
|
||||
NEXT_ARG();
|
||||
|
||||
if (get_u32(&opts.sc_id, *argv, 0))
|
||||
invarg("Invalid schema ID", *argv);
|
||||
|
||||
NEXT_ARG();
|
||||
|
||||
if (strlen(*argv) > IOAM6_MAX_SCHEMA_DATA_LEN)
|
||||
invarg("Schema DATA too big", *argv);
|
||||
|
||||
memcpy(opts.sc_data, *argv, strlen(*argv));
|
||||
opts.cmd = IOAM6_CMD_ADD_SCHEMA;
|
||||
|
||||
} else if (strcmp(*argv, "del") == 0) {
|
||||
NEXT_ARG();
|
||||
|
||||
if (get_u32(&opts.sc_id, *argv, 0))
|
||||
invarg("Invalid schema ID", *argv);
|
||||
|
||||
opts.cmd = IOAM6_CMD_DEL_SCHEMA;
|
||||
|
||||
} else {
|
||||
invarg("Unknown", *argv);
|
||||
}
|
||||
|
||||
} else {
|
||||
invarg("Unknown", *argv);
|
||||
}
|
||||
|
||||
return ioam6_do_cmd();
|
||||
}
|
||||
23
ip/iplink.c
23
ip/iplink.c
|
|
@ -50,20 +50,21 @@ void iplink_types_usage(void)
|
|||
{
|
||||
/* Remember to add new entry here if new type is added. */
|
||||
fprintf(stderr,
|
||||
"TYPE := { bareudp | bond | bond_slave | bridge | bridge_slave |\n"
|
||||
"TYPE := { amt | bareudp | bond | bond_slave | bridge | bridge_slave |\n"
|
||||
" dummy | erspan | geneve | gre | gretap | ifb |\n"
|
||||
" ip6erspan | ip6gre | ip6gretap | ip6tnl |\n"
|
||||
" ipip | ipoib | ipvlan | ipvtap |\n"
|
||||
" macsec | macvlan | macvtap |\n"
|
||||
" netdevsim | nlmon | rmnet | sit | team | team_slave |\n"
|
||||
" vcan | veth | vlan | vrf | vti | vxcan | vxlan | xfrm }\n");
|
||||
" vcan | veth | vlan | vrf | vti | vxcan | vxlan | wwan |\n"
|
||||
" xfrm }\n");
|
||||
}
|
||||
|
||||
void iplink_usage(void)
|
||||
{
|
||||
if (iplink_have_newlink()) {
|
||||
fprintf(stderr,
|
||||
"Usage: ip link add [link DEV] [ name ] NAME\n"
|
||||
"Usage: ip link add [link DEV | parentdev NAME] [ name ] NAME\n"
|
||||
" [ txqueuelen PACKETS ]\n"
|
||||
" [ address LLADDR ]\n"
|
||||
" [ broadcast LLADDR ]\n"
|
||||
|
|
@ -119,6 +120,7 @@ void iplink_usage(void)
|
|||
" [ gso_max_size BYTES ] | [ gso_max_segs PACKETS ]\n"
|
||||
"\n"
|
||||
" ip link show [ DEVICE | group GROUP ] [up] [master DEV] [vrf NAME] [type TYPE]\n"
|
||||
" [nomaster]\n"
|
||||
"\n"
|
||||
" ip link xstats type TYPE [ ARGS ]\n"
|
||||
"\n"
|
||||
|
|
@ -577,6 +579,7 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
|
|||
|
||||
int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
|
||||
{
|
||||
bool move_netns = false;
|
||||
char *name = NULL;
|
||||
char *dev = NULL;
|
||||
char *link = NULL;
|
||||
|
|
@ -682,6 +685,7 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
|
|||
IFLA_NET_NS_PID, &netns, 4);
|
||||
else
|
||||
invarg("Invalid \"netns\" value\n", *argv);
|
||||
move_netns = true;
|
||||
} else if (strcmp(*argv, "multicast") == 0) {
|
||||
NEXT_ARG();
|
||||
req->i.ifi_change |= IFF_MULTICAST;
|
||||
|
|
@ -938,6 +942,10 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
|
|||
*argv);
|
||||
addattr32(&req->n, sizeof(*req),
|
||||
IFLA_GSO_MAX_SEGS, max_segs);
|
||||
} else if (strcmp(*argv, "parentdev") == 0) {
|
||||
NEXT_ARG();
|
||||
addattr_l(&req->n, sizeof(*req), IFLA_PARENT_DEV_NAME,
|
||||
*argv, strlen(*argv) + 1);
|
||||
} else {
|
||||
if (matches(*argv, "help") == 0)
|
||||
usage();
|
||||
|
|
@ -975,9 +983,11 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
|
|||
}
|
||||
}
|
||||
|
||||
if (!(req->n.nlmsg_flags & NLM_F_CREATE) && index) {
|
||||
if (index &&
|
||||
(!(req->n.nlmsg_flags & NLM_F_CREATE) &&
|
||||
!move_netns)) {
|
||||
fprintf(stderr,
|
||||
"index can be used only when creating devices.\n");
|
||||
"index can be used only when creating devices or when moving device to another netns.\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
|
@ -1014,6 +1024,9 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
|
|||
/* Not renaming to the same name */
|
||||
if (name == dev)
|
||||
name = NULL;
|
||||
|
||||
if (index)
|
||||
addattr32(&req->n, sizeof(*req), IFLA_NEW_IFINDEX, index);
|
||||
} else {
|
||||
if (name != dev) {
|
||||
fprintf(stderr,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* iplink_amt.c AMT device support
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Authors: Taehee Yoo <ap420073@gmail.com>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <net/if.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/if_link.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/amt.h>
|
||||
|
||||
#include "rt_names.h"
|
||||
#include "utils.h"
|
||||
#include "ip_common.h"
|
||||
|
||||
#define AMT_ATTRSET(attrs, type) (((attrs) & (1L << (type))) != 0)
|
||||
|
||||
static void print_usage(FILE *f)
|
||||
{
|
||||
fprintf(f,
|
||||
"Usage: ... amt\n"
|
||||
" [ discovery IP_ADDRESS ]\n"
|
||||
" [ mode MODE ]\n"
|
||||
" [ local ADDR ]\n"
|
||||
" [ dev PHYS_DEV ]\n"
|
||||
" [ relay_port PORT ]\n"
|
||||
" [ gateway_port PORT ]\n"
|
||||
" [ max_tunnels NUMBER ]\n"
|
||||
"\n"
|
||||
"Where: ADDR := { IP_ADDRESS }\n"
|
||||
" MODE := { gateway | relay }\n"
|
||||
);
|
||||
}
|
||||
|
||||
static char *modename[] = {"gateway", "relay"};
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
print_usage(stderr);
|
||||
}
|
||||
|
||||
static void check_duparg(__u64 *attrs, int type, const char *key,
|
||||
const char *argv)
|
||||
{
|
||||
if (!AMT_ATTRSET(*attrs, type)) {
|
||||
*attrs |= (1L << type);
|
||||
return;
|
||||
}
|
||||
duparg2(key, argv);
|
||||
}
|
||||
|
||||
static int amt_parse_opt(struct link_util *lu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
{
|
||||
unsigned int mode, max_tunnels;
|
||||
inet_prefix saddr, daddr;
|
||||
__u64 attrs = 0;
|
||||
__u16 port;
|
||||
|
||||
saddr.family = daddr.family = AF_UNSPEC;
|
||||
|
||||
inet_prefix_reset(&saddr);
|
||||
inet_prefix_reset(&daddr);
|
||||
|
||||
while (argc > 0) {
|
||||
if (strcmp(*argv, "mode") == 0) {
|
||||
NEXT_ARG();
|
||||
if (strcmp(*argv, "gateway") == 0) {
|
||||
mode = 0;
|
||||
} else if (strcmp(*argv, "relay") == 0) {
|
||||
mode = 1;
|
||||
} else {
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
addattr32(n, 1024, IFLA_AMT_MODE, mode);
|
||||
} else if (strcmp(*argv, "relay_port") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_u16(&port, *argv, 0))
|
||||
invarg("relay_port", *argv);
|
||||
addattr16(n, 1024, IFLA_AMT_RELAY_PORT, htons(port));
|
||||
} else if (strcmp(*argv, "gateway_port") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_u16(&port, *argv, 0))
|
||||
invarg("gateway_port", *argv);
|
||||
addattr16(n, 1024, IFLA_AMT_GATEWAY_PORT, htons(port));
|
||||
} else if (strcmp(*argv, "max_tunnels") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_u32(&max_tunnels, *argv, 0))
|
||||
invarg("max_tunnels", *argv);
|
||||
addattr32(n, 1024, IFLA_AMT_MAX_TUNNELS, max_tunnels);
|
||||
} else if (strcmp(*argv, "dev") == 0) {
|
||||
unsigned int link;
|
||||
|
||||
NEXT_ARG();
|
||||
link = ll_name_to_index(*argv);
|
||||
if (!link)
|
||||
exit(nodev(*argv));
|
||||
addattr32(n, 1024, IFLA_AMT_LINK, link);
|
||||
} else if (strcmp(*argv, "local") == 0) {
|
||||
NEXT_ARG();
|
||||
check_duparg(&attrs, IFLA_AMT_LOCAL_IP, "local", *argv);
|
||||
get_addr(&saddr, *argv, daddr.family);
|
||||
|
||||
if (is_addrtype_inet(&saddr))
|
||||
addattr_l(n, 1024, IFLA_AMT_LOCAL_IP,
|
||||
saddr.data, saddr.bytelen);
|
||||
} else if (strcmp(*argv, "discovery") == 0) {
|
||||
NEXT_ARG();
|
||||
check_duparg(&attrs, IFLA_AMT_DISCOVERY_IP,
|
||||
"discovery", *argv);
|
||||
get_addr(&daddr, *argv, daddr.family);
|
||||
if (is_addrtype_inet(&daddr))
|
||||
addattr_l(n, 1024, IFLA_AMT_DISCOVERY_IP,
|
||||
daddr.data, daddr.bytelen);
|
||||
} else if (strcmp(*argv, "help") == 0) {
|
||||
usage();
|
||||
return -1;
|
||||
} else {
|
||||
fprintf(stderr, "amt: unknown command \"%s\"?\n", *argv);
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
argc--, argv++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amt_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
||||
{
|
||||
if (!tb)
|
||||
return;
|
||||
|
||||
if (tb[IFLA_AMT_MODE])
|
||||
print_string(PRINT_ANY, "mode", "%s ",
|
||||
modename[rta_getattr_u32(tb[IFLA_AMT_MODE])]);
|
||||
|
||||
if (tb[IFLA_AMT_GATEWAY_PORT])
|
||||
print_uint(PRINT_ANY, "gateway_port", "gateway_port %u ",
|
||||
rta_getattr_be16(tb[IFLA_AMT_GATEWAY_PORT]));
|
||||
|
||||
if (tb[IFLA_AMT_RELAY_PORT])
|
||||
print_uint(PRINT_ANY, "relay_port", "relay_port %u ",
|
||||
rta_getattr_be16(tb[IFLA_AMT_RELAY_PORT]));
|
||||
|
||||
if (tb[IFLA_AMT_LOCAL_IP]) {
|
||||
__be32 addr = rta_getattr_u32(tb[IFLA_AMT_LOCAL_IP]);
|
||||
|
||||
print_string(PRINT_ANY, "local", "local %s ",
|
||||
format_host(AF_INET, 4, &addr));
|
||||
}
|
||||
|
||||
if (tb[IFLA_AMT_REMOTE_IP]) {
|
||||
__be32 addr = rta_getattr_u32(tb[IFLA_AMT_REMOTE_IP]);
|
||||
|
||||
print_string(PRINT_ANY, "remote", "remote %s ",
|
||||
format_host(AF_INET, 4, &addr));
|
||||
}
|
||||
|
||||
if (tb[IFLA_AMT_DISCOVERY_IP]) {
|
||||
__be32 addr = rta_getattr_u32(tb[IFLA_AMT_DISCOVERY_IP]);
|
||||
|
||||
print_string(PRINT_ANY, "discovery", "discovery %s ",
|
||||
format_host(AF_INET, 4, &addr));
|
||||
}
|
||||
|
||||
if (tb[IFLA_AMT_LINK]) {
|
||||
unsigned int link = rta_getattr_u32(tb[IFLA_AMT_LINK]);
|
||||
|
||||
print_string(PRINT_ANY, "link", "dev %s ",
|
||||
ll_index_to_name(link));
|
||||
}
|
||||
|
||||
if (tb[IFLA_AMT_MAX_TUNNELS])
|
||||
print_uint(PRINT_ANY, "max_tunnels", "max_tunnels %u ",
|
||||
rta_getattr_u32(tb[IFLA_AMT_MAX_TUNNELS]));
|
||||
}
|
||||
|
||||
static void amt_print_help(struct link_util *lu, int argc, char **argv, FILE *f)
|
||||
{
|
||||
print_usage(f);
|
||||
}
|
||||
|
||||
struct link_util amt_link_util = {
|
||||
.id = "amt",
|
||||
.maxattr = IFLA_AMT_MAX,
|
||||
.parse_opt = amt_parse_opt,
|
||||
.print_opt = amt_print_opt,
|
||||
.print_help = amt_print_help,
|
||||
};
|
||||
|
|
@ -41,6 +41,9 @@ static const char *arp_validate_tbl[] = {
|
|||
"active",
|
||||
"backup",
|
||||
"all",
|
||||
"filter",
|
||||
"filter_active",
|
||||
"filter_backup",
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
|
@ -74,6 +77,12 @@ static const char *xmit_hash_policy_tbl[] = {
|
|||
NULL,
|
||||
};
|
||||
|
||||
static const char *lacp_active_tbl[] = {
|
||||
"off",
|
||||
"on",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const char *lacp_rate_tbl[] = {
|
||||
"slow",
|
||||
"fast",
|
||||
|
|
@ -139,17 +148,19 @@ static void print_explain(FILE *f)
|
|||
" [ packets_per_slave PACKETS_PER_SLAVE ]\n"
|
||||
" [ tlb_dynamic_lb TLB_DYNAMIC_LB ]\n"
|
||||
" [ lacp_rate LACP_RATE ]\n"
|
||||
" [ lacp_active LACP_ACTIVE]\n"
|
||||
" [ ad_select AD_SELECT ]\n"
|
||||
" [ ad_user_port_key PORTKEY ]\n"
|
||||
" [ ad_actor_sys_prio SYSPRIO ]\n"
|
||||
" [ ad_actor_system LLADDR ]\n"
|
||||
"\n"
|
||||
"BONDMODE := balance-rr|active-backup|balance-xor|broadcast|802.3ad|balance-tlb|balance-alb\n"
|
||||
"ARP_VALIDATE := none|active|backup|all\n"
|
||||
"ARP_VALIDATE := none|active|backup|all|filter|filter_active|filter_backup\n"
|
||||
"ARP_ALL_TARGETS := any|all\n"
|
||||
"PRIMARY_RESELECT := always|better|failure\n"
|
||||
"FAIL_OVER_MAC := none|active|follow\n"
|
||||
"XMIT_HASH_POLICY := layer2|layer2+3|layer3+4|encap2+3|encap3+4|vlan+srcmac\n"
|
||||
"LACP_ACTIVE := off|on\n"
|
||||
"LACP_RATE := slow|fast\n"
|
||||
"AD_SELECT := stable|bandwidth|count\n"
|
||||
);
|
||||
|
|
@ -165,7 +176,7 @@ static int bond_parse_opt(struct link_util *lu, int argc, char **argv,
|
|||
{
|
||||
__u8 mode, use_carrier, primary_reselect, fail_over_mac;
|
||||
__u8 xmit_hash_policy, num_peer_notif, all_slaves_active;
|
||||
__u8 lacp_rate, ad_select, tlb_dynamic_lb;
|
||||
__u8 lacp_active, lacp_rate, ad_select, tlb_dynamic_lb;
|
||||
__u16 ad_user_port_key, ad_actor_sys_prio;
|
||||
__u32 miimon, updelay, downdelay, peer_notify_delay, arp_interval, arp_validate;
|
||||
__u32 arp_all_targets, resend_igmp, min_links, lp_interval;
|
||||
|
|
@ -323,6 +334,13 @@ static int bond_parse_opt(struct link_util *lu, int argc, char **argv,
|
|||
|
||||
lacp_rate = get_index(lacp_rate_tbl, *argv);
|
||||
addattr8(n, 1024, IFLA_BOND_AD_LACP_RATE, lacp_rate);
|
||||
} else if (strcmp(*argv, "lacp_active") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_index(lacp_active_tbl, *argv) < 0)
|
||||
invarg("invalid lacp_active", *argv);
|
||||
|
||||
lacp_active = get_index(lacp_active_tbl, *argv);
|
||||
addattr8(n, 1024, IFLA_BOND_AD_LACP_ACTIVE, lacp_active);
|
||||
} else if (matches(*argv, "ad_select") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_index(ad_select_tbl, *argv) < 0)
|
||||
|
|
@ -561,6 +579,15 @@ static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
|||
"packets_per_slave %u ",
|
||||
rta_getattr_u32(tb[IFLA_BOND_PACKETS_PER_SLAVE]));
|
||||
|
||||
if (tb[IFLA_BOND_AD_LACP_ACTIVE]) {
|
||||
const char *lacp_active = get_name(lacp_active_tbl,
|
||||
rta_getattr_u8(tb[IFLA_BOND_AD_LACP_ACTIVE]));
|
||||
print_string(PRINT_ANY,
|
||||
"ad_lacp_active",
|
||||
"lacp_active %s ",
|
||||
lacp_active);
|
||||
}
|
||||
|
||||
if (tb[IFLA_BOND_AD_LACP_RATE]) {
|
||||
const char *lacp_rate = get_name(lacp_rate_tbl,
|
||||
rta_getattr_u8(tb[IFLA_BOND_AD_LACP_RATE]));
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ static void print_explain(FILE *f)
|
|||
" [ vlan_stats_enabled VLAN_STATS_ENABLED ]\n"
|
||||
" [ vlan_stats_per_port VLAN_STATS_PER_PORT ]\n"
|
||||
" [ mcast_snooping MULTICAST_SNOOPING ]\n"
|
||||
" [ mcast_vlan_snooping MULTICAST_VLAN_SNOOPING ]\n"
|
||||
" [ mcast_router MULTICAST_ROUTER ]\n"
|
||||
" [ mcast_query_use_ifaddr MCAST_QUERY_USE_IFADDR ]\n"
|
||||
" [ mcast_querier MULTICAST_QUERIER ]\n"
|
||||
|
|
@ -83,6 +84,7 @@ void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf, size_t len)
|
|||
static int bridge_parse_opt(struct link_util *lu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
{
|
||||
struct br_boolopt_multi bm = {};
|
||||
__u32 val;
|
||||
|
||||
while (argc > 0) {
|
||||
|
|
@ -200,6 +202,18 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv,
|
|||
invarg("invalid mcast_snooping", *argv);
|
||||
|
||||
addattr8(n, 1024, IFLA_BR_MCAST_SNOOPING, mcast_snoop);
|
||||
} else if (strcmp(*argv, "mcast_vlan_snooping") == 0) {
|
||||
__u32 mcvl_bit = 1 << BR_BOOLOPT_MCAST_VLAN_SNOOPING;
|
||||
__u8 mcast_vlan_snooping;
|
||||
|
||||
NEXT_ARG();
|
||||
if (get_u8(&mcast_vlan_snooping, *argv, 0))
|
||||
invarg("invalid mcast_vlan_snooping", *argv);
|
||||
bm.optmask |= 1 << BR_BOOLOPT_MCAST_VLAN_SNOOPING;
|
||||
if (mcast_vlan_snooping)
|
||||
bm.optval |= mcvl_bit;
|
||||
else
|
||||
bm.optval &= ~mcvl_bit;
|
||||
} else if (matches(*argv, "mcast_query_use_ifaddr") == 0) {
|
||||
__u8 mcast_qui;
|
||||
|
||||
|
|
@ -379,6 +393,9 @@ static int bridge_parse_opt(struct link_util *lu, int argc, char **argv,
|
|||
argc--, argv++;
|
||||
}
|
||||
|
||||
if (bm.optmask)
|
||||
addattr_l(n, 1024, IFLA_BR_MULTI_BOOLOPT,
|
||||
&bm, sizeof(bm));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -559,6 +576,18 @@ static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
|||
"mcast_snooping %u ",
|
||||
rta_getattr_u8(tb[IFLA_BR_MCAST_SNOOPING]));
|
||||
|
||||
if (tb[IFLA_BR_MULTI_BOOLOPT]) {
|
||||
__u32 mcvl_bit = 1 << BR_BOOLOPT_MCAST_VLAN_SNOOPING;
|
||||
struct br_boolopt_multi *bm;
|
||||
|
||||
bm = RTA_DATA(tb[IFLA_BR_MULTI_BOOLOPT]);
|
||||
if (bm->optmask & mcvl_bit)
|
||||
print_uint(PRINT_ANY,
|
||||
"mcast_vlan_snooping",
|
||||
"mcast_vlan_snooping %u ",
|
||||
!!(bm->optval & mcvl_bit));
|
||||
}
|
||||
|
||||
if (tb[IFLA_BR_MCAST_ROUTER])
|
||||
print_uint(PRINT_ANY,
|
||||
"mcast_router",
|
||||
|
|
|
|||
504
ip/iplink_can.c
504
ip/iplink_can.c
|
|
@ -28,6 +28,7 @@ static void print_usage(FILE *f)
|
|||
"\n"
|
||||
"\t[ dbitrate BITRATE [ dsample-point SAMPLE-POINT] ] |\n"
|
||||
"\t[ dtq TQ dprop-seg PROP_SEG dphase-seg1 PHASE-SEG1\n \t dphase-seg2 PHASE-SEG2 [ dsjw SJW ] ]\n"
|
||||
"\t[ tdcv TDCV tdco TDCO tdcf TDCF ]\n"
|
||||
"\n"
|
||||
"\t[ loopback { on | off } ]\n"
|
||||
"\t[ listen-only { on | off } ]\n"
|
||||
|
|
@ -38,20 +39,24 @@ static void print_usage(FILE *f)
|
|||
"\t[ fd-non-iso { on | off } ]\n"
|
||||
"\t[ presume-ack { on | off } ]\n"
|
||||
"\t[ cc-len8-dlc { on | off } ]\n"
|
||||
"\t[ tdc-mode { auto | manual | off } ]\n"
|
||||
"\n"
|
||||
"\t[ restart-ms TIME-MS ]\n"
|
||||
"\t[ restart ]\n"
|
||||
"\n"
|
||||
"\t[ termination { 0..65535 } ]\n"
|
||||
"\n"
|
||||
"\tWhere: BITRATE := { 1..1000000 }\n"
|
||||
"\tWhere: BITRATE := { NUMBER in bps }\n"
|
||||
"\t SAMPLE-POINT := { 0.000..0.999 }\n"
|
||||
"\t TQ := { NUMBER }\n"
|
||||
"\t PROP-SEG := { 1..8 }\n"
|
||||
"\t PHASE-SEG1 := { 1..8 }\n"
|
||||
"\t PHASE-SEG2 := { 1..8 }\n"
|
||||
"\t SJW := { 1..4 }\n"
|
||||
"\t RESTART-MS := { 0 | NUMBER }\n"
|
||||
"\t TQ := { NUMBER in ns }\n"
|
||||
"\t PROP-SEG := { NUMBER in tq }\n"
|
||||
"\t PHASE-SEG1 := { NUMBER in tq }\n"
|
||||
"\t PHASE-SEG2 := { NUMBER in tq }\n"
|
||||
"\t SJW := { NUMBER in tq }\n"
|
||||
"\t TDCV := { NUMBER in tc}\n"
|
||||
"\t TDCO := { NUMBER in tc}\n"
|
||||
"\t TDCF := { NUMBER in tc}\n"
|
||||
"\t RESTART-MS := { 0 | NUMBER in ms }\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -88,34 +93,47 @@ static void set_ctrlmode(char *name, char *arg,
|
|||
cm->mask |= flags;
|
||||
}
|
||||
|
||||
static void print_ctrlmode(FILE *f, __u32 cm)
|
||||
static void print_flag(enum output_type t, __u32 *flags, __u32 flag,
|
||||
const char* name)
|
||||
{
|
||||
open_json_array(PRINT_ANY, is_json_context() ? "ctrlmode" : "<");
|
||||
#define _PF(cmflag, cmname) \
|
||||
if (cm & cmflag) { \
|
||||
cm &= ~cmflag; \
|
||||
print_string(PRINT_ANY, NULL, cm ? "%s," : "%s", cmname); \
|
||||
if (*flags & flag) {
|
||||
*flags &= ~flag;
|
||||
print_string(t, NULL, *flags ? "%s," : "%s", name);
|
||||
}
|
||||
_PF(CAN_CTRLMODE_LOOPBACK, "LOOPBACK");
|
||||
_PF(CAN_CTRLMODE_LISTENONLY, "LISTEN-ONLY");
|
||||
_PF(CAN_CTRLMODE_3_SAMPLES, "TRIPLE-SAMPLING");
|
||||
_PF(CAN_CTRLMODE_ONE_SHOT, "ONE-SHOT");
|
||||
_PF(CAN_CTRLMODE_BERR_REPORTING, "BERR-REPORTING");
|
||||
_PF(CAN_CTRLMODE_FD, "FD");
|
||||
_PF(CAN_CTRLMODE_FD_NON_ISO, "FD-NON-ISO");
|
||||
_PF(CAN_CTRLMODE_PRESUME_ACK, "PRESUME-ACK");
|
||||
_PF(CAN_CTRLMODE_CC_LEN8_DLC, "CC-LEN8-DLC");
|
||||
#undef _PF
|
||||
if (cm)
|
||||
print_hex(PRINT_ANY, NULL, "%x", cm);
|
||||
close_json_array(PRINT_ANY, "> ");
|
||||
}
|
||||
|
||||
static void print_ctrlmode(enum output_type t, __u32 flags, const char* key)
|
||||
{
|
||||
if (!flags)
|
||||
return;
|
||||
|
||||
open_json_array(t, is_json_context() ? key : "<");
|
||||
|
||||
print_flag(t, &flags, CAN_CTRLMODE_LOOPBACK, "LOOPBACK");
|
||||
print_flag(t, &flags, CAN_CTRLMODE_LISTENONLY, "LISTEN-ONLY");
|
||||
print_flag(t, &flags, CAN_CTRLMODE_3_SAMPLES, "TRIPLE-SAMPLING");
|
||||
print_flag(t, &flags, CAN_CTRLMODE_ONE_SHOT, "ONE-SHOT");
|
||||
print_flag(t, &flags, CAN_CTRLMODE_BERR_REPORTING, "BERR-REPORTING");
|
||||
print_flag(t, &flags, CAN_CTRLMODE_FD, "FD");
|
||||
print_flag(t, &flags, CAN_CTRLMODE_FD_NON_ISO, "FD-NON-ISO");
|
||||
print_flag(t, &flags, CAN_CTRLMODE_PRESUME_ACK, "PRESUME-ACK");
|
||||
print_flag(t, &flags, CAN_CTRLMODE_CC_LEN8_DLC, "CC-LEN8-DLC");
|
||||
print_flag(t, &flags, CAN_CTRLMODE_TDC_AUTO, "TDC-AUTO");
|
||||
print_flag(t, &flags, CAN_CTRLMODE_TDC_MANUAL, "TDC-MANUAL");
|
||||
|
||||
if (flags)
|
||||
print_hex(t, NULL, "%x", flags);
|
||||
|
||||
close_json_array(t, "> ");
|
||||
}
|
||||
|
||||
static int can_parse_opt(struct link_util *lu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
{
|
||||
struct can_bittiming bt = {}, dbt = {};
|
||||
struct can_ctrlmode cm = {0, 0};
|
||||
struct can_ctrlmode cm = { 0 };
|
||||
struct rtattr *tdc;
|
||||
__u32 tdcv = -1, tdco = -1, tdcf = -1;
|
||||
|
||||
while (argc > 0) {
|
||||
if (matches(*argv, "bitrate") == 0) {
|
||||
|
|
@ -181,6 +199,18 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
|
|||
NEXT_ARG();
|
||||
if (get_u32(&dbt.sjw, *argv, 0))
|
||||
invarg("invalid \"dsjw\" value\n", *argv);
|
||||
} else if (matches(*argv, "tdcv") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_u32(&tdcv, *argv, 0))
|
||||
invarg("invalid \"tdcv\" value\n", *argv);
|
||||
} else if (matches(*argv, "tdco") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_u32(&tdco, *argv, 0))
|
||||
invarg("invalid \"tdco\" value\n", *argv);
|
||||
} else if (matches(*argv, "tdcf") == 0) {
|
||||
NEXT_ARG();
|
||||
if (get_u32(&tdcf, *argv, 0))
|
||||
invarg("invalid \"tdcf\" value\n", *argv);
|
||||
} else if (matches(*argv, "loopback") == 0) {
|
||||
NEXT_ARG();
|
||||
set_ctrlmode("loopback", *argv, &cm,
|
||||
|
|
@ -217,6 +247,23 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
|
|||
NEXT_ARG();
|
||||
set_ctrlmode("cc-len8-dlc", *argv, &cm,
|
||||
CAN_CTRLMODE_CC_LEN8_DLC);
|
||||
} else if (matches(*argv, "tdc-mode") == 0) {
|
||||
NEXT_ARG();
|
||||
if (strcmp(*argv, "auto") == 0) {
|
||||
cm.flags |= CAN_CTRLMODE_TDC_AUTO;
|
||||
cm.mask |= CAN_CTRLMODE_TDC_AUTO;
|
||||
} else if (strcmp(*argv, "manual") == 0) {
|
||||
cm.flags |= CAN_CTRLMODE_TDC_MANUAL;
|
||||
cm.mask |= CAN_CTRLMODE_TDC_MANUAL;
|
||||
} else if (strcmp(*argv, "off") == 0) {
|
||||
cm.mask |= CAN_CTRLMODE_TDC_AUTO |
|
||||
CAN_CTRLMODE_TDC_MANUAL;
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Error: argument of \"tdc-mode\" must be \"auto\", \"manual\" or \"off\", not \"%s\"\n",
|
||||
*argv);
|
||||
exit (-1);
|
||||
}
|
||||
} else if (matches(*argv, "restart") == 0) {
|
||||
__u32 val = 1;
|
||||
|
||||
|
|
@ -254,6 +301,17 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
|
|||
if (cm.mask)
|
||||
addattr_l(n, 1024, IFLA_CAN_CTRLMODE, &cm, sizeof(cm));
|
||||
|
||||
if (tdcv != -1 || tdco != -1 || tdcf != -1) {
|
||||
tdc = addattr_nest(n, 1024, IFLA_CAN_TDC | NLA_F_NESTED);
|
||||
if (tdcv != -1)
|
||||
addattr32(n, 1024, IFLA_CAN_TDC_TDCV, tdcv);
|
||||
if (tdco != -1)
|
||||
addattr32(n, 1024, IFLA_CAN_TDC_TDCO, tdco);
|
||||
if (tdcf != -1)
|
||||
addattr32(n, 1024, IFLA_CAN_TDC_TDCF, tdcf);
|
||||
addattr_nest_end(n, tdc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -266,11 +324,75 @@ static const char *can_state_names[CAN_STATE_MAX] = {
|
|||
[CAN_STATE_SLEEPING] = "SLEEPING"
|
||||
};
|
||||
|
||||
static void can_print_json_timing_min_max(const char *attr, int min, int max)
|
||||
static void can_print_nl_indent(void)
|
||||
{
|
||||
open_json_object(attr);
|
||||
print_int(PRINT_JSON, "min", NULL, min);
|
||||
print_int(PRINT_JSON, "max", NULL, max);
|
||||
print_nl();
|
||||
print_string(PRINT_FP, NULL, "%s", "\t ");
|
||||
}
|
||||
|
||||
static void can_print_timing_min_max(const char *json_attr, const char *fp_attr,
|
||||
int min, int max)
|
||||
{
|
||||
print_null(PRINT_FP, NULL, fp_attr, NULL);
|
||||
open_json_object(json_attr);
|
||||
print_uint(PRINT_ANY, "min", " %d", min);
|
||||
print_uint(PRINT_ANY, "max", "..%d", max);
|
||||
close_json_object();
|
||||
}
|
||||
|
||||
static void can_print_tdc_opt(FILE *f, struct rtattr *tdc_attr)
|
||||
{
|
||||
struct rtattr *tb[IFLA_CAN_TDC_MAX + 1];
|
||||
|
||||
parse_rtattr_nested(tb, IFLA_CAN_TDC_MAX, tdc_attr);
|
||||
if (tb[IFLA_CAN_TDC_TDCV] || tb[IFLA_CAN_TDC_TDCO] ||
|
||||
tb[IFLA_CAN_TDC_TDCF]) {
|
||||
open_json_object("tdc");
|
||||
can_print_nl_indent();
|
||||
if (tb[IFLA_CAN_TDC_TDCV]) {
|
||||
__u32 *tdcv = RTA_DATA(tb[IFLA_CAN_TDC_TDCV]);
|
||||
|
||||
print_uint(PRINT_ANY, "tdcv", " tdcv %u", *tdcv);
|
||||
}
|
||||
if (tb[IFLA_CAN_TDC_TDCO]) {
|
||||
__u32 *tdco = RTA_DATA(tb[IFLA_CAN_TDC_TDCO]);
|
||||
|
||||
print_uint(PRINT_ANY, "tdco", " tdco %u", *tdco);
|
||||
}
|
||||
if (tb[IFLA_CAN_TDC_TDCF]) {
|
||||
__u32 *tdcf = RTA_DATA(tb[IFLA_CAN_TDC_TDCF]);
|
||||
|
||||
print_uint(PRINT_ANY, "tdcf", " tdcf %u", *tdcf);
|
||||
}
|
||||
close_json_object();
|
||||
}
|
||||
}
|
||||
|
||||
static void can_print_tdc_const_opt(FILE *f, struct rtattr *tdc_attr)
|
||||
{
|
||||
struct rtattr *tb[IFLA_CAN_TDC_MAX + 1];
|
||||
|
||||
parse_rtattr_nested(tb, IFLA_CAN_TDC_MAX, tdc_attr);
|
||||
open_json_object("tdc");
|
||||
can_print_nl_indent();
|
||||
if (tb[IFLA_CAN_TDC_TDCV_MIN] && tb[IFLA_CAN_TDC_TDCV_MAX]) {
|
||||
__u32 *tdcv_min = RTA_DATA(tb[IFLA_CAN_TDC_TDCV_MIN]);
|
||||
__u32 *tdcv_max = RTA_DATA(tb[IFLA_CAN_TDC_TDCV_MAX]);
|
||||
|
||||
can_print_timing_min_max("tdcv", " tdcv", *tdcv_min, *tdcv_max);
|
||||
}
|
||||
if (tb[IFLA_CAN_TDC_TDCO_MIN] && tb[IFLA_CAN_TDC_TDCO_MAX]) {
|
||||
__u32 *tdco_min = RTA_DATA(tb[IFLA_CAN_TDC_TDCO_MIN]);
|
||||
__u32 *tdco_max = RTA_DATA(tb[IFLA_CAN_TDC_TDCO_MAX]);
|
||||
|
||||
can_print_timing_min_max("tdco", " tdco", *tdco_min, *tdco_max);
|
||||
}
|
||||
if (tb[IFLA_CAN_TDC_TDCF_MIN] && tb[IFLA_CAN_TDC_TDCF_MAX]) {
|
||||
__u32 *tdcf_min = RTA_DATA(tb[IFLA_CAN_TDC_TDCF_MIN]);
|
||||
__u32 *tdcf_max = RTA_DATA(tb[IFLA_CAN_TDC_TDCF_MAX]);
|
||||
|
||||
can_print_timing_min_max("tdcf", " tdcf", *tdcf_min, *tdcf_max);
|
||||
}
|
||||
close_json_object();
|
||||
}
|
||||
|
||||
|
|
@ -282,8 +404,7 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
|||
if (tb[IFLA_CAN_CTRLMODE]) {
|
||||
struct can_ctrlmode *cm = RTA_DATA(tb[IFLA_CAN_CTRLMODE]);
|
||||
|
||||
if (cm->flags)
|
||||
print_ctrlmode(f, cm->flags);
|
||||
print_ctrlmode(PRINT_ANY, cm->flags, "ctrlmode");
|
||||
}
|
||||
|
||||
if (tb[IFLA_CAN_STATE]) {
|
||||
|
|
@ -297,56 +418,39 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
|||
struct can_berr_counter *bc =
|
||||
RTA_DATA(tb[IFLA_CAN_BERR_COUNTER]);
|
||||
|
||||
if (is_json_context()) {
|
||||
open_json_object("berr_counter");
|
||||
print_int(PRINT_JSON, "tx", NULL, bc->txerr);
|
||||
print_int(PRINT_JSON, "rx", NULL, bc->rxerr);
|
||||
close_json_object();
|
||||
} else {
|
||||
fprintf(f, "(berr-counter tx %d rx %d) ",
|
||||
bc->txerr, bc->rxerr);
|
||||
}
|
||||
open_json_object("berr_counter");
|
||||
print_uint(PRINT_ANY, "tx", "(berr-counter tx %u", bc->txerr);
|
||||
print_uint(PRINT_ANY, "rx", " rx %u) ", bc->rxerr);
|
||||
close_json_object();
|
||||
}
|
||||
|
||||
if (tb[IFLA_CAN_RESTART_MS]) {
|
||||
__u32 *restart_ms = RTA_DATA(tb[IFLA_CAN_RESTART_MS]);
|
||||
|
||||
print_int(PRINT_ANY,
|
||||
"restart_ms",
|
||||
"restart-ms %d ",
|
||||
*restart_ms);
|
||||
print_uint(PRINT_ANY, "restart_ms", "restart-ms %u ",
|
||||
*restart_ms);
|
||||
}
|
||||
|
||||
/* bittiming is irrelevant if fixed bitrate is defined */
|
||||
if (tb[IFLA_CAN_BITTIMING] && !tb[IFLA_CAN_BITRATE_CONST]) {
|
||||
struct can_bittiming *bt = RTA_DATA(tb[IFLA_CAN_BITTIMING]);
|
||||
char sp[6];
|
||||
|
||||
if (is_json_context()) {
|
||||
json_writer_t *jw;
|
||||
|
||||
open_json_object("bittiming");
|
||||
print_int(PRINT_ANY, "bitrate", NULL, bt->bitrate);
|
||||
jw = get_json_writer();
|
||||
jsonw_name(jw, "sample_point");
|
||||
jsonw_printf(jw, "%.3f",
|
||||
(float) bt->sample_point / 1000);
|
||||
print_int(PRINT_ANY, "tq", NULL, bt->tq);
|
||||
print_int(PRINT_ANY, "prop_seg", NULL, bt->prop_seg);
|
||||
print_int(PRINT_ANY, "phase_seg1",
|
||||
NULL, bt->phase_seg1);
|
||||
print_int(PRINT_ANY, "phase_seg2",
|
||||
NULL, bt->phase_seg2);
|
||||
print_int(PRINT_ANY, "sjw", NULL, bt->sjw);
|
||||
close_json_object();
|
||||
} else {
|
||||
fprintf(f, "\n bitrate %d sample-point %.3f ",
|
||||
bt->bitrate, (float) bt->sample_point / 1000.);
|
||||
fprintf(f,
|
||||
"\n tq %d prop-seg %d phase-seg1 %d phase-seg2 %d sjw %d",
|
||||
bt->tq, bt->prop_seg,
|
||||
bt->phase_seg1, bt->phase_seg2,
|
||||
bt->sjw);
|
||||
}
|
||||
open_json_object("bittiming");
|
||||
can_print_nl_indent();
|
||||
print_uint(PRINT_ANY, "bitrate", " bitrate %u", bt->bitrate);
|
||||
snprintf(sp, sizeof(sp), "%.3f", bt->sample_point / 1000.);
|
||||
print_string(PRINT_ANY, "sample_point", " sample-point %s", sp);
|
||||
can_print_nl_indent();
|
||||
print_uint(PRINT_ANY, "tq", " tq %u", bt->tq);
|
||||
print_uint(PRINT_ANY, "prop_seg", " prop-seg %u", bt->prop_seg);
|
||||
print_uint(PRINT_ANY, "phase_seg1", " phase-seg1 %u",
|
||||
bt->phase_seg1);
|
||||
print_uint(PRINT_ANY, "phase_seg2", " phase-seg2 %u",
|
||||
bt->phase_seg2);
|
||||
print_uint(PRINT_ANY, "sjw", " sjw %u", bt->sjw);
|
||||
print_uint(PRINT_ANY, "brp", " brp %u", bt->brp);
|
||||
close_json_object();
|
||||
}
|
||||
|
||||
/* bittiming const is irrelevant if fixed bitrate is defined */
|
||||
|
|
@ -354,28 +458,18 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
|||
struct can_bittiming_const *btc =
|
||||
RTA_DATA(tb[IFLA_CAN_BITTIMING_CONST]);
|
||||
|
||||
if (is_json_context()) {
|
||||
open_json_object("bittiming_const");
|
||||
print_string(PRINT_JSON, "name", NULL, btc->name);
|
||||
can_print_json_timing_min_max("tseg1",
|
||||
btc->tseg1_min,
|
||||
btc->tseg1_max);
|
||||
can_print_json_timing_min_max("tseg2",
|
||||
btc->tseg2_min,
|
||||
btc->tseg2_max);
|
||||
can_print_json_timing_min_max("sjw", 1, btc->sjw_max);
|
||||
can_print_json_timing_min_max("brp",
|
||||
btc->brp_min,
|
||||
btc->brp_max);
|
||||
print_int(PRINT_JSON, "brp_inc", NULL, btc->brp_inc);
|
||||
close_json_object();
|
||||
} else {
|
||||
fprintf(f, "\n %s: tseg1 %d..%d tseg2 %d..%d "
|
||||
"sjw 1..%d brp %d..%d brp-inc %d",
|
||||
btc->name, btc->tseg1_min, btc->tseg1_max,
|
||||
btc->tseg2_min, btc->tseg2_max, btc->sjw_max,
|
||||
btc->brp_min, btc->brp_max, btc->brp_inc);
|
||||
}
|
||||
open_json_object("bittiming_const");
|
||||
can_print_nl_indent();
|
||||
print_string(PRINT_ANY, "name", " %s:", btc->name);
|
||||
can_print_timing_min_max("tseg1", " tseg1",
|
||||
btc->tseg1_min, btc->tseg1_max);
|
||||
can_print_timing_min_max("tseg2", " tseg2",
|
||||
btc->tseg2_min, btc->tseg2_max);
|
||||
can_print_timing_min_max("sjw", " sjw", 1, btc->sjw_max);
|
||||
can_print_timing_min_max("brp", " brp",
|
||||
btc->brp_min, btc->brp_max);
|
||||
print_uint(PRINT_ANY, "brp_inc", " brp_inc %u", btc->brp_inc);
|
||||
close_json_object();
|
||||
}
|
||||
|
||||
if (tb[IFLA_CAN_BITRATE_CONST]) {
|
||||
|
|
@ -391,64 +485,52 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
|||
bitrate = bt->bitrate;
|
||||
}
|
||||
|
||||
if (is_json_context()) {
|
||||
print_uint(PRINT_JSON,
|
||||
"bittiming_bitrate",
|
||||
NULL, bitrate);
|
||||
open_json_array(PRINT_JSON, "bitrate_const");
|
||||
for (i = 0; i < bitrate_cnt; ++i)
|
||||
print_uint(PRINT_JSON, NULL, NULL,
|
||||
bitrate_const[i]);
|
||||
close_json_array(PRINT_JSON, NULL);
|
||||
} else {
|
||||
fprintf(f, "\n bitrate %u", bitrate);
|
||||
fprintf(f, "\n [");
|
||||
|
||||
for (i = 0; i < bitrate_cnt - 1; ++i) {
|
||||
/* This will keep lines below 80 signs */
|
||||
if (!(i % 6) && i)
|
||||
fprintf(f, "\n ");
|
||||
|
||||
fprintf(f, "%8u, ", bitrate_const[i]);
|
||||
can_print_nl_indent();
|
||||
print_uint(PRINT_ANY, "bittiming_bitrate", " bitrate %u",
|
||||
bitrate);
|
||||
can_print_nl_indent();
|
||||
open_json_array(PRINT_ANY, is_json_context() ?
|
||||
"bitrate_const" : " [");
|
||||
for (i = 0; i < bitrate_cnt; ++i) {
|
||||
/* This will keep lines below 80 signs */
|
||||
if (!(i % 6) && i) {
|
||||
can_print_nl_indent();
|
||||
print_string(PRINT_FP, NULL, "%s", " ");
|
||||
}
|
||||
|
||||
if (!(i % 6) && i)
|
||||
fprintf(f, "\n ");
|
||||
fprintf(f, "%8u ]", bitrate_const[i]);
|
||||
print_uint(PRINT_ANY, NULL,
|
||||
i < bitrate_cnt - 1 ? "%8u, " : "%8u",
|
||||
bitrate_const[i]);
|
||||
}
|
||||
close_json_array(PRINT_JSON, " ]");
|
||||
}
|
||||
|
||||
/* data bittiming is irrelevant if fixed bitrate is defined */
|
||||
if (tb[IFLA_CAN_DATA_BITTIMING] && !tb[IFLA_CAN_DATA_BITRATE_CONST]) {
|
||||
struct can_bittiming *dbt =
|
||||
RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING]);
|
||||
char dsp[6];
|
||||
|
||||
if (is_json_context()) {
|
||||
json_writer_t *jw;
|
||||
open_json_object("data_bittiming");
|
||||
can_print_nl_indent();
|
||||
print_uint(PRINT_ANY, "bitrate", " dbitrate %u", dbt->bitrate);
|
||||
snprintf(dsp, sizeof(dsp), "%.3f", dbt->sample_point / 1000.);
|
||||
print_string(PRINT_ANY, "sample_point", " dsample-point %s",
|
||||
dsp);
|
||||
can_print_nl_indent();
|
||||
print_uint(PRINT_ANY, "tq", " dtq %u", dbt->tq);
|
||||
print_uint(PRINT_ANY, "prop_seg", " dprop-seg %u",
|
||||
dbt->prop_seg);
|
||||
print_uint(PRINT_ANY, "phase_seg1", " dphase-seg1 %u",
|
||||
dbt->phase_seg1);
|
||||
print_uint(PRINT_ANY, "phase_seg2", " dphase-seg2 %u",
|
||||
dbt->phase_seg2);
|
||||
print_uint(PRINT_ANY, "sjw", " dsjw %u", dbt->sjw);
|
||||
print_uint(PRINT_ANY, "brp", " dbrp %u", dbt->brp);
|
||||
|
||||
open_json_object("data_bittiming");
|
||||
print_int(PRINT_JSON, "bitrate", NULL, dbt->bitrate);
|
||||
jw = get_json_writer();
|
||||
jsonw_name(jw, "sample_point");
|
||||
jsonw_printf(jw, "%.3f",
|
||||
(float) dbt->sample_point / 1000.);
|
||||
print_int(PRINT_JSON, "tq", NULL, dbt->tq);
|
||||
print_int(PRINT_JSON, "prop_seg", NULL, dbt->prop_seg);
|
||||
print_int(PRINT_JSON, "phase_seg1",
|
||||
NULL, dbt->phase_seg1);
|
||||
print_int(PRINT_JSON, "phase_seg2",
|
||||
NULL, dbt->phase_seg2);
|
||||
print_int(PRINT_JSON, "sjw", NULL, dbt->sjw);
|
||||
close_json_object();
|
||||
} else {
|
||||
fprintf(f, "\n dbitrate %d dsample-point %.3f ",
|
||||
dbt->bitrate,
|
||||
(float) dbt->sample_point / 1000.);
|
||||
fprintf(f, "\n dtq %d dprop-seg %d dphase-seg1 %d "
|
||||
"dphase-seg2 %d dsjw %d",
|
||||
dbt->tq, dbt->prop_seg, dbt->phase_seg1,
|
||||
dbt->phase_seg2, dbt->sjw);
|
||||
}
|
||||
if (tb[IFLA_CAN_TDC])
|
||||
can_print_tdc_opt(f, tb[IFLA_CAN_TDC]);
|
||||
|
||||
close_json_object();
|
||||
}
|
||||
|
||||
/* data bittiming const is irrelevant if fixed bitrate is defined */
|
||||
|
|
@ -457,29 +539,22 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
|||
struct can_bittiming_const *dbtc =
|
||||
RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING_CONST]);
|
||||
|
||||
if (is_json_context()) {
|
||||
open_json_object("data_bittiming_const");
|
||||
print_string(PRINT_JSON, "name", NULL, dbtc->name);
|
||||
can_print_json_timing_min_max("tseg1",
|
||||
dbtc->tseg1_min,
|
||||
dbtc->tseg1_max);
|
||||
can_print_json_timing_min_max("tseg2",
|
||||
dbtc->tseg2_min,
|
||||
dbtc->tseg2_max);
|
||||
can_print_json_timing_min_max("sjw", 1, dbtc->sjw_max);
|
||||
can_print_json_timing_min_max("brp",
|
||||
dbtc->brp_min,
|
||||
dbtc->brp_max);
|
||||
open_json_object("data_bittiming_const");
|
||||
can_print_nl_indent();
|
||||
print_string(PRINT_ANY, "name", " %s:", dbtc->name);
|
||||
can_print_timing_min_max("tseg1", " dtseg1",
|
||||
dbtc->tseg1_min, dbtc->tseg1_max);
|
||||
can_print_timing_min_max("tseg2", " dtseg2",
|
||||
dbtc->tseg2_min, dbtc->tseg2_max);
|
||||
can_print_timing_min_max("sjw", " dsjw", 1, dbtc->sjw_max);
|
||||
can_print_timing_min_max("brp", " dbrp",
|
||||
dbtc->brp_min, dbtc->brp_max);
|
||||
print_uint(PRINT_ANY, "brp_inc", " dbrp_inc %u", dbtc->brp_inc);
|
||||
|
||||
print_int(PRINT_JSON, "brp_inc", NULL, dbtc->brp_inc);
|
||||
close_json_object();
|
||||
} else {
|
||||
fprintf(f, "\n %s: dtseg1 %d..%d dtseg2 %d..%d "
|
||||
"dsjw 1..%d dbrp %d..%d dbrp-inc %d",
|
||||
dbtc->name, dbtc->tseg1_min, dbtc->tseg1_max,
|
||||
dbtc->tseg2_min, dbtc->tseg2_max, dbtc->sjw_max,
|
||||
dbtc->brp_min, dbtc->brp_max, dbtc->brp_inc);
|
||||
}
|
||||
if (tb[IFLA_CAN_TDC])
|
||||
can_print_tdc_const_opt(f, tb[IFLA_CAN_TDC]);
|
||||
|
||||
close_json_object();
|
||||
}
|
||||
|
||||
if (tb[IFLA_CAN_DATA_BITRATE_CONST]) {
|
||||
|
|
@ -497,30 +572,23 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
|||
dbitrate = dbt->bitrate;
|
||||
}
|
||||
|
||||
if (is_json_context()) {
|
||||
print_uint(PRINT_JSON, "data_bittiming_bitrate",
|
||||
NULL, dbitrate);
|
||||
open_json_array(PRINT_JSON, "data_bitrate_const");
|
||||
for (i = 0; i < dbitrate_cnt; ++i)
|
||||
print_uint(PRINT_JSON, NULL, NULL,
|
||||
dbitrate_const[i]);
|
||||
close_json_array(PRINT_JSON, NULL);
|
||||
} else {
|
||||
fprintf(f, "\n dbitrate %u", dbitrate);
|
||||
fprintf(f, "\n [");
|
||||
|
||||
for (i = 0; i < dbitrate_cnt - 1; ++i) {
|
||||
/* This will keep lines below 80 signs */
|
||||
if (!(i % 6) && i)
|
||||
fprintf(f, "\n ");
|
||||
|
||||
fprintf(f, "%8u, ", dbitrate_const[i]);
|
||||
can_print_nl_indent();
|
||||
print_uint(PRINT_ANY, "data_bittiming_bitrate", " dbitrate %u",
|
||||
dbitrate);
|
||||
can_print_nl_indent();
|
||||
open_json_array(PRINT_ANY, is_json_context() ?
|
||||
"data_bitrate_const" : " [");
|
||||
for (i = 0; i < dbitrate_cnt; ++i) {
|
||||
/* This will keep lines below 80 signs */
|
||||
if (!(i % 6) && i) {
|
||||
can_print_nl_indent();
|
||||
print_string(PRINT_FP, NULL, "%s", " ");
|
||||
}
|
||||
|
||||
if (!(i % 6) && i)
|
||||
fprintf(f, "\n ");
|
||||
fprintf(f, "%8u ]", dbitrate_const[i]);
|
||||
print_uint(PRINT_ANY, NULL,
|
||||
i < dbitrate_cnt - 1 ? "%8u, " : "%8u",
|
||||
dbitrate_const[i]);
|
||||
}
|
||||
close_json_array(PRINT_JSON, " ]");
|
||||
}
|
||||
|
||||
if (tb[IFLA_CAN_TERMINATION_CONST] && tb[IFLA_CAN_TERMINATION]) {
|
||||
|
|
@ -530,29 +598,21 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
|||
sizeof(*trm_const);
|
||||
int i;
|
||||
|
||||
if (is_json_context()) {
|
||||
print_hu(PRINT_JSON, "termination", NULL, *trm);
|
||||
open_json_array(PRINT_JSON, "termination_const");
|
||||
for (i = 0; i < trm_cnt; ++i)
|
||||
print_hu(PRINT_JSON, NULL, NULL, trm_const[i]);
|
||||
close_json_array(PRINT_JSON, NULL);
|
||||
} else {
|
||||
fprintf(f, "\n termination %hu [ ", *trm);
|
||||
|
||||
for (i = 0; i < trm_cnt - 1; ++i)
|
||||
fprintf(f, "%hu, ", trm_const[i]);
|
||||
|
||||
fprintf(f, "%hu ]", trm_const[i]);
|
||||
}
|
||||
can_print_nl_indent();
|
||||
print_hu(PRINT_ANY, "termination", " termination %hu [ ", *trm);
|
||||
open_json_array(PRINT_JSON, "termination_const");
|
||||
for (i = 0; i < trm_cnt; ++i)
|
||||
print_hu(PRINT_ANY, NULL,
|
||||
i < trm_cnt - 1 ? "%hu, " : "%hu",
|
||||
trm_const[i]);
|
||||
close_json_array(PRINT_JSON, " ]");
|
||||
}
|
||||
|
||||
if (tb[IFLA_CAN_CLOCK]) {
|
||||
struct can_clock *clock = RTA_DATA(tb[IFLA_CAN_CLOCK]);
|
||||
|
||||
print_int(PRINT_ANY,
|
||||
"clock",
|
||||
"\n clock %d ",
|
||||
clock->freq);
|
||||
can_print_nl_indent();
|
||||
print_uint(PRINT_ANY, "clock", " clock %u ", clock->freq);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -565,31 +625,23 @@ static void can_print_xstats(struct link_util *lu,
|
|||
if (xstats && RTA_PAYLOAD(xstats) == sizeof(*stats)) {
|
||||
stats = RTA_DATA(xstats);
|
||||
|
||||
if (is_json_context()) {
|
||||
print_int(PRINT_JSON, "restarts",
|
||||
NULL, stats->restarts);
|
||||
print_int(PRINT_JSON, "bus_error",
|
||||
NULL, stats->bus_error);
|
||||
print_int(PRINT_JSON, "arbitration_lost",
|
||||
NULL, stats->arbitration_lost);
|
||||
print_int(PRINT_JSON, "error_warning",
|
||||
NULL, stats->error_warning);
|
||||
print_int(PRINT_JSON, "error_passive",
|
||||
NULL, stats->error_passive);
|
||||
print_int(PRINT_JSON, "bus_off", NULL, stats->bus_off);
|
||||
} else {
|
||||
fprintf(f, "\n re-started bus-errors arbit-lost "
|
||||
"error-warn error-pass bus-off");
|
||||
fprintf(f, "\n %-10d %-10d %-10d %-10d %-10d %-10d",
|
||||
stats->restarts, stats->bus_error,
|
||||
stats->arbitration_lost, stats->error_warning,
|
||||
stats->error_passive, stats->bus_off);
|
||||
}
|
||||
can_print_nl_indent();
|
||||
print_string(PRINT_FP, NULL, "%s",
|
||||
" re-started bus-errors arbit-lost error-warn error-pass bus-off");
|
||||
can_print_nl_indent();
|
||||
print_uint(PRINT_ANY, "restarts", " %-10u", stats->restarts);
|
||||
print_uint(PRINT_ANY, "bus_error", " %-10u", stats->bus_error);
|
||||
print_uint(PRINT_ANY, "arbitration_lost", " %-10u",
|
||||
stats->arbitration_lost);
|
||||
print_uint(PRINT_ANY, "error_warning", " %-10u",
|
||||
stats->error_warning);
|
||||
print_uint(PRINT_ANY, "error_passive", " %-10u",
|
||||
stats->error_passive);
|
||||
print_uint(PRINT_ANY, "bus_off", " %-10u", stats->bus_off);
|
||||
}
|
||||
}
|
||||
|
||||
static void can_print_help(struct link_util *lu, int argc, char **argv,
|
||||
FILE *f)
|
||||
static void can_print_help(struct link_util *lu, int argc, char **argv, FILE *f)
|
||||
{
|
||||
print_usage(f);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -243,7 +243,6 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv,
|
|||
|
||||
static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
||||
{
|
||||
__u32 vni;
|
||||
__u8 ttl = 0;
|
||||
__u8 tos = 0;
|
||||
|
||||
|
|
@ -252,15 +251,12 @@ static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
|||
|
||||
if (tb[IFLA_GENEVE_COLLECT_METADATA]) {
|
||||
print_bool(PRINT_ANY, "external", "external ", true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tb[IFLA_GENEVE_ID] ||
|
||||
RTA_PAYLOAD(tb[IFLA_GENEVE_ID]) < sizeof(__u32))
|
||||
return;
|
||||
|
||||
vni = rta_getattr_u32(tb[IFLA_GENEVE_ID]);
|
||||
print_uint(PRINT_ANY, "id", "id %u ", vni);
|
||||
if (tb[IFLA_GENEVE_ID] &&
|
||||
RTA_PAYLOAD(tb[IFLA_GENEVE_ID]) >= sizeof(__u32)) {
|
||||
print_uint(PRINT_ANY, "id", "id %u ", rta_getattr_u32(tb[IFLA_GENEVE_ID]));
|
||||
}
|
||||
|
||||
if (tb[IFLA_GENEVE_REMOTE]) {
|
||||
__be32 addr = rta_getattr_u32(tb[IFLA_GENEVE_REMOTE]);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ static void print_explain(struct link_util *lu, FILE *f)
|
|||
"Usage: ... %s mode MODE [flag MODE_FLAG] MODE_OPTS [bcqueuelen BC_QUEUE_LEN]\n"
|
||||
"\n"
|
||||
"MODE: private | vepa | bridge | passthru | source\n"
|
||||
"MODE_FLAG: null | nopromisc\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",
|
||||
|
|
@ -58,7 +58,7 @@ static int mode_arg(const char *arg)
|
|||
static int flag_arg(const char *arg)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Error: argument of \"flag\" must be \"nopromisc\" or \"null\", not \"%s\"\n",
|
||||
"Error: argument of \"flag\" must be \"nopromisc\", \"nodst\" or \"null\", not \"%s\"\n",
|
||||
arg);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -102,6 +102,8 @@ static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv,
|
|||
|
||||
if (strcmp(*argv, "nopromisc") == 0)
|
||||
flags |= MACVLAN_FLAG_NOPROMISC;
|
||||
else if (strcmp(*argv, "nodst") == 0)
|
||||
flags |= MACVLAN_FLAG_NODST;
|
||||
else if (strcmp(*argv, "null") == 0)
|
||||
flags |= 0;
|
||||
else
|
||||
|
|
@ -159,6 +161,9 @@ static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv,
|
|||
} else if (matches(*argv, "nopromisc") == 0) {
|
||||
flags |= MACVLAN_FLAG_NOPROMISC;
|
||||
has_flags = 1;
|
||||
} else if (matches(*argv, "nodst") == 0) {
|
||||
flags |= MACVLAN_FLAG_NODST;
|
||||
has_flags = 1;
|
||||
} else if (matches(*argv, "bcqueuelen") == 0) {
|
||||
__u32 bc_queue_len;
|
||||
NEXT_ARG();
|
||||
|
|
@ -229,6 +234,9 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]
|
|||
if (flags & MACVLAN_FLAG_NOPROMISC)
|
||||
print_bool(PRINT_ANY, "nopromisc", "nopromisc ", true);
|
||||
|
||||
if (flags & MACVLAN_FLAG_NODST)
|
||||
print_bool(PRINT_ANY, "nodst", "nodst ", true);
|
||||
|
||||
if (tb[IFLA_MACVLAN_BC_QUEUE_LEN] &&
|
||||
RTA_PAYLOAD(tb[IFLA_MACVLAN_BC_QUEUE_LEN]) >= sizeof(__u32)) {
|
||||
__u32 bc_queue_len = rta_getattr_u32(tb[IFLA_MACVLAN_BC_QUEUE_LEN]);
|
||||
|
|
|
|||
|
|
@ -408,7 +408,6 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
|
|||
|
||||
static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
||||
{
|
||||
__u32 vni;
|
||||
__u8 ttl = 0;
|
||||
__u8 tos = 0;
|
||||
__u32 maxaddr;
|
||||
|
|
@ -419,15 +418,12 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
|||
if (tb[IFLA_VXLAN_COLLECT_METADATA] &&
|
||||
rta_getattr_u8(tb[IFLA_VXLAN_COLLECT_METADATA])) {
|
||||
print_bool(PRINT_ANY, "external", "external ", true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tb[IFLA_VXLAN_ID] ||
|
||||
RTA_PAYLOAD(tb[IFLA_VXLAN_ID]) < sizeof(__u32))
|
||||
return;
|
||||
|
||||
vni = rta_getattr_u32(tb[IFLA_VXLAN_ID]);
|
||||
print_uint(PRINT_ANY, "id", "id %u ", vni);
|
||||
if (tb[IFLA_VXLAN_ID] &&
|
||||
RTA_PAYLOAD(tb[IFLA_VXLAN_ID]) >= sizeof(__u32)) {
|
||||
print_uint(PRINT_ANY, "id", "id %u ", rta_getattr_u32(tb[IFLA_VXLAN_ID]));
|
||||
}
|
||||
|
||||
if (tb[IFLA_VXLAN_GROUP]) {
|
||||
__be32 addr = rta_getattr_u32(tb[IFLA_VXLAN_GROUP]);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/wwan.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "ip_common.h"
|
||||
|
||||
static void print_explain(FILE *f)
|
||||
{
|
||||
fprintf(f,
|
||||
"Usage: ... wwan linkid LINKID\n"
|
||||
"\n"
|
||||
"Where: LINKID := 0-4294967295\n"
|
||||
);
|
||||
}
|
||||
|
||||
static void explain(void)
|
||||
{
|
||||
print_explain(stderr);
|
||||
}
|
||||
|
||||
static int wwan_parse_opt(struct link_util *lu, int argc, char **argv,
|
||||
struct nlmsghdr *n)
|
||||
{
|
||||
while (argc > 0) {
|
||||
if (matches(*argv, "linkid") == 0) {
|
||||
__u32 linkid;
|
||||
|
||||
NEXT_ARG();
|
||||
if (get_u32(&linkid, *argv, 0))
|
||||
invarg("linkid", *argv);
|
||||
addattr32(n, 1024, IFLA_WWAN_LINK_ID, linkid);
|
||||
} else if (matches(*argv, "help") == 0) {
|
||||
explain();
|
||||
return -1;
|
||||
} else {
|
||||
fprintf(stderr, "wwan: unknown command \"%s\"?\n",
|
||||
*argv);
|
||||
explain();
|
||||
return -1;
|
||||
}
|
||||
argc--, argv++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wwan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
||||
{
|
||||
if (!tb)
|
||||
return;
|
||||
|
||||
if (tb[IFLA_WWAN_LINK_ID])
|
||||
print_uint(PRINT_ANY, "linkid", "linkid %u ",
|
||||
rta_getattr_u32(tb[IFLA_WWAN_LINK_ID]));
|
||||
}
|
||||
|
||||
static void wwan_print_help(struct link_util *lu, int argc, char **argv,
|
||||
FILE *f)
|
||||
{
|
||||
print_explain(f);
|
||||
}
|
||||
|
||||
struct link_util wwan_link_util = {
|
||||
.id = "wwan",
|
||||
.maxattr = IFLA_WWAN_MAX,
|
||||
.parse_opt = wwan_parse_opt,
|
||||
.print_opt = wwan_print_opt,
|
||||
.print_help = wwan_print_help,
|
||||
};
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "utils.h"
|
||||
#include "ip_common.h"
|
||||
#include "nh_common.h"
|
||||
|
||||
static void usage(void) __attribute__((noreturn));
|
||||
static int prefix_banner;
|
||||
|
|
@ -88,7 +89,7 @@ static int accept_msg(struct rtnl_ctrl_data *ctrl,
|
|||
case RTM_NEWNEXTHOP:
|
||||
case RTM_DELNEXTHOP:
|
||||
print_headers(fp, "[NEXTHOP]", ctrl);
|
||||
print_nexthop(n, arg);
|
||||
print_cache_nexthop(n, arg, true);
|
||||
return 0;
|
||||
|
||||
case RTM_NEWNEXTHOPBUCKET:
|
||||
|
|
|
|||
23
ip/ipmptcp.c
23
ip/ipmptcp.c
|
|
@ -1,17 +1,23 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <rt_names.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <linux/genetlink.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/mptcp.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "ip_common.h"
|
||||
#include "libgenl.h"
|
||||
#include "json_print.h"
|
||||
#include "libgenl.h"
|
||||
#include "libnetlink.h"
|
||||
#include "ll_map.h"
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
|
|
@ -143,6 +149,9 @@ static int mptcp_parse_opt(int argc, char **argv, struct nlmsghdr *n,
|
|||
if (!id_set && !adding)
|
||||
missarg("ID");
|
||||
|
||||
if (port && !(flags & MPTCP_PM_ADDR_FLAG_SIGNAL))
|
||||
invarg("flags must have signal when using port", "port");
|
||||
|
||||
attr_addr = addattr_nest(n, MPTCP_BUFLEN,
|
||||
MPTCP_PM_ATTR_ADDR | NLA_F_NESTED);
|
||||
if (id_set)
|
||||
|
|
@ -275,7 +284,7 @@ static int mptcp_addr_dump(void)
|
|||
return -2;
|
||||
}
|
||||
|
||||
close_json_object();
|
||||
delete_json_obj();
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -296,7 +305,11 @@ static int mptcp_addr_show(int argc, char **argv)
|
|||
if (rtnl_talk(&genl_rth, &req.n, &answer) < 0)
|
||||
return -2;
|
||||
|
||||
return print_mptcp_addr(answer, stdout);
|
||||
new_json_obj(json);
|
||||
ret = print_mptcp_addr(answer, stdout);
|
||||
delete_json_obj();
|
||||
fflush(stdout);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mptcp_addr_flush(int argc, char **argv)
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ static void usage(void)
|
|||
{
|
||||
fprintf(stderr,
|
||||
"Usage: ip mroute show [ [ to ] PREFIX ] [ from PREFIX ] [ iif DEVICE ]\n"
|
||||
" [ table TABLE_ID ]\n"
|
||||
"TABLE_ID := [ local | main | default | all | NUMBER ]\n"
|
||||
" [ table TABLE_ID ]\n"
|
||||
"TABLE_ID := [ local | main | default | all | NUMBER ]\n"
|
||||
#if 0
|
||||
"Usage: ip mroute [ add | del ] DESTINATION from SOURCE [ iif DEVICE ] [ oif DEVICE ]\n"
|
||||
#endif
|
||||
|
|
|
|||
97
ip/ipneigh.c
97
ip/ipneigh.c
|
|
@ -50,11 +50,12 @@ static void usage(void)
|
|||
{
|
||||
fprintf(stderr,
|
||||
"Usage: ip neigh { add | del | change | replace }\n"
|
||||
" { ADDR [ lladdr LLADDR ] [ nud STATE ] proxy ADDR }\n"
|
||||
" [ dev DEV ] [ router ] [ extern_learn ] [ protocol PROTO ]\n"
|
||||
" { ADDR [ lladdr LLADDR ] [ nud STATE ] proxy ADDR }\n"
|
||||
" [ dev DEV ] [ router ] [ use ] [ managed ] [ extern_learn ]\n"
|
||||
" [ protocol PROTO ]\n"
|
||||
"\n"
|
||||
" ip neigh { show | flush } [ proxy ] [ to PREFIX ] [ dev DEV ] [ nud STATE ]\n"
|
||||
" [ vrf NAME ]\n"
|
||||
" [ vrf NAME ] [ nomaster ]\n"
|
||||
" ip neigh get { ADDR | proxy ADDR } dev DEV\n"
|
||||
"\n"
|
||||
"STATE := { delay | failed | incomplete | noarp | none |\n"
|
||||
|
|
@ -115,6 +116,7 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv)
|
|||
.ndm.ndm_family = preferred_family,
|
||||
.ndm.ndm_state = NUD_PERMANENT,
|
||||
};
|
||||
__u32 ext_flags = 0;
|
||||
char *dev = NULL;
|
||||
int dst_ok = 0;
|
||||
int dev_ok = 0;
|
||||
|
|
@ -148,6 +150,11 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv)
|
|||
req.ndm.ndm_flags |= NTF_PROXY;
|
||||
} else if (strcmp(*argv, "router") == 0) {
|
||||
req.ndm.ndm_flags |= NTF_ROUTER;
|
||||
} else if (strcmp(*argv, "use") == 0) {
|
||||
req.ndm.ndm_flags |= NTF_USE;
|
||||
} else if (strcmp(*argv, "managed") == 0) {
|
||||
ext_flags |= NTF_EXT_MANAGED;
|
||||
req.ndm.ndm_state = NUD_NONE;
|
||||
} else if (matches(*argv, "extern_learn") == 0) {
|
||||
req.ndm.ndm_flags |= NTF_EXT_LEARNED;
|
||||
} else if (strcmp(*argv, "dev") == 0) {
|
||||
|
|
@ -183,7 +190,10 @@ static int ipneigh_modify(int cmd, int flags, int argc, char **argv)
|
|||
req.ndm.ndm_family = dst.family;
|
||||
if (addattr_l(&req.n, sizeof(req), NDA_DST, &dst.data, dst.bytelen) < 0)
|
||||
return -1;
|
||||
|
||||
if (ext_flags &&
|
||||
addattr_l(&req.n, sizeof(req), NDA_FLAGS_EXT, &ext_flags,
|
||||
sizeof(ext_flags)) < 0)
|
||||
return -1;
|
||||
if (lla && strcmp(lla, "null")) {
|
||||
char llabuf[20];
|
||||
int l;
|
||||
|
|
@ -235,7 +245,7 @@ static void print_neigh_state(unsigned int nud)
|
|||
#define PRINT_FLAG(f) \
|
||||
if (nud & NUD_##f) { \
|
||||
nud &= ~NUD_##f; \
|
||||
print_string(PRINT_ANY, NULL, " %s", #f); \
|
||||
print_string(PRINT_ANY, NULL, "%s ", #f); \
|
||||
}
|
||||
|
||||
PRINT_FLAG(INCOMPLETE);
|
||||
|
|
@ -251,6 +261,51 @@ static void print_neigh_state(unsigned int nud)
|
|||
close_json_array(PRINT_JSON, NULL);
|
||||
}
|
||||
|
||||
static int print_neigh_brief(FILE *fp, struct ndmsg *r, struct rtattr *tb[])
|
||||
{
|
||||
if (tb[NDA_DST]) {
|
||||
const char *dst;
|
||||
int family = r->ndm_family;
|
||||
|
||||
if (family == AF_BRIDGE) {
|
||||
if (RTA_PAYLOAD(tb[NDA_DST]) == sizeof(struct in6_addr))
|
||||
family = AF_INET6;
|
||||
else
|
||||
family = AF_INET;
|
||||
}
|
||||
|
||||
dst = format_host_rta(family, tb[NDA_DST]);
|
||||
print_color_string(PRINT_ANY, ifa_family_color(family),
|
||||
"dst", "%-39s ", dst);
|
||||
}
|
||||
|
||||
if (!filter.index && r->ndm_ifindex) {
|
||||
print_color_string(PRINT_ANY, COLOR_IFNAME,
|
||||
"dev", "%-16s ",
|
||||
ll_index_to_name(r->ndm_ifindex));
|
||||
}
|
||||
|
||||
if (tb[NDA_LLADDR]) {
|
||||
const char *lladdr;
|
||||
|
||||
SPRINT_BUF(b1);
|
||||
|
||||
lladdr = ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
|
||||
RTA_PAYLOAD(tb[NDA_LLADDR]),
|
||||
ll_index_to_type(r->ndm_ifindex),
|
||||
b1, sizeof(b1));
|
||||
|
||||
print_color_string(PRINT_ANY, COLOR_MAC,
|
||||
"lladdr", "%s", lladdr);
|
||||
}
|
||||
|
||||
print_string(PRINT_FP, NULL, "%s", "\n");
|
||||
close_json_object();
|
||||
fflush(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int print_neigh(struct nlmsghdr *n, void *arg)
|
||||
{
|
||||
FILE *fp = (FILE *)arg;
|
||||
|
|
@ -258,6 +313,7 @@ int print_neigh(struct nlmsghdr *n, void *arg)
|
|||
int len = n->nlmsg_len;
|
||||
struct rtattr *tb[NDA_MAX+1];
|
||||
static int logit = 1;
|
||||
__u32 ext_flags = 0;
|
||||
__u8 protocol = 0;
|
||||
|
||||
if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH &&
|
||||
|
|
@ -283,8 +339,7 @@ int print_neigh(struct nlmsghdr *n, void *arg)
|
|||
if (!(filter.state&r->ndm_state) &&
|
||||
!(r->ndm_flags & NTF_PROXY) &&
|
||||
!(r->ndm_flags & NTF_EXT_LEARNED) &&
|
||||
(r->ndm_state || !(filter.state&0x100)) &&
|
||||
(r->ndm_family != AF_DECnet))
|
||||
(r->ndm_state || !(filter.state&0x100)))
|
||||
return 0;
|
||||
|
||||
if (filter.master && !(n->nlmsg_flags & NLM_F_DUMP_FILTERED)) {
|
||||
|
|
@ -302,6 +357,8 @@ int print_neigh(struct nlmsghdr *n, void *arg)
|
|||
|
||||
if (tb[NDA_PROTOCOL])
|
||||
protocol = rta_getattr_u8(tb[NDA_PROTOCOL]);
|
||||
if (tb[NDA_FLAGS_EXT])
|
||||
ext_flags = rta_getattr_u32(tb[NDA_FLAGS_EXT]);
|
||||
|
||||
if (filter.protocol && filter.protocol != protocol)
|
||||
return 0;
|
||||
|
|
@ -337,6 +394,9 @@ int print_neigh(struct nlmsghdr *n, void *arg)
|
|||
else if (n->nlmsg_type == RTM_GETNEIGH)
|
||||
print_null(PRINT_ANY, "miss", "%s ", "miss");
|
||||
|
||||
if (brief)
|
||||
return print_neigh_brief(fp, r, tb);
|
||||
|
||||
if (tb[NDA_DST]) {
|
||||
const char *dst;
|
||||
int family = r->ndm_family;
|
||||
|
|
@ -376,27 +436,26 @@ int print_neigh(struct nlmsghdr *n, void *arg)
|
|||
fprintf(fp, "lladdr ");
|
||||
|
||||
print_color_string(PRINT_ANY, COLOR_MAC,
|
||||
"lladdr", "%s", lladdr);
|
||||
"lladdr", "%s ", lladdr);
|
||||
}
|
||||
|
||||
if (r->ndm_flags & NTF_ROUTER)
|
||||
print_null(PRINT_ANY, "router", " %s", "router");
|
||||
|
||||
print_null(PRINT_ANY, "router", "%s ", "router");
|
||||
if (r->ndm_flags & NTF_PROXY)
|
||||
print_null(PRINT_ANY, "proxy", " %s", "proxy");
|
||||
|
||||
print_null(PRINT_ANY, "proxy", "%s ", "proxy");
|
||||
if (ext_flags & NTF_EXT_MANAGED)
|
||||
print_null(PRINT_ANY, "managed", "%s ", "managed");
|
||||
if (r->ndm_flags & NTF_EXT_LEARNED)
|
||||
print_null(PRINT_ANY, "extern_learn", " %s ", "extern_learn");
|
||||
|
||||
print_null(PRINT_ANY, "extern_learn", "%s ", "extern_learn");
|
||||
if (r->ndm_flags & NTF_OFFLOADED)
|
||||
print_null(PRINT_ANY, "offload", " %s", "offload");
|
||||
print_null(PRINT_ANY, "offload", "%s ", "offload");
|
||||
|
||||
if (show_stats) {
|
||||
if (tb[NDA_CACHEINFO])
|
||||
print_cacheinfo(RTA_DATA(tb[NDA_CACHEINFO]));
|
||||
|
||||
if (tb[NDA_PROBES])
|
||||
print_uint(PRINT_ANY, "probes", " probes %u",
|
||||
print_uint(PRINT_ANY, "probes", "probes %u ",
|
||||
rta_getattr_u32(tb[NDA_PROBES]));
|
||||
}
|
||||
|
||||
|
|
@ -406,13 +465,13 @@ int print_neigh(struct nlmsghdr *n, void *arg)
|
|||
if (protocol) {
|
||||
SPRINT_BUF(b1);
|
||||
|
||||
print_string(PRINT_ANY, "protocol", " proto %s ",
|
||||
print_string(PRINT_ANY, "protocol", "proto %s ",
|
||||
rtnl_rtprot_n2a(protocol, b1, sizeof(b1)));
|
||||
}
|
||||
|
||||
print_string(PRINT_FP, NULL, "\n", "");
|
||||
close_json_object();
|
||||
fflush(stdout);
|
||||
fflush(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -488,6 +547,8 @@ static int do_show_or_flush(int argc, char **argv, int flush)
|
|||
if (!name_is_vrf(*argv))
|
||||
invarg("Not a valid VRF name\n", *argv);
|
||||
filter.master = ifindex;
|
||||
} else if (strcmp(*argv, "nomaster") == 0) {
|
||||
filter.master = -1;
|
||||
} else if (strcmp(*argv, "unused") == 0) {
|
||||
filter.unused_only = 1;
|
||||
} else if (strcmp(*argv, "nud") == 0) {
|
||||
|
|
|
|||
483
ip/ipnexthop.c
483
ip/ipnexthop.c
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/nexthop.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <rt_names.h>
|
||||
|
|
@ -13,6 +14,7 @@
|
|||
|
||||
#include "utils.h"
|
||||
#include "ip_common.h"
|
||||
#include "nh_common.h"
|
||||
|
||||
static struct {
|
||||
unsigned int flushed;
|
||||
|
|
@ -33,6 +35,9 @@ enum {
|
|||
#define RTM_NHA(h) ((struct rtattr *)(((char *)(h)) + \
|
||||
NLMSG_ALIGN(sizeof(struct nhmsg))))
|
||||
|
||||
static struct hlist_head nh_cache[NH_CACHE_SIZE];
|
||||
static struct rtnl_handle nh_cache_rth = { .fd = -1 };
|
||||
|
||||
static void usage(void) __attribute__((noreturn));
|
||||
|
||||
static void usage(void)
|
||||
|
|
@ -212,28 +217,29 @@ out:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void print_nh_group(FILE *fp, const struct rtattr *grps_attr)
|
||||
static bool __valid_nh_group_attr(const struct rtattr *g_attr)
|
||||
{
|
||||
struct nexthop_grp *nhg = RTA_DATA(grps_attr);
|
||||
int num = RTA_PAYLOAD(grps_attr) / sizeof(*nhg);
|
||||
int i;
|
||||
int num = RTA_PAYLOAD(g_attr) / sizeof(struct nexthop_grp);
|
||||
|
||||
if (!num || num * sizeof(*nhg) != RTA_PAYLOAD(grps_attr)) {
|
||||
fprintf(fp, "<invalid nexthop group>");
|
||||
return;
|
||||
}
|
||||
return num && num * sizeof(struct nexthop_grp) == RTA_PAYLOAD(g_attr);
|
||||
}
|
||||
|
||||
static void print_nh_group(const struct nh_entry *nhe)
|
||||
{
|
||||
int i;
|
||||
|
||||
open_json_array(PRINT_JSON, "group");
|
||||
print_string(PRINT_FP, NULL, "%s", "group ");
|
||||
for (i = 0; i < num; ++i) {
|
||||
for (i = 0; i < nhe->nh_groups_cnt; ++i) {
|
||||
open_json_object(NULL);
|
||||
|
||||
if (i)
|
||||
print_string(PRINT_FP, NULL, "%s", "/");
|
||||
|
||||
print_uint(PRINT_ANY, "id", "%u", nhg[i].id);
|
||||
if (nhg[i].weight)
|
||||
print_uint(PRINT_ANY, "weight", ",%u", nhg[i].weight + 1);
|
||||
print_uint(PRINT_ANY, "id", "%u", nhe->nh_groups[i].id);
|
||||
if (nhe->nh_groups[i].weight)
|
||||
print_uint(PRINT_ANY, "weight", ",%u",
|
||||
nhe->nh_groups[i].weight + 1);
|
||||
|
||||
close_json_object();
|
||||
}
|
||||
|
|
@ -253,50 +259,59 @@ static const char *nh_group_type_name(__u16 type)
|
|||
}
|
||||
}
|
||||
|
||||
static void print_nh_group_type(FILE *fp, const struct rtattr *grp_type_attr)
|
||||
static void print_nh_group_type(__u16 nh_grp_type)
|
||||
{
|
||||
__u16 type = rta_getattr_u16(grp_type_attr);
|
||||
|
||||
if (type == NEXTHOP_GRP_TYPE_MPATH)
|
||||
if (nh_grp_type == NEXTHOP_GRP_TYPE_MPATH)
|
||||
/* Do not print type in order not to break existing output. */
|
||||
return;
|
||||
|
||||
print_string(PRINT_ANY, "type", "type %s ", nh_group_type_name(type));
|
||||
print_string(PRINT_ANY, "type", "type %s ", nh_group_type_name(nh_grp_type));
|
||||
}
|
||||
|
||||
static void print_nh_res_group(FILE *fp, const struct rtattr *res_grp_attr)
|
||||
static void parse_nh_res_group_rta(const struct rtattr *res_grp_attr,
|
||||
struct nha_res_grp *res_grp)
|
||||
{
|
||||
struct rtattr *tb[NHA_RES_GROUP_MAX + 1];
|
||||
struct rtattr *rta;
|
||||
struct timeval tv;
|
||||
|
||||
memset(res_grp, 0, sizeof(*res_grp));
|
||||
parse_rtattr_nested(tb, NHA_RES_GROUP_MAX, res_grp_attr);
|
||||
|
||||
open_json_object("resilient_args");
|
||||
|
||||
if (tb[NHA_RES_GROUP_BUCKETS])
|
||||
print_uint(PRINT_ANY, "buckets", "buckets %u ",
|
||||
rta_getattr_u16(tb[NHA_RES_GROUP_BUCKETS]));
|
||||
res_grp->buckets = rta_getattr_u16(tb[NHA_RES_GROUP_BUCKETS]);
|
||||
|
||||
if (tb[NHA_RES_GROUP_IDLE_TIMER]) {
|
||||
rta = tb[NHA_RES_GROUP_IDLE_TIMER];
|
||||
__jiffies_to_tv(&tv, rta_getattr_u32(rta));
|
||||
print_tv(PRINT_ANY, "idle_timer", "idle_timer %g ", &tv);
|
||||
res_grp->idle_timer = rta_getattr_u32(rta);
|
||||
}
|
||||
|
||||
if (tb[NHA_RES_GROUP_UNBALANCED_TIMER]) {
|
||||
rta = tb[NHA_RES_GROUP_UNBALANCED_TIMER];
|
||||
__jiffies_to_tv(&tv, rta_getattr_u32(rta));
|
||||
print_tv(PRINT_ANY, "unbalanced_timer", "unbalanced_timer %g ",
|
||||
&tv);
|
||||
res_grp->unbalanced_timer = rta_getattr_u32(rta);
|
||||
}
|
||||
|
||||
if (tb[NHA_RES_GROUP_UNBALANCED_TIME]) {
|
||||
rta = tb[NHA_RES_GROUP_UNBALANCED_TIME];
|
||||
__jiffies_to_tv(&tv, rta_getattr_u32(rta));
|
||||
print_tv(PRINT_ANY, "unbalanced_time", "unbalanced_time %g ",
|
||||
&tv);
|
||||
res_grp->unbalanced_time = rta_getattr_u64(rta);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_nh_res_group(const struct nha_res_grp *res_grp)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
open_json_object("resilient_args");
|
||||
|
||||
print_uint(PRINT_ANY, "buckets", "buckets %u ", res_grp->buckets);
|
||||
|
||||
__jiffies_to_tv(&tv, res_grp->idle_timer);
|
||||
print_tv(PRINT_ANY, "idle_timer", "idle_timer %g ", &tv);
|
||||
|
||||
__jiffies_to_tv(&tv, res_grp->unbalanced_timer);
|
||||
print_tv(PRINT_ANY, "unbalanced_timer", "unbalanced_timer %g ", &tv);
|
||||
|
||||
__jiffies_to_tv(&tv, res_grp->unbalanced_time);
|
||||
print_tv(PRINT_ANY, "unbalanced_time", "unbalanced_time %g ", &tv);
|
||||
|
||||
close_json_object();
|
||||
}
|
||||
|
|
@ -328,14 +343,325 @@ static void print_nh_res_bucket(FILE *fp, const struct rtattr *res_bucket_attr)
|
|||
close_json_object();
|
||||
}
|
||||
|
||||
int print_nexthop(struct nlmsghdr *n, void *arg)
|
||||
static void ipnh_destroy_entry(struct nh_entry *nhe)
|
||||
{
|
||||
if (nhe->nh_encap)
|
||||
free(nhe->nh_encap);
|
||||
if (nhe->nh_groups)
|
||||
free(nhe->nh_groups);
|
||||
}
|
||||
|
||||
/* parse nhmsg into nexthop entry struct which must be destroyed by
|
||||
* ipnh_destroy_enty when it's not needed anymore
|
||||
*/
|
||||
static int ipnh_parse_nhmsg(FILE *fp, const struct nhmsg *nhm, int len,
|
||||
struct nh_entry *nhe)
|
||||
{
|
||||
struct rtattr *tb[NHA_MAX+1];
|
||||
int err = 0;
|
||||
|
||||
memset(nhe, 0, sizeof(*nhe));
|
||||
parse_rtattr_flags(tb, NHA_MAX, RTM_NHA(nhm), len, NLA_F_NESTED);
|
||||
|
||||
if (tb[NHA_ID])
|
||||
nhe->nh_id = rta_getattr_u32(tb[NHA_ID]);
|
||||
|
||||
if (tb[NHA_OIF])
|
||||
nhe->nh_oif = rta_getattr_u32(tb[NHA_OIF]);
|
||||
|
||||
if (tb[NHA_GROUP_TYPE])
|
||||
nhe->nh_grp_type = rta_getattr_u16(tb[NHA_GROUP_TYPE]);
|
||||
|
||||
if (tb[NHA_GATEWAY]) {
|
||||
if (RTA_PAYLOAD(tb[NHA_GATEWAY]) > sizeof(nhe->nh_gateway)) {
|
||||
fprintf(fp, "<nexthop id %u invalid gateway length %lu>\n",
|
||||
nhe->nh_id, RTA_PAYLOAD(tb[NHA_GATEWAY]));
|
||||
err = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
nhe->nh_gateway_len = RTA_PAYLOAD(tb[NHA_GATEWAY]);
|
||||
memcpy(&nhe->nh_gateway, RTA_DATA(tb[NHA_GATEWAY]),
|
||||
RTA_PAYLOAD(tb[NHA_GATEWAY]));
|
||||
}
|
||||
|
||||
if (tb[NHA_ENCAP]) {
|
||||
nhe->nh_encap = malloc(RTA_LENGTH(RTA_PAYLOAD(tb[NHA_ENCAP])));
|
||||
if (!nhe->nh_encap) {
|
||||
err = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
memcpy(nhe->nh_encap, tb[NHA_ENCAP],
|
||||
RTA_LENGTH(RTA_PAYLOAD(tb[NHA_ENCAP])));
|
||||
memcpy(&nhe->nh_encap_type, tb[NHA_ENCAP_TYPE],
|
||||
sizeof(nhe->nh_encap_type));
|
||||
}
|
||||
|
||||
if (tb[NHA_GROUP]) {
|
||||
if (!__valid_nh_group_attr(tb[NHA_GROUP])) {
|
||||
fprintf(fp, "<nexthop id %u invalid nexthop group>",
|
||||
nhe->nh_id);
|
||||
err = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
nhe->nh_groups = malloc(RTA_PAYLOAD(tb[NHA_GROUP]));
|
||||
if (!nhe->nh_groups) {
|
||||
err = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
nhe->nh_groups_cnt = RTA_PAYLOAD(tb[NHA_GROUP]) /
|
||||
sizeof(struct nexthop_grp);
|
||||
memcpy(nhe->nh_groups, RTA_DATA(tb[NHA_GROUP]),
|
||||
RTA_PAYLOAD(tb[NHA_GROUP]));
|
||||
}
|
||||
|
||||
if (tb[NHA_RES_GROUP]) {
|
||||
parse_nh_res_group_rta(tb[NHA_RES_GROUP], &nhe->nh_res_grp);
|
||||
nhe->nh_has_res_grp = true;
|
||||
}
|
||||
|
||||
nhe->nh_blackhole = !!tb[NHA_BLACKHOLE];
|
||||
nhe->nh_fdb = !!tb[NHA_FDB];
|
||||
|
||||
nhe->nh_family = nhm->nh_family;
|
||||
nhe->nh_protocol = nhm->nh_protocol;
|
||||
nhe->nh_scope = nhm->nh_scope;
|
||||
nhe->nh_flags = nhm->nh_flags;
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
ipnh_destroy_entry(nhe);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __print_nexthop_entry(FILE *fp, const char *jsobj,
|
||||
struct nh_entry *nhe,
|
||||
bool deleted)
|
||||
{
|
||||
SPRINT_BUF(b1);
|
||||
|
||||
open_json_object(jsobj);
|
||||
|
||||
if (deleted)
|
||||
print_bool(PRINT_ANY, "deleted", "Deleted ", true);
|
||||
|
||||
print_uint(PRINT_ANY, "id", "id %u ", nhe->nh_id);
|
||||
|
||||
if (nhe->nh_groups)
|
||||
print_nh_group(nhe);
|
||||
|
||||
print_nh_group_type(nhe->nh_grp_type);
|
||||
|
||||
if (nhe->nh_has_res_grp)
|
||||
print_nh_res_group(&nhe->nh_res_grp);
|
||||
|
||||
if (nhe->nh_encap)
|
||||
lwt_print_encap(fp, &nhe->nh_encap_type.rta, nhe->nh_encap);
|
||||
|
||||
if (nhe->nh_gateway_len)
|
||||
__print_rta_gateway(fp, nhe->nh_family,
|
||||
format_host(nhe->nh_family,
|
||||
nhe->nh_gateway_len,
|
||||
&nhe->nh_gateway));
|
||||
|
||||
if (nhe->nh_oif)
|
||||
print_rta_ifidx(fp, nhe->nh_oif, "dev");
|
||||
|
||||
if (nhe->nh_scope != RT_SCOPE_UNIVERSE || show_details > 0) {
|
||||
print_string(PRINT_ANY, "scope", "scope %s ",
|
||||
rtnl_rtscope_n2a(nhe->nh_scope, b1, sizeof(b1)));
|
||||
}
|
||||
|
||||
if (nhe->nh_blackhole)
|
||||
print_null(PRINT_ANY, "blackhole", "blackhole ", NULL);
|
||||
|
||||
if (nhe->nh_protocol != RTPROT_UNSPEC || show_details > 0) {
|
||||
print_string(PRINT_ANY, "protocol", "proto %s ",
|
||||
rtnl_rtprot_n2a(nhe->nh_protocol, b1, sizeof(b1)));
|
||||
}
|
||||
|
||||
print_rt_flags(fp, nhe->nh_flags);
|
||||
|
||||
if (nhe->nh_fdb)
|
||||
print_null(PRINT_ANY, "fdb", "fdb", NULL);
|
||||
|
||||
close_json_object();
|
||||
}
|
||||
|
||||
static int __ipnh_get_id(struct rtnl_handle *rthp, __u32 nh_id,
|
||||
struct nlmsghdr **answer)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct nhmsg nhm;
|
||||
char buf[1024];
|
||||
} req = {
|
||||
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)),
|
||||
.n.nlmsg_flags = NLM_F_REQUEST,
|
||||
.n.nlmsg_type = RTM_GETNEXTHOP,
|
||||
.nhm.nh_family = preferred_family,
|
||||
};
|
||||
|
||||
addattr32(&req.n, sizeof(req), NHA_ID, nh_id);
|
||||
|
||||
return rtnl_talk(rthp, &req.n, answer);
|
||||
}
|
||||
|
||||
static struct hlist_head *ipnh_cache_head(__u32 nh_id)
|
||||
{
|
||||
nh_id ^= nh_id >> 20;
|
||||
nh_id ^= nh_id >> 10;
|
||||
|
||||
return &nh_cache[nh_id % NH_CACHE_SIZE];
|
||||
}
|
||||
|
||||
static void ipnh_cache_link_entry(struct nh_entry *nhe)
|
||||
{
|
||||
struct hlist_head *head = ipnh_cache_head(nhe->nh_id);
|
||||
|
||||
hlist_add_head(&nhe->nh_hash, head);
|
||||
}
|
||||
|
||||
static void ipnh_cache_unlink_entry(struct nh_entry *nhe)
|
||||
{
|
||||
hlist_del(&nhe->nh_hash);
|
||||
}
|
||||
|
||||
static struct nh_entry *ipnh_cache_get(__u32 nh_id)
|
||||
{
|
||||
struct hlist_head *head = ipnh_cache_head(nh_id);
|
||||
struct nh_entry *nhe;
|
||||
struct hlist_node *n;
|
||||
|
||||
hlist_for_each(n, head) {
|
||||
nhe = container_of(n, struct nh_entry, nh_hash);
|
||||
if (nhe->nh_id == nh_id)
|
||||
return nhe;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int __ipnh_cache_parse_nlmsg(const struct nlmsghdr *n,
|
||||
struct nh_entry *nhe)
|
||||
{
|
||||
int err, len;
|
||||
|
||||
len = n->nlmsg_len - NLMSG_SPACE(sizeof(struct nhmsg));
|
||||
if (len < 0) {
|
||||
fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = ipnh_parse_nhmsg(stderr, NLMSG_DATA(n), len, nhe);
|
||||
if (err) {
|
||||
fprintf(stderr, "Error parsing nexthop: %s\n", strerror(-err));
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nh_entry *ipnh_cache_add(__u32 nh_id)
|
||||
{
|
||||
struct nlmsghdr *answer = NULL;
|
||||
struct nh_entry *nhe = NULL;
|
||||
|
||||
if (nh_cache_rth.fd < 0 && rtnl_open(&nh_cache_rth, 0) < 0) {
|
||||
nh_cache_rth.fd = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (__ipnh_get_id(&nh_cache_rth, nh_id, &answer) < 0)
|
||||
goto out;
|
||||
|
||||
nhe = malloc(sizeof(*nhe));
|
||||
if (!nhe)
|
||||
goto out;
|
||||
|
||||
if (__ipnh_cache_parse_nlmsg(answer, nhe))
|
||||
goto out_free_nhe;
|
||||
|
||||
ipnh_cache_link_entry(nhe);
|
||||
|
||||
out:
|
||||
if (answer)
|
||||
free(answer);
|
||||
|
||||
return nhe;
|
||||
|
||||
out_free_nhe:
|
||||
free(nhe);
|
||||
nhe = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
static void ipnh_cache_del(struct nh_entry *nhe)
|
||||
{
|
||||
ipnh_cache_unlink_entry(nhe);
|
||||
ipnh_destroy_entry(nhe);
|
||||
free(nhe);
|
||||
}
|
||||
|
||||
/* update, add or delete a nexthop entry based on nlmsghdr */
|
||||
static int ipnh_cache_process_nlmsg(const struct nlmsghdr *n,
|
||||
struct nh_entry *new_nhe)
|
||||
{
|
||||
struct nh_entry *nhe;
|
||||
|
||||
nhe = ipnh_cache_get(new_nhe->nh_id);
|
||||
switch (n->nlmsg_type) {
|
||||
case RTM_DELNEXTHOP:
|
||||
if (nhe)
|
||||
ipnh_cache_del(nhe);
|
||||
ipnh_destroy_entry(new_nhe);
|
||||
break;
|
||||
case RTM_NEWNEXTHOP:
|
||||
if (!nhe) {
|
||||
nhe = malloc(sizeof(*nhe));
|
||||
if (!nhe) {
|
||||
ipnh_destroy_entry(new_nhe);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* this allows us to save 1 allocation on updates by
|
||||
* reusing the old nh entry, but we need to cleanup its
|
||||
* internal storage
|
||||
*/
|
||||
ipnh_cache_unlink_entry(nhe);
|
||||
ipnh_destroy_entry(nhe);
|
||||
}
|
||||
memcpy(nhe, new_nhe, sizeof(*nhe));
|
||||
ipnh_cache_link_entry(nhe);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_cache_nexthop_id(FILE *fp, const char *fp_prefix, const char *jsobj,
|
||||
__u32 nh_id)
|
||||
{
|
||||
struct nh_entry *nhe = ipnh_cache_get(nh_id);
|
||||
|
||||
if (!nhe) {
|
||||
nhe = ipnh_cache_add(nh_id);
|
||||
if (!nhe)
|
||||
return;
|
||||
}
|
||||
|
||||
if (fp_prefix)
|
||||
print_string(PRINT_FP, NULL, "%s", fp_prefix);
|
||||
__print_nexthop_entry(fp, jsobj, nhe, false);
|
||||
}
|
||||
|
||||
int print_cache_nexthop(struct nlmsghdr *n, void *arg, bool process_cache)
|
||||
{
|
||||
struct nhmsg *nhm = NLMSG_DATA(n);
|
||||
struct rtattr *tb[NHA_MAX+1];
|
||||
FILE *fp = (FILE *)arg;
|
||||
int len;
|
||||
|
||||
SPRINT_BUF(b1);
|
||||
struct nh_entry nhe;
|
||||
int len, err;
|
||||
|
||||
if (n->nlmsg_type != RTM_DELNEXTHOP &&
|
||||
n->nlmsg_type != RTM_NEWNEXTHOP) {
|
||||
|
|
@ -354,60 +680,29 @@ int print_nexthop(struct nlmsghdr *n, void *arg)
|
|||
if (filter.proto && filter.proto != nhm->nh_protocol)
|
||||
return 0;
|
||||
|
||||
parse_rtattr_flags(tb, NHA_MAX, RTM_NHA(nhm), len, NLA_F_NESTED);
|
||||
|
||||
open_json_object(NULL);
|
||||
|
||||
if (n->nlmsg_type == RTM_DELNEXTHOP)
|
||||
print_bool(PRINT_ANY, "deleted", "Deleted ", true);
|
||||
|
||||
if (tb[NHA_ID])
|
||||
print_uint(PRINT_ANY, "id", "id %u ",
|
||||
rta_getattr_u32(tb[NHA_ID]));
|
||||
|
||||
if (tb[NHA_GROUP])
|
||||
print_nh_group(fp, tb[NHA_GROUP]);
|
||||
|
||||
if (tb[NHA_GROUP_TYPE])
|
||||
print_nh_group_type(fp, tb[NHA_GROUP_TYPE]);
|
||||
|
||||
if (tb[NHA_RES_GROUP])
|
||||
print_nh_res_group(fp, tb[NHA_RES_GROUP]);
|
||||
|
||||
if (tb[NHA_ENCAP])
|
||||
lwt_print_encap(fp, tb[NHA_ENCAP_TYPE], tb[NHA_ENCAP]);
|
||||
|
||||
if (tb[NHA_GATEWAY])
|
||||
print_rta_gateway(fp, nhm->nh_family, tb[NHA_GATEWAY]);
|
||||
|
||||
if (tb[NHA_OIF])
|
||||
print_rta_if(fp, tb[NHA_OIF], "dev");
|
||||
|
||||
if (nhm->nh_scope != RT_SCOPE_UNIVERSE || show_details > 0) {
|
||||
print_string(PRINT_ANY, "scope", "scope %s ",
|
||||
rtnl_rtscope_n2a(nhm->nh_scope, b1, sizeof(b1)));
|
||||
err = ipnh_parse_nhmsg(fp, nhm, len, &nhe);
|
||||
if (err) {
|
||||
close_json_object();
|
||||
fprintf(stderr, "Error parsing nexthop: %s\n", strerror(-err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tb[NHA_BLACKHOLE])
|
||||
print_null(PRINT_ANY, "blackhole", "blackhole ", NULL);
|
||||
|
||||
if (nhm->nh_protocol != RTPROT_UNSPEC || show_details > 0) {
|
||||
print_string(PRINT_ANY, "protocol", "proto %s ",
|
||||
rtnl_rtprot_n2a(nhm->nh_protocol, b1, sizeof(b1)));
|
||||
}
|
||||
|
||||
print_rt_flags(fp, nhm->nh_flags);
|
||||
|
||||
if (tb[NHA_FDB])
|
||||
print_null(PRINT_ANY, "fdb", "fdb", NULL);
|
||||
|
||||
__print_nexthop_entry(fp, NULL, &nhe, n->nlmsg_type == RTM_DELNEXTHOP);
|
||||
print_string(PRINT_FP, NULL, "%s", "\n");
|
||||
close_json_object();
|
||||
fflush(fp);
|
||||
|
||||
if (process_cache)
|
||||
ipnh_cache_process_nlmsg(n, &nhe);
|
||||
else
|
||||
ipnh_destroy_entry(&nhe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_nexthop_nocache(struct nlmsghdr *n, void *arg)
|
||||
{
|
||||
return print_cache_nexthop(n, arg, false);
|
||||
}
|
||||
|
||||
int print_nexthop_bucket(struct nlmsghdr *n, void *arg)
|
||||
{
|
||||
struct nhmsg *nhm = NLMSG_DATA(n);
|
||||
|
|
@ -546,7 +841,7 @@ static void parse_nh_group_type_res(struct nlmsghdr *n, int maxlen, int *argcp,
|
|||
|
||||
NEXT_ARG();
|
||||
if (get_unsigned(&idle_timer, *argv, 0) ||
|
||||
idle_timer >= ~0UL / 100)
|
||||
idle_timer >= UINT32_MAX / 100)
|
||||
invarg("invalid idle timer value", *argv);
|
||||
|
||||
addattr32(n, maxlen, NHA_RES_GROUP_IDLE_TIMER,
|
||||
|
|
@ -556,7 +851,7 @@ static void parse_nh_group_type_res(struct nlmsghdr *n, int maxlen, int *argcp,
|
|||
|
||||
NEXT_ARG();
|
||||
if (get_unsigned(&unbalanced_timer, *argv, 0) ||
|
||||
unbalanced_timer >= ~0UL / 100)
|
||||
unbalanced_timer >= UINT32_MAX / 100)
|
||||
invarg("invalid unbalanced timer value", *argv);
|
||||
|
||||
addattr32(n, maxlen, NHA_RES_GROUP_UNBALANCED_TIMER,
|
||||
|
|
@ -712,26 +1007,14 @@ static int ipnh_modify(int cmd, unsigned int flags, int argc, char **argv)
|
|||
|
||||
static int ipnh_get_id(__u32 id)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct nhmsg nhm;
|
||||
char buf[1024];
|
||||
} req = {
|
||||
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)),
|
||||
.n.nlmsg_flags = NLM_F_REQUEST,
|
||||
.n.nlmsg_type = RTM_GETNEXTHOP,
|
||||
.nhm.nh_family = preferred_family,
|
||||
};
|
||||
struct nlmsghdr *answer;
|
||||
|
||||
addattr32(&req.n, sizeof(req), NHA_ID, id);
|
||||
|
||||
if (rtnl_talk(&rth, &req.n, &answer) < 0)
|
||||
if (__ipnh_get_id(&rth, id, &answer) < 0)
|
||||
return -2;
|
||||
|
||||
new_json_obj(json);
|
||||
|
||||
if (print_nexthop(answer, (void *)stdout) < 0) {
|
||||
if (print_nexthop_nocache(answer, (void *)stdout) < 0) {
|
||||
free(answer);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -816,7 +1099,7 @@ static int ipnh_list_flush(int argc, char **argv, int action)
|
|||
|
||||
new_json_obj(json);
|
||||
|
||||
if (rtnl_dump_filter(&rth, print_nexthop, stdout) < 0) {
|
||||
if (rtnl_dump_filter(&rth, print_nexthop_nocache, stdout) < 0) {
|
||||
fprintf(stderr, "Dump terminated\n");
|
||||
return -2;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,15 +47,15 @@ static void usage(void)
|
|||
{
|
||||
fprintf(stderr,
|
||||
"Usage: ip ntable change name NAME [ dev DEV ]\n"
|
||||
" [ thresh1 VAL ] [ thresh2 VAL ] [ thresh3 VAL ] [ gc_int MSEC ]\n"
|
||||
" [ PARMS ]\n"
|
||||
" [ thresh1 VAL ] [ thresh2 VAL ] [ thresh3 VAL ] [ gc_int MSEC ]\n"
|
||||
" [ PARMS ]\n"
|
||||
"Usage: ip ntable show [ dev DEV ] [ name NAME ]\n"
|
||||
|
||||
"PARMS := [ base_reachable MSEC ] [ retrans MSEC ] [ gc_stale MSEC ]\n"
|
||||
" [ delay_probe MSEC ] [ queue LEN ]\n"
|
||||
" [ app_probes VAL ] [ ucast_probes VAL ] [ mcast_probes VAL ]\n"
|
||||
" [ anycast_delay MSEC ] [ proxy_delay MSEC ] [ proxy_queue LEN ]\n"
|
||||
" [ locktime MSEC ]\n"
|
||||
" [ delay_probe MSEC ] [ queue LEN ]\n"
|
||||
" [ app_probes VAL ] [ ucast_probes VAL ] [ mcast_probes VAL ]\n"
|
||||
" [ anycast_delay MSEC ] [ proxy_delay MSEC ] [ proxy_queue LEN ]\n"
|
||||
" [ locktime MSEC ]\n"
|
||||
);
|
||||
|
||||
exit(-1);
|
||||
|
|
|
|||
61
ip/iproute.c
61
ip/iproute.c
|
|
@ -28,6 +28,7 @@
|
|||
#include "rt_names.h"
|
||||
#include "utils.h"
|
||||
#include "ip_common.h"
|
||||
#include "nh_common.h"
|
||||
|
||||
#ifndef RTAX_RTTVAR
|
||||
#define RTAX_RTTVAR RTAX_HOPS
|
||||
|
|
@ -82,7 +83,7 @@ static void usage(void)
|
|||
" [ ttl-propagate { enabled | disabled } ]\n"
|
||||
"INFO_SPEC := { NH | nhid ID } OPTIONS FLAGS [ nexthop NH ]...\n"
|
||||
"NH := [ encap ENCAPTYPE ENCAPHDR ] [ via [ FAMILY ] ADDRESS ]\n"
|
||||
" [ dev STRING ] [ weight NUMBER ] NHFLAGS\n"
|
||||
" [ dev STRING ] [ weight NUMBER ] NHFLAGS\n"
|
||||
"FAMILY := [ inet | inet6 | mpls | bridge | link ]\n"
|
||||
"OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ] [ as [ to ] ADDRESS ]\n"
|
||||
" [ rtt TIME ] [ rttvar TIME ] [ reordering NUMBER ]\n"
|
||||
|
|
@ -101,10 +102,18 @@ static void usage(void)
|
|||
"TIME := NUMBER[s|ms]\n"
|
||||
"BOOL := [1|0]\n"
|
||||
"FEATURES := ecn\n"
|
||||
"ENCAPTYPE := [ mpls | ip | ip6 | seg6 | seg6local | rpl ]\n"
|
||||
"ENCAPHDR := [ MPLSLABEL | SEG6HDR ]\n"
|
||||
"ENCAPTYPE := [ mpls | ip | ip6 | seg6 | seg6local | rpl | ioam6 ]\n"
|
||||
"ENCAPHDR := [ MPLSLABEL | SEG6HDR | SEG6LOCAL | IOAM6HDR ]\n"
|
||||
"SEG6HDR := [ mode SEGMODE ] segs ADDR1,ADDRi,ADDRn [hmac HMACKEYID] [cleanup]\n"
|
||||
"SEGMODE := [ encap | inline ]\n"
|
||||
"SEG6LOCAL := action ACTION [ OPTIONS ] [ count ]\n"
|
||||
"ACTION := { End | End.X | End.T | End.DX2 | End.DX6 | End.DX4 |\n"
|
||||
" End.DT6 | End.DT4 | End.DT46 | End.B6 | End.B6.Encaps |\n"
|
||||
" End.BM | End.S | End.AS | End.AM | End.BPF }\n"
|
||||
"OPTIONS := OPTION [ OPTIONS ]\n"
|
||||
"OPTION := { srh SEG6HDR | nh4 ADDR | nh6 ADDR | iif DEV | oif DEV |\n"
|
||||
" table TABLEID | vrftable TABLEID | endpoint PROGNAME }\n"
|
||||
"IOAM6HDR := trace prealloc type IOAM6_TRACE_TYPE ns IOAM6_NAMESPACE size IOAM6_TRACE_SIZE\n"
|
||||
"ROUTE_GET_FLAGS := [ fibmatch ]\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
|
@ -402,13 +411,13 @@ static void print_rt_pref(FILE *fp, unsigned int pref)
|
|||
}
|
||||
}
|
||||
|
||||
void print_rta_if(FILE *fp, const struct rtattr *rta, const char *prefix)
|
||||
void print_rta_ifidx(FILE *fp, __u32 ifidx, const char *prefix)
|
||||
{
|
||||
const char *ifname = ll_index_to_name(rta_getattr_u32(rta));
|
||||
const char *ifname = ll_index_to_name(ifidx);
|
||||
|
||||
if (is_json_context())
|
||||
if (is_json_context()) {
|
||||
print_string(PRINT_JSON, prefix, NULL, ifname);
|
||||
else {
|
||||
} else {
|
||||
fprintf(fp, "%s ", prefix);
|
||||
color_fprintf(fp, COLOR_IFNAME, "%s ", ifname);
|
||||
}
|
||||
|
|
@ -539,13 +548,11 @@ static void print_rta_newdst(FILE *fp, const struct rtmsg *r,
|
|||
}
|
||||
}
|
||||
|
||||
void print_rta_gateway(FILE *fp, unsigned char family, const struct rtattr *rta)
|
||||
void __print_rta_gateway(FILE *fp, unsigned char family, const char *gateway)
|
||||
{
|
||||
const char *gateway = format_host_rta(family, rta);
|
||||
|
||||
if (is_json_context())
|
||||
if (is_json_context()) {
|
||||
print_string(PRINT_JSON, "gateway", NULL, gateway);
|
||||
else {
|
||||
} else {
|
||||
fprintf(fp, "via ");
|
||||
print_color_string(PRINT_FP,
|
||||
ifa_family_color(family),
|
||||
|
|
@ -553,6 +560,13 @@ void print_rta_gateway(FILE *fp, unsigned char family, const struct rtattr *rta)
|
|||
}
|
||||
}
|
||||
|
||||
void print_rta_gateway(FILE *fp, unsigned char family, const struct rtattr *rta)
|
||||
{
|
||||
const char *gateway = format_host_rta(family, rta);
|
||||
|
||||
__print_rta_gateway(fp, family, gateway);
|
||||
}
|
||||
|
||||
static void print_rta_via(FILE *fp, const struct rtattr *rta)
|
||||
{
|
||||
size_t len = RTA_PAYLOAD(rta) - 2;
|
||||
|
|
@ -854,7 +868,7 @@ int print_route(struct nlmsghdr *n, void *arg)
|
|||
print_rta_via(fp, tb[RTA_VIA]);
|
||||
|
||||
if (tb[RTA_OIF] && filter.oifmask != -1)
|
||||
print_rta_if(fp, tb[RTA_OIF], "dev");
|
||||
print_rta_ifidx(fp, rta_getattr_u32(tb[RTA_OIF]), "dev");
|
||||
|
||||
if (table && (table != RT_TABLE_MAIN || show_details > 0) && !filter.tb)
|
||||
print_string(PRINT_ANY,
|
||||
|
|
@ -938,7 +952,7 @@ int print_route(struct nlmsghdr *n, void *arg)
|
|||
print_rta_metrics(fp, tb[RTA_METRICS]);
|
||||
|
||||
if (tb[RTA_IIF] && filter.iifmask != -1)
|
||||
print_rta_if(fp, tb[RTA_IIF], "iif");
|
||||
print_rta_ifidx(fp, rta_getattr_u32(tb[RTA_IIF]), "iif");
|
||||
|
||||
if (tb[RTA_PREF])
|
||||
print_rt_pref(fp, rta_getattr_u8(tb[RTA_PREF]));
|
||||
|
|
@ -955,6 +969,10 @@ int print_route(struct nlmsghdr *n, void *arg)
|
|||
propagate ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
if (tb[RTA_NH_ID] && show_details)
|
||||
print_cache_nexthop_id(fp, "\n\tnh_info ", "nh_info",
|
||||
rta_getattr_u32(tb[RTA_NH_ID]));
|
||||
|
||||
if (tb[RTA_MULTIPATH])
|
||||
print_rta_multipath(fp, r, tb[RTA_MULTIPATH]);
|
||||
|
||||
|
|
@ -1727,6 +1745,18 @@ static int iproute_flush(int family, rtnl_filter_t filter_fn)
|
|||
}
|
||||
}
|
||||
|
||||
static int save_route_errhndlr(struct nlmsghdr *n, void *arg)
|
||||
{
|
||||
int err = -*(int *)NLMSG_DATA(n);
|
||||
|
||||
if (n->nlmsg_type == NLMSG_DONE &&
|
||||
filter.tb == RT_TABLE_MAIN &&
|
||||
err == ENOENT)
|
||||
return RTNL_SUPPRESS_NLMSG_DONE_NLERR;
|
||||
|
||||
return RTNL_LET_NLERR;
|
||||
}
|
||||
|
||||
static int iproute_list_flush_or_save(int argc, char **argv, int action)
|
||||
{
|
||||
int dump_family = preferred_family;
|
||||
|
|
@ -1939,7 +1969,8 @@ static int iproute_list_flush_or_save(int argc, char **argv, int action)
|
|||
|
||||
new_json_obj(json);
|
||||
|
||||
if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
|
||||
if (rtnl_dump_filter_errhndlr(&rth, filter_fn, stdout,
|
||||
save_route_errhndlr, NULL) < 0) {
|
||||
fprintf(stderr, "Dump terminated\n");
|
||||
return -2;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@
|
|||
#include <linux/seg6_hmac.h>
|
||||
#include <linux/seg6_local.h>
|
||||
#include <linux/if_tunnel.h>
|
||||
#include <linux/ioam6.h>
|
||||
#include <linux/ioam6_iptunnel.h>
|
||||
|
||||
static const char *format_encap_type(int type)
|
||||
{
|
||||
|
|
@ -54,6 +56,8 @@ static const char *format_encap_type(int type)
|
|||
return "seg6local";
|
||||
case LWTUNNEL_ENCAP_RPL:
|
||||
return "rpl";
|
||||
case LWTUNNEL_ENCAP_IOAM6:
|
||||
return "ioam6";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
|
|
@ -90,6 +94,8 @@ static int read_encap_type(const char *name)
|
|||
return LWTUNNEL_ENCAP_SEG6_LOCAL;
|
||||
else if (strcmp(name, "rpl") == 0)
|
||||
return LWTUNNEL_ENCAP_RPL;
|
||||
else if (strcmp(name, "ioam6") == 0)
|
||||
return LWTUNNEL_ENCAP_IOAM6;
|
||||
else if (strcmp(name, "help") == 0)
|
||||
encap_type_usage();
|
||||
|
||||
|
|
@ -204,6 +210,63 @@ static void print_encap_rpl(FILE *fp, struct rtattr *encap)
|
|||
print_rpl_srh(fp, srh);
|
||||
}
|
||||
|
||||
static const char *ioam6_mode_types[IOAM6_IPTUNNEL_MODE_MAX + 1] = {
|
||||
[IOAM6_IPTUNNEL_MODE_INLINE] = "inline",
|
||||
[IOAM6_IPTUNNEL_MODE_ENCAP] = "encap",
|
||||
[IOAM6_IPTUNNEL_MODE_AUTO] = "auto",
|
||||
};
|
||||
|
||||
static const char *format_ioam6mode_type(int mode)
|
||||
{
|
||||
if (mode < IOAM6_IPTUNNEL_MODE_MIN ||
|
||||
mode > IOAM6_IPTUNNEL_MODE_MAX ||
|
||||
!ioam6_mode_types[mode])
|
||||
return "<unknown>";
|
||||
|
||||
return ioam6_mode_types[mode];
|
||||
}
|
||||
|
||||
static __u8 read_ioam6mode_type(const char *mode)
|
||||
{
|
||||
__u8 i;
|
||||
|
||||
for (i = IOAM6_IPTUNNEL_MODE_MIN; i <= IOAM6_IPTUNNEL_MODE_MAX; i++) {
|
||||
if (ioam6_mode_types[i] && !strcmp(mode, ioam6_mode_types[i]))
|
||||
return i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_encap_ioam6(FILE *fp, struct rtattr *encap)
|
||||
{
|
||||
struct rtattr *tb[IOAM6_IPTUNNEL_MAX + 1];
|
||||
struct ioam6_trace_hdr *trace;
|
||||
__u8 mode;
|
||||
|
||||
parse_rtattr_nested(tb, IOAM6_IPTUNNEL_MAX, encap);
|
||||
if (!tb[IOAM6_IPTUNNEL_MODE] || !tb[IOAM6_IPTUNNEL_TRACE])
|
||||
return;
|
||||
|
||||
mode = rta_getattr_u8(tb[IOAM6_IPTUNNEL_MODE]);
|
||||
if (!tb[IOAM6_IPTUNNEL_DST] && mode != IOAM6_IPTUNNEL_MODE_INLINE)
|
||||
return;
|
||||
|
||||
print_string(PRINT_ANY, "mode", "mode %s ", format_ioam6mode_type(mode));
|
||||
|
||||
if (mode != IOAM6_IPTUNNEL_MODE_INLINE)
|
||||
print_string(PRINT_ANY, "tundst", "tundst %s ",
|
||||
rt_addr_n2a_rta(AF_INET6, tb[IOAM6_IPTUNNEL_DST]));
|
||||
|
||||
trace = RTA_DATA(tb[IOAM6_IPTUNNEL_TRACE]);
|
||||
|
||||
print_null(PRINT_ANY, "trace", "trace ", NULL);
|
||||
print_null(PRINT_ANY, "prealloc", "prealloc ", NULL);
|
||||
print_hex(PRINT_ANY, "type", "type %#08x ", ntohl(trace->type_be32) >> 8);
|
||||
print_uint(PRINT_ANY, "ns", "ns %u ", ntohs(trace->namespace_id));
|
||||
print_uint(PRINT_ANY, "size", "size %u ", trace->remlen * 4);
|
||||
}
|
||||
|
||||
static const char *seg6_action_names[SEG6_LOCAL_ACTION_MAX + 1] = {
|
||||
[SEG6_LOCAL_ACTION_END] = "End",
|
||||
[SEG6_LOCAL_ACTION_END_X] = "End.X",
|
||||
|
|
@ -220,6 +283,7 @@ static const char *seg6_action_names[SEG6_LOCAL_ACTION_MAX + 1] = {
|
|||
[SEG6_LOCAL_ACTION_END_AS] = "End.AS",
|
||||
[SEG6_LOCAL_ACTION_END_AM] = "End.AM",
|
||||
[SEG6_LOCAL_ACTION_END_BPF] = "End.BPF",
|
||||
[SEG6_LOCAL_ACTION_END_DT46] = "End.DT46",
|
||||
};
|
||||
|
||||
static const char *format_action_type(int action)
|
||||
|
|
@ -266,6 +330,42 @@ static void print_encap_bpf_prog(FILE *fp, struct rtattr *encap,
|
|||
}
|
||||
}
|
||||
|
||||
static void print_seg6_local_counters(FILE *fp, struct rtattr *encap)
|
||||
{
|
||||
struct rtattr *tb[SEG6_LOCAL_CNT_MAX + 1];
|
||||
__u64 packets = 0, bytes = 0, errors = 0;
|
||||
|
||||
parse_rtattr_nested(tb, SEG6_LOCAL_CNT_MAX, encap);
|
||||
|
||||
if (tb[SEG6_LOCAL_CNT_PACKETS])
|
||||
packets = rta_getattr_u64(tb[SEG6_LOCAL_CNT_PACKETS]);
|
||||
|
||||
if (tb[SEG6_LOCAL_CNT_BYTES])
|
||||
bytes = rta_getattr_u64(tb[SEG6_LOCAL_CNT_BYTES]);
|
||||
|
||||
if (tb[SEG6_LOCAL_CNT_ERRORS])
|
||||
errors = rta_getattr_u64(tb[SEG6_LOCAL_CNT_ERRORS]);
|
||||
|
||||
if (is_json_context()) {
|
||||
open_json_object("stats64");
|
||||
|
||||
print_u64(PRINT_JSON, "packets", NULL, packets);
|
||||
print_u64(PRINT_JSON, "bytes", NULL, bytes);
|
||||
print_u64(PRINT_JSON, "errors", NULL, errors);
|
||||
|
||||
close_json_object();
|
||||
} else {
|
||||
print_string(PRINT_FP, NULL, "%s ", "packets");
|
||||
print_num(fp, 1, packets);
|
||||
|
||||
print_string(PRINT_FP, NULL, "%s ", "bytes");
|
||||
print_num(fp, 1, bytes);
|
||||
|
||||
print_string(PRINT_FP, NULL, "%s ", "errors");
|
||||
print_num(fp, 1, errors);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_encap_seg6local(FILE *fp, struct rtattr *encap)
|
||||
{
|
||||
struct rtattr *tb[SEG6_LOCAL_MAX + 1];
|
||||
|
|
@ -325,6 +425,9 @@ static void print_encap_seg6local(FILE *fp, struct rtattr *encap)
|
|||
|
||||
if (tb[SEG6_LOCAL_BPF])
|
||||
print_encap_bpf_prog(fp, tb[SEG6_LOCAL_BPF], "endpoint");
|
||||
|
||||
if (tb[SEG6_LOCAL_COUNTERS] && show_stats)
|
||||
print_seg6_local_counters(fp, tb[SEG6_LOCAL_COUNTERS]);
|
||||
}
|
||||
|
||||
static void print_encap_mpls(FILE *fp, struct rtattr *encap)
|
||||
|
|
@ -617,6 +720,9 @@ void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
|
|||
case LWTUNNEL_ENCAP_RPL:
|
||||
print_encap_rpl(fp, encap);
|
||||
break;
|
||||
case LWTUNNEL_ENCAP_IOAM6:
|
||||
print_encap_ioam6(fp, encap);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -813,6 +919,122 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int parse_encap_ioam6(struct rtattr *rta, size_t len, int *argcp,
|
||||
char ***argvp)
|
||||
{
|
||||
int ns_found = 0, argc = *argcp;
|
||||
__u16 trace_ns, trace_size = 0;
|
||||
struct ioam6_trace_hdr *trace;
|
||||
char **argv = *argvp;
|
||||
__u32 trace_type = 0;
|
||||
inet_prefix addr;
|
||||
__u8 mode;
|
||||
|
||||
if (strcmp(*argv, "mode") != 0) {
|
||||
mode = IOAM6_IPTUNNEL_MODE_INLINE;
|
||||
} else {
|
||||
NEXT_ARG();
|
||||
|
||||
mode = read_ioam6mode_type(*argv);
|
||||
if (!mode)
|
||||
invarg("Invalid mode", *argv);
|
||||
|
||||
NEXT_ARG();
|
||||
}
|
||||
|
||||
if (strcmp(*argv, "tundst") != 0) {
|
||||
if (mode != IOAM6_IPTUNNEL_MODE_INLINE)
|
||||
missarg("tundst");
|
||||
} else {
|
||||
if (mode == IOAM6_IPTUNNEL_MODE_INLINE)
|
||||
invarg("Inline mode does not need tundst", *argv);
|
||||
|
||||
NEXT_ARG();
|
||||
|
||||
get_addr(&addr, *argv, AF_INET6);
|
||||
if (addr.family != AF_INET6 || addr.bytelen != 16)
|
||||
invarg("Invalid IPv6 address for tundst", *argv);
|
||||
|
||||
NEXT_ARG();
|
||||
}
|
||||
|
||||
if (strcmp(*argv, "trace") != 0)
|
||||
missarg("trace");
|
||||
|
||||
NEXT_ARG();
|
||||
|
||||
if (strcmp(*argv, "prealloc") != 0)
|
||||
missarg("prealloc");
|
||||
|
||||
while (NEXT_ARG_OK()) {
|
||||
NEXT_ARG_FWD();
|
||||
|
||||
if (strcmp(*argv, "type") == 0) {
|
||||
NEXT_ARG();
|
||||
|
||||
if (trace_type)
|
||||
duparg2("type", *argv);
|
||||
|
||||
if (get_u32(&trace_type, *argv, 0) || !trace_type)
|
||||
invarg("Invalid trace type", *argv);
|
||||
} else if (strcmp(*argv, "ns") == 0) {
|
||||
NEXT_ARG();
|
||||
|
||||
if (ns_found++)
|
||||
duparg2("ns", *argv);
|
||||
|
||||
if (get_u16(&trace_ns, *argv, 0))
|
||||
invarg("Invalid namespace ID", *argv);
|
||||
} else if (strcmp(*argv, "size") == 0) {
|
||||
NEXT_ARG();
|
||||
|
||||
if (trace_size)
|
||||
duparg2("size", *argv);
|
||||
|
||||
if (get_u16(&trace_size, *argv, 0) || !trace_size)
|
||||
invarg("Invalid trace size", *argv);
|
||||
|
||||
if (trace_size % 4)
|
||||
invarg("Trace size must be a 4-octet multiple",
|
||||
*argv);
|
||||
|
||||
if (trace_size > IOAM6_TRACE_DATA_SIZE_MAX)
|
||||
invarg("Trace size is too big", *argv);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!trace_type)
|
||||
missarg("type");
|
||||
if (!ns_found)
|
||||
missarg("ns");
|
||||
if (!trace_size)
|
||||
missarg("size");
|
||||
|
||||
trace = calloc(1, sizeof(*trace));
|
||||
if (!trace)
|
||||
return -1;
|
||||
|
||||
trace->type_be32 = htonl(trace_type << 8);
|
||||
trace->namespace_id = htons(trace_ns);
|
||||
trace->remlen = (__u8)(trace_size / 4);
|
||||
|
||||
if (rta_addattr8(rta, len, IOAM6_IPTUNNEL_MODE, mode) ||
|
||||
(mode != IOAM6_IPTUNNEL_MODE_INLINE &&
|
||||
rta_addattr_l(rta, len, IOAM6_IPTUNNEL_DST, &addr.data, addr.bytelen)) ||
|
||||
rta_addattr_l(rta, len, IOAM6_IPTUNNEL_TRACE, trace, sizeof(*trace))) {
|
||||
free(trace);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*argcp = argc + 1;
|
||||
*argvp = argv - 1;
|
||||
|
||||
free(trace);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct lwt_x {
|
||||
struct rtattr *rta;
|
||||
size_t len;
|
||||
|
|
@ -862,13 +1084,39 @@ static int lwt_parse_bpf(struct rtattr *rta, size_t len,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* for the moment, counters are always initialized to zero by the kernel; so we
|
||||
* do not expect to parse any argument here.
|
||||
*/
|
||||
static int seg6local_fill_counters(struct rtattr *rta, size_t len, int attr)
|
||||
{
|
||||
struct rtattr *nest;
|
||||
int ret;
|
||||
|
||||
nest = rta_nest(rta, len, attr);
|
||||
|
||||
ret = rta_addattr64(rta, len, SEG6_LOCAL_CNT_PACKETS, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = rta_addattr64(rta, len, SEG6_LOCAL_CNT_BYTES, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = rta_addattr64(rta, len, SEG6_LOCAL_CNT_ERRORS, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
rta_nest_end(rta, nest);
|
||||
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, vrftable_ok = 0;
|
||||
int action_ok = 0, srh_ok = 0, bpf_ok = 0, counters_ok = 0;
|
||||
int nh4_ok = 0, nh6_ok = 0, iif_ok = 0, oif_ok = 0;
|
||||
__u32 action = 0, table, vrftable, iif, oif;
|
||||
int action_ok = 0, srh_ok = 0, bpf_ok = 0;
|
||||
struct ipv6_sr_hdr *srh;
|
||||
char **argv = *argvp;
|
||||
int argc = *argcp;
|
||||
|
|
@ -932,6 +1180,11 @@ static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
|
|||
if (!oif)
|
||||
exit(nodev(*argv));
|
||||
ret = rta_addattr32(rta, len, SEG6_LOCAL_OIF, oif);
|
||||
} else if (strcmp(*argv, "count") == 0) {
|
||||
if (counters_ok++)
|
||||
duparg2("count", *argv);
|
||||
ret = seg6local_fill_counters(rta, len,
|
||||
SEG6_LOCAL_COUNTERS);
|
||||
} else if (strcmp(*argv, "srh") == 0) {
|
||||
NEXT_ARG();
|
||||
if (srh_ok++)
|
||||
|
|
@ -1673,6 +1926,9 @@ int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp,
|
|||
case LWTUNNEL_ENCAP_RPL:
|
||||
ret = parse_encap_rpl(rta, len, &argc, &argv);
|
||||
break;
|
||||
case LWTUNNEL_ENCAP_IOAM6:
|
||||
ret = parse_encap_ioam6(rta, len, &argc, &argv);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Error: unsupported encap type\n");
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -34,10 +34,10 @@ static void usage(void)
|
|||
{
|
||||
fprintf(stderr,
|
||||
"Usage: ip sr { COMMAND | help }\n"
|
||||
" ip sr hmac show\n"
|
||||
" ip sr hmac set KEYID ALGO\n"
|
||||
" ip sr tunsrc show\n"
|
||||
" ip sr tunsrc set ADDRESS\n"
|
||||
" ip sr hmac show\n"
|
||||
" ip sr hmac set KEYID ALGO\n"
|
||||
" ip sr tunsrc show\n"
|
||||
" ip sr tunsrc set ADDRESS\n"
|
||||
"where ALGO := { sha1 | sha256 }\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,18 +34,18 @@ static void usage(void)
|
|||
{
|
||||
fprintf(stderr,
|
||||
"Usage: ip tunnel { add | change | del | show | prl | 6rd } [ NAME ]\n"
|
||||
" [ mode { gre | ipip | isatap | sit | vti } ]\n"
|
||||
" [ remote ADDR ] [ local ADDR ]\n"
|
||||
" [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n"
|
||||
" [ prl-default ADDR ] [ prl-nodefault ADDR ] [ prl-delete ADDR ]\n"
|
||||
" [ 6rd-prefix ADDR ] [ 6rd-relay_prefix ADDR ] [ 6rd-reset ]\n"
|
||||
" [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n"
|
||||
" [ mode { gre | ipip | isatap | sit | vti } ]\n"
|
||||
" [ remote ADDR ] [ local ADDR ]\n"
|
||||
" [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n"
|
||||
" [ prl-default ADDR ] [ prl-nodefault ADDR ] [ prl-delete ADDR ]\n"
|
||||
" [ 6rd-prefix ADDR ] [ 6rd-relay_prefix ADDR ] [ 6rd-reset ]\n"
|
||||
" [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n"
|
||||
"\n"
|
||||
"Where: NAME := STRING\n"
|
||||
" ADDR := { IP_ADDRESS | any }\n"
|
||||
" TOS := { STRING | 00..ff | inherit | inherit/STRING | inherit/00..ff }\n"
|
||||
" TTL := { 1..255 | inherit }\n"
|
||||
" KEY := { DOTTED_QUAD | NUMBER }\n");
|
||||
"Where: NAME := STRING\n"
|
||||
" ADDR := { IP_ADDRESS | any }\n"
|
||||
" TOS := { STRING | 00..ff | inherit | inherit/STRING | inherit/00..ff }\n"
|
||||
" TTL := { 1..255 | inherit }\n"
|
||||
" KEY := { DOTTED_QUAD | NUMBER }\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,11 +42,11 @@ static void usage(void)
|
|||
{
|
||||
fprintf(stderr,
|
||||
"Usage: ip tuntap { add | del | show | list | lst | help } [ dev PHYS_DEV ]\n"
|
||||
" [ mode { tun | tap } ] [ user USER ] [ group GROUP ]\n"
|
||||
" [ one_queue ] [ pi ] [ vnet_hdr ] [ multi_queue ] [ name NAME ]\n"
|
||||
" [ mode { tun | tap } ] [ user USER ] [ group GROUP ]\n"
|
||||
" [ one_queue ] [ pi ] [ vnet_hdr ] [ multi_queue ] [ name NAME ]\n"
|
||||
"\n"
|
||||
"Where: USER := { STRING | NUMBER }\n"
|
||||
" GROUP := { STRING | NUMBER }\n");
|
||||
"Where: USER := { STRING | NUMBER }\n"
|
||||
" GROUP := { STRING | NUMBER }\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
|
@ -243,6 +243,9 @@ static void print_flags(long flags)
|
|||
if (flags & IFF_ONE_QUEUE)
|
||||
print_string(PRINT_ANY, NULL, " %s", "one_queue");
|
||||
|
||||
if (flags & IFF_MULTI_QUEUE)
|
||||
print_string(PRINT_ANY, NULL, " %s", "multi_queue");
|
||||
|
||||
if (flags & IFF_VNET_HDR)
|
||||
print_string(PRINT_ANY, NULL, " %s", "vnet_hdr");
|
||||
|
||||
|
|
@ -253,9 +256,10 @@ static void print_flags(long flags)
|
|||
print_string(PRINT_ANY, NULL, " %s", "filter");
|
||||
|
||||
flags &= ~(IFF_TUN | IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE |
|
||||
IFF_VNET_HDR | IFF_PERSIST | IFF_NOFILTER);
|
||||
IFF_MULTI_QUEUE | IFF_VNET_HDR | IFF_PERSIST |
|
||||
IFF_NOFILTER);
|
||||
if (flags)
|
||||
print_0xhex(PRINT_ANY, NULL, "%#llx", flags);
|
||||
print_0xhex(PRINT_ANY, NULL, " %#llx", flags);
|
||||
|
||||
close_json_array(PRINT_JSON, NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -442,7 +442,6 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
|||
|
||||
if (tb[IFLA_GRE_COLLECT_METADATA]) {
|
||||
print_bool(PRINT_ANY, "external", "external ", true);
|
||||
return;
|
||||
}
|
||||
|
||||
tnl_print_endpoint("remote", tb[IFLA_GRE_REMOTE], AF_INET);
|
||||
|
|
|
|||
|
|
@ -461,7 +461,6 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
|||
|
||||
if (tb[IFLA_GRE_COLLECT_METADATA]) {
|
||||
print_bool(PRINT_ANY, "external", "external ", true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tb[IFLA_GRE_FLAGS])
|
||||
|
|
|
|||
|
|
@ -344,7 +344,6 @@ static void ip6tunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb
|
|||
|
||||
if (tb[IFLA_IPTUN_COLLECT_METADATA]) {
|
||||
print_bool(PRINT_ANY, "external", "external ", true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tb[IFLA_IPTUN_FLAGS])
|
||||
|
|
|
|||
|
|
@ -368,7 +368,6 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[
|
|||
|
||||
if (tb[IFLA_IPTUN_COLLECT_METADATA]) {
|
||||
print_bool(PRINT_ANY, "external", "external ", true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tb[IFLA_IPTUN_PROTO]) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __NH_COMMON_H__
|
||||
#define __NH_COMMON_H__ 1
|
||||
|
||||
#include <list.h>
|
||||
|
||||
#define NH_CACHE_SIZE 1024
|
||||
|
||||
struct nha_res_grp {
|
||||
__u16 buckets;
|
||||
__u32 idle_timer;
|
||||
__u32 unbalanced_timer;
|
||||
__u64 unbalanced_time;
|
||||
};
|
||||
|
||||
struct nh_entry {
|
||||
struct hlist_node nh_hash;
|
||||
|
||||
__u32 nh_id;
|
||||
__u32 nh_oif;
|
||||
__u32 nh_flags;
|
||||
__u16 nh_grp_type;
|
||||
__u8 nh_family;
|
||||
__u8 nh_scope;
|
||||
__u8 nh_protocol;
|
||||
|
||||
bool nh_blackhole;
|
||||
bool nh_fdb;
|
||||
|
||||
int nh_gateway_len;
|
||||
union {
|
||||
__be32 ipv4;
|
||||
struct in6_addr ipv6;
|
||||
} nh_gateway;
|
||||
|
||||
struct rtattr *nh_encap;
|
||||
union {
|
||||
struct rtattr rta;
|
||||
__u8 _buf[RTA_LENGTH(sizeof(__u16))];
|
||||
} nh_encap_type;
|
||||
|
||||
bool nh_has_res_grp;
|
||||
struct nha_res_grp nh_res_grp;
|
||||
|
||||
int nh_groups_cnt;
|
||||
struct nexthop_grp *nh_groups;
|
||||
};
|
||||
|
||||
void print_cache_nexthop_id(FILE *fp, const char *fp_prefix, const char *jsobj,
|
||||
__u32 nh_id);
|
||||
int print_cache_nexthop(struct nlmsghdr *n, void *arg, bool process_cache);
|
||||
|
||||
#endif /* __NH_COMMON_H__ */
|
||||
10
ip/routef
10
ip/routef
|
|
@ -1,10 +0,0 @@
|
|||
#! /bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
if [ -z "$*" ] ; then
|
||||
exec ip -4 ro flush scope global type unicast
|
||||
else
|
||||
echo "Usage: routef"
|
||||
echo
|
||||
echo "This script will flush the IPv4 routing table"
|
||||
fi
|
||||
124
ip/routel
124
ip/routel
|
|
@ -1,72 +1,62 @@
|
|||
#!/bin/sh
|
||||
#! /usr/bin/env python3
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#
|
||||
# Script created by: Stephen R. van den Berg <srb@cuci.nl>, 1999/04/18
|
||||
# Donated to the public domain.
|
||||
#
|
||||
# This script transforms the output of "ip" into more readable text.
|
||||
# "ip" is the Linux-advanced-routing configuration tool part of the
|
||||
# iproute package.
|
||||
#
|
||||
# This is simple script to process JSON output from ip route
|
||||
# command and format it. Based on earlier shell script version.
|
||||
"""Script to parse ip route output into more readable text."""
|
||||
|
||||
test "X-h" = "X$1" && echo "Usage: $0 [tablenr [raw ip args...]]" && exit 64
|
||||
import sys
|
||||
import json
|
||||
import getopt
|
||||
import subprocess
|
||||
|
||||
test -z "$*" && set 0
|
||||
|
||||
ip route list table "$@" |
|
||||
while read network rest
|
||||
do set xx $rest
|
||||
shift
|
||||
proto=""
|
||||
via=""
|
||||
dev=""
|
||||
scope=""
|
||||
src=""
|
||||
table=""
|
||||
case $network in
|
||||
broadcast|local|unreachable) via=$network
|
||||
network=$1
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
while test $# != 0
|
||||
do
|
||||
case "$1" in
|
||||
proto|via|dev|scope|src|table)
|
||||
key=$1
|
||||
val=$2
|
||||
eval "$key='$val'"
|
||||
shift 2
|
||||
;;
|
||||
dead|onlink|pervasive|offload|notify|linkdown|unresolved)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
# avoid infinite loop on unknown keyword without value at line end
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
echo "$network $via $src $proto $scope $dev $table"
|
||||
done | awk -F ' ' '
|
||||
BEGIN {
|
||||
format="%15s%-3s %15s %15s %8s %8s%7s %s\n";
|
||||
printf(format,"target","","gateway","source","proto","scope","dev","tbl");
|
||||
}
|
||||
{ network=$1;
|
||||
mask="";
|
||||
if(match(network,"/"))
|
||||
{ mask=" "substr(network,RSTART+1);
|
||||
network=substr(network,0,RSTART);
|
||||
}
|
||||
via=$2;
|
||||
src=$3;
|
||||
proto=$4;
|
||||
scope=$5;
|
||||
dev=$6;
|
||||
table=$7;
|
||||
printf(format,network,mask,via,src,proto,scope,dev,table);
|
||||
}
|
||||
'
|
||||
def usage():
|
||||
'''Print usage and exit'''
|
||||
print("Usage: {} [tablenr [raw ip args...]]".format(sys.argv[0]))
|
||||
sys.exit(64)
|
||||
|
||||
|
||||
def main():
|
||||
'''Process the arguments'''
|
||||
family = 'inet'
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "h46f:", ["help", "family="])
|
||||
except getopt.GetoptError as err:
|
||||
print(err)
|
||||
usage()
|
||||
|
||||
for opt, arg in opts:
|
||||
if opt in ["-h", "--help"]:
|
||||
usage()
|
||||
elif opt == '-6':
|
||||
family = 'inet6'
|
||||
elif opt == "-4":
|
||||
family = 'inet'
|
||||
elif opt in ["-f", "--family"]:
|
||||
family = arg
|
||||
else:
|
||||
assert False, "unhandled option"
|
||||
|
||||
if not args:
|
||||
args = ['0']
|
||||
|
||||
cmd = ['ip', '-f', family, '-j', 'route', 'list', 'table'] + args
|
||||
process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||||
tbl = json.load(process.stdout)
|
||||
if family == 'inet':
|
||||
fmt = '{:15} {:15} {:15} {:8} {:8}{:<16} {}'
|
||||
else:
|
||||
fmt = '{:32} {:32} {:32} {:8} {:8}{:<16} {}'
|
||||
|
||||
# ip route json keys
|
||||
keys = ['dst', 'gateway', 'prefsrc', 'protocol', 'scope', 'dev', 'table']
|
||||
print(fmt.format(*map(lambda x: x.capitalize(), keys)))
|
||||
|
||||
for record in tbl:
|
||||
fields = [record[k] if k in record else '' for k in keys]
|
||||
print(fmt.format(*fields))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ static void usage(void)
|
|||
fprintf(stderr,
|
||||
"Usage: rtmon [ OPTIONS ] file FILE [ all | LISTofOBJECTS ]\n"
|
||||
"OPTIONS := { -f[amily] { inet | inet6 | link | help } |\n"
|
||||
" -4 | -6 | -0 | -V[ersion] }\n"
|
||||
" -4 | -6 | -0 | -V[ersion] }\n"
|
||||
"LISTofOBJECTS := [ link ] [ address ] [ route ]\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
|
|
|||
5
ip/rtpr
5
ip/rtpr
|
|
@ -1,5 +0,0 @@
|
|||
#! /bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
exec tr "[\\\\]" "[
|
||||
]"
|
||||
|
|
@ -132,6 +132,7 @@ void xfrm_state_info_print(struct xfrm_usersa_info *xsinfo,
|
|||
void xfrm_policy_info_print(struct xfrm_userpolicy_info *xpinfo,
|
||||
struct rtattr *tb[], FILE *fp, const char *prefix,
|
||||
const char *title);
|
||||
int xfrm_policy_default_print(struct nlmsghdr *n, FILE *fp);
|
||||
int xfrm_id_parse(xfrm_address_t *saddr, struct xfrm_id *id, __u16 *family,
|
||||
int loose, int *argcp, char ***argvp);
|
||||
int xfrm_mode_parse(__u8 *mode, int *argcp, char ***argvp);
|
||||
|
|
|
|||
|
|
@ -323,6 +323,9 @@ static int xfrm_accept_msg(struct rtnl_ctrl_data *ctrl,
|
|||
case XFRM_MSG_MAPPING:
|
||||
xfrm_mapping_print(n, arg);
|
||||
return 0;
|
||||
case XFRM_MSG_GETDEFAULT:
|
||||
xfrm_policy_default_print(n, arg);
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
133
ip/xfrm_policy.c
133
ip/xfrm_policy.c
|
|
@ -66,6 +66,8 @@ static void usage(void)
|
|||
"Usage: ip xfrm policy flush [ ptype PTYPE ]\n"
|
||||
"Usage: ip xfrm policy count\n"
|
||||
"Usage: ip xfrm policy set [ hthresh4 LBITS RBITS ] [ hthresh6 LBITS RBITS ]\n"
|
||||
"Usage: ip xfrm policy setdefault DIR ACTION [ DIR ACTION ] [ DIR ACTION ]\n"
|
||||
"Usage: ip xfrm policy getdefault\n"
|
||||
"SELECTOR := [ src ADDR[/PLEN] ] [ dst ADDR[/PLEN] ] [ dev DEV ] [ UPSPEC ]\n"
|
||||
"UPSPEC := proto { { tcp | udp | sctp | dccp } [ sport PORT ] [ dport PORT ] |\n"
|
||||
" { icmp | ipv6-icmp | mobility-header } [ type NUMBER ] [ code NUMBER ] |\n"
|
||||
|
|
@ -1124,6 +1126,133 @@ static int xfrm_spd_getinfo(int argc, char **argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int xfrm_str_to_policy(char *name, uint8_t *policy)
|
||||
{
|
||||
if (strcmp(name, "block") == 0) {
|
||||
*policy = XFRM_USERPOLICY_BLOCK;
|
||||
return 0;
|
||||
} else if (strcmp(name, "accept") == 0) {
|
||||
*policy = XFRM_USERPOLICY_ACCEPT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *xfrm_policy_to_str(uint8_t policy)
|
||||
{
|
||||
switch (policy) {
|
||||
case XFRM_USERPOLICY_UNSPEC:
|
||||
return "unspec";
|
||||
case XFRM_USERPOLICY_BLOCK:
|
||||
return "block";
|
||||
case XFRM_USERPOLICY_ACCEPT:
|
||||
return "accept";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static int xfrm_spd_setdefault(int argc, char **argv)
|
||||
{
|
||||
struct rtnl_handle rth;
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct xfrm_userpolicy_default up;
|
||||
} req = {
|
||||
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_default)),
|
||||
.n.nlmsg_flags = NLM_F_REQUEST,
|
||||
.n.nlmsg_type = XFRM_MSG_SETDEFAULT,
|
||||
};
|
||||
|
||||
while (argc > 0) {
|
||||
if (strcmp(*argv, "in") == 0) {
|
||||
if (req.up.in)
|
||||
duparg("in", *argv);
|
||||
|
||||
NEXT_ARG();
|
||||
if (xfrm_str_to_policy(*argv, &req.up.in) < 0)
|
||||
invarg("in policy value is invalid", *argv);
|
||||
} else if (strcmp(*argv, "fwd") == 0) {
|
||||
if (req.up.fwd)
|
||||
duparg("fwd", *argv);
|
||||
|
||||
NEXT_ARG();
|
||||
if (xfrm_str_to_policy(*argv, &req.up.fwd) < 0)
|
||||
invarg("fwd policy value is invalid", *argv);
|
||||
} else if (strcmp(*argv, "out") == 0) {
|
||||
if (req.up.out)
|
||||
duparg("out", *argv);
|
||||
|
||||
NEXT_ARG();
|
||||
if (xfrm_str_to_policy(*argv, &req.up.out) < 0)
|
||||
invarg("out policy value is invalid", *argv);
|
||||
} else {
|
||||
invarg("unknown direction", *argv);
|
||||
}
|
||||
|
||||
argc--; argv++;
|
||||
}
|
||||
|
||||
if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
|
||||
exit(1);
|
||||
|
||||
if (rtnl_talk(&rth, &req.n, NULL) < 0)
|
||||
exit(2);
|
||||
|
||||
rtnl_close(&rth);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xfrm_policy_default_print(struct nlmsghdr *n, FILE *fp)
|
||||
{
|
||||
struct xfrm_userpolicy_default *up = NLMSG_DATA(n);
|
||||
int len = n->nlmsg_len - NLMSG_SPACE(sizeof(*up));
|
||||
|
||||
if (len < 0) {
|
||||
fprintf(stderr,
|
||||
"BUG: short nlmsg len %u (expect %lu) for XFRM_MSG_GETDEFAULT\n",
|
||||
n->nlmsg_len, NLMSG_SPACE(sizeof(*up)));
|
||||
return -1;
|
||||
}
|
||||
|
||||
fprintf(fp, "Default policies:\n");
|
||||
fprintf(fp, " in: %s\n", xfrm_policy_to_str(up->in));
|
||||
fprintf(fp, " fwd: %s\n", xfrm_policy_to_str(up->fwd));
|
||||
fprintf(fp, " out: %s\n", xfrm_policy_to_str(up->out));
|
||||
fflush(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xfrm_spd_getdefault(int argc, char **argv)
|
||||
{
|
||||
struct rtnl_handle rth;
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct xfrm_userpolicy_default up;
|
||||
} req = {
|
||||
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_default)),
|
||||
.n.nlmsg_flags = NLM_F_REQUEST,
|
||||
.n.nlmsg_type = XFRM_MSG_GETDEFAULT,
|
||||
};
|
||||
struct nlmsghdr *answer;
|
||||
|
||||
if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0)
|
||||
exit(1);
|
||||
|
||||
if (rtnl_talk(&rth, &req.n, &answer) < 0)
|
||||
exit(2);
|
||||
|
||||
xfrm_policy_default_print(answer, (FILE *)stdout);
|
||||
|
||||
free(answer);
|
||||
rtnl_close(&rth);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xfrm_policy_flush(int argc, char **argv)
|
||||
{
|
||||
struct rtnl_handle rth;
|
||||
|
|
@ -1197,6 +1326,10 @@ int do_xfrm_policy(int argc, char **argv)
|
|||
return xfrm_spd_getinfo(argc, argv);
|
||||
if (matches(*argv, "set") == 0)
|
||||
return xfrm_spd_setinfo(argc-1, argv+1);
|
||||
if (matches(*argv, "setdefault") == 0)
|
||||
return xfrm_spd_setdefault(argc-1, argv+1);
|
||||
if (matches(*argv, "getdefault") == 0)
|
||||
return xfrm_spd_getdefault(argc-1, argv+1);
|
||||
if (matches(*argv, "help") == 0)
|
||||
usage();
|
||||
fprintf(stderr, "Command \"%s\" is unknown, try \"ip xfrm policy help\".\n", *argv);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netax25/ax25.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
const char *ax25_ntop1(const ax25_address *src, char *dst, socklen_t size);
|
||||
|
||||
/*
|
||||
* AX.25 addresses are based on Amateur radio callsigns followed by an SSID
|
||||
* like XXXXXX-SS where the callsign consists of up to 6 ASCII characters
|
||||
* which are either letters or digits and the SSID is a decimal number in the
|
||||
* range 0..15.
|
||||
* Amateur radio callsigns are assigned by a country's relevant authorities
|
||||
* and are 3..6 characters though a few countries have assigned callsigns
|
||||
* longer than that. AX.25 is not able to handle such longer callsigns.
|
||||
* There are further restrictions on the format of valid callsigns by
|
||||
* applicable national and international law. Linux doesn't need to care and
|
||||
* will happily accept anything that consists of 6 ASCII characters in the
|
||||
* range of A-Z and 0-9 for a callsign such as the default AX.25 MAC address
|
||||
* LINUX-1 and the default broadcast address QST-0.
|
||||
* The SSID is just a number and not encoded in ASCII digits.
|
||||
*
|
||||
* Being based on HDLC AX.25 encodes addresses by shifting them one bit left
|
||||
* thus zeroing bit 0, the HDLC extension bit for all but the last bit of
|
||||
* a packet's address field but for our purposes here we're not considering
|
||||
* the HDLC extension bit that is it will always be zero.
|
||||
*
|
||||
* Linux' internal representation of AX.25 addresses in Linux is very similar
|
||||
* to this on the on-air or on-the-wire format. The callsign is padded to
|
||||
* 6 octets by adding spaces, followed by the SSID octet then all 7 octets
|
||||
* are left-shifted by one bit.
|
||||
*
|
||||
* For example, for the address "LINUX-1" the callsign is LINUX and SSID is 1
|
||||
* the internal format is 98:92:9c:aa:b0:40:02.
|
||||
*/
|
||||
|
||||
const char *ax25_ntop1(const ax25_address *src, char *dst, socklen_t size)
|
||||
{
|
||||
char c, *s;
|
||||
int n;
|
||||
|
||||
for (n = 0, s = dst; n < 6; n++) {
|
||||
c = (src->ax25_call[n] >> 1) & 0x7f;
|
||||
if (c != ' ')
|
||||
*s++ = c;
|
||||
}
|
||||
|
||||
*s++ = '-';
|
||||
|
||||
n = ((src->ax25_call[6] >> 1) & 0x0f);
|
||||
if (n > 9) {
|
||||
*s++ = '1';
|
||||
n -= 10;
|
||||
}
|
||||
|
||||
*s++ = n + '0';
|
||||
*s++ = '\0';
|
||||
|
||||
if (*dst == '\0' || *dst == '-') {
|
||||
dst[0] = '*';
|
||||
dst[1] = '\0';
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
const char *ax25_ntop(int af, const void *addr, char *buf, socklen_t buflen)
|
||||
{
|
||||
switch (af) {
|
||||
case AF_AX25:
|
||||
errno = 0;
|
||||
return ax25_ntop1((ax25_address *)addr, buf, buflen);
|
||||
|
||||
default:
|
||||
errno = EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -63,7 +63,7 @@ const char *get_libbpf_version(void)
|
|||
if (fp == NULL)
|
||||
goto out;
|
||||
|
||||
while ((s = fgets(buf, sizeof(buf), fp)) != NULL) {
|
||||
while (fgets(buf, sizeof(buf), fp) != NULL) {
|
||||
if ((s = strstr(buf, "libbpf.so.")) != NULL) {
|
||||
strncpy(_libbpf_version, s+10, sizeof(_libbpf_version)-1);
|
||||
strtok(_libbpf_version, "\n");
|
||||
|
|
|
|||
|
|
@ -203,12 +203,30 @@ int bpf_dump_prog_info(FILE *f, uint32_t id)
|
|||
if (!ret && len) {
|
||||
int jited = !!info.jited_prog_len;
|
||||
|
||||
print_string(PRINT_ANY, "name", "name %s ", info.name);
|
||||
print_string(PRINT_ANY, "tag", "tag %s ",
|
||||
hexstring_n2a(info.tag, sizeof(info.tag),
|
||||
tmp, sizeof(tmp)));
|
||||
print_uint(PRINT_JSON, "jited", NULL, jited);
|
||||
if (jited && !is_json_context())
|
||||
fprintf(f, "jited ");
|
||||
|
||||
if (show_details) {
|
||||
if (info.load_time) {
|
||||
/* ns since boottime */
|
||||
print_lluint(PRINT_ANY, "load_time",
|
||||
"load_time %llu ", info.load_time);
|
||||
|
||||
print_luint(PRINT_ANY, "created_by_uid",
|
||||
"created_by_uid %lu ",
|
||||
info.created_by_uid);
|
||||
}
|
||||
|
||||
if (info.btf_id)
|
||||
print_luint(PRINT_ANY, "btf_id", "btf_id %lu ",
|
||||
info.btf_id);
|
||||
}
|
||||
|
||||
dump_ok = 1;
|
||||
}
|
||||
|
||||
|
|
@ -513,9 +531,12 @@ static int bpf_mnt_check_target(const char *target)
|
|||
int ret;
|
||||
|
||||
ret = mkdir(target, S_IRWXU);
|
||||
if (ret && errno != EEXIST)
|
||||
if (ret) {
|
||||
if (errno == EEXIST)
|
||||
return 0;
|
||||
fprintf(stderr, "mkdir %s failed: %s\n", target,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1531,7 +1552,7 @@ retry:
|
|||
* into our buffer. Still, try to give a debuggable error
|
||||
* log for the user, so enlarge it and re-fail.
|
||||
*/
|
||||
if (fd < 0 && (errno == ENOSPC || !ctx->log_size)) {
|
||||
if (fd < 0 && errno == ENOSPC) {
|
||||
if (tries++ < 10 && !bpf_log_realloc(ctx))
|
||||
goto retry;
|
||||
|
||||
|
|
@ -2069,7 +2090,7 @@ retry:
|
|||
fd = bpf_btf_load(ctx->btf_data->d_buf, ctx->btf_data->d_size,
|
||||
ctx->log, ctx->log_size);
|
||||
if (fd < 0 || ctx->verbose) {
|
||||
if (fd < 0 && (errno == ENOSPC || !ctx->log_size)) {
|
||||
if (fd < 0 && errno == ENOSPC) {
|
||||
if (tries++ < 10 && !bpf_log_realloc(ctx))
|
||||
goto retry;
|
||||
|
||||
|
|
@ -2992,7 +3013,7 @@ static int bpf_obj_open(const char *pathname, enum bpf_prog_type type,
|
|||
out:
|
||||
bpf_elf_ctx_destroy(ctx, ret < 0);
|
||||
if (ret < 0) {
|
||||
if (fd)
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -3284,8 +3305,7 @@ bool iproute2_is_map_in_map(const char *libbpf_map_name, struct bpf_elf_map *ima
|
|||
continue;
|
||||
|
||||
if (!ctx->maps[i].id ||
|
||||
ctx->maps[i].inner_id ||
|
||||
ctx->maps[i].inner_idx == -1)
|
||||
ctx->maps[i].inner_id)
|
||||
continue;
|
||||
|
||||
*imap = ctx->maps[i];
|
||||
|
|
@ -3298,6 +3318,9 @@ bool iproute2_is_map_in_map(const char *libbpf_map_name, struct bpf_elf_map *ima
|
|||
|
||||
*omap = ctx->maps[j];
|
||||
outer_map_name = bpf_map_fetch_name(ctx, j);
|
||||
if (!outer_map_name)
|
||||
return false;
|
||||
|
||||
memcpy(omap_name, outer_map_name, strlen(outer_map_name) + 1);
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -268,10 +268,12 @@ static int load_bpf_object(struct bpf_cfg_in *cfg)
|
|||
}
|
||||
|
||||
bpf_object__for_each_program(p, obj) {
|
||||
bool prog_to_attach = !prog && cfg->section &&
|
||||
!strcmp(get_bpf_program__section_name(p), cfg->section);
|
||||
|
||||
/* Only load the programs that will either be subsequently
|
||||
* attached or inserted into a tail call map */
|
||||
if (find_legacy_tail_calls(p, obj) < 0 && cfg->section &&
|
||||
strcmp(get_bpf_program__section_name(p), cfg->section)) {
|
||||
if (find_legacy_tail_calls(p, obj) < 0 && !prog_to_attach) {
|
||||
ret = bpf_program__set_autoload(p, false);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
|
@ -280,7 +282,8 @@ static int load_bpf_object(struct bpf_cfg_in *cfg)
|
|||
|
||||
bpf_program__set_type(p, cfg->type);
|
||||
bpf_program__set_ifindex(p, cfg->ifindex);
|
||||
if (!prog)
|
||||
|
||||
if (prog_to_attach)
|
||||
prog = p;
|
||||
}
|
||||
|
||||
|
|
|
|||
26
lib/fs.c
26
lib/fs.c
|
|
@ -25,11 +25,36 @@
|
|||
|
||||
#include "utils.h"
|
||||
|
||||
#ifndef HAVE_HANDLE_AT
|
||||
# include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
#define CGROUP2_FS_NAME "cgroup2"
|
||||
|
||||
/* if not already mounted cgroup2 is mounted here for iproute2's use */
|
||||
#define MNT_CGRP2_PATH "/var/run/cgroup2"
|
||||
|
||||
|
||||
#ifndef HAVE_HANDLE_AT
|
||||
struct file_handle {
|
||||
unsigned handle_bytes;
|
||||
int handle_type;
|
||||
unsigned char f_handle[];
|
||||
};
|
||||
|
||||
static int name_to_handle_at(int dirfd, const char *pathname,
|
||||
struct file_handle *handle, int *mount_id, int flags)
|
||||
{
|
||||
return syscall(__NR_name_to_handle_at, dirfd, pathname, handle,
|
||||
mount_id, flags);
|
||||
}
|
||||
|
||||
static int open_by_handle_at(int mount_fd, struct file_handle *handle, int flags)
|
||||
{
|
||||
return syscall(__NR_open_by_handle_at, mount_fd, handle, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* return mount path of first occurrence of given fstype */
|
||||
static char *find_fs_mount(const char *fs_to_find)
|
||||
{
|
||||
|
|
@ -339,4 +364,3 @@ char *get_task_name(pid_t pid)
|
|||
|
||||
return comm;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -718,7 +718,8 @@ int rtnl_dump_request_n(struct rtnl_handle *rth, struct nlmsghdr *n)
|
|||
return sendmsg(rth->fd, &msg, 0);
|
||||
}
|
||||
|
||||
static int rtnl_dump_done(struct nlmsghdr *h)
|
||||
static int rtnl_dump_done(struct nlmsghdr *h,
|
||||
const struct rtnl_dump_filter_arg *a)
|
||||
{
|
||||
int len = *(int *)NLMSG_DATA(h);
|
||||
|
||||
|
|
@ -728,11 +729,15 @@ static int rtnl_dump_done(struct nlmsghdr *h)
|
|||
}
|
||||
|
||||
if (len < 0) {
|
||||
errno = -len;
|
||||
|
||||
if (a->errhndlr && (a->errhndlr(h, a->arg2) & RTNL_SUPPRESS_NLMSG_DONE_NLERR))
|
||||
return 0;
|
||||
|
||||
/* check for any messages returned from kernel */
|
||||
if (nl_dump_ext_ack_done(h, len))
|
||||
return len;
|
||||
|
||||
errno = -len;
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
case EOPNOTSUPP:
|
||||
|
|
@ -753,8 +758,9 @@ static int rtnl_dump_done(struct nlmsghdr *h)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void rtnl_dump_error(const struct rtnl_handle *rth,
|
||||
struct nlmsghdr *h)
|
||||
static int rtnl_dump_error(const struct rtnl_handle *rth,
|
||||
struct nlmsghdr *h,
|
||||
const struct rtnl_dump_filter_arg *a)
|
||||
{
|
||||
|
||||
if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
|
||||
|
|
@ -766,11 +772,16 @@ static void rtnl_dump_error(const struct rtnl_handle *rth,
|
|||
if (rth->proto == NETLINK_SOCK_DIAG &&
|
||||
(errno == ENOENT ||
|
||||
errno == EOPNOTSUPP))
|
||||
return;
|
||||
return -1;
|
||||
|
||||
if (a->errhndlr && (a->errhndlr(h, a->arg2) & RTNL_SUPPRESS_NLMSG_ERROR_NLERR))
|
||||
return 0;
|
||||
|
||||
if (!(rth->flags & RTNL_HANDLE_F_SUPPRESS_NLERR))
|
||||
perror("RTNETLINK answers");
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int __rtnl_recvmsg(int fd, struct msghdr *msg, int flags)
|
||||
|
|
@ -879,7 +890,7 @@ static int rtnl_dump_filter_l(struct rtnl_handle *rth,
|
|||
dump_intr = 1;
|
||||
|
||||
if (h->nlmsg_type == NLMSG_DONE) {
|
||||
err = rtnl_dump_done(h);
|
||||
err = rtnl_dump_done(h, a);
|
||||
if (err < 0) {
|
||||
free(buf);
|
||||
return -1;
|
||||
|
|
@ -890,9 +901,13 @@ static int rtnl_dump_filter_l(struct rtnl_handle *rth,
|
|||
}
|
||||
|
||||
if (h->nlmsg_type == NLMSG_ERROR) {
|
||||
rtnl_dump_error(rth, h);
|
||||
free(buf);
|
||||
return -1;
|
||||
err = rtnl_dump_error(rth, h, a);
|
||||
if (err < 0) {
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
goto skip_it;
|
||||
}
|
||||
|
||||
if (!rth->dump_fp) {
|
||||
|
|
@ -928,12 +943,34 @@ skip_it:
|
|||
}
|
||||
|
||||
int rtnl_dump_filter_nc(struct rtnl_handle *rth,
|
||||
rtnl_filter_t filter,
|
||||
void *arg1, __u16 nc_flags)
|
||||
rtnl_filter_t filter,
|
||||
void *arg1, __u16 nc_flags)
|
||||
{
|
||||
const struct rtnl_dump_filter_arg a[2] = {
|
||||
{ .filter = filter, .arg1 = arg1, .nc_flags = nc_flags, },
|
||||
{ .filter = NULL, .arg1 = NULL, .nc_flags = 0, },
|
||||
const struct rtnl_dump_filter_arg a[] = {
|
||||
{
|
||||
.filter = filter, .arg1 = arg1,
|
||||
.nc_flags = nc_flags,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
return rtnl_dump_filter_l(rth, a);
|
||||
}
|
||||
|
||||
int rtnl_dump_filter_errhndlr_nc(struct rtnl_handle *rth,
|
||||
rtnl_filter_t filter,
|
||||
void *arg1,
|
||||
rtnl_err_hndlr_t errhndlr,
|
||||
void *arg2,
|
||||
__u16 nc_flags)
|
||||
{
|
||||
const struct rtnl_dump_filter_arg a[] = {
|
||||
{
|
||||
.filter = filter, .arg1 = arg1,
|
||||
.errhndlr = errhndlr, .arg2 = arg2,
|
||||
.nc_flags = nc_flags,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
return rtnl_dump_filter_l(rth, a);
|
||||
|
|
@ -1138,16 +1175,16 @@ int rtnl_listen(struct rtnl_handle *rtnl,
|
|||
char buf[16384];
|
||||
char cmsgbuf[BUFSIZ];
|
||||
|
||||
if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) {
|
||||
msg.msg_control = &cmsgbuf;
|
||||
msg.msg_controllen = sizeof(cmsgbuf);
|
||||
}
|
||||
|
||||
iov.iov_base = buf;
|
||||
while (1) {
|
||||
struct rtnl_ctrl_data ctrl;
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) {
|
||||
msg.msg_control = &cmsgbuf;
|
||||
msg.msg_controllen = sizeof(cmsgbuf);
|
||||
}
|
||||
|
||||
iov.iov_len = sizeof(buf);
|
||||
status = recvmsg(rtnl->fd, &msg, 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,12 @@ const char *ll_addr_n2a(const unsigned char *addr, int alen, int type,
|
|||
|
||||
if (alen == 16 && (type == ARPHRD_TUNNEL6 || type == ARPHRD_IP6GRE))
|
||||
return inet_ntop(AF_INET6, addr, buf, blen);
|
||||
if (alen == 7 && type == ARPHRD_AX25)
|
||||
return ax25_ntop(AF_AX25, addr, buf, blen);
|
||||
if (alen == 7 && type == ARPHRD_NETROM)
|
||||
return netrom_ntop(AF_NETROM, addr, buf, blen);
|
||||
if (alen == 5 && type == ARPHRD_ROSE)
|
||||
return rose_ntop(AF_ROSE, addr, buf, blen);
|
||||
|
||||
snprintf(buf, blen, "%02x", addr[0]);
|
||||
for (i = 1, l = 2; i < alen && l < blen; i++, l += 3)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <linux/ax25.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
const char *ax25_ntop1(const ax25_address *src, char *dst, socklen_t size);
|
||||
|
||||
const char *netrom_ntop(int af, const void *addr, char *buf, socklen_t buflen)
|
||||
{
|
||||
switch (af) {
|
||||
case AF_NETROM:
|
||||
errno = 0;
|
||||
return ax25_ntop1((ax25_address *)addr, buf, buflen);
|
||||
|
||||
default:
|
||||
errno = EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/rose.h>
|
||||
|
||||
#include "rt_names.h"
|
||||
#include "utils.h"
|
||||
|
||||
static const char *rose_ntop1(const rose_address *src, char *dst,
|
||||
socklen_t size)
|
||||
{
|
||||
char *p = dst;
|
||||
int i;
|
||||
|
||||
if (size < 10)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
*p++ = '0' + ((src->rose_addr[i] >> 4) & 0xf);
|
||||
*p++ = '0' + ((src->rose_addr[i] ) & 0xf);
|
||||
}
|
||||
|
||||
if (size == 10)
|
||||
return dst;
|
||||
|
||||
*p = '\0';
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
const char *rose_ntop(int af, const void *addr, char *buf, socklen_t buflen)
|
||||
{
|
||||
switch (af) {
|
||||
case AF_ROSE:
|
||||
errno = 0;
|
||||
return rose_ntop1((rose_address *)addr, buf, buflen);
|
||||
|
||||
default:
|
||||
errno = EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
26
lib/utils.c
26
lib/utils.c
|
|
@ -540,7 +540,7 @@ static int __get_addr_1(inet_prefix *addr, const char *name, int family)
|
|||
memset(addr, 0, sizeof(*addr));
|
||||
|
||||
if (strcmp(name, "default") == 0) {
|
||||
if ((family == AF_DECnet) || (family == AF_MPLS))
|
||||
if (family == AF_MPLS)
|
||||
return -1;
|
||||
addr->family = family;
|
||||
addr->bytelen = af_byte_len(addr->family);
|
||||
|
|
@ -551,7 +551,7 @@ static int __get_addr_1(inet_prefix *addr, const char *name, int family)
|
|||
|
||||
if (strcmp(name, "all") == 0 ||
|
||||
strcmp(name, "any") == 0) {
|
||||
if ((family == AF_DECnet) || (family == AF_MPLS))
|
||||
if (family == AF_MPLS)
|
||||
return -1;
|
||||
addr->family = family;
|
||||
addr->bytelen = 0;
|
||||
|
|
@ -636,10 +636,6 @@ int af_bit_len(int af)
|
|||
return 128;
|
||||
case AF_INET:
|
||||
return 32;
|
||||
case AF_DECnet:
|
||||
return 16;
|
||||
case AF_IPX:
|
||||
return 80;
|
||||
case AF_MPLS:
|
||||
return 20;
|
||||
}
|
||||
|
|
@ -729,16 +725,6 @@ int get_addr_rta(inet_prefix *dst, const struct rtattr *rta, int family)
|
|||
dst->bytelen = 16;
|
||||
memcpy(dst->data, data, 16);
|
||||
break;
|
||||
case 2:
|
||||
dst->family = AF_DECnet;
|
||||
dst->bytelen = 2;
|
||||
memcpy(dst->data, data, 2);
|
||||
break;
|
||||
case 10:
|
||||
dst->family = AF_IPX;
|
||||
dst->bytelen = 10;
|
||||
memcpy(dst->data, data, 10);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -1029,8 +1015,6 @@ int read_family(const char *name)
|
|||
family = AF_INET6;
|
||||
else if (strcmp(name, "link") == 0)
|
||||
family = AF_PACKET;
|
||||
else if (strcmp(name, "ipx") == 0)
|
||||
family = AF_IPX;
|
||||
else if (strcmp(name, "mpls") == 0)
|
||||
family = AF_MPLS;
|
||||
else if (strcmp(name, "bridge") == 0)
|
||||
|
|
@ -1046,8 +1030,6 @@ const char *family_name(int family)
|
|||
return "inet6";
|
||||
if (family == AF_PACKET)
|
||||
return "link";
|
||||
if (family == AF_IPX)
|
||||
return "ipx";
|
||||
if (family == AF_MPLS)
|
||||
return "mpls";
|
||||
if (family == AF_BRIDGE)
|
||||
|
|
@ -1714,10 +1696,10 @@ int do_batch(const char *name, bool force,
|
|||
|
||||
cmdlineno = 0;
|
||||
while (getcmdline(&line, &len, stdin) != -1) {
|
||||
char *largv[100];
|
||||
char *largv[MAX_ARGS];
|
||||
int largc;
|
||||
|
||||
largc = makeargs(line, largv, 100);
|
||||
largc = makeargs(line, largv, MAX_ARGS);
|
||||
if (!largc)
|
||||
continue; /* blank line */
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ bridge \- show / manipulate bridge addresses and devices
|
|||
\fB\-s\fR[\fItatistics\fR] |
|
||||
\fB\-n\fR[\fIetns\fR] name |
|
||||
\fB\-b\fR[\fIatch\fR] filename |
|
||||
\fB\-c\fR[\folor\fR] |
|
||||
\fB\-c\fR[\fIolor\fR] |
|
||||
\fB\-p\fR[\fIretty\fR] |
|
||||
\fB\-j\fR[\fIson\fR] |
|
||||
\fB\-o\fR[\fIneline\fr] }
|
||||
|
|
@ -145,13 +145,53 @@ bridge \- show / manipulate bridge addresses and devices
|
|||
.B vid
|
||||
.IR VID " [ "
|
||||
.B state
|
||||
.IR STP_STATE " ] "
|
||||
.IR STP_STATE " ] [ "
|
||||
.B mcast_router
|
||||
.IR MULTICAST_ROUTER " ]"
|
||||
|
||||
.ti -8
|
||||
.BR "bridge vlan" " [ " show " | " tunnelshow " ] [ "
|
||||
.B dev
|
||||
.IR DEV " ]"
|
||||
|
||||
.ti -8
|
||||
.BR "bridge vlan global set"
|
||||
.B dev
|
||||
.I DEV
|
||||
.B vid
|
||||
.IR VID " [ "
|
||||
.B mcast_snooping
|
||||
.IR MULTICAST_SNOOPING " ] [ "
|
||||
.B mcast_querier
|
||||
.IR MULTICAST_QUERIER " ] [ "
|
||||
.B mcast_igmp_version
|
||||
.IR IGMP_VERSION " ] [ "
|
||||
.B mcast_mld_version
|
||||
.IR MLD_VERSION " ] [ "
|
||||
.B mcast_last_member_count
|
||||
.IR LAST_MEMBER_COUNT " ] [ "
|
||||
.B mcast_last_member_interval
|
||||
.IR LAST_MEMBER_INTERVAL " ] [ "
|
||||
.B mcast_startup_query_count
|
||||
.IR STARTUP_QUERY_COUNT " ] [ "
|
||||
.B mcast_startup_query_interval
|
||||
.IR STARTUP_QUERY_INTERVAL " ] [ "
|
||||
.B mcast_membership_interval
|
||||
.IR MEMBERSHIP_INTERVAL " ] [ "
|
||||
.B mcast_querier_interval
|
||||
.IR QUERIER_INTERVAL " ] [ "
|
||||
.B mcast_query_interval
|
||||
.IR QUERY_INTERVAL " ] [ "
|
||||
.B mcast_query_response_interval
|
||||
.IR QUERY_RESPONSE_INTERVAL " ]"
|
||||
|
||||
.ti -8
|
||||
.BR "bridge vlan global" " [ " show " ] [ "
|
||||
.B dev
|
||||
.IR DEV " ] [ "
|
||||
.B vid
|
||||
.IR VID " ]"
|
||||
|
||||
.ti -8
|
||||
.BR "bridge monitor" " [ " all " | " neigh " | " link " | " mdb " | " vlan " ]"
|
||||
|
||||
|
|
@ -877,6 +917,31 @@ is used during the STP election process. In this state, the vlan will only proce
|
|||
STP BPDUs.
|
||||
.sp
|
||||
|
||||
.TP
|
||||
.BI mcast_router " MULTICAST_ROUTER "
|
||||
configure this vlan and interface's multicast router mode, note that only modes
|
||||
0 - 2 are available for bridge devices.
|
||||
A vlan and interface with a multicast router will receive all multicast traffic.
|
||||
.I MULTICAST_ROUTER
|
||||
may be either
|
||||
.sp
|
||||
.B 0
|
||||
- to disable multicast router.
|
||||
.sp
|
||||
|
||||
.B 1
|
||||
- to let the system detect the presence of routers (default).
|
||||
.sp
|
||||
|
||||
.B 2
|
||||
- to permanently enable multicast traffic forwarding on this vlan and interface.
|
||||
.sp
|
||||
|
||||
.B 3
|
||||
- to temporarily mark this vlan and port as having a multicast router, i.e.
|
||||
enable multicast traffic forwarding. This mode is available only for ports.
|
||||
.sp
|
||||
|
||||
.SS bridge vlan show - list vlan configuration.
|
||||
|
||||
This command displays the current VLAN filter table.
|
||||
|
|
@ -895,6 +960,98 @@ option, the command displays per-vlan traffic statistics.
|
|||
|
||||
This command displays the current vlan tunnel info mapping.
|
||||
|
||||
.SS bridge vlan global set - change vlan filter entry's global options
|
||||
|
||||
This command changes vlan filter entry's global options.
|
||||
|
||||
.TP
|
||||
.BI dev " NAME"
|
||||
the interface with which this vlan is associated. Only bridge devices are
|
||||
supported for global options.
|
||||
|
||||
.TP
|
||||
.BI vid " VID"
|
||||
the VLAN ID that identifies the vlan.
|
||||
|
||||
.TP
|
||||
.BI mcast_snooping " MULTICAST_SNOOPING "
|
||||
turn multicast snooping for VLAN entry with VLAN ID on
|
||||
.RI ( MULTICAST_SNOOPING " > 0) "
|
||||
or off
|
||||
.RI ( MULTICAST_SNOOPING " == 0). Default is on. "
|
||||
|
||||
.TP
|
||||
.BI mcast_querier " MULTICAST_QUERIER "
|
||||
enable
|
||||
.RI ( MULTICAST_QUERIER " > 0) "
|
||||
or disable
|
||||
.RI ( MULTICAST_QUERIER " == 0) "
|
||||
IGMP/MLD querier, ie sending of multicast queries by the bridge. Default is disabled.
|
||||
|
||||
.TP
|
||||
.BI mcast_igmp_version " IGMP_VERSION "
|
||||
set the IGMP version. Default is 2.
|
||||
|
||||
.TP
|
||||
.BI mcast_mld_version " MLD_VERSION "
|
||||
set the MLD version. Default is 1.
|
||||
|
||||
.TP
|
||||
.BI mcast_last_member_count " LAST_MEMBER_COUNT "
|
||||
set multicast last member count, ie the number of queries the bridge
|
||||
will send before stopping forwarding a multicast group after a "leave"
|
||||
message has been received. Default is 2.
|
||||
|
||||
.TP
|
||||
.BI mcast_last_member_interval " LAST_MEMBER_INTERVAL "
|
||||
interval between queries to find remaining members of a group,
|
||||
after a "leave" message is received.
|
||||
|
||||
.TP
|
||||
.BI mcast_startup_query_count " STARTUP_QUERY_COUNT "
|
||||
set the number of queries to send during startup phase. Default is 2.
|
||||
|
||||
.TP
|
||||
.BI mcast_startup_query_interval " STARTUP_QUERY_INTERVAL "
|
||||
interval between queries in the startup phase.
|
||||
|
||||
.TP
|
||||
.BI mcast_membership_interval " MEMBERSHIP_INTERVAL "
|
||||
delay after which the bridge will leave a group,
|
||||
if no membership reports for this group are received.
|
||||
|
||||
.TP
|
||||
.BI mcast_querier_interval " QUERIER_INTERVAL "
|
||||
interval between queries sent by other routers. If no queries are seen
|
||||
after this delay has passed, the bridge will start to send its own queries
|
||||
(as if
|
||||
.BI mcast_querier
|
||||
was enabled).
|
||||
|
||||
.TP
|
||||
.BI mcast_query_interval " QUERY_INTERVAL "
|
||||
interval between queries sent by the bridge after the end of the
|
||||
startup phase.
|
||||
|
||||
.TP
|
||||
.BI mcast_query_response_interval " QUERY_RESPONSE_INTERVAL "
|
||||
set the Max Response Time/Maximum Response Delay for IGMP/MLD
|
||||
queries sent by the bridge.
|
||||
|
||||
.SS bridge vlan global show - list global vlan options.
|
||||
|
||||
This command displays the global VLAN options for each VLAN entry.
|
||||
|
||||
.TP
|
||||
.BI dev " DEV"
|
||||
the interface only whose VLAN global options should be listed. Default is to list
|
||||
all bridge interfaces.
|
||||
|
||||
.TP
|
||||
.BI vid " VID"
|
||||
the VLAN ID only whose global options should be listed. Default is to list
|
||||
all vlans.
|
||||
|
||||
.SH bridge monitor - state monitoring
|
||||
|
||||
The
|
||||
|
|
|
|||
|
|
@ -45,15 +45,17 @@ devlink-port \- devlink port configuration
|
|||
|
||||
.ti -8
|
||||
.BI "devlink port add"
|
||||
.RB "["
|
||||
.RB "{"
|
||||
.IR "DEV | DEV/PORT_INDEX"
|
||||
.RB "] "
|
||||
.RB "} "
|
||||
.RB "[ " flavour
|
||||
.IR FLAVOUR " ]"
|
||||
.RB "[ " pcipf
|
||||
.RB "[ " pfnum
|
||||
.IR PFNUMBER " ]"
|
||||
.RB "{ " pcisf
|
||||
.IR SFNUMBER " }"
|
||||
.RB "[ " sfnum
|
||||
.IR SFNUMBER " ]"
|
||||
.RB "[ " controller
|
||||
.IR CNUM " ]"
|
||||
.br
|
||||
|
||||
.ti -8
|
||||
|
|
@ -63,12 +65,16 @@ devlink-port \- devlink port configuration
|
|||
.ti -8
|
||||
.BR "devlink port function set "
|
||||
.IR DEV/PORT_INDEX
|
||||
.RI "{ "
|
||||
.RI "[ "
|
||||
.BR "hw_addr "
|
||||
.RI "ADDR }"
|
||||
.RI "{ "
|
||||
.BR "state"
|
||||
.RI "STATE }"
|
||||
.RI "ADDR ]"
|
||||
.RI "[ "
|
||||
.BR state " { " active " | " inactive " }"
|
||||
.RI "]"
|
||||
|
||||
.ti -8
|
||||
.BR "devlink port function rate "
|
||||
.RI "{ " show " | " set " | " add " | " del " | " help " }"
|
||||
|
||||
.ti -8
|
||||
.B devlink dev param set
|
||||
|
|
@ -94,7 +100,7 @@ devlink-port \- devlink port configuration
|
|||
.SS devlink port set - change devlink port attributes
|
||||
|
||||
.PP
|
||||
.B "DEV/PORT_INDEX"
|
||||
.I "DEV/PORT_INDEX"
|
||||
- specifies the devlink port to operate on.
|
||||
|
||||
.in +4
|
||||
|
|
@ -118,7 +124,7 @@ set port type
|
|||
.SS devlink port split - split devlink port into more
|
||||
|
||||
.PP
|
||||
.B "DEV/PORT_INDEX"
|
||||
.I "DEV/PORT_INDEX"
|
||||
- specifies the devlink port to operate on.
|
||||
|
||||
.TP
|
||||
|
|
@ -129,7 +135,7 @@ number of ports to split to.
|
|||
Could be performed on any split port of the same split group.
|
||||
|
||||
.PP
|
||||
.B "DEV/PORT_INDEX"
|
||||
.I "DEV/PORT_INDEX"
|
||||
- specifies the devlink port to operate on.
|
||||
|
||||
.SS devlink port show - display devlink port attributes
|
||||
|
|
@ -146,13 +152,13 @@ Is an alias for
|
|||
.ti -8
|
||||
.SS devlink port add - add a devlink port
|
||||
.PP
|
||||
.B "DEV"
|
||||
.I "DEV"
|
||||
- specifies the devlink device to operate on. or
|
||||
|
||||
.PP
|
||||
.B "DEV/PORT_INDEX"
|
||||
.I "DEV/PORT_INDEX"
|
||||
- specifies the devlink port index to use for the requested new port.
|
||||
This is optional. When ommited, driver allocates unique port index.
|
||||
This is optional. When omitted, driver allocates unique port index.
|
||||
|
||||
.TP
|
||||
.BR flavour " { " pcipf " | " pcisf " } "
|
||||
|
|
@ -165,30 +171,36 @@ set port flavour
|
|||
- PCI SF port
|
||||
|
||||
.TP
|
||||
.BR pfnum " { " pfnumber " } "
|
||||
.BI pfnum " PFNUMBER "
|
||||
Specifies PCI pfnumber to use on which a SF device to create
|
||||
|
||||
.TP
|
||||
.BR sfnum " { " sfnumber " } "
|
||||
.BI sfnum " SFNUMBER "
|
||||
Specifies sfnumber to assign to the device of the SF.
|
||||
This field is optional for those devices which supports auto assignment of the
|
||||
SF number.
|
||||
|
||||
.TP
|
||||
.BI controller " CNUM "
|
||||
Specifies controller number for which the SF port is created.
|
||||
This field is optional. It is used only when SF port is created for the
|
||||
external controller.
|
||||
|
||||
.ti -8
|
||||
.SS devlink port function set - Set the port function attribute(s).
|
||||
|
||||
.PP
|
||||
.B "DEV/PORT_INDEX"
|
||||
.I "DEV/PORT_INDEX"
|
||||
- specifies the devlink port to operate on.
|
||||
|
||||
.TP
|
||||
.BR hw_addr " ADDR"
|
||||
- hardware address of the function to set. This is a Ethernet MAC address when
|
||||
.BI hw_addr " ADDR"
|
||||
Hardware address of the function to set. This is a Ethernet MAC address when
|
||||
port type is Ethernet.
|
||||
|
||||
.TP
|
||||
.BR state " { " active " | " inactive " } "
|
||||
- new state of the function to change to.
|
||||
New state of the function to change to.
|
||||
|
||||
.I active
|
||||
- Once configuration of the function is done, activate the function.
|
||||
|
|
@ -199,13 +211,13 @@ port type is Ethernet.
|
|||
.ti -8
|
||||
.SS devlink port del - delete a devlink port
|
||||
.PP
|
||||
.B "DEV/PORT_INDEX"
|
||||
.I "DEV/PORT_INDEX"
|
||||
- specifies the devlink port to delete.
|
||||
|
||||
.ti -8
|
||||
.SS devlink port param set - set new value to devlink port configuration parameter
|
||||
.PP
|
||||
.B "DEV/PORT_INDEX"
|
||||
.I "DEV/PORT_INDEX"
|
||||
- specifies the devlink port to operate on.
|
||||
|
||||
.TP
|
||||
|
|
@ -232,7 +244,7 @@ Configuration mode in which the new value is set.
|
|||
.SS devlink port param show - display devlink port supported configuration parameters attributes
|
||||
|
||||
.PP
|
||||
.B "DEV/PORT_INDEX"
|
||||
.I "DEV/PORT_INDEX"
|
||||
- specifies the devlink port to operate on.
|
||||
|
||||
.B name
|
||||
|
|
@ -240,6 +252,10 @@ Configuration mode in which the new value is set.
|
|||
Specify parameter name to show.
|
||||
If this argument, as well as port index, are omitted - all parameters supported by devlink device ports are listed.
|
||||
|
||||
.SS devlink port function rate - manage devlink rate objects
|
||||
Is an alias for
|
||||
.BR devlink-rate (8).
|
||||
|
||||
.SH "EXAMPLES"
|
||||
.PP
|
||||
devlink port show
|
||||
|
|
@ -327,6 +343,17 @@ devlink dev param set pci/0000:01:00.0/1 name internal_error_reset value true cm
|
|||
.RS 4
|
||||
Sets the parameter internal_error_reset of specified devlink port (#1) to true.
|
||||
.RE
|
||||
.PP
|
||||
devlink port add pci/0000:06:00.0 flavour pcisf pfnum 0 sfnum 88 controller 1
|
||||
.RS 4
|
||||
Add a devlink port of flavour PCI SF on controller 1 which has PCI PF of number
|
||||
0 with SF number 88. To make use of the function an example sequence is to add
|
||||
a port, configure the function attribute and activate the function. Once
|
||||
the function usage is completed, deactivate the function and finally delete
|
||||
the port. When there is desire to reuse the port without deletion, it can be
|
||||
reconfigured and activated again when function is in inactive state and
|
||||
function's operational state is detached.
|
||||
.RE
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR devlink (8),
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue