mirror of
https://git.kernel.org/pub/scm/network/iproute2/iproute2.git
synced 2024-11-15 14:05:22 +08:00
Merge git://git.kernel.org/pub/scm/network/iproute2/iproute2-next
This commit is contained in:
commit
b1521ec002
@ -1,5 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
BROBJ = bridge.o fdb.o monitor.o link.o mdb.o vlan.o
|
||||
BROBJ = bridge.o fdb.o monitor.o link.o mdb.o vlan.o vni.o
|
||||
|
||||
include ../config.mk
|
||||
|
||||
|
@ -14,6 +14,7 @@ void print_stp_state(__u8 state);
|
||||
int parse_stp_state(const char *arg);
|
||||
int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor,
|
||||
bool global_only);
|
||||
int print_vnifilter_rtm(struct nlmsghdr *n, void *arg, bool monitor);
|
||||
void br_print_router_port_stats(struct rtattr *pattr);
|
||||
|
||||
int do_fdb(int argc, char **argv);
|
||||
@ -21,6 +22,7 @@ int do_mdb(int argc, char **argv);
|
||||
int do_monitor(int argc, char **argv);
|
||||
int do_vlan(int argc, char **argv);
|
||||
int do_link(int argc, char **argv);
|
||||
int do_vni(int argc, char **argv);
|
||||
|
||||
extern int preferred_family;
|
||||
extern int show_stats;
|
||||
|
@ -58,6 +58,7 @@ static const struct cmd {
|
||||
{ "fdb", do_fdb },
|
||||
{ "mdb", do_mdb },
|
||||
{ "vlan", do_vlan },
|
||||
{ "vni", do_vni },
|
||||
{ "monitor", do_monitor },
|
||||
{ "help", do_help },
|
||||
{ 0 }
|
||||
|
@ -31,10 +31,20 @@ static int prefix_banner;
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: bridge monitor [file | link | fdb | mdb | vlan | all]\n");
|
||||
fprintf(stderr, "Usage: bridge monitor [file | link | fdb | mdb | vlan | vni | all]\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
static int print_tunnel_rtm(struct nlmsghdr *n, void *arg, bool monitor)
|
||||
{
|
||||
struct tunnel_msg *tmsg = NLMSG_DATA(n);
|
||||
|
||||
if (tmsg->family == PF_BRIDGE)
|
||||
return print_vnifilter_rtm(n, arg, monitor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int accept_msg(struct rtnl_ctrl_data *ctrl,
|
||||
struct nlmsghdr *n, void *arg)
|
||||
{
|
||||
@ -73,6 +83,12 @@ static int accept_msg(struct rtnl_ctrl_data *ctrl,
|
||||
fprintf(fp, "[VLAN]");
|
||||
return print_vlan_rtm(n, arg, true, false);
|
||||
|
||||
case RTM_NEWTUNNEL:
|
||||
case RTM_DELTUNNEL:
|
||||
if (prefix_banner)
|
||||
fprintf(fp, "[TUNNEL]");
|
||||
return print_tunnel_rtm(n, arg, true);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -86,6 +102,7 @@ int do_monitor(int argc, char **argv)
|
||||
int lneigh = 0;
|
||||
int lmdb = 0;
|
||||
int lvlan = 0;
|
||||
int lvni = 0;
|
||||
|
||||
rtnl_close(&rth);
|
||||
|
||||
@ -105,9 +122,13 @@ int do_monitor(int argc, char **argv)
|
||||
} else if (matches(*argv, "vlan") == 0) {
|
||||
lvlan = 1;
|
||||
groups = 0;
|
||||
} else if (strcmp(*argv, "vni") == 0) {
|
||||
lvni = 1;
|
||||
groups = 0;
|
||||
} else if (strcmp(*argv, "all") == 0) {
|
||||
groups = ~RTMGRP_TC;
|
||||
lvlan = 1;
|
||||
lvni = 1;
|
||||
prefix_banner = 1;
|
||||
} else if (matches(*argv, "help") == 0) {
|
||||
usage();
|
||||
@ -151,6 +172,11 @@ int do_monitor(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (lvni && rtnl_add_nl_group(&rth, RTNLGRP_TUNNEL) < 0) {
|
||||
fprintf(stderr, "Failed to add bridge vni group to list\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ll_init_map(&rth);
|
||||
|
||||
if (rtnl_listen(&rth, accept_msg, stdout) < 0)
|
||||
|
@ -1179,7 +1179,8 @@ static int vlan_show(int argc, char **argv, int subject)
|
||||
__u32 filt_mask;
|
||||
|
||||
filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS);
|
||||
if (rtnl_statsdump_req_filter(&rth, AF_UNSPEC, filt_mask) < 0) {
|
||||
if (rtnl_statsdump_req_filter(&rth, AF_UNSPEC, filt_mask,
|
||||
NULL, NULL) < 0) {
|
||||
perror("Cannot send dump request");
|
||||
exit(1);
|
||||
}
|
||||
@ -1194,7 +1195,8 @@ static int vlan_show(int argc, char **argv, int subject)
|
||||
}
|
||||
|
||||
filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS_SLAVE);
|
||||
if (rtnl_statsdump_req_filter(&rth, AF_UNSPEC, filt_mask) < 0) {
|
||||
if (rtnl_statsdump_req_filter(&rth, AF_UNSPEC, filt_mask,
|
||||
NULL, NULL) < 0) {
|
||||
perror("Cannot send slave dump request");
|
||||
exit(1);
|
||||
}
|
||||
|
439
bridge/vni.c
Normal file
439
bridge/vni.c
Normal file
@ -0,0 +1,439 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Command to manage vnifiltering on a vxlan device
|
||||
*
|
||||
* Authors: Roopa Prabhu <roopa@nvidia.com>
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <linux/if_link.h>
|
||||
#include <linux/if_bridge.h>
|
||||
#include <linux/if_ether.h>
|
||||
|
||||
#include "json_print.h"
|
||||
#include "libnetlink.h"
|
||||
#include "br_common.h"
|
||||
#include "utils.h"
|
||||
|
||||
static unsigned int filter_index;
|
||||
|
||||
#define VXLAN_ID_LEN 15
|
||||
|
||||
#define __stringify_1(x...) #x
|
||||
#define __stringify(x...) __stringify_1(x)
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: bridge vni { add | del } vni VNI\n"
|
||||
" [ { group | remote } IP_ADDRESS ]\n"
|
||||
" [ dev DEV ]\n"
|
||||
" bridge vni { show }\n"
|
||||
"\n"
|
||||
"Where: VNI := 0-16777215\n"
|
||||
);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
static int parse_vni_filter(const char *argv, struct nlmsghdr *n, int reqsize,
|
||||
inet_prefix *group)
|
||||
{
|
||||
char *vnilist = strdupa(argv);
|
||||
char *vni = strtok(vnilist, ",");
|
||||
int group_type = AF_UNSPEC;
|
||||
struct rtattr *nlvlist_e;
|
||||
char *v;
|
||||
int i;
|
||||
|
||||
if (group && is_addrtype_inet(group))
|
||||
group_type = (group->family == AF_INET) ? VXLAN_VNIFILTER_ENTRY_GROUP :
|
||||
VXLAN_VNIFILTER_ENTRY_GROUP6;
|
||||
|
||||
for (i = 0; vni; i++) {
|
||||
__u32 vni_start = 0, vni_end = 0;
|
||||
|
||||
v = strchr(vni, '-');
|
||||
if (v) {
|
||||
*v = '\0';
|
||||
v++;
|
||||
vni_start = atoi(vni);
|
||||
vni_end = atoi(v);
|
||||
} else {
|
||||
vni_start = atoi(vni);
|
||||
}
|
||||
nlvlist_e = addattr_nest(n, reqsize, VXLAN_VNIFILTER_ENTRY |
|
||||
NLA_F_NESTED);
|
||||
addattr32(n, 1024, VXLAN_VNIFILTER_ENTRY_START, vni_start);
|
||||
if (vni_end)
|
||||
addattr32(n, 1024, VXLAN_VNIFILTER_ENTRY_END, vni_end);
|
||||
if (group)
|
||||
addattr_l(n, 1024, group_type, group->data, group->bytelen);
|
||||
addattr_nest_end(n, nlvlist_e);
|
||||
vni = strtok(NULL, ",");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vni_modify(int cmd, int argc, char **argv)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct tunnel_msg tmsg;
|
||||
char buf[1024];
|
||||
} req = {
|
||||
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tunnel_msg)),
|
||||
.n.nlmsg_flags = NLM_F_REQUEST,
|
||||
.n.nlmsg_type = cmd,
|
||||
.tmsg.family = PF_BRIDGE,
|
||||
};
|
||||
bool group_present = false;
|
||||
inet_prefix daddr;
|
||||
char *vni = NULL;
|
||||
char *d = NULL;
|
||||
|
||||
while (argc > 0) {
|
||||
if (strcmp(*argv, "dev") == 0) {
|
||||
NEXT_ARG();
|
||||
d = *argv;
|
||||
} else if (strcmp(*argv, "vni") == 0) {
|
||||
NEXT_ARG();
|
||||
if (vni)
|
||||
invarg("duplicate vni", *argv);
|
||||
vni = *argv;
|
||||
} else if (strcmp(*argv, "group") == 0) {
|
||||
if (group_present)
|
||||
invarg("duplicate group", *argv);
|
||||
if (is_addrtype_inet_not_multi(&daddr)) {
|
||||
fprintf(stderr, "vxlan: both group and remote");
|
||||
fprintf(stderr, " cannot be specified\n");
|
||||
return -1;
|
||||
}
|
||||
NEXT_ARG();
|
||||
get_addr(&daddr, *argv, AF_UNSPEC);
|
||||
if (!is_addrtype_inet_multi(&daddr))
|
||||
invarg("invalid group address", *argv);
|
||||
group_present = true;
|
||||
} else if (strcmp(*argv, "remote") == 0) {
|
||||
if (group_present)
|
||||
invarg("duplicate group", *argv);
|
||||
NEXT_ARG();
|
||||
get_addr(&daddr, *argv, AF_UNSPEC);
|
||||
group_present = true;
|
||||
} else {
|
||||
if (strcmp(*argv, "help") == 0)
|
||||
usage();
|
||||
}
|
||||
argc--; argv++;
|
||||
}
|
||||
|
||||
if (d == NULL || vni == NULL) {
|
||||
fprintf(stderr, "Device and VNI ID are required arguments.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!vni && group_present) {
|
||||
fprintf(stderr, "Group can only be specified with a vni\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vni)
|
||||
parse_vni_filter(vni, &req.n, sizeof(req),
|
||||
(group_present ? &daddr : NULL));
|
||||
|
||||
req.tmsg.ifindex = ll_name_to_index(d);
|
||||
if (req.tmsg.ifindex == 0) {
|
||||
fprintf(stderr, "Cannot find vxlan device \"%s\"\n", d);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rtnl_talk(&rth, &req.n, NULL) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void open_vni_port(int ifi_index, const char *fmt)
|
||||
{
|
||||
open_json_object(NULL);
|
||||
print_color_string(PRINT_ANY, COLOR_IFNAME, "ifname",
|
||||
"%-" __stringify(IFNAMSIZ) "s ",
|
||||
ll_index_to_name(ifi_index));
|
||||
open_json_array(PRINT_JSON, "vnis");
|
||||
}
|
||||
|
||||
static void close_vni_port(void)
|
||||
{
|
||||
close_json_array(PRINT_JSON, NULL);
|
||||
close_json_object();
|
||||
}
|
||||
|
||||
static void print_range(const char *name, __u32 start, __u32 id)
|
||||
{
|
||||
char end[64];
|
||||
|
||||
snprintf(end, sizeof(end), "%sEnd", name);
|
||||
|
||||
print_uint(PRINT_ANY, name, " %u", start);
|
||||
if (start != id)
|
||||
print_uint(PRINT_ANY, end, "-%-14u ", id);
|
||||
|
||||
}
|
||||
|
||||
static void print_vnifilter_entry_stats(struct rtattr *stats_attr)
|
||||
{
|
||||
struct rtattr *stb[VNIFILTER_ENTRY_STATS_MAX+1];
|
||||
__u64 stat;
|
||||
|
||||
open_json_object("stats");
|
||||
parse_rtattr_flags(stb, VNIFILTER_ENTRY_STATS_MAX, RTA_DATA(stats_attr),
|
||||
RTA_PAYLOAD(stats_attr), NLA_F_NESTED);
|
||||
|
||||
print_nl();
|
||||
print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
|
||||
print_string(PRINT_FP, NULL, "RX: ", "");
|
||||
|
||||
if (stb[VNIFILTER_ENTRY_STATS_RX_BYTES]) {
|
||||
stat = rta_getattr_u64(stb[VNIFILTER_ENTRY_STATS_RX_BYTES]);
|
||||
print_lluint(PRINT_ANY, "rx_bytes", "bytes %llu ", stat);
|
||||
}
|
||||
if (stb[VNIFILTER_ENTRY_STATS_RX_PKTS]) {
|
||||
stat = rta_getattr_u64(stb[VNIFILTER_ENTRY_STATS_RX_PKTS]);
|
||||
print_lluint(PRINT_ANY, "rx_pkts", "pkts %llu ", stat);
|
||||
}
|
||||
if (stb[VNIFILTER_ENTRY_STATS_RX_DROPS]) {
|
||||
stat = rta_getattr_u64(stb[VNIFILTER_ENTRY_STATS_RX_DROPS]);
|
||||
print_lluint(PRINT_ANY, "rx_drops", "drops %llu ", stat);
|
||||
}
|
||||
if (stb[VNIFILTER_ENTRY_STATS_RX_ERRORS]) {
|
||||
stat = rta_getattr_u64(stb[VNIFILTER_ENTRY_STATS_RX_ERRORS]);
|
||||
print_lluint(PRINT_ANY, "rx_errors", "errors %llu ", stat);
|
||||
}
|
||||
|
||||
print_nl();
|
||||
print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
|
||||
print_string(PRINT_FP, NULL, "TX: ", "");
|
||||
|
||||
if (stb[VNIFILTER_ENTRY_STATS_TX_BYTES]) {
|
||||
stat = rta_getattr_u64(stb[VNIFILTER_ENTRY_STATS_TX_BYTES]);
|
||||
print_lluint(PRINT_ANY, "tx_bytes", "bytes %llu ", stat);
|
||||
}
|
||||
if (stb[VNIFILTER_ENTRY_STATS_TX_PKTS]) {
|
||||
stat = rta_getattr_u64(stb[VNIFILTER_ENTRY_STATS_TX_PKTS]);
|
||||
print_lluint(PRINT_ANY, "tx_pkts", "pkts %llu ", stat);
|
||||
}
|
||||
if (stb[VNIFILTER_ENTRY_STATS_TX_DROPS]) {
|
||||
stat = rta_getattr_u64(stb[VNIFILTER_ENTRY_STATS_TX_DROPS]);
|
||||
print_lluint(PRINT_ANY, "tx_drops", "drops %llu ", stat);
|
||||
}
|
||||
if (stb[VNIFILTER_ENTRY_STATS_TX_ERRORS]) {
|
||||
stat = rta_getattr_u64(stb[VNIFILTER_ENTRY_STATS_TX_ERRORS]);
|
||||
print_lluint(PRINT_ANY, "tx_errors", "errors %llu ", stat);
|
||||
}
|
||||
close_json_object();
|
||||
}
|
||||
|
||||
static void print_vni(struct rtattr *t, int ifindex)
|
||||
{
|
||||
struct rtattr *ttb[VXLAN_VNIFILTER_ENTRY_MAX+1];
|
||||
__u32 vni_start = 0;
|
||||
__u32 vni_end = 0;
|
||||
|
||||
parse_rtattr_flags(ttb, VXLAN_VNIFILTER_ENTRY_MAX, RTA_DATA(t),
|
||||
RTA_PAYLOAD(t), NLA_F_NESTED);
|
||||
|
||||
if (ttb[VXLAN_VNIFILTER_ENTRY_START])
|
||||
vni_start = rta_getattr_u32(ttb[VXLAN_VNIFILTER_ENTRY_START]);
|
||||
|
||||
if (ttb[VXLAN_VNIFILTER_ENTRY_END])
|
||||
vni_end = rta_getattr_u32(ttb[VXLAN_VNIFILTER_ENTRY_END]);
|
||||
|
||||
if (vni_end)
|
||||
print_range("vni", vni_start, vni_end);
|
||||
else
|
||||
print_uint(PRINT_ANY, "vni", " %-14u", vni_start);
|
||||
|
||||
if (ttb[VXLAN_VNIFILTER_ENTRY_GROUP]) {
|
||||
__be32 addr = rta_getattr_u32(ttb[VXLAN_VNIFILTER_ENTRY_GROUP]);
|
||||
|
||||
if (addr) {
|
||||
if (IN_MULTICAST(ntohl(addr)))
|
||||
print_string(PRINT_ANY,
|
||||
"group",
|
||||
" %s",
|
||||
format_host(AF_INET, 4, &addr));
|
||||
else
|
||||
print_string(PRINT_ANY,
|
||||
"remote",
|
||||
" %s",
|
||||
format_host(AF_INET, 4, &addr));
|
||||
}
|
||||
} else if (ttb[VXLAN_VNIFILTER_ENTRY_GROUP6]) {
|
||||
struct in6_addr addr;
|
||||
|
||||
memcpy(&addr, RTA_DATA(ttb[VXLAN_VNIFILTER_ENTRY_GROUP6]), sizeof(struct in6_addr));
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&addr)) {
|
||||
if (IN6_IS_ADDR_MULTICAST(&addr))
|
||||
print_string(PRINT_ANY,
|
||||
"group",
|
||||
" %s",
|
||||
format_host(AF_INET6,
|
||||
sizeof(struct in6_addr),
|
||||
&addr));
|
||||
else
|
||||
print_string(PRINT_ANY,
|
||||
"remote",
|
||||
" %s",
|
||||
format_host(AF_INET6,
|
||||
sizeof(struct in6_addr),
|
||||
&addr));
|
||||
}
|
||||
}
|
||||
|
||||
if (ttb[VXLAN_VNIFILTER_ENTRY_STATS])
|
||||
print_vnifilter_entry_stats(ttb[VXLAN_VNIFILTER_ENTRY_STATS]);
|
||||
|
||||
close_json_object();
|
||||
print_string(PRINT_FP, NULL, "%s", _SL_);
|
||||
}
|
||||
|
||||
int print_vnifilter_rtm(struct nlmsghdr *n, void *arg, bool monitor)
|
||||
{
|
||||
struct tunnel_msg *tmsg = NLMSG_DATA(n);
|
||||
int len = n->nlmsg_len;
|
||||
bool first = true;
|
||||
struct rtattr *t;
|
||||
int rem;
|
||||
|
||||
if (n->nlmsg_type != RTM_NEWTUNNEL &&
|
||||
n->nlmsg_type != RTM_DELTUNNEL &&
|
||||
n->nlmsg_type != RTM_GETTUNNEL) {
|
||||
fprintf(stderr, "Unknown vni tunnel rtm msg: %08x %08x %08x\n",
|
||||
n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
len -= NLMSG_LENGTH(sizeof(*tmsg));
|
||||
if (len < 0) {
|
||||
fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tmsg->family != AF_BRIDGE)
|
||||
return 0;
|
||||
|
||||
if (filter_index && filter_index != tmsg->ifindex)
|
||||
return 0;
|
||||
|
||||
if (n->nlmsg_type == RTM_DELTUNNEL)
|
||||
print_bool(PRINT_ANY, "deleted", "Deleted ", true);
|
||||
|
||||
rem = len;
|
||||
for (t = TUNNEL_RTA(tmsg); RTA_OK(t, rem); t = RTA_NEXT(t, rem)) {
|
||||
unsigned short rta_type = t->rta_type & NLA_TYPE_MASK;
|
||||
|
||||
if (rta_type != VXLAN_VNIFILTER_ENTRY)
|
||||
continue;
|
||||
if (first) {
|
||||
open_vni_port(tmsg->ifindex, "%s");
|
||||
open_json_object(NULL);
|
||||
first = false;
|
||||
} else {
|
||||
open_json_object(NULL);
|
||||
print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
|
||||
}
|
||||
|
||||
print_vni(t, tmsg->ifindex);
|
||||
}
|
||||
close_vni_port();
|
||||
|
||||
print_string(PRINT_FP, NULL, "%s", _SL_);
|
||||
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_vnifilter_rtm_filter(struct nlmsghdr *n, void *arg)
|
||||
{
|
||||
return print_vnifilter_rtm(n, arg, false);
|
||||
}
|
||||
|
||||
static int vni_show(int argc, char **argv)
|
||||
{
|
||||
char *filter_dev = NULL;
|
||||
__u8 flags = 0;
|
||||
int ret = 0;
|
||||
|
||||
while (argc > 0) {
|
||||
if (strcmp(*argv, "dev") == 0) {
|
||||
NEXT_ARG();
|
||||
if (filter_dev)
|
||||
duparg("dev", *argv);
|
||||
filter_dev = *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 (show_stats)
|
||||
flags = TUNNEL_MSG_FLAG_STATS;
|
||||
|
||||
if (rtnl_tunneldump_req(&rth, PF_BRIDGE, filter_index, flags) < 0) {
|
||||
perror("Cannot send dump request");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!is_json_context()) {
|
||||
printf("%-" __stringify(IFNAMSIZ) "s %-"
|
||||
__stringify(VXLAN_ID_LEN) "s %-"
|
||||
__stringify(15) "s",
|
||||
"dev", "vni", "group/remote");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
ret = rtnl_dump_filter(&rth, print_vnifilter_rtm_filter, NULL);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Dump ternminated\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
delete_json_obj();
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_vni(int argc, char **argv)
|
||||
{
|
||||
ll_init_map(&rth);
|
||||
|
||||
if (argc > 0) {
|
||||
if (strcmp(*argv, "add") == 0)
|
||||
return vni_modify(RTM_NEWTUNNEL, argc-1, argv+1);
|
||||
if (strcmp(*argv, "delete") == 0)
|
||||
return vni_modify(RTM_DELTUNNEL, argc-1, argv+1);
|
||||
if (strcmp(*argv, "show") == 0 ||
|
||||
strcmp(*argv, "lst") == 0 ||
|
||||
strcmp(*argv, "list") == 0)
|
||||
return vni_show(argc-1, argv+1);
|
||||
if (strcmp(*argv, "help") == 0)
|
||||
usage();
|
||||
} else {
|
||||
return vni_show(0, NULL);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Command \"%s\" is unknown, try \"bridge vni help\".\n", *argv);
|
||||
exit(-1);
|
||||
}
|
@ -367,6 +367,7 @@ struct dl {
|
||||
bool pretty_output;
|
||||
bool verbose;
|
||||
bool stats;
|
||||
bool hex;
|
||||
struct {
|
||||
bool present;
|
||||
char *bus_name;
|
||||
@ -8044,6 +8045,8 @@ static int cmd_health_dump_clear(struct dl *dl)
|
||||
|
||||
static int fmsg_value_show(struct dl *dl, int type, struct nlattr *nl_data)
|
||||
{
|
||||
const char *num_fmt = dl->hex ? "%#x" : "%u";
|
||||
const char *num64_fmt = dl->hex ? "%#"PRIx64 : "%"PRIu64;
|
||||
uint8_t *data;
|
||||
uint32_t len;
|
||||
|
||||
@ -8053,16 +8056,16 @@ static int fmsg_value_show(struct dl *dl, int type, struct nlattr *nl_data)
|
||||
print_bool(PRINT_ANY, NULL, "%s", mnl_attr_get_u8(nl_data));
|
||||
break;
|
||||
case MNL_TYPE_U8:
|
||||
print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u8(nl_data));
|
||||
print_uint(PRINT_ANY, NULL, num_fmt, mnl_attr_get_u8(nl_data));
|
||||
break;
|
||||
case MNL_TYPE_U16:
|
||||
print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u16(nl_data));
|
||||
print_uint(PRINT_ANY, NULL, num_fmt, mnl_attr_get_u16(nl_data));
|
||||
break;
|
||||
case MNL_TYPE_U32:
|
||||
print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u32(nl_data));
|
||||
print_uint(PRINT_ANY, NULL, num_fmt, mnl_attr_get_u32(nl_data));
|
||||
break;
|
||||
case MNL_TYPE_U64:
|
||||
print_u64(PRINT_ANY, NULL, "%"PRIu64, mnl_attr_get_u64(nl_data));
|
||||
print_u64(PRINT_ANY, NULL, num64_fmt, mnl_attr_get_u64(nl_data));
|
||||
break;
|
||||
case MNL_TYPE_NUL_STRING:
|
||||
print_string(PRINT_ANY, NULL, "%s", mnl_attr_get_str(nl_data));
|
||||
@ -8939,7 +8942,7 @@ static void help(void)
|
||||
pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
|
||||
" devlink [ -f[orce] ] -b[atch] filename -N[etns] netnsname\n"
|
||||
"where OBJECT := { dev | port | sb | monitor | dpipe | resource | region | health | trap }\n"
|
||||
" OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] -s[tatistics] }\n");
|
||||
" OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] -s[tatistics] -[he]x }\n");
|
||||
}
|
||||
|
||||
static int dl_cmd(struct dl *dl, int argc, char **argv)
|
||||
@ -9053,6 +9056,7 @@ int main(int argc, char **argv)
|
||||
{ "statistics", no_argument, NULL, 's' },
|
||||
{ "Netns", required_argument, NULL, 'N' },
|
||||
{ "iec", no_argument, NULL, 'i' },
|
||||
{ "hex", no_argument, NULL, 'x' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
const char *batch_file = NULL;
|
||||
@ -9068,7 +9072,7 @@ int main(int argc, char **argv)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "Vfb:njpvsN:i",
|
||||
while ((opt = getopt_long(argc, argv, "Vfb:njpvsN:ix",
|
||||
long_options, NULL)) >= 0) {
|
||||
|
||||
switch (opt) {
|
||||
@ -9106,6 +9110,9 @@ int main(int argc, char **argv)
|
||||
case 'i':
|
||||
use_iec = true;
|
||||
break;
|
||||
case 'x':
|
||||
dl->hex = true;
|
||||
break;
|
||||
default:
|
||||
pr_err("Unknown option.\n");
|
||||
help();
|
||||
|
@ -37,6 +37,12 @@ struct nlmsg_chain {
|
||||
struct nlmsg_list *tail;
|
||||
};
|
||||
|
||||
struct ipstats_req {
|
||||
struct nlmsghdr nlh;
|
||||
struct if_stats_msg ifsm;
|
||||
char buf[128];
|
||||
};
|
||||
|
||||
extern int rcvbuf;
|
||||
|
||||
int rtnl_open(struct rtnl_handle *rth, unsigned int subscriptions)
|
||||
@ -88,7 +94,10 @@ int rtnl_fdb_linkdump_req_filter_fn(struct rtnl_handle *rth,
|
||||
int rtnl_nsiddump_req_filter_fn(struct rtnl_handle *rth, int family,
|
||||
req_filter_fn_t filter_fn)
|
||||
__attribute__((warn_unused_result));
|
||||
int rtnl_statsdump_req_filter(struct rtnl_handle *rth, int fam, __u32 filt_mask)
|
||||
int rtnl_statsdump_req_filter(struct rtnl_handle *rth, int fam, __u32 filt_mask,
|
||||
int (*filter_fn)(struct ipstats_req *req,
|
||||
void *data),
|
||||
void *filter_data)
|
||||
__attribute__((warn_unused_result));
|
||||
int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req,
|
||||
int len)
|
||||
@ -103,6 +112,10 @@ int rtnl_nexthop_bucket_dump_req(struct rtnl_handle *rth, int family,
|
||||
req_filter_fn_t filter_fn)
|
||||
__attribute__((warn_unused_result));
|
||||
|
||||
int rtnl_tunneldump_req(struct rtnl_handle *rth, int family, int ifindex,
|
||||
__u8 flags)
|
||||
__attribute__((warn_unused_result));
|
||||
|
||||
struct rtnl_ctrl_data {
|
||||
int nsid;
|
||||
};
|
||||
@ -322,6 +335,11 @@ int rtnl_from_file(FILE *, rtnl_listen_filter_t handler,
|
||||
((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct br_vlan_msg))))
|
||||
#endif
|
||||
|
||||
#ifndef TUNNEL_RTA
|
||||
#define TUNNEL_RTA(r) \
|
||||
((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct tunnel_msg))))
|
||||
#endif
|
||||
|
||||
/* User defined nlmsg_type which is used mostly for logging netlink
|
||||
* messages from dump file */
|
||||
#define NLMSG_TSTAMP 15
|
||||
|
@ -1013,6 +1013,7 @@ enum bpf_link_type {
|
||||
BPF_LINK_TYPE_XDP = 6,
|
||||
BPF_LINK_TYPE_PERF_EVENT = 7,
|
||||
BPF_LINK_TYPE_KPROBE_MULTI = 8,
|
||||
BPF_LINK_TYPE_STRUCT_OPS = 9,
|
||||
|
||||
MAX_BPF_LINK_TYPE,
|
||||
};
|
||||
@ -1489,6 +1490,15 @@ union bpf_attr {
|
||||
__aligned_u64 addrs;
|
||||
__aligned_u64 cookies;
|
||||
} kprobe_multi;
|
||||
struct {
|
||||
/* this is overlaid with the target_btf_id above. */
|
||||
__u32 target_btf_id;
|
||||
/* black box user-provided value passed through
|
||||
* to BPF program at the execution time and
|
||||
* accessible through bpf_get_attach_cookie() BPF helper
|
||||
*/
|
||||
__u64 cookie;
|
||||
} tracing;
|
||||
};
|
||||
} link_create;
|
||||
|
||||
@ -5143,6 +5153,102 @@ union bpf_attr {
|
||||
* The **hash_algo** is returned on success,
|
||||
* **-EOPNOTSUP** if the hash calculation failed or **-EINVAL** if
|
||||
* invalid arguments are passed.
|
||||
*
|
||||
* void *bpf_kptr_xchg(void *map_value, void *ptr)
|
||||
* Description
|
||||
* Exchange kptr at pointer *map_value* with *ptr*, and return the
|
||||
* old value. *ptr* can be NULL, otherwise it must be a referenced
|
||||
* pointer which will be released when this helper is called.
|
||||
* Return
|
||||
* The old value of kptr (which can be NULL). The returned pointer
|
||||
* if not NULL, is a reference which must be released using its
|
||||
* corresponding release function, or moved into a BPF map before
|
||||
* program exit.
|
||||
*
|
||||
* void *bpf_map_lookup_percpu_elem(struct bpf_map *map, const void *key, u32 cpu)
|
||||
* Description
|
||||
* Perform a lookup in *percpu map* for an entry associated to
|
||||
* *key* on *cpu*.
|
||||
* Return
|
||||
* Map value associated to *key* on *cpu*, or **NULL** if no entry
|
||||
* was found or *cpu* is invalid.
|
||||
*
|
||||
* struct mptcp_sock *bpf_skc_to_mptcp_sock(void *sk)
|
||||
* Description
|
||||
* Dynamically cast a *sk* pointer to a *mptcp_sock* pointer.
|
||||
* Return
|
||||
* *sk* if casting is valid, or **NULL** otherwise.
|
||||
*
|
||||
* long bpf_dynptr_from_mem(void *data, u32 size, u64 flags, struct bpf_dynptr *ptr)
|
||||
* Description
|
||||
* Get a dynptr to local memory *data*.
|
||||
*
|
||||
* *data* must be a ptr to a map value.
|
||||
* The maximum *size* supported is DYNPTR_MAX_SIZE.
|
||||
* *flags* is currently unused.
|
||||
* Return
|
||||
* 0 on success, -E2BIG if the size exceeds DYNPTR_MAX_SIZE,
|
||||
* -EINVAL if flags is not 0.
|
||||
*
|
||||
* long bpf_ringbuf_reserve_dynptr(void *ringbuf, u32 size, u64 flags, struct bpf_dynptr *ptr)
|
||||
* Description
|
||||
* Reserve *size* bytes of payload in a ring buffer *ringbuf*
|
||||
* through the dynptr interface. *flags* must be 0.
|
||||
*
|
||||
* Please note that a corresponding bpf_ringbuf_submit_dynptr or
|
||||
* bpf_ringbuf_discard_dynptr must be called on *ptr*, even if the
|
||||
* reservation fails. This is enforced by the verifier.
|
||||
* Return
|
||||
* 0 on success, or a negative error in case of failure.
|
||||
*
|
||||
* void bpf_ringbuf_submit_dynptr(struct bpf_dynptr *ptr, u64 flags)
|
||||
* Description
|
||||
* Submit reserved ring buffer sample, pointed to by *data*,
|
||||
* through the dynptr interface. This is a no-op if the dynptr is
|
||||
* invalid/null.
|
||||
*
|
||||
* For more information on *flags*, please see
|
||||
* 'bpf_ringbuf_submit'.
|
||||
* Return
|
||||
* Nothing. Always succeeds.
|
||||
*
|
||||
* void bpf_ringbuf_discard_dynptr(struct bpf_dynptr *ptr, u64 flags)
|
||||
* Description
|
||||
* Discard reserved ring buffer sample through the dynptr
|
||||
* interface. This is a no-op if the dynptr is invalid/null.
|
||||
*
|
||||
* For more information on *flags*, please see
|
||||
* 'bpf_ringbuf_discard'.
|
||||
* Return
|
||||
* Nothing. Always succeeds.
|
||||
*
|
||||
* long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset)
|
||||
* Description
|
||||
* Read *len* bytes from *src* into *dst*, starting from *offset*
|
||||
* into *src*.
|
||||
* Return
|
||||
* 0 on success, -E2BIG if *offset* + *len* exceeds the length
|
||||
* of *src*'s data, -EINVAL if *src* is an invalid dynptr.
|
||||
*
|
||||
* long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len)
|
||||
* Description
|
||||
* Write *len* bytes from *src* into *dst*, starting from *offset*
|
||||
* into *dst*.
|
||||
* Return
|
||||
* 0 on success, -E2BIG if *offset* + *len* exceeds the length
|
||||
* of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst*
|
||||
* is a read-only dynptr.
|
||||
*
|
||||
* void *bpf_dynptr_data(struct bpf_dynptr *ptr, u32 offset, u32 len)
|
||||
* Description
|
||||
* Get a pointer to the underlying dynptr data.
|
||||
*
|
||||
* *len* must be a statically known value. The returned data slice
|
||||
* is invalidated whenever the dynptr is invalidated.
|
||||
* Return
|
||||
* Pointer to the underlying dynptr data, NULL if the dynptr is
|
||||
* read-only, if the dynptr is invalid, or if the offset and length
|
||||
* is out of bounds.
|
||||
*/
|
||||
#define __BPF_FUNC_MAPPER(FN) \
|
||||
FN(unspec), \
|
||||
@ -5339,6 +5445,16 @@ union bpf_attr {
|
||||
FN(copy_from_user_task), \
|
||||
FN(skb_set_tstamp), \
|
||||
FN(ima_file_hash), \
|
||||
FN(kptr_xchg), \
|
||||
FN(map_lookup_percpu_elem), \
|
||||
FN(skc_to_mptcp_sock), \
|
||||
FN(dynptr_from_mem), \
|
||||
FN(ringbuf_reserve_dynptr), \
|
||||
FN(ringbuf_submit_dynptr), \
|
||||
FN(ringbuf_discard_dynptr), \
|
||||
FN(dynptr_read), \
|
||||
FN(dynptr_write), \
|
||||
FN(dynptr_data), \
|
||||
/* */
|
||||
|
||||
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
|
||||
@ -5592,6 +5708,10 @@ struct bpf_tunnel_key {
|
||||
__u8 tunnel_ttl;
|
||||
__u16 tunnel_ext; /* Padding, future use. */
|
||||
__u32 tunnel_label;
|
||||
union {
|
||||
__u32 local_ipv4;
|
||||
__u32 local_ipv6[4];
|
||||
};
|
||||
};
|
||||
|
||||
/* user accessible mirror of in-kernel xfrm_state.
|
||||
@ -6486,6 +6606,11 @@ struct bpf_timer {
|
||||
__u64 :64;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
struct bpf_dynptr {
|
||||
__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.
|
||||
|
@ -33,8 +33,8 @@ struct btf_type {
|
||||
/* "info" bits arrangement
|
||||
* bits 0-15: vlen (e.g. # of struct's members)
|
||||
* bits 16-23: unused
|
||||
* bits 24-27: kind (e.g. int, ptr, array...etc)
|
||||
* bits 28-30: unused
|
||||
* bits 24-28: kind (e.g. int, ptr, array...etc)
|
||||
* bits 29-30: unused
|
||||
* bit 31: kind_flag, currently used by
|
||||
* struct, union and fwd
|
||||
*/
|
||||
|
@ -131,6 +131,11 @@ enum devlink_command {
|
||||
DEVLINK_CMD_RATE_NEW,
|
||||
DEVLINK_CMD_RATE_DEL,
|
||||
|
||||
DEVLINK_CMD_LINECARD_GET, /* can dump */
|
||||
DEVLINK_CMD_LINECARD_SET,
|
||||
DEVLINK_CMD_LINECARD_NEW,
|
||||
DEVLINK_CMD_LINECARD_DEL,
|
||||
|
||||
/* add new commands above here */
|
||||
__DEVLINK_CMD_MAX,
|
||||
DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1
|
||||
@ -338,6 +343,19 @@ enum devlink_reload_limit {
|
||||
|
||||
#define DEVLINK_RELOAD_LIMITS_VALID_MASK (_BITUL(__DEVLINK_RELOAD_LIMIT_MAX) - 1)
|
||||
|
||||
enum devlink_linecard_state {
|
||||
DEVLINK_LINECARD_STATE_UNSPEC,
|
||||
DEVLINK_LINECARD_STATE_UNPROVISIONED,
|
||||
DEVLINK_LINECARD_STATE_UNPROVISIONING,
|
||||
DEVLINK_LINECARD_STATE_PROVISIONING,
|
||||
DEVLINK_LINECARD_STATE_PROVISIONING_FAILED,
|
||||
DEVLINK_LINECARD_STATE_PROVISIONED,
|
||||
DEVLINK_LINECARD_STATE_ACTIVE,
|
||||
|
||||
__DEVLINK_LINECARD_STATE_MAX,
|
||||
DEVLINK_LINECARD_STATE_MAX = __DEVLINK_LINECARD_STATE_MAX - 1
|
||||
};
|
||||
|
||||
enum devlink_attr {
|
||||
/* don't change the order or add anything between, this is ABI! */
|
||||
DEVLINK_ATTR_UNSPEC,
|
||||
@ -553,6 +571,11 @@ enum devlink_attr {
|
||||
|
||||
DEVLINK_ATTR_REGION_MAX_SNAPSHOTS, /* u32 */
|
||||
|
||||
DEVLINK_ATTR_LINECARD_INDEX, /* u32 */
|
||||
DEVLINK_ATTR_LINECARD_STATE, /* u8 */
|
||||
DEVLINK_ATTR_LINECARD_TYPE, /* string */
|
||||
DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES, /* nested */
|
||||
|
||||
/* add new attributes above here, update the policy in devlink.c */
|
||||
|
||||
__DEVLINK_ATTR_MAX,
|
||||
|
@ -211,6 +211,9 @@ struct rtnl_link_stats {
|
||||
* @rx_nohandler: Number of packets received on the interface
|
||||
* but dropped by the networking stack because the device is
|
||||
* not designated to receive packets (e.g. backup link in a bond).
|
||||
*
|
||||
* @rx_otherhost_dropped: Number of packets dropped due to mismatch
|
||||
* in destination MAC address.
|
||||
*/
|
||||
struct rtnl_link_stats64 {
|
||||
__u64 rx_packets;
|
||||
@ -243,6 +246,8 @@ struct rtnl_link_stats64 {
|
||||
__u64 rx_compressed;
|
||||
__u64 tx_compressed;
|
||||
__u64 rx_nohandler;
|
||||
|
||||
__u64 rx_otherhost_dropped;
|
||||
};
|
||||
|
||||
/* Subset of link stats useful for in-HW collection. Meaning of the fields is as
|
||||
@ -363,6 +368,8 @@ enum {
|
||||
IFLA_PARENT_DEV_NAME,
|
||||
IFLA_PARENT_DEV_BUS_NAME,
|
||||
IFLA_GRO_MAX_SIZE,
|
||||
IFLA_TSO_MAX_SIZE,
|
||||
IFLA_TSO_MAX_SEGS,
|
||||
|
||||
__IFLA_MAX
|
||||
};
|
||||
|
@ -53,6 +53,9 @@ enum {
|
||||
MPTCP_PM_ATTR_ADDR, /* nested address */
|
||||
MPTCP_PM_ATTR_RCV_ADD_ADDRS, /* u32 */
|
||||
MPTCP_PM_ATTR_SUBFLOWS, /* u32 */
|
||||
MPTCP_PM_ATTR_TOKEN, /* u32 */
|
||||
MPTCP_PM_ATTR_LOC_ID, /* u8 */
|
||||
MPTCP_PM_ATTR_ADDR_REMOTE, /* nested address */
|
||||
|
||||
__MPTCP_PM_ATTR_MAX
|
||||
};
|
||||
@ -91,6 +94,10 @@ enum {
|
||||
MPTCP_PM_CMD_SET_LIMITS,
|
||||
MPTCP_PM_CMD_GET_LIMITS,
|
||||
MPTCP_PM_CMD_SET_FLAGS,
|
||||
MPTCP_PM_CMD_ANNOUNCE,
|
||||
MPTCP_PM_CMD_REMOVE,
|
||||
MPTCP_PM_CMD_SUBFLOW_CREATE,
|
||||
MPTCP_PM_CMD_SUBFLOW_DESTROY,
|
||||
|
||||
__MPTCP_PM_CMD_AFTER_LAST
|
||||
};
|
||||
@ -186,6 +193,7 @@ enum mptcp_event_attr {
|
||||
MPTCP_ATTR_IF_IDX, /* s32 */
|
||||
MPTCP_ATTR_RESET_REASON,/* u32 */
|
||||
MPTCP_ATTR_RESET_FLAGS, /* u32 */
|
||||
MPTCP_ATTR_SERVER_SIDE, /* u8 */
|
||||
|
||||
__MPTCP_ATTR_AFTER_LAST
|
||||
};
|
||||
|
@ -32,6 +32,8 @@ enum {
|
||||
NDA_NH_ID,
|
||||
NDA_FDB_EXT_ATTRS,
|
||||
NDA_FLAGS_EXT,
|
||||
NDA_NDM_STATE_MASK,
|
||||
NDA_NDM_FLAGS_MASK,
|
||||
__NDA_MAX
|
||||
};
|
||||
|
||||
|
@ -72,6 +72,7 @@ struct nlmsghdr {
|
||||
|
||||
/* Modifiers to DELETE request */
|
||||
#define NLM_F_NONREC 0x100 /* Do not delete recursively */
|
||||
#define NLM_F_BULK 0x200 /* Delete multiple objects */
|
||||
|
||||
/* Flags for ACK message */
|
||||
#define NLM_F_CAPPED 0x100 /* request was capped */
|
||||
|
@ -587,6 +587,8 @@ enum {
|
||||
TCA_FLOWER_KEY_HASH, /* u32 */
|
||||
TCA_FLOWER_KEY_HASH_MASK, /* u32 */
|
||||
|
||||
TCA_FLOWER_KEY_NUM_OF_VLANS, /* u8 */
|
||||
|
||||
__TCA_FLOWER_MAX,
|
||||
};
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#define SKBEDIT_F_PTYPE 0x8
|
||||
#define SKBEDIT_F_MASK 0x10
|
||||
#define SKBEDIT_F_INHERITDSFIELD 0x20
|
||||
#define SKBEDIT_F_TXQ_SKBHASH 0x40
|
||||
|
||||
struct tc_skbedit {
|
||||
tc_gen;
|
||||
@ -45,6 +46,7 @@ enum {
|
||||
TCA_SKBEDIT_PTYPE,
|
||||
TCA_SKBEDIT_MASK,
|
||||
TCA_SKBEDIT_FLAGS,
|
||||
TCA_SKBEDIT_QUEUE_MAPPING_MAX,
|
||||
__TCA_SKBEDIT_MAX
|
||||
};
|
||||
#define TCA_SKBEDIT_MAX (__TCA_SKBEDIT_MAX - 1)
|
||||
|
@ -39,6 +39,7 @@
|
||||
/* TLS socket options */
|
||||
#define TLS_TX 1 /* Set transmit parameters */
|
||||
#define TLS_RX 2 /* Set receive parameters */
|
||||
#define TLS_TX_ZEROCOPY_SENDFILE 3 /* transmit zerocopy sendfile */
|
||||
|
||||
/* Supported versions */
|
||||
#define TLS_VERSION_MINOR(ver) ((ver) & 0xFF)
|
||||
@ -160,6 +161,7 @@ enum {
|
||||
TLS_INFO_CIPHER,
|
||||
TLS_INFO_TXCONF,
|
||||
TLS_INFO_RXCONF,
|
||||
TLS_INFO_ZC_SENDFILE,
|
||||
__TLS_INFO_MAX,
|
||||
};
|
||||
#define TLS_INFO_MAX (__TLS_INFO_MAX - 1)
|
||||
|
@ -21,6 +21,9 @@
|
||||
#define __bitwise
|
||||
#endif
|
||||
|
||||
/* The kernel doesn't use this legacy form, but user space does */
|
||||
#define __bitwise__ __bitwise
|
||||
|
||||
typedef __u16 __bitwise __le16;
|
||||
typedef __u16 __bitwise __be16;
|
||||
typedef __u32 __bitwise __le32;
|
||||
|
@ -12,7 +12,8 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.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 iplink_wwan.o ipioam6.o \
|
||||
iplink_amt.o iplink_batadv.o iplink_gtp.o
|
||||
iplink_amt.o iplink_batadv.o iplink_gtp.o iplink_virt_wifi.o \
|
||||
ipstats.o
|
||||
|
||||
RTMONOBJ=rtmon.o
|
||||
|
||||
|
1
ip/ip.c
1
ip/ip.c
@ -123,6 +123,7 @@ static const struct cmd {
|
||||
{ "mptcp", do_mptcp },
|
||||
{ "ioam", do_ioam6 },
|
||||
{ "help", do_help },
|
||||
{ "stats", do_ipstats },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
#define _IP_COMMON_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <linux/mpls.h>
|
||||
|
||||
#include "json_print.h"
|
||||
|
||||
@ -57,6 +58,7 @@ int print_nexthop_bucket(struct nlmsghdr *n, void *arg);
|
||||
void netns_map_init(void);
|
||||
void netns_nsid_socket_init(void);
|
||||
int print_nsid(struct nlmsghdr *n, void *arg);
|
||||
int ipstats_print(struct nlmsghdr *n, void *arg);
|
||||
char *get_name_from_nsid(int nsid);
|
||||
int get_netnsid_from_name(const char *name);
|
||||
int set_netnsid_from_name(const char *name, int nsid);
|
||||
@ -90,6 +92,7 @@ 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 do_ipstats(int argc, char **argv);
|
||||
|
||||
int iplink_get(char *name, __u32 filt_mask);
|
||||
int iplink_ifla_xstats(int argc, char **argv);
|
||||
@ -139,9 +142,14 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type);
|
||||
void br_dump_bridge_id(const struct ifla_bridge_id *id, char *buf, size_t len);
|
||||
int bridge_parse_xstats(struct link_util *lu, int argc, char **argv);
|
||||
int bridge_print_xstats(struct nlmsghdr *n, void *arg);
|
||||
extern const struct ipstats_stat_desc ipstats_stat_desc_xstats_bridge_group;
|
||||
extern const struct ipstats_stat_desc ipstats_stat_desc_xstats_slave_bridge_group;
|
||||
|
||||
/* iplink_bond.c */
|
||||
int bond_parse_xstats(struct link_util *lu, int argc, char **argv);
|
||||
int bond_print_xstats(struct nlmsghdr *n, void *arg);
|
||||
extern const struct ipstats_stat_desc ipstats_stat_desc_xstats_bond_group;
|
||||
extern const struct ipstats_stat_desc ipstats_stat_desc_xstats_slave_bond_group;
|
||||
|
||||
/* iproute_lwtunnel.c */
|
||||
int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp,
|
||||
@ -157,6 +165,46 @@ void xdp_dump(FILE *fp, struct rtattr *tb, bool link, bool details);
|
||||
__u32 ipvrf_get_table(const char *name);
|
||||
int name_is_vrf(const char *name);
|
||||
|
||||
/* ipstats.c */
|
||||
enum ipstats_stat_desc_kind {
|
||||
IPSTATS_STAT_DESC_KIND_LEAF,
|
||||
IPSTATS_STAT_DESC_KIND_GROUP,
|
||||
};
|
||||
|
||||
struct ipstats_stat_dump_filters;
|
||||
struct ipstats_stat_show_attrs;
|
||||
|
||||
struct ipstats_stat_desc {
|
||||
const char *name;
|
||||
enum ipstats_stat_desc_kind kind;
|
||||
union {
|
||||
struct {
|
||||
const struct ipstats_stat_desc **subs;
|
||||
size_t nsubs;
|
||||
};
|
||||
struct {
|
||||
void (*pack)(struct ipstats_stat_dump_filters *filters,
|
||||
const struct ipstats_stat_desc *desc);
|
||||
int (*show)(struct ipstats_stat_show_attrs *attrs,
|
||||
const struct ipstats_stat_desc *desc);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
struct ipstats_stat_desc_xstats {
|
||||
const struct ipstats_stat_desc desc;
|
||||
int xstats_at;
|
||||
int link_type_at;
|
||||
int inner_max;
|
||||
int inner_at;
|
||||
void (*show_cb)(const struct rtattr *at);
|
||||
};
|
||||
|
||||
void ipstats_stat_desc_pack_xstats(struct ipstats_stat_dump_filters *filters,
|
||||
const struct ipstats_stat_desc *desc);
|
||||
int ipstats_stat_desc_show_xstats(struct ipstats_stat_show_attrs *attrs,
|
||||
const struct ipstats_stat_desc *desc);
|
||||
|
||||
#ifndef INFINITY_LIFE_TIME
|
||||
#define INFINITY_LIFE_TIME 0xFFFFFFFFU
|
||||
#endif
|
||||
@ -171,4 +219,9 @@ 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);
|
||||
void size_columns(unsigned int cols[], unsigned int n, ...);
|
||||
void print_stats64(FILE *fp, struct rtnl_link_stats64 *s,
|
||||
const struct rtattr *carrier_changes, const char *what);
|
||||
void print_mpls_link_stats(FILE *fp, const struct mpls_link_stats *stats,
|
||||
const char *indent);
|
||||
#endif /* _IP_COMMON_H_ */
|
||||
|
@ -546,7 +546,7 @@ 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, ...)
|
||||
void size_columns(unsigned int cols[], unsigned int n, ...)
|
||||
{
|
||||
unsigned int i, len;
|
||||
uint64_t val, powi;
|
||||
@ -680,10 +680,10 @@ static void print_vf_stats64(FILE *fp, struct rtattr *vfstats)
|
||||
}
|
||||
}
|
||||
|
||||
static void __print_link_stats(FILE *fp, struct rtattr *tb[])
|
||||
void print_stats64(FILE *fp, struct rtnl_link_stats64 *s,
|
||||
const struct rtattr *carrier_changes,
|
||||
const char *what)
|
||||
{
|
||||
const struct rtattr *carrier_changes = tb[IFLA_CARRIER_CHANGES];
|
||||
struct rtnl_link_stats64 _s, *s = &_s;
|
||||
unsigned int cols[] = {
|
||||
strlen("*X errors:"),
|
||||
strlen("packets"),
|
||||
@ -693,14 +693,10 @@ static void __print_link_stats(FILE *fp, struct rtattr *tb[])
|
||||
strlen("overrun"),
|
||||
strlen("compressed"),
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = get_rtnl_link_stats_rta(s, tb);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
if (is_json_context()) {
|
||||
open_json_object((ret == sizeof(*s)) ? "stats64" : "stats");
|
||||
if (what)
|
||||
open_json_object(what);
|
||||
|
||||
/* RX stats */
|
||||
open_json_object("rx");
|
||||
@ -771,7 +767,8 @@ static void __print_link_stats(FILE *fp, struct rtattr *tb[])
|
||||
}
|
||||
|
||||
close_json_object();
|
||||
close_json_object();
|
||||
if (what)
|
||||
close_json_object();
|
||||
} else {
|
||||
size_columns(cols, ARRAY_SIZE(cols),
|
||||
s->rx_bytes, s->rx_packets, s->rx_errors,
|
||||
@ -870,6 +867,20 @@ static void __print_link_stats(FILE *fp, struct rtattr *tb[])
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
int ret;
|
||||
|
||||
ret = get_rtnl_link_stats_rta(s, tb);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
print_stats64(fp, s, carrier_changes,
|
||||
(ret == sizeof(*s)) ? "stats64" : "stats");
|
||||
}
|
||||
|
||||
static void print_link_stats(FILE *fp, struct nlmsghdr *n)
|
||||
{
|
||||
struct ifinfomsg *ifi = NLMSG_DATA(n);
|
||||
|
80
ip/iplink.c
80
ip/iplink.c
@ -54,7 +54,7 @@ void iplink_types_usage(void)
|
||||
" macsec | macvlan | macvtap |\n"
|
||||
" netdevsim | nlmon | rmnet | sit | team | team_slave |\n"
|
||||
" vcan | veth | vlan | vrf | vti | vxcan | vxlan | wwan |\n"
|
||||
" xfrm }\n");
|
||||
" xfrm | virt_wifi }\n");
|
||||
}
|
||||
|
||||
void iplink_usage(void)
|
||||
@ -1514,6 +1514,65 @@ static int do_set(int argc, char **argv)
|
||||
}
|
||||
#endif /* IPLINK_IOCTL_COMPAT */
|
||||
|
||||
void print_mpls_link_stats(FILE *fp, const struct mpls_link_stats *stats,
|
||||
const char *indent)
|
||||
{
|
||||
unsigned int cols[] = {
|
||||
strlen("*X: bytes"),
|
||||
strlen("packets"),
|
||||
strlen("errors"),
|
||||
strlen("dropped"),
|
||||
strlen("noroute"),
|
||||
};
|
||||
|
||||
if (is_json_context()) {
|
||||
/* RX stats */
|
||||
open_json_object("rx");
|
||||
print_u64(PRINT_JSON, "bytes", NULL, stats->rx_bytes);
|
||||
print_u64(PRINT_JSON, "packets", NULL, stats->rx_packets);
|
||||
print_u64(PRINT_JSON, "errors", NULL, stats->rx_errors);
|
||||
print_u64(PRINT_JSON, "dropped", NULL, stats->rx_dropped);
|
||||
print_u64(PRINT_JSON, "noroute", NULL, stats->rx_noroute);
|
||||
close_json_object();
|
||||
|
||||
/* TX stats */
|
||||
open_json_object("tx");
|
||||
print_u64(PRINT_JSON, "bytes", NULL, stats->tx_bytes);
|
||||
print_u64(PRINT_JSON, "packets", NULL, stats->tx_packets);
|
||||
print_u64(PRINT_JSON, "errors", NULL, stats->tx_errors);
|
||||
print_u64(PRINT_JSON, "dropped", NULL, stats->tx_dropped);
|
||||
close_json_object();
|
||||
} else {
|
||||
size_columns(cols, ARRAY_SIZE(cols), stats->rx_bytes,
|
||||
stats->rx_packets, stats->rx_errors,
|
||||
stats->rx_dropped, stats->rx_noroute);
|
||||
size_columns(cols, ARRAY_SIZE(cols), stats->tx_bytes,
|
||||
stats->tx_packets, stats->tx_errors,
|
||||
stats->tx_dropped, 0);
|
||||
|
||||
fprintf(fp, "%sRX: %*s %*s %*s %*s %*s%s", indent,
|
||||
cols[0] - 4, "bytes", cols[1], "packets",
|
||||
cols[2], "errors", cols[3], "dropped",
|
||||
cols[4], "noroute", _SL_);
|
||||
fprintf(fp, "%s", indent);
|
||||
print_num(fp, cols[0], stats->rx_bytes);
|
||||
print_num(fp, cols[1], stats->rx_packets);
|
||||
print_num(fp, cols[2], stats->rx_errors);
|
||||
print_num(fp, cols[3], stats->rx_dropped);
|
||||
print_num(fp, cols[4], stats->rx_noroute);
|
||||
fprintf(fp, "\n");
|
||||
|
||||
fprintf(fp, "%sTX: %*s %*s %*s %*s%s", indent,
|
||||
cols[0] - 4, "bytes", cols[1], "packets",
|
||||
cols[2], "errors", cols[3], "dropped", _SL_);
|
||||
fprintf(fp, "%s", indent);
|
||||
print_num(fp, cols[0], stats->tx_bytes);
|
||||
print_num(fp, cols[1], stats->tx_packets);
|
||||
print_num(fp, cols[2], stats->tx_errors);
|
||||
print_num(fp, cols[3], stats->tx_dropped);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_mpls_stats(FILE *fp, struct rtattr *attr)
|
||||
{
|
||||
struct rtattr *mrtb[MPLS_STATS_MAX+1];
|
||||
@ -1525,22 +1584,8 @@ static void print_mpls_stats(FILE *fp, struct rtattr *attr)
|
||||
return;
|
||||
|
||||
stats = RTA_DATA(mrtb[MPLS_STATS_LINK]);
|
||||
|
||||
fprintf(fp, " mpls:\n");
|
||||
fprintf(fp, " RX: bytes packets errors dropped noroute\n");
|
||||
fprintf(fp, " ");
|
||||
print_num(fp, 10, stats->rx_bytes);
|
||||
print_num(fp, 8, stats->rx_packets);
|
||||
print_num(fp, 7, stats->rx_errors);
|
||||
print_num(fp, 8, stats->rx_dropped);
|
||||
print_num(fp, 7, stats->rx_noroute);
|
||||
fprintf(fp, "\n");
|
||||
fprintf(fp, " TX: bytes packets errors dropped\n");
|
||||
fprintf(fp, " ");
|
||||
print_num(fp, 10, stats->tx_bytes);
|
||||
print_num(fp, 8, stats->tx_packets);
|
||||
print_num(fp, 7, stats->tx_errors);
|
||||
print_num(fp, 7, stats->tx_dropped);
|
||||
print_mpls_link_stats(fp, stats, " ");
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
@ -1641,7 +1686,8 @@ static int iplink_afstats(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (rtnl_statsdump_req_filter(&rth, AF_UNSPEC, filt_mask) < 0) {
|
||||
if (rtnl_statsdump_req_filter(&rth, AF_UNSPEC, filt_mask,
|
||||
NULL, NULL) < 0) {
|
||||
perror("Cannont send dump request");
|
||||
return 1;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <string.h>
|
||||
#include <linux/if_bonding.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "rt_names.h"
|
||||
#include "utils.h"
|
||||
#include "ip_common.h"
|
||||
@ -761,7 +762,7 @@ static void bond_print_xstats_help(struct link_util *lu, FILE *f)
|
||||
fprintf(f, "Usage: ... %s [ 802.3ad ] [ dev DEVICE ]\n", lu->id);
|
||||
}
|
||||
|
||||
static void bond_print_3ad_stats(struct rtattr *lacpattr)
|
||||
static void bond_print_3ad_stats(const struct rtattr *lacpattr)
|
||||
{
|
||||
struct rtattr *lacptb[BOND_3AD_STAT_MAX+1];
|
||||
__u64 val;
|
||||
@ -912,7 +913,6 @@ int bond_parse_xstats(struct link_util *lu, int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct link_util bond_link_util = {
|
||||
.id = "bond",
|
||||
.maxattr = IFLA_BOND_MAX,
|
||||
@ -922,3 +922,54 @@ struct link_util bond_link_util = {
|
||||
.parse_ifla_xstats = bond_parse_xstats,
|
||||
.print_ifla_xstats = bond_print_xstats,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc ipstats_stat_desc_bond_tmpl_lacp = {
|
||||
.name = "802.3ad",
|
||||
.kind = IPSTATS_STAT_DESC_KIND_LEAF,
|
||||
.show = &ipstats_stat_desc_show_xstats,
|
||||
.pack = &ipstats_stat_desc_pack_xstats,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc_xstats
|
||||
ipstats_stat_desc_xstats_bond_lacp = {
|
||||
.desc = ipstats_stat_desc_bond_tmpl_lacp,
|
||||
.xstats_at = IFLA_STATS_LINK_XSTATS,
|
||||
.link_type_at = LINK_XSTATS_TYPE_BOND,
|
||||
.inner_max = BOND_XSTATS_MAX,
|
||||
.inner_at = BOND_XSTATS_3AD,
|
||||
.show_cb = &bond_print_3ad_stats,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc *
|
||||
ipstats_stat_desc_xstats_bond_subs[] = {
|
||||
&ipstats_stat_desc_xstats_bond_lacp.desc,
|
||||
};
|
||||
|
||||
const struct ipstats_stat_desc ipstats_stat_desc_xstats_bond_group = {
|
||||
.name = "bond",
|
||||
.kind = IPSTATS_STAT_DESC_KIND_GROUP,
|
||||
.subs = ipstats_stat_desc_xstats_bond_subs,
|
||||
.nsubs = ARRAY_SIZE(ipstats_stat_desc_xstats_bond_subs),
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc_xstats
|
||||
ipstats_stat_desc_xstats_slave_bond_lacp = {
|
||||
.desc = ipstats_stat_desc_bond_tmpl_lacp,
|
||||
.xstats_at = IFLA_STATS_LINK_XSTATS_SLAVE,
|
||||
.link_type_at = LINK_XSTATS_TYPE_BOND,
|
||||
.inner_max = BOND_XSTATS_MAX,
|
||||
.inner_at = BOND_XSTATS_3AD,
|
||||
.show_cb = &bond_print_3ad_stats,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc *
|
||||
ipstats_stat_desc_xstats_slave_bond_subs[] = {
|
||||
&ipstats_stat_desc_xstats_slave_bond_lacp.desc,
|
||||
};
|
||||
|
||||
const struct ipstats_stat_desc ipstats_stat_desc_xstats_slave_bond_group = {
|
||||
.name = "bond",
|
||||
.kind = IPSTATS_STAT_DESC_KIND_GROUP,
|
||||
.subs = ipstats_stat_desc_xstats_slave_bond_subs,
|
||||
.nsubs = ARRAY_SIZE(ipstats_stat_desc_xstats_slave_bond_subs),
|
||||
};
|
||||
|
@ -714,11 +714,140 @@ static void bridge_print_xstats_help(struct link_util *lu, FILE *f)
|
||||
fprintf(f, "Usage: ... %s [ igmp ] [ dev DEVICE ]\n", lu->id);
|
||||
}
|
||||
|
||||
static void bridge_print_stats_mcast(const struct rtattr *attr)
|
||||
{
|
||||
struct br_mcast_stats *mstats;
|
||||
|
||||
mstats = RTA_DATA(attr);
|
||||
open_json_object("multicast");
|
||||
open_json_object("igmp_queries");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s IGMP queries:\n", "");
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
|
||||
mstats->igmp_v1queries[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v2", "v2 %llu ",
|
||||
mstats->igmp_v2queries[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v3", "v3 %llu\n",
|
||||
mstats->igmp_v3queries[BR_MCAST_DIR_RX]);
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
|
||||
mstats->igmp_v1queries[BR_MCAST_DIR_TX]);
|
||||
print_u64(PRINT_ANY, "tx_v2", "v2 %llu ",
|
||||
mstats->igmp_v2queries[BR_MCAST_DIR_TX]);
|
||||
print_u64(PRINT_ANY, "tx_v3", "v3 %llu\n",
|
||||
mstats->igmp_v3queries[BR_MCAST_DIR_TX]);
|
||||
close_json_object();
|
||||
|
||||
open_json_object("igmp_reports");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s IGMP reports:\n", "");
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
|
||||
mstats->igmp_v1reports[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v2", "v2 %llu ",
|
||||
mstats->igmp_v2reports[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v3", "v3 %llu\n",
|
||||
mstats->igmp_v3reports[BR_MCAST_DIR_RX]);
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
|
||||
mstats->igmp_v1reports[BR_MCAST_DIR_TX]);
|
||||
print_u64(PRINT_ANY, "tx_v2", "v2 %llu ",
|
||||
mstats->igmp_v2reports[BR_MCAST_DIR_TX]);
|
||||
print_u64(PRINT_ANY, "tx_v3", "v3 %llu\n",
|
||||
mstats->igmp_v3reports[BR_MCAST_DIR_TX]);
|
||||
close_json_object();
|
||||
|
||||
open_json_object("igmp_leaves");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s IGMP leaves: ", "");
|
||||
print_u64(PRINT_ANY, "rx", "RX: %llu ",
|
||||
mstats->igmp_leaves[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "tx", "TX: %llu\n",
|
||||
mstats->igmp_leaves[BR_MCAST_DIR_TX]);
|
||||
close_json_object();
|
||||
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s IGMP parse errors: ", "");
|
||||
print_u64(PRINT_ANY, "igmp_parse_errors", "%llu\n",
|
||||
mstats->igmp_parse_errors);
|
||||
|
||||
open_json_object("mld_queries");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s MLD queries:\n", "");
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
|
||||
mstats->mld_v1queries[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v2", "v2 %llu\n",
|
||||
mstats->mld_v2queries[BR_MCAST_DIR_RX]);
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
|
||||
mstats->mld_v1queries[BR_MCAST_DIR_TX]);
|
||||
print_u64(PRINT_ANY, "tx_v2", "v2 %llu\n",
|
||||
mstats->mld_v2queries[BR_MCAST_DIR_TX]);
|
||||
close_json_object();
|
||||
|
||||
open_json_object("mld_reports");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s MLD reports:\n", "");
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
|
||||
mstats->mld_v1reports[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v2", "v2 %llu\n",
|
||||
mstats->mld_v2reports[BR_MCAST_DIR_RX]);
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
|
||||
mstats->mld_v1reports[BR_MCAST_DIR_TX]);
|
||||
print_u64(PRINT_ANY, "tx_v2", "v2 %llu\n",
|
||||
mstats->mld_v2reports[BR_MCAST_DIR_TX]);
|
||||
close_json_object();
|
||||
|
||||
open_json_object("mld_leaves");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s MLD leaves: ", "");
|
||||
print_u64(PRINT_ANY, "rx", "RX: %llu ",
|
||||
mstats->mld_leaves[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "tx", "TX: %llu\n",
|
||||
mstats->mld_leaves[BR_MCAST_DIR_TX]);
|
||||
close_json_object();
|
||||
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s MLD parse errors: ", "");
|
||||
print_u64(PRINT_ANY, "mld_parse_errors", "%llu\n",
|
||||
mstats->mld_parse_errors);
|
||||
close_json_object();
|
||||
}
|
||||
|
||||
static void bridge_print_stats_stp(const struct rtattr *attr)
|
||||
{
|
||||
struct bridge_stp_xstats *sstats;
|
||||
|
||||
sstats = RTA_DATA(attr);
|
||||
open_json_object("stp");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s STP BPDU: ", "");
|
||||
print_u64(PRINT_ANY, "rx_bpdu", "RX: %llu ",
|
||||
sstats->rx_bpdu);
|
||||
print_u64(PRINT_ANY, "tx_bpdu", "TX: %llu\n",
|
||||
sstats->tx_bpdu);
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s STP TCN: ", "");
|
||||
print_u64(PRINT_ANY, "rx_tcn", "RX: %llu ",
|
||||
sstats->rx_tcn);
|
||||
print_u64(PRINT_ANY, "tx_tcn", "TX: %llu\n",
|
||||
sstats->tx_tcn);
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s STP Transitions: ", "");
|
||||
print_u64(PRINT_ANY, "transition_blk", "Blocked: %llu ",
|
||||
sstats->transition_blk);
|
||||
print_u64(PRINT_ANY, "transition_fwd", "Forwarding: %llu\n",
|
||||
sstats->transition_fwd);
|
||||
close_json_object();
|
||||
}
|
||||
|
||||
static void bridge_print_stats_attr(struct rtattr *attr, int ifindex)
|
||||
{
|
||||
struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1];
|
||||
struct bridge_stp_xstats *sstats;
|
||||
struct br_mcast_stats *mstats;
|
||||
struct rtattr *i, *list;
|
||||
const char *ifname = "";
|
||||
int rem;
|
||||
@ -738,127 +867,10 @@ static void bridge_print_stats_attr(struct rtattr *attr, int ifindex)
|
||||
continue;
|
||||
switch (i->rta_type) {
|
||||
case BRIDGE_XSTATS_MCAST:
|
||||
mstats = RTA_DATA(i);
|
||||
open_json_object("multicast");
|
||||
open_json_object("igmp_queries");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s IGMP queries:\n", "");
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
|
||||
mstats->igmp_v1queries[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v2", "v2 %llu ",
|
||||
mstats->igmp_v2queries[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v3", "v3 %llu\n",
|
||||
mstats->igmp_v3queries[BR_MCAST_DIR_RX]);
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
|
||||
mstats->igmp_v1queries[BR_MCAST_DIR_TX]);
|
||||
print_u64(PRINT_ANY, "tx_v2", "v2 %llu ",
|
||||
mstats->igmp_v2queries[BR_MCAST_DIR_TX]);
|
||||
print_u64(PRINT_ANY, "tx_v3", "v3 %llu\n",
|
||||
mstats->igmp_v3queries[BR_MCAST_DIR_TX]);
|
||||
close_json_object();
|
||||
|
||||
open_json_object("igmp_reports");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s IGMP reports:\n", "");
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
|
||||
mstats->igmp_v1reports[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v2", "v2 %llu ",
|
||||
mstats->igmp_v2reports[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v3", "v3 %llu\n",
|
||||
mstats->igmp_v3reports[BR_MCAST_DIR_RX]);
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
|
||||
mstats->igmp_v1reports[BR_MCAST_DIR_TX]);
|
||||
print_u64(PRINT_ANY, "tx_v2", "v2 %llu ",
|
||||
mstats->igmp_v2reports[BR_MCAST_DIR_TX]);
|
||||
print_u64(PRINT_ANY, "tx_v3", "v3 %llu\n",
|
||||
mstats->igmp_v3reports[BR_MCAST_DIR_TX]);
|
||||
close_json_object();
|
||||
|
||||
open_json_object("igmp_leaves");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s IGMP leaves: ", "");
|
||||
print_u64(PRINT_ANY, "rx", "RX: %llu ",
|
||||
mstats->igmp_leaves[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "tx", "TX: %llu\n",
|
||||
mstats->igmp_leaves[BR_MCAST_DIR_TX]);
|
||||
close_json_object();
|
||||
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s IGMP parse errors: ", "");
|
||||
print_u64(PRINT_ANY, "igmp_parse_errors", "%llu\n",
|
||||
mstats->igmp_parse_errors);
|
||||
|
||||
open_json_object("mld_queries");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s MLD queries:\n", "");
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
|
||||
mstats->mld_v1queries[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v2", "v2 %llu\n",
|
||||
mstats->mld_v2queries[BR_MCAST_DIR_RX]);
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
|
||||
mstats->mld_v1queries[BR_MCAST_DIR_TX]);
|
||||
print_u64(PRINT_ANY, "tx_v2", "v2 %llu\n",
|
||||
mstats->mld_v2queries[BR_MCAST_DIR_TX]);
|
||||
close_json_object();
|
||||
|
||||
open_json_object("mld_reports");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s MLD reports:\n", "");
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "rx_v1", "RX: v1 %llu ",
|
||||
mstats->mld_v1reports[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "rx_v2", "v2 %llu\n",
|
||||
mstats->mld_v2reports[BR_MCAST_DIR_RX]);
|
||||
print_string(PRINT_FP, NULL, "%-16s ", "");
|
||||
print_u64(PRINT_ANY, "tx_v1", "TX: v1 %llu ",
|
||||
mstats->mld_v1reports[BR_MCAST_DIR_TX]);
|
||||
print_u64(PRINT_ANY, "tx_v2", "v2 %llu\n",
|
||||
mstats->mld_v2reports[BR_MCAST_DIR_TX]);
|
||||
close_json_object();
|
||||
|
||||
open_json_object("mld_leaves");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s MLD leaves: ", "");
|
||||
print_u64(PRINT_ANY, "rx", "RX: %llu ",
|
||||
mstats->mld_leaves[BR_MCAST_DIR_RX]);
|
||||
print_u64(PRINT_ANY, "tx", "TX: %llu\n",
|
||||
mstats->mld_leaves[BR_MCAST_DIR_TX]);
|
||||
close_json_object();
|
||||
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s MLD parse errors: ", "");
|
||||
print_u64(PRINT_ANY, "mld_parse_errors", "%llu\n",
|
||||
mstats->mld_parse_errors);
|
||||
close_json_object();
|
||||
bridge_print_stats_mcast(i);
|
||||
break;
|
||||
case BRIDGE_XSTATS_STP:
|
||||
sstats = RTA_DATA(i);
|
||||
open_json_object("stp");
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s STP BPDU: ", "");
|
||||
print_u64(PRINT_ANY, "rx_bpdu", "RX: %llu ",
|
||||
sstats->rx_bpdu);
|
||||
print_u64(PRINT_ANY, "tx_bpdu", "TX: %llu\n",
|
||||
sstats->tx_bpdu);
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s STP TCN: ", "");
|
||||
print_u64(PRINT_ANY, "rx_tcn", "RX: %llu ",
|
||||
sstats->rx_tcn);
|
||||
print_u64(PRINT_ANY, "tx_tcn", "TX: %llu\n",
|
||||
sstats->tx_tcn);
|
||||
print_string(PRINT_FP, NULL,
|
||||
"%-16s STP Transitions: ", "");
|
||||
print_u64(PRINT_ANY, "transition_blk", "Blocked: %llu ",
|
||||
sstats->transition_blk);
|
||||
print_u64(PRINT_ANY, "transition_fwd", "Forwarding: %llu\n",
|
||||
sstats->transition_fwd);
|
||||
close_json_object();
|
||||
bridge_print_stats_stp(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -924,3 +936,83 @@ struct link_util bridge_link_util = {
|
||||
.parse_ifla_xstats = bridge_parse_xstats,
|
||||
.print_ifla_xstats = bridge_print_xstats,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc ipstats_stat_desc_bridge_tmpl_stp = {
|
||||
.name = "stp",
|
||||
.kind = IPSTATS_STAT_DESC_KIND_LEAF,
|
||||
.show = &ipstats_stat_desc_show_xstats,
|
||||
.pack = &ipstats_stat_desc_pack_xstats,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc ipstats_stat_desc_bridge_tmpl_mcast = {
|
||||
.name = "mcast",
|
||||
.kind = IPSTATS_STAT_DESC_KIND_LEAF,
|
||||
.show = &ipstats_stat_desc_show_xstats,
|
||||
.pack = &ipstats_stat_desc_pack_xstats,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc_xstats
|
||||
ipstats_stat_desc_xstats_bridge_stp = {
|
||||
.desc = ipstats_stat_desc_bridge_tmpl_stp,
|
||||
.xstats_at = IFLA_STATS_LINK_XSTATS,
|
||||
.link_type_at = LINK_XSTATS_TYPE_BRIDGE,
|
||||
.inner_max = BRIDGE_XSTATS_MAX,
|
||||
.inner_at = BRIDGE_XSTATS_STP,
|
||||
.show_cb = &bridge_print_stats_stp,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc_xstats
|
||||
ipstats_stat_desc_xstats_bridge_mcast = {
|
||||
.desc = ipstats_stat_desc_bridge_tmpl_mcast,
|
||||
.xstats_at = IFLA_STATS_LINK_XSTATS,
|
||||
.link_type_at = LINK_XSTATS_TYPE_BRIDGE,
|
||||
.inner_max = BRIDGE_XSTATS_MAX,
|
||||
.inner_at = BRIDGE_XSTATS_MCAST,
|
||||
.show_cb = &bridge_print_stats_mcast,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc *
|
||||
ipstats_stat_desc_xstats_bridge_subs[] = {
|
||||
&ipstats_stat_desc_xstats_bridge_stp.desc,
|
||||
&ipstats_stat_desc_xstats_bridge_mcast.desc,
|
||||
};
|
||||
|
||||
const struct ipstats_stat_desc ipstats_stat_desc_xstats_bridge_group = {
|
||||
.name = "bridge",
|
||||
.kind = IPSTATS_STAT_DESC_KIND_GROUP,
|
||||
.subs = ipstats_stat_desc_xstats_bridge_subs,
|
||||
.nsubs = ARRAY_SIZE(ipstats_stat_desc_xstats_bridge_subs),
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc_xstats
|
||||
ipstats_stat_desc_xstats_slave_bridge_stp = {
|
||||
.desc = ipstats_stat_desc_bridge_tmpl_stp,
|
||||
.xstats_at = IFLA_STATS_LINK_XSTATS_SLAVE,
|
||||
.link_type_at = LINK_XSTATS_TYPE_BRIDGE,
|
||||
.inner_max = BRIDGE_XSTATS_MAX,
|
||||
.inner_at = BRIDGE_XSTATS_STP,
|
||||
.show_cb = &bridge_print_stats_stp,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc_xstats
|
||||
ipstats_stat_desc_xstats_slave_bridge_mcast = {
|
||||
.desc = ipstats_stat_desc_bridge_tmpl_mcast,
|
||||
.xstats_at = IFLA_STATS_LINK_XSTATS_SLAVE,
|
||||
.link_type_at = LINK_XSTATS_TYPE_BRIDGE,
|
||||
.inner_max = BRIDGE_XSTATS_MAX,
|
||||
.inner_at = BRIDGE_XSTATS_MCAST,
|
||||
.show_cb = &bridge_print_stats_mcast,
|
||||
};
|
||||
|
||||
static const struct ipstats_stat_desc *
|
||||
ipstats_stat_desc_xstats_slave_bridge_subs[] = {
|
||||
&ipstats_stat_desc_xstats_slave_bridge_stp.desc,
|
||||
&ipstats_stat_desc_xstats_slave_bridge_mcast.desc,
|
||||
};
|
||||
|
||||
const struct ipstats_stat_desc ipstats_stat_desc_xstats_slave_bridge_group = {
|
||||
.name = "bridge",
|
||||
.kind = IPSTATS_STAT_DESC_KIND_GROUP,
|
||||
.subs = ipstats_stat_desc_xstats_slave_bridge_subs,
|
||||
.nsubs = ARRAY_SIZE(ipstats_stat_desc_xstats_slave_bridge_subs),
|
||||
};
|
||||
|
25
ip/iplink_virt_wifi.c
Normal file
25
ip/iplink_virt_wifi.c
Normal file
@ -0,0 +1,25 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* iplink_virt_wifi.c A fake implementation of cfg80211_ops that can be tacked
|
||||
* on to an ethernet net_device to make it appear as a
|
||||
* wireless connection.
|
||||
*
|
||||
* Authors: Baligh Gasmi <gasmibal@gmail.com>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "ip_common.h"
|
||||
|
||||
static void virt_wifi_print_help(struct link_util *lu,
|
||||
int argc, char **argv, FILE *f)
|
||||
{
|
||||
fprintf(f, "Usage: ... virt_wifi \n");
|
||||
}
|
||||
|
||||
struct link_util virt_wifi_link_util = {
|
||||
.id = "virt_wifi",
|
||||
.print_help = virt_wifi_print_help,
|
||||
};
|
@ -48,6 +48,7 @@ static void print_explain(FILE *f)
|
||||
" [ [no]udp6zerocsumrx ]\n"
|
||||
" [ [no]remcsumtx ] [ [no]remcsumrx ]\n"
|
||||
" [ [no]external ] [ gbp ] [ gpe ]\n"
|
||||
" [ [no]vnifilter ]\n"
|
||||
"\n"
|
||||
"Where: VNI := 0-16777215\n"
|
||||
" ADDR := { IP_ADDRESS | any }\n"
|
||||
@ -81,6 +82,7 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
|
||||
__u8 learning = 1;
|
||||
__u16 dstport = 0;
|
||||
__u8 metadata = 0;
|
||||
__u8 vnifilter = 0;
|
||||
__u64 attrs = 0;
|
||||
bool set_op = (n->nlmsg_type == RTM_NEWLINK &&
|
||||
!(n->nlmsg_flags & NLM_F_CREATE));
|
||||
@ -330,6 +332,15 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
|
||||
} else if (!matches(*argv, "gpe")) {
|
||||
check_duparg(&attrs, IFLA_VXLAN_GPE, *argv, *argv);
|
||||
addattr_l(n, 1024, IFLA_VXLAN_GPE, NULL, 0);
|
||||
} else if (!strcmp(*argv, "vnifilter")) {
|
||||
check_duparg(&attrs, IFLA_VXLAN_VNIFILTER,
|
||||
*argv, *argv);
|
||||
addattr8(n, 1024, IFLA_VXLAN_VNIFILTER, 1);
|
||||
vnifilter = 1;
|
||||
} else if (!strcmp(*argv, "novnifilter")) {
|
||||
check_duparg(&attrs, IFLA_VXLAN_VNIFILTER,
|
||||
*argv, *argv);
|
||||
addattr8(n, 1024, IFLA_VXLAN_VNIFILTER, 0);
|
||||
} else if (matches(*argv, "help") == 0) {
|
||||
explain();
|
||||
return -1;
|
||||
@ -341,12 +352,17 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
|
||||
argc--, argv++;
|
||||
}
|
||||
|
||||
if (!metadata && vnifilter) {
|
||||
fprintf(stderr, "vxlan: vnifilter is valid only when 'external' is set\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (metadata && VXLAN_ATTRSET(attrs, IFLA_VXLAN_ID)) {
|
||||
fprintf(stderr, "vxlan: both 'external' and vni cannot be specified\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!metadata && !VXLAN_ATTRSET(attrs, IFLA_VXLAN_ID) && !set_op) {
|
||||
if (!metadata && !vnifilter && !VXLAN_ATTRSET(attrs, IFLA_VXLAN_ID) && !set_op) {
|
||||
fprintf(stderr, "vxlan: missing virtual network identifier\n");
|
||||
return -1;
|
||||
}
|
||||
@ -420,6 +436,11 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
|
||||
print_bool(PRINT_ANY, "external", "external ", true);
|
||||
}
|
||||
|
||||
if (tb[IFLA_VXLAN_VNIFILTER] &&
|
||||
rta_getattr_u8(tb[IFLA_VXLAN_VNIFILTER])) {
|
||||
print_bool(PRINT_ANY, "vnifilter", "vnifilter", true);
|
||||
}
|
||||
|
||||
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]));
|
||||
|
@ -65,7 +65,8 @@ int iplink_ifla_xstats(int argc, char **argv)
|
||||
else
|
||||
filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS);
|
||||
|
||||
if (rtnl_statsdump_req_filter(&rth, AF_UNSPEC, filt_mask) < 0) {
|
||||
if (rtnl_statsdump_req_filter(&rth, AF_UNSPEC, filt_mask,
|
||||
NULL, NULL) < 0) {
|
||||
perror("Cannont send dump request");
|
||||
return -1;
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ static void usage(void)
|
||||
"Usage: ip monitor [ all | OBJECTS ] [ FILE ] [ label ] [ all-nsid ]\n"
|
||||
" [ dev DEVICE ]\n"
|
||||
"OBJECTS := address | link | mroute | neigh | netconf |\n"
|
||||
" nexthop | nsid | prefix | route | rule\n"
|
||||
" nexthop | nsid | prefix | route | rule | stats\n"
|
||||
"FILE := file FILENAME\n");
|
||||
exit(-1);
|
||||
}
|
||||
@ -158,6 +158,11 @@ static int accept_msg(struct rtnl_ctrl_data *ctrl,
|
||||
print_nsid(n, arg);
|
||||
return 0;
|
||||
|
||||
case RTM_NEWSTATS:
|
||||
print_headers(fp, "[STATS]", ctrl);
|
||||
ipstats_print(n, arg);
|
||||
return 0;
|
||||
|
||||
case NLMSG_ERROR:
|
||||
case NLMSG_NOOP:
|
||||
case NLMSG_DONE:
|
||||
@ -185,6 +190,7 @@ int do_ipmonitor(int argc, char **argv)
|
||||
int lprefix = 0;
|
||||
int lneigh = 0;
|
||||
int lnetconf = 0;
|
||||
int lstats = 0;
|
||||
int lrule = 0;
|
||||
int lnsid = 0;
|
||||
int ifindex = 0;
|
||||
@ -253,6 +259,9 @@ int do_ipmonitor(int argc, char **argv)
|
||||
} else if (matches(*argv, "nexthop") == 0) {
|
||||
lnexthop = 1;
|
||||
groups = 0;
|
||||
} else if (strcmp(*argv, "stats") == 0) {
|
||||
lstats = 1;
|
||||
groups = 0;
|
||||
} else if (strcmp(*argv, "all") == 0) {
|
||||
prefix_banner = 1;
|
||||
} else if (matches(*argv, "all-nsid") == 0) {
|
||||
@ -349,6 +358,11 @@ int do_ipmonitor(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (lstats && rtnl_add_nl_group(&rth, RTNLGRP_STATS) < 0) {
|
||||
fprintf(stderr, "Failed to add stats group to list\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (listen_all_nsid && rtnl_listen_all_nsid(&rth) < 0)
|
||||
exit(1);
|
||||
|
||||
|
1356
ip/ipstats.c
Normal file
1356
ip/ipstats.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -619,12 +619,13 @@ int rtnl_fdb_linkdump_req_filter_fn(struct rtnl_handle *rth,
|
||||
return send(rth->fd, &req, sizeof(req), 0);
|
||||
}
|
||||
|
||||
int rtnl_statsdump_req_filter(struct rtnl_handle *rth, int fam, __u32 filt_mask)
|
||||
int rtnl_statsdump_req_filter(struct rtnl_handle *rth, int fam,
|
||||
__u32 filt_mask,
|
||||
int (*filter_fn)(struct ipstats_req *req,
|
||||
void *data),
|
||||
void *filter_data)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct if_stats_msg ifsm;
|
||||
} req;
|
||||
struct ipstats_req req;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct if_stats_msg));
|
||||
@ -635,6 +636,14 @@ int rtnl_statsdump_req_filter(struct rtnl_handle *rth, int fam, __u32 filt_mask)
|
||||
req.ifsm.family = fam;
|
||||
req.ifsm.filter_mask = filt_mask;
|
||||
|
||||
if (filter_fn) {
|
||||
int err;
|
||||
|
||||
err = filter_fn(&req, filter_data);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return send(rth->fd, &req, sizeof(req), 0);
|
||||
}
|
||||
|
||||
@ -1600,3 +1609,23 @@ void nl_print_policy(const struct rtattr *attr, FILE *fp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int rtnl_tunneldump_req(struct rtnl_handle *rth, int family, int ifindex,
|
||||
__u8 flags)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct tunnel_msg tmsg;
|
||||
char buf[256];
|
||||
} req = {
|
||||
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tunnel_msg)),
|
||||
.nlh.nlmsg_type = RTM_GETTUNNEL,
|
||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||
.tmsg.family = family,
|
||||
.tmsg.flags = flags,
|
||||
.tmsg.ifindex = ifindex,
|
||||
};
|
||||
|
||||
return send(rth->fd, &req, sizeof(req), 0);
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ bridge \- show / manipulate bridge addresses and devices
|
||||
|
||||
.ti -8
|
||||
.IR OBJECT " := { "
|
||||
.BR link " | " fdb " | " mdb " | " vlan " | " monitor " }"
|
||||
.BR link " | " fdb " | " mdb " | " vlan " | " vni " | " monitor " }"
|
||||
.sp
|
||||
|
||||
.ti -8
|
||||
@ -196,6 +196,25 @@ bridge \- show / manipulate bridge addresses and devices
|
||||
.B vid
|
||||
.IR VID " ]"
|
||||
|
||||
.ti -8
|
||||
.BR "bridge vlan" " show " [ "
|
||||
.B dev
|
||||
.IR DEV " ]"
|
||||
|
||||
.ti -8
|
||||
.BR "bridge vni" " { " add " | " del " } "
|
||||
.B dev
|
||||
.I DEV
|
||||
.B vni
|
||||
.IR VNI " [ { "
|
||||
.B group | remote "} "
|
||||
.IR IPADDR " ] "
|
||||
|
||||
.ti -8
|
||||
.BR "bridge vni" " show " [ "
|
||||
.B dev
|
||||
.IR DEV " ]"
|
||||
|
||||
.ti -8
|
||||
.BR "bridge monitor" " [ " all " | " neigh " | " link " | " mdb " | " vlan " ]"
|
||||
|
||||
@ -303,6 +322,10 @@ the output.
|
||||
.B vlan
|
||||
- VLAN filter list.
|
||||
|
||||
.TP
|
||||
.B vni
|
||||
- VNI filter list.
|
||||
|
||||
.SS
|
||||
.I COMMAND
|
||||
|
||||
@ -1084,6 +1107,58 @@ all bridge interfaces.
|
||||
the VLAN ID only whose global options should be listed. Default is to list
|
||||
all vlans.
|
||||
|
||||
.SH bridge vni - VNI filter list
|
||||
|
||||
.B vni
|
||||
objects contain known VNI IDs for a dst metadata vxlan link.
|
||||
|
||||
.P
|
||||
The corresponding commands display vni filter entries, add new entries,
|
||||
and delete old ones.
|
||||
|
||||
.SS bridge vni add - add a new vni filter entry
|
||||
|
||||
This command creates a new vni filter entry.
|
||||
|
||||
.TP
|
||||
.BI dev " NAME"
|
||||
the interface with which this vni is associated.
|
||||
|
||||
.TP
|
||||
.BI vni " VNI"
|
||||
the VNI ID that identifies the vni.
|
||||
|
||||
.TP
|
||||
.BI remote " IPADDR"
|
||||
specifies the unicast destination IP address to use in outgoing packets
|
||||
when the destination link layer address is not known in the VXLAN device
|
||||
forwarding database. This parameter cannot be specified with the group.
|
||||
|
||||
.TP
|
||||
.BI group " IPADDR"
|
||||
specifies the multicast IP address to join for this VNI
|
||||
|
||||
.SS bridge vni del - delete a new vni filter entry
|
||||
|
||||
This command removes an existing vni filter entry.
|
||||
|
||||
.PP
|
||||
The arguments are the same as with
|
||||
.BR "bridge vni add".
|
||||
|
||||
.SS bridge vni show - list vni filtering configuration.
|
||||
|
||||
This command displays the current vni filter table.
|
||||
|
||||
.PP
|
||||
With the
|
||||
.B -statistics
|
||||
option, the command displays per-vni traffic statistics.
|
||||
|
||||
.TP
|
||||
.BI dev " NAME"
|
||||
shows vni filtering table associated with the vxlan device
|
||||
|
||||
.SH bridge monitor - state monitoring
|
||||
|
||||
The
|
||||
|
@ -63,6 +63,10 @@ Switches to the specified network namespace.
|
||||
.BR "\-i", " --iec"
|
||||
Print human readable rates in IEC units (e.g. 1Ki = 1024).
|
||||
|
||||
.TP
|
||||
.BR "\-x", " --hex"
|
||||
Print dump numbers in hexadecimal format.
|
||||
|
||||
.SS
|
||||
.I OBJECT
|
||||
|
||||
|
@ -209,42 +209,43 @@ ip-link \- network device configuration
|
||||
.ti -8
|
||||
.IR TYPE " := [ "
|
||||
.BR amt " | "
|
||||
.BR bridge " | "
|
||||
.BR bareudp " |"
|
||||
.BR bond " | "
|
||||
.BR bridge " | "
|
||||
.BR can " | "
|
||||
.BR dummy " | "
|
||||
.BR hsr " | "
|
||||
.BR ifb " | "
|
||||
.BR ipoib " |"
|
||||
.BR macvlan " | "
|
||||
.BR macvtap " | "
|
||||
.BR vcan " | "
|
||||
.BR vxcan " | "
|
||||
.BR veth " | "
|
||||
.BR vlan " | "
|
||||
.BR vxlan " |"
|
||||
.BR ip6tnl " |"
|
||||
.BR ipip " |"
|
||||
.BR sit " |"
|
||||
.BR erspan " |"
|
||||
.BR geneve " |"
|
||||
.BR gre " |"
|
||||
.BR gretap " |"
|
||||
.BR erspan " |"
|
||||
.BR gtp " |"
|
||||
.BR hsr " | "
|
||||
.BR ifb " | "
|
||||
.BR ip6erspan " |"
|
||||
.BR ip6gre " |"
|
||||
.BR ip6gretap " |"
|
||||
.BR ip6erspan " |"
|
||||
.BR vti " |"
|
||||
.BR nlmon " |"
|
||||
.BR ip6tnl " |"
|
||||
.BR ipip " |"
|
||||
.BR ipoib " |"
|
||||
.BR ipvlan " |"
|
||||
.BR ipvtap " |"
|
||||
.BR lowpan " |"
|
||||
.BR geneve " |"
|
||||
.BR bareudp " |"
|
||||
.BR vrf " |"
|
||||
.BR macsec " |"
|
||||
.BR macvlan " | "
|
||||
.BR macvtap " | "
|
||||
.BR netdevsim " |"
|
||||
.BR nlmon " |"
|
||||
.BR rmnet " |"
|
||||
.BR xfrm " |"
|
||||
.BR gtp " ]"
|
||||
.BR sit " |"
|
||||
.BR vcan " | "
|
||||
.BR veth " | "
|
||||
.BR virt_wifi " |"
|
||||
.BR vlan " | "
|
||||
.BR vrf " |"
|
||||
.BR vti " |"
|
||||
.BR vxcan " | "
|
||||
.BR vxlan " |"
|
||||
.BR xfrm " ]"
|
||||
|
||||
.ti -8
|
||||
.IR ETYPE " := [ " TYPE " |"
|
||||
@ -289,62 +290,46 @@ specifies the type of the new device.
|
||||
Link types:
|
||||
|
||||
.in +8
|
||||
.B bridge
|
||||
- Ethernet Bridge device
|
||||
.BR amt
|
||||
- Automatic Multicast Tunneling (AMT)
|
||||
.sp
|
||||
.BR bareudp
|
||||
- Bare UDP L3 encapsulation support
|
||||
.sp
|
||||
.B bond
|
||||
- Bonding device
|
||||
.B bridge
|
||||
- Ethernet Bridge device
|
||||
.sp
|
||||
.B can
|
||||
- Controller Area Network
|
||||
.sp
|
||||
.B dummy
|
||||
- Dummy network interface
|
||||
.sp
|
||||
.BR erspan
|
||||
- Encapsulated Remote SPAN over GRE and IPv4
|
||||
.sp
|
||||
.B geneve
|
||||
- GEneric NEtwork Virtualization Encapsulation
|
||||
.sp
|
||||
.B gre
|
||||
- Virtual tunnel interface GRE over IPv4
|
||||
.sp
|
||||
.BR gretap
|
||||
- Virtual L2 tunnel interface GRE over IPv4
|
||||
.sp
|
||||
.BR gtp
|
||||
- GPRS Tunneling Protocol
|
||||
.sp
|
||||
.B hsr
|
||||
- High-availability Seamless Redundancy device
|
||||
.sp
|
||||
.B ifb
|
||||
- Intermediate Functional Block device
|
||||
.sp
|
||||
.B ipoib
|
||||
- IP over Infiniband device
|
||||
.sp
|
||||
.B macvlan
|
||||
- Virtual interface base on link layer address (MAC)
|
||||
.sp
|
||||
.B macvtap
|
||||
- Virtual interface based on link layer address (MAC) and TAP.
|
||||
.sp
|
||||
.B vcan
|
||||
- Virtual Controller Area Network interface
|
||||
.sp
|
||||
.B vxcan
|
||||
- Virtual Controller Area Network tunnel interface
|
||||
.sp
|
||||
.B veth
|
||||
- Virtual ethernet interface
|
||||
.sp
|
||||
.BR vlan
|
||||
- 802.1q tagged virtual LAN interface
|
||||
.sp
|
||||
.BR vxlan
|
||||
- Virtual eXtended LAN
|
||||
.sp
|
||||
.BR ip6tnl
|
||||
- Virtual tunnel interface IPv4|IPv6 over IPv6
|
||||
.sp
|
||||
.BR ipip
|
||||
- Virtual tunnel interface IPv4 over IPv4
|
||||
.sp
|
||||
.BR sit
|
||||
- Virtual tunnel interface IPv6 over IPv4
|
||||
.sp
|
||||
.BR gre
|
||||
- Virtual tunnel interface GRE over IPv4
|
||||
.sp
|
||||
.BR gretap
|
||||
- Virtual L2 tunnel interface GRE over IPv4
|
||||
.sp
|
||||
.BR erspan
|
||||
- Encapsulated Remote SPAN over GRE and IPv4
|
||||
.BR ip6erspan
|
||||
- Encapsulated Remote SPAN over GRE and IPv6
|
||||
.sp
|
||||
.BR ip6gre
|
||||
- Virtual tunnel interface GRE over IPv6
|
||||
@ -352,14 +337,14 @@ Link types:
|
||||
.BR ip6gretap
|
||||
- Virtual L2 tunnel interface GRE over IPv6
|
||||
.sp
|
||||
.BR ip6erspan
|
||||
- Encapsulated Remote SPAN over GRE and IPv6
|
||||
.BR ip6tnl
|
||||
- Virtual tunnel interface IPv4|IPv6 over IPv6
|
||||
.sp
|
||||
.BR vti
|
||||
- Virtual tunnel interface
|
||||
.BR ipip
|
||||
- Virtual tunnel interface IPv4 over IPv4
|
||||
.sp
|
||||
.BR nlmon
|
||||
- Netlink monitoring device
|
||||
.B ipoib
|
||||
- IP over Infiniband device
|
||||
.sp
|
||||
.BR ipvlan
|
||||
- Interface for L3 (IPv6/IPv4) based VLANs
|
||||
@ -370,32 +355,54 @@ Link types:
|
||||
.BR lowpan
|
||||
- Interface for 6LoWPAN (IPv6) over IEEE 802.15.4 / Bluetooth
|
||||
.sp
|
||||
.BR geneve
|
||||
- GEneric NEtwork Virtualization Encapsulation
|
||||
.sp
|
||||
.BR bareudp
|
||||
- Bare UDP L3 encapsulation support
|
||||
.sp
|
||||
.BR amt
|
||||
- Automatic Multicast Tunneling (AMT)
|
||||
.sp
|
||||
.BR macsec
|
||||
- Interface for IEEE 802.1AE MAC Security (MACsec)
|
||||
.sp
|
||||
.BR vrf
|
||||
- Interface for L3 VRF domains
|
||||
.B macvlan
|
||||
- Virtual interface base on link layer address (MAC)
|
||||
.sp
|
||||
.B macvtap
|
||||
- Virtual interface based on link layer address (MAC) and TAP.
|
||||
.sp
|
||||
.BR netdevsim
|
||||
- Interface for netdev API tests
|
||||
.sp
|
||||
.BR nlmon
|
||||
- Netlink monitoring device
|
||||
.sp
|
||||
.BR rmnet
|
||||
- Qualcomm rmnet device
|
||||
.sp
|
||||
.BR sit
|
||||
- Virtual tunnel interface IPv6 over IPv4
|
||||
.sp
|
||||
.B vcan
|
||||
- Virtual Controller Area Network interface
|
||||
.sp
|
||||
.B veth
|
||||
- Virtual ethernet interface
|
||||
.sp
|
||||
.BR virt_wifi
|
||||
- rtnetlink wifi simulation device
|
||||
.sp
|
||||
.BR vlan
|
||||
- 802.1q tagged virtual LAN interface
|
||||
.sp
|
||||
.BR vrf
|
||||
- Interface for L3 VRF domains
|
||||
.sp
|
||||
.BR vti
|
||||
- Virtual tunnel interface
|
||||
.sp
|
||||
.B vxcan
|
||||
- Virtual Controller Area Network tunnel interface
|
||||
.sp
|
||||
.BR vxlan
|
||||
- Virtual eXtended LAN
|
||||
.sp
|
||||
.BR xfrm
|
||||
- Virtual xfrm interface
|
||||
.sp
|
||||
.BR gtp
|
||||
- GPRS Tunneling Protocol
|
||||
.in -8
|
||||
|
||||
.TP
|
||||
@ -594,6 +601,8 @@ the following additional arguments are supported:
|
||||
.B gbp
|
||||
] [
|
||||
.B gpe
|
||||
] [
|
||||
.RB [ no ] vnifilter
|
||||
]
|
||||
|
||||
.in +8
|
||||
@ -705,6 +714,13 @@ are entered into the VXLAN device forwarding database.
|
||||
.RB "(e.g. " "ip route encap" )
|
||||
or the internal FDB should be used.
|
||||
|
||||
.sp
|
||||
.RB [ no ] vnifilter
|
||||
- specifies whether the vxlan device is capable of vni filtering. Only works with a vxlan
|
||||
device with external flag set. once enabled, bridge vni command is used to manage the
|
||||
vni filtering table on the device. The device can only receive packets with vni's configured
|
||||
in the vni filtering table.
|
||||
|
||||
.sp
|
||||
.B gbp
|
||||
- enables the Group Policy extension (VXLAN-GBP).
|
||||
|
@ -55,7 +55,7 @@ command is the first in the command line and then the object list follows:
|
||||
is the list of object types that we want to monitor.
|
||||
It may contain
|
||||
.BR link ", " address ", " route ", " mroute ", " prefix ", "
|
||||
.BR neigh ", " netconf ", " rule ", " nsid " and " nexthop "."
|
||||
.BR neigh ", " netconf ", " rule ", " stats ", " nsid " and " nexthop "."
|
||||
If no
|
||||
.B file
|
||||
argument is given,
|
||||
|
208
man/man8/ip-stats.8
Normal file
208
man/man8/ip-stats.8
Normal file
@ -0,0 +1,208 @@
|
||||
.TH IP\-STATS 8 "16 Mar 2022" "iproute2" "Linux"
|
||||
.SH NAME
|
||||
ip-stats \- manage and show interface statistics
|
||||
.SH SYNOPSIS
|
||||
.sp
|
||||
.ad l
|
||||
.in +8
|
||||
.ti -8
|
||||
.B ip
|
||||
.B stats
|
||||
.RI " { " COMMAND " | "
|
||||
.BR help " }"
|
||||
.sp
|
||||
|
||||
.ti -8
|
||||
.BR "ip stats show"
|
||||
.RB "[ " dev
|
||||
.IR DEV " ] "
|
||||
.RB "[ " group
|
||||
.IR GROUP " [ "
|
||||
.BI subgroup " SUBGROUP"
|
||||
.RB " [ " suite
|
||||
.IR " SUITE" " ] ... ] ... ] ..."
|
||||
|
||||
.ti -8
|
||||
.BR "ip stats set"
|
||||
.BI dev " DEV"
|
||||
.BR l3_stats " { "
|
||||
.BR on " | " off " }"
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
.TP
|
||||
.B ip stats set
|
||||
is used for toggling whether a certain HW statistics suite is collected on
|
||||
a given netdevice. The following statistics suites are supported:
|
||||
|
||||
.in 21
|
||||
|
||||
.ti 14
|
||||
.B l3_stats
|
||||
L3 stats reflect traffic that takes place in a HW device on an object that
|
||||
corresponds to the given software netdevice.
|
||||
|
||||
.TP
|
||||
.B ip stats show
|
||||
is used for showing stats on a given netdevice, or dumping statistics
|
||||
across all netdevices. By default, all stats are requested. It is possible
|
||||
to filter which stats are requested by using the
|
||||
.B group
|
||||
and
|
||||
.B subgroup
|
||||
keywords.
|
||||
|
||||
It is possible to specify several groups, or several subgroups for one
|
||||
group. When no subgroups are given for a group, all the subgroups are
|
||||
requested.
|
||||
|
||||
The following groups are recognized:
|
||||
.in 21
|
||||
|
||||
.ti 14
|
||||
.B group link
|
||||
- Link statistics. The same suite that "ip -s link show" shows.
|
||||
|
||||
.ti 14
|
||||
.B group offload
|
||||
- A group that contains a number of HW-oriented statistics. See below for
|
||||
individual subgroups within this group.
|
||||
|
||||
.ti 14
|
||||
.B group xstats
|
||||
- Extended statistics. A subgroup identifies the type of netdevice to show the
|
||||
statistics for.
|
||||
|
||||
.ti 14
|
||||
.B group xstats_slave
|
||||
- Extended statistics for the slave of a netdevice of a given type. A subgroup
|
||||
identifies the type of master netdevice.
|
||||
|
||||
.ti 14
|
||||
.B group afstats
|
||||
- A group for address-family specific netdevice statistics.
|
||||
|
||||
.TQ
|
||||
.BR "group offload " subgroups:
|
||||
.in 21
|
||||
|
||||
.ti 14
|
||||
.B subgroup cpu_hit
|
||||
- The
|
||||
.B cpu_hit
|
||||
statistics suite is useful on hardware netdevices. The
|
||||
.B link
|
||||
statistics on these devices reflect both the hardware- and
|
||||
software-datapath traffic. The
|
||||
.B cpu_hit
|
||||
statistics then only reflect software-datapath traffic.
|
||||
|
||||
.ti 14
|
||||
.B subgroup hw_stats_info
|
||||
- This suite does not include traffic statistics, but rather communicates
|
||||
the state of other statistics. Through this subgroup, it is possible to
|
||||
discover whether a given statistic was enabled, and when it was, whether
|
||||
any device driver actually configured its device to collect these
|
||||
statistics. For example,
|
||||
.B l3_stats
|
||||
was enabled in the following case, but no driver has installed it:
|
||||
|
||||
# ip stats show dev swp1 group offload subgroup hw_stats_info
|
||||
.br
|
||||
56: swp1: group offload subgroup hw_stats_info
|
||||
.br
|
||||
l3_stats on used off
|
||||
|
||||
After an L3 address is added to the netdevice, the counter will be
|
||||
installed:
|
||||
|
||||
# ip addr add dev swp1 192.0.2.1/28
|
||||
.br
|
||||
# ip stats show dev swp1 group offload subgroup hw_stats_info
|
||||
.br
|
||||
56: swp1: group offload subgroup hw_stats_info
|
||||
.br
|
||||
l3_stats on used on
|
||||
|
||||
.ti 14
|
||||
.B subgroup l3_stats
|
||||
- These statistics reflect L3 traffic that takes place in HW on an object
|
||||
that corresponds to the netdevice. Note that this suite is disabled by
|
||||
default and needs to be first enabled through
|
||||
.B ip stats set\fR.
|
||||
|
||||
For example:
|
||||
|
||||
# ip stats show dev swp2.200 group offload subgroup l3_stats
|
||||
.br
|
||||
112: swp2.200: group offload subgroup l3_stats on used on
|
||||
.br
|
||||
RX: bytes packets errors dropped mcast
|
||||
.br
|
||||
8900 72 2 0 3
|
||||
.br
|
||||
TX: bytes packets errors dropped
|
||||
.br
|
||||
7176 58 0 0
|
||||
|
||||
Note how the l3_stats_info for the selected group is also part of the dump.
|
||||
|
||||
.TQ
|
||||
.BR "group xstats " and " group xstats_slave " subgroups:
|
||||
.in 21
|
||||
|
||||
.ti 14
|
||||
.B subgroup bridge \fR[\fB suite stp \fR] [\fB suite mcast \fR]
|
||||
- Statistics for STP and, respectively, IGMP / MLD (under the keyword
|
||||
\fBmcast\fR) traffic on bridges and their slaves.
|
||||
|
||||
.ti 14
|
||||
.B subgroup bond \fR[\fB suite 802.3ad \fR]
|
||||
- Statistics for LACP traffic on bond devices and their slaves.
|
||||
|
||||
.TQ
|
||||
.BR "group afstats " subgroups:
|
||||
.in 21
|
||||
|
||||
.ti 14
|
||||
.B subgroup mpls
|
||||
- Statistics for MPLS traffic seen on the netdevice. For example:
|
||||
|
||||
# ip stats show dev veth01 group afstats subgroup mpls
|
||||
.br
|
||||
3: veth01: group afstats subgroup mpls
|
||||
.br
|
||||
RX: bytes packets errors dropped noroute
|
||||
.br
|
||||
0 0 0 0 0
|
||||
.br
|
||||
TX: bytes packets errors dropped
|
||||
.br
|
||||
216 2 0 0
|
||||
|
||||
.SH EXAMPLES
|
||||
.PP
|
||||
# ip stats set dev swp1 l3_stats on
|
||||
.RS
|
||||
Enables collection of L3 HW statistics on swp1.
|
||||
.RE
|
||||
|
||||
.PP
|
||||
# ip stats show group offload
|
||||
.RS
|
||||
Shows all offload statistics on all netdevices.
|
||||
.RE
|
||||
|
||||
.PP
|
||||
# ip stats show dev swp1 group link
|
||||
.RS
|
||||
Shows link statistics on the given netdevice.
|
||||
.RE
|
||||
|
||||
.SH SEE ALSO
|
||||
.br
|
||||
.BR ip (8),
|
||||
.BR ip-link (8),
|
||||
|
||||
.SH AUTHOR
|
||||
Manpage by Petr Machata.
|
@ -22,7 +22,7 @@ ip \- show / manipulate routing, network devices, interfaces and tunnels
|
||||
.BR link " | " address " | " addrlabel " | " route " | " rule " | " neigh " | "\
|
||||
ntable " | " tunnel " | " tuntap " | " maddress " | " mroute " | " mrule " | "\
|
||||
monitor " | " xfrm " | " netns " | " l2tp " | " tcp_metrics " | " token " | "\
|
||||
macsec " | " vrf " | " mptcp " | " ioam " }"
|
||||
macsec " | " vrf " | " mptcp " | " ioam " | " stats " }"
|
||||
.sp
|
||||
|
||||
.ti -8
|
||||
@ -302,6 +302,10 @@ readability.
|
||||
.B rule
|
||||
- rule in routing policy database.
|
||||
|
||||
.TP
|
||||
.B stats
|
||||
- manage and show interface statistics.
|
||||
|
||||
.TP
|
||||
.B tcp_metrics/tcpmetrics
|
||||
- manage TCP Metrics
|
||||
@ -419,6 +423,7 @@ was written by Alexey N. Kuznetsov and added in Linux 2.2.
|
||||
.BR ip-ntable (8),
|
||||
.BR ip-route (8),
|
||||
.BR ip-rule (8),
|
||||
.BR ip-stats (8)
|
||||
.BR ip-tcp_metrics (8),
|
||||
.BR ip-token (8),
|
||||
.BR ip-tunnel (8),
|
||||
|
@ -164,6 +164,11 @@ provided in LLADDR format, in which case it is a bitwise mask, or as a
|
||||
number of high bits to match. If the mask is missing then a match on all
|
||||
bits is assumed.
|
||||
.TP
|
||||
.BI num_of_vlans " NUM"
|
||||
Match on the number of vlan tags in the packet.
|
||||
.I NUM
|
||||
can be 0 or small positive integer. Typically in 0-4 range.
|
||||
.TP
|
||||
.BI vlan_id " VID"
|
||||
Match on vlan tag id.
|
||||
.I VID
|
||||
|
@ -202,7 +202,7 @@ static void load_info(void)
|
||||
ll_init_map(&rth);
|
||||
filter_mask = IFLA_STATS_FILTER_BIT(filter_type);
|
||||
if (rtnl_statsdump_req_filter(&rth, AF_UNSPEC,
|
||||
filter_mask) < 0) {
|
||||
filter_mask, NULL, NULL) < 0) {
|
||||
perror("Cannot send dump request");
|
||||
exit(1);
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ static void explain(void)
|
||||
"\n"
|
||||
"Where: MATCH-LIST := [ MATCH-LIST ] MATCH\n"
|
||||
" MATCH := { indev DEV-NAME |\n"
|
||||
" num_of_vlans VLANS_COUNT |\n"
|
||||
" vlan_id VID |\n"
|
||||
" vlan_prio PRIORITY |\n"
|
||||
" vlan_ethtype [ ipv4 | ipv6 | ETH-TYPE ] |\n"
|
||||
@ -159,21 +160,23 @@ err:
|
||||
return err;
|
||||
}
|
||||
|
||||
static bool eth_type_vlan(__be16 ethertype)
|
||||
static bool eth_type_vlan(__be16 ethertype, bool good_num_of_vlans)
|
||||
{
|
||||
return ethertype == htons(ETH_P_8021Q) ||
|
||||
ethertype == htons(ETH_P_8021AD);
|
||||
ethertype == htons(ETH_P_8021AD) ||
|
||||
good_num_of_vlans;
|
||||
}
|
||||
|
||||
static int flower_parse_vlan_eth_type(char *str, __be16 eth_type, int type,
|
||||
__be16 *p_vlan_eth_type,
|
||||
struct nlmsghdr *n)
|
||||
struct nlmsghdr *n, bool good_num_of_vlans)
|
||||
{
|
||||
__be16 vlan_eth_type;
|
||||
|
||||
if (!eth_type_vlan(eth_type)) {
|
||||
fprintf(stderr, "Can't set \"%s\" if ethertype isn't 802.1Q or 802.1AD\n",
|
||||
type == TCA_FLOWER_KEY_VLAN_ETH_TYPE ? "vlan_ethtype" : "cvlan_ethtype");
|
||||
if (!eth_type_vlan(eth_type, good_num_of_vlans)) {
|
||||
fprintf(stderr, "Can't set \"%s\" if ethertype isn't 802.1Q or 802.1AD and num_of_vlans %s\n",
|
||||
type == TCA_FLOWER_KEY_VLAN_ETH_TYPE ? "vlan_ethtype" : "cvlan_ethtype",
|
||||
type == TCA_FLOWER_KEY_VLAN_ETH_TYPE ? "is 0" : "less than 2");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1424,6 +1427,7 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
|
||||
__be16 tc_proto = TC_H_MIN(t->tcm_info);
|
||||
__be16 eth_type = tc_proto;
|
||||
__be16 vlan_ethtype = 0;
|
||||
__u8 num_of_vlans = 0;
|
||||
__u8 ip_proto = 0xff;
|
||||
__u32 flags = 0;
|
||||
__u32 mtf = 0;
|
||||
@ -1525,12 +1529,22 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
|
||||
if (check_ifname(*argv))
|
||||
invarg("\"indev\" not a valid ifname", *argv);
|
||||
addattrstrz(n, MAX_MSG, TCA_FLOWER_INDEV, *argv);
|
||||
} else if (strcmp(*argv, "num_of_vlans") == 0) {
|
||||
NEXT_ARG();
|
||||
ret = get_u8(&num_of_vlans, *argv, 10);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Illegal \"num_of_vlans\"\n");
|
||||
return -1;
|
||||
}
|
||||
addattr8(n, MAX_MSG,
|
||||
TCA_FLOWER_KEY_NUM_OF_VLANS, num_of_vlans);
|
||||
} else if (matches(*argv, "vlan_id") == 0) {
|
||||
__u16 vid;
|
||||
|
||||
NEXT_ARG();
|
||||
if (!eth_type_vlan(tc_proto)) {
|
||||
fprintf(stderr, "Can't set \"vlan_id\" if ethertype isn't 802.1Q or 802.1AD\n");
|
||||
if (!eth_type_vlan(tc_proto, num_of_vlans > 0)) {
|
||||
fprintf(stderr, "Can't set \"vlan_id\" if ethertype isn't 802.1Q or 802.1AD"
|
||||
" and num_of_vlans is 0\n");
|
||||
return -1;
|
||||
}
|
||||
ret = get_u16(&vid, *argv, 10);
|
||||
@ -1543,8 +1557,9 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
|
||||
__u8 vlan_prio;
|
||||
|
||||
NEXT_ARG();
|
||||
if (!eth_type_vlan(tc_proto)) {
|
||||
fprintf(stderr, "Can't set \"vlan_prio\" if ethertype isn't 802.1Q or 802.1AD\n");
|
||||
if (!eth_type_vlan(tc_proto, num_of_vlans > 0)) {
|
||||
fprintf(stderr, "Can't set \"vlan_prio\" if ethertype isn't 802.1Q or 802.1AD"
|
||||
" and num_of_vlans is 0\n");
|
||||
return -1;
|
||||
}
|
||||
ret = get_u8(&vlan_prio, *argv, 10);
|
||||
@ -1558,7 +1573,7 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
|
||||
NEXT_ARG();
|
||||
ret = flower_parse_vlan_eth_type(*argv, eth_type,
|
||||
TCA_FLOWER_KEY_VLAN_ETH_TYPE,
|
||||
&vlan_ethtype, n);
|
||||
&vlan_ethtype, n, num_of_vlans > 0);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
/* get new ethtype for later parsing */
|
||||
@ -1567,8 +1582,9 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
|
||||
__u16 vid;
|
||||
|
||||
NEXT_ARG();
|
||||
if (!eth_type_vlan(vlan_ethtype)) {
|
||||
fprintf(stderr, "Can't set \"cvlan_id\" if inner vlan ethertype isn't 802.1Q or 802.1AD\n");
|
||||
if (!eth_type_vlan(vlan_ethtype, num_of_vlans > 1)) {
|
||||
fprintf(stderr, "Can't set \"cvlan_id\" if inner vlan ethertype isn't 802.1Q or 802.1AD"
|
||||
" and num_of_vlans is less than 2\n");
|
||||
return -1;
|
||||
}
|
||||
ret = get_u16(&vid, *argv, 10);
|
||||
@ -1581,8 +1597,9 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
|
||||
__u8 cvlan_prio;
|
||||
|
||||
NEXT_ARG();
|
||||
if (!eth_type_vlan(vlan_ethtype)) {
|
||||
fprintf(stderr, "Can't set \"cvlan_prio\" if inner vlan ethertype isn't 802.1Q or 802.1AD\n");
|
||||
if (!eth_type_vlan(vlan_ethtype, num_of_vlans > 1)) {
|
||||
fprintf(stderr, "Can't set \"cvlan_prio\" if inner vlan ethertype isn't 802.1Q or 802.1AD"
|
||||
" and num_of_vlans is less than 2\n");
|
||||
return -1;
|
||||
}
|
||||
ret = get_u8(&cvlan_prio, *argv, 10);
|
||||
@ -1597,7 +1614,7 @@ static int flower_parse_opt(struct filter_util *qu, char *handle,
|
||||
/* get new ethtype for later parsing */
|
||||
ret = flower_parse_vlan_eth_type(*argv, vlan_ethtype,
|
||||
TCA_FLOWER_KEY_CVLAN_ETH_TYPE,
|
||||
ð_type, n);
|
||||
ð_type, n, num_of_vlans > 1);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
} else if (matches(*argv, "mpls") == 0) {
|
||||
@ -2694,6 +2711,14 @@ static int flower_print_opt(struct filter_util *qu, FILE *f,
|
||||
|
||||
open_json_object("keys");
|
||||
|
||||
if (tb[TCA_FLOWER_KEY_NUM_OF_VLANS]) {
|
||||
struct rtattr *attr = tb[TCA_FLOWER_KEY_NUM_OF_VLANS];
|
||||
|
||||
print_nl();
|
||||
print_uint(PRINT_ANY, "num_of_vlans", " num_of_vlans %d",
|
||||
rta_getattr_u8(attr));
|
||||
}
|
||||
|
||||
if (tb[TCA_FLOWER_KEY_VLAN_ID]) {
|
||||
struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_ID];
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user