Merge branch 'bridge-vlan' into next
Nikolay Aleksandrov says:
====================
From: Nikolay Aleksandrov <nikolay@nvidia.com>
This set extends the bridge vlan code to use the new vlan RTM calls
which allow to dump detailed per-port, per-vlan information and also to
manipulate the per-vlan options. It also allows to monitor any vlan
changes (add/del/option change). The rtm vlan dumps have an extensible
format which allows us to add new options and attributes easily, and
also to request the kernel to filter on different vlan information when
dumping. The new kernel dump code tries to use compressed vlan format as
much as possible (it includes netlink attributes for vlan start and
end) to reduce the number of generated messages and netlink traffic.
The iproute2 support is activated by using the "-d" flag when showing
vlan information, that will cause it to use the new rtm dump call and
get all the detailed information, if "-s" is also specified it will dump
per-vlan statistics as well. Obviously in that case the vlans cannot be
compressed. To change per-vlan options (currently only STP state is
supported) a new vlan command is added - "set". It can be used to set
options of bridge or port vlans and vlan ranges can be used, all of the
new vlan option code uses extack to show more understandable errors.
The set adds the first supported per-vlan option - STP state.
Man pages and usage information are updated accordingly.
Example:
$ bridge -d vlan show
port vlan-id
ens13 1 PVID Egress Untagged
state forwarding
bridge 1 PVID Egress Untagged
state forwarding
$ bridge vlan set vid 1 dev ens13 state blocking
$ bridge -d vlan show
port vlan-id
ens13 1 PVID Egress Untagged
state blocking
bridge 1 PVID Egress Untagged
state forwarding
====================
Signed-off-by: David Ahern <dsahern@kernel.org>
This commit is contained in:
commit
75a35d50a3
|
|
@ -10,6 +10,9 @@ void print_vlan_info(struct rtattr *tb, int ifindex);
|
|||
int print_linkinfo(struct nlmsghdr *n, void *arg);
|
||||
int print_mdb_mon(struct nlmsghdr *n, void *arg);
|
||||
int print_fdb(struct nlmsghdr *n, void *arg);
|
||||
void print_stp_state(__u8 state);
|
||||
int parse_stp_state(const char *arg);
|
||||
int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor);
|
||||
|
||||
int do_fdb(int argc, char **argv);
|
||||
int do_mdb(int argc, char **argv);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
static unsigned int filter_index;
|
||||
|
||||
static const char *port_states[] = {
|
||||
static const char *stp_states[] = {
|
||||
[BR_STATE_DISABLED] = "disabled",
|
||||
[BR_STATE_LISTENING] = "listening",
|
||||
[BR_STATE_LEARNING] = "learning",
|
||||
|
|
@ -68,16 +68,31 @@ static void print_link_flags(FILE *fp, unsigned int flags, unsigned int mdown)
|
|||
close_json_array(PRINT_ANY, "> ");
|
||||
}
|
||||
|
||||
static void print_portstate(__u8 state)
|
||||
void print_stp_state(__u8 state)
|
||||
{
|
||||
if (state <= BR_STATE_BLOCKING)
|
||||
print_string(PRINT_ANY, "state",
|
||||
"state %s ", port_states[state]);
|
||||
"state %s ", stp_states[state]);
|
||||
else
|
||||
print_uint(PRINT_ANY, "state",
|
||||
"state (%d) ", state);
|
||||
}
|
||||
|
||||
int parse_stp_state(const char *arg)
|
||||
{
|
||||
size_t nstates = ARRAY_SIZE(stp_states);
|
||||
int state;
|
||||
|
||||
for (state = 0; state < nstates; state++)
|
||||
if (strcmp(stp_states[state], arg) == 0)
|
||||
break;
|
||||
|
||||
if (state == nstates)
|
||||
state = -1;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static void print_hwmode(__u16 mode)
|
||||
{
|
||||
if (mode >= ARRAY_SIZE(hw_mode))
|
||||
|
|
@ -96,7 +111,7 @@ static void print_protinfo(FILE *fp, struct rtattr *attr)
|
|||
parse_rtattr_nested(prtb, IFLA_BRPORT_MAX, attr);
|
||||
|
||||
if (prtb[IFLA_BRPORT_STATE])
|
||||
print_portstate(rta_getattr_u8(prtb[IFLA_BRPORT_STATE]));
|
||||
print_stp_state(rta_getattr_u8(prtb[IFLA_BRPORT_STATE]));
|
||||
|
||||
if (prtb[IFLA_BRPORT_PRIORITY])
|
||||
print_uint(PRINT_ANY, "priority",
|
||||
|
|
@ -161,7 +176,7 @@ static void print_protinfo(FILE *fp, struct rtattr *attr)
|
|||
print_on_off(PRINT_ANY, "isolated", "isolated %s ",
|
||||
rta_getattr_u8(prtb[IFLA_BRPORT_ISOLATED]));
|
||||
} else
|
||||
print_portstate(rta_getattr_u8(attr));
|
||||
print_stp_state(rta_getattr_u8(attr));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -359,14 +374,11 @@ static int brlink_modify(int argc, char **argv)
|
|||
} else if (strcmp(*argv, "state") == 0) {
|
||||
NEXT_ARG();
|
||||
char *endptr;
|
||||
size_t nstates = ARRAY_SIZE(port_states);
|
||||
|
||||
state = strtol(*argv, &endptr, 10);
|
||||
if (!(**argv != '\0' && *endptr == '\0')) {
|
||||
for (state = 0; state < nstates; state++)
|
||||
if (strcasecmp(port_states[state], *argv) == 0)
|
||||
break;
|
||||
if (state == nstates) {
|
||||
state = parse_stp_state(*argv);
|
||||
if (state == -1) {
|
||||
fprintf(stderr,
|
||||
"Error: invalid STP port state\n");
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@
|
|||
#include <arpa/inet.h>
|
||||
|
||||
#include "libnetlink.h"
|
||||
#include "utils.h"
|
||||
#include "br_common.h"
|
||||
#include "rt_names.h"
|
||||
#include "utils.h"
|
||||
#include "json_print.h"
|
||||
|
||||
#ifndef MDBA_RTA
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ static int prefix_banner;
|
|||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: bridge monitor [file | link | fdb | mdb | all]\n");
|
||||
fprintf(stderr, "Usage: bridge monitor [file | link | fdb | mdb | vlan | all]\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
|
@ -67,6 +67,12 @@ static int accept_msg(struct rtnl_ctrl_data *ctrl,
|
|||
print_nlmsg_timestamp(fp, n);
|
||||
return 0;
|
||||
|
||||
case RTM_NEWVLAN:
|
||||
case RTM_DELVLAN:
|
||||
if (prefix_banner)
|
||||
fprintf(fp, "[VLAN]");
|
||||
return print_vlan_rtm(n, arg, true);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -79,6 +85,7 @@ int do_monitor(int argc, char **argv)
|
|||
int llink = 0;
|
||||
int lneigh = 0;
|
||||
int lmdb = 0;
|
||||
int lvlan = 0;
|
||||
|
||||
rtnl_close(&rth);
|
||||
|
||||
|
|
@ -95,8 +102,12 @@ int do_monitor(int argc, char **argv)
|
|||
} else if (matches(*argv, "mdb") == 0) {
|
||||
lmdb = 1;
|
||||
groups = 0;
|
||||
} else if (matches(*argv, "vlan") == 0) {
|
||||
lvlan = 1;
|
||||
groups = 0;
|
||||
} else if (strcmp(*argv, "all") == 0) {
|
||||
groups = ~RTMGRP_TC;
|
||||
lvlan = 1;
|
||||
prefix_banner = 1;
|
||||
} else if (matches(*argv, "help") == 0) {
|
||||
usage();
|
||||
|
|
@ -134,6 +145,12 @@ int do_monitor(int argc, char **argv)
|
|||
|
||||
if (rtnl_open(&rth, groups) < 0)
|
||||
exit(1);
|
||||
|
||||
if (lvlan && rtnl_add_nl_group(&rth, RTNLGRP_BRVLAN) < 0) {
|
||||
fprintf(stderr, "Failed to add bridge vlan group to list\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ll_init_map(&rth);
|
||||
|
||||
if (rtnl_listen(&rth, accept_msg, stdout) < 0)
|
||||
|
|
|
|||
255
bridge/vlan.c
255
bridge/vlan.c
|
|
@ -16,6 +16,7 @@
|
|||
#include "utils.h"
|
||||
|
||||
static unsigned int filter_index, filter_vlan;
|
||||
static int vlan_rtm_cur_ifidx = -1;
|
||||
|
||||
enum vlan_show_subject {
|
||||
VLAN_SHOW_VLAN,
|
||||
|
|
@ -33,6 +34,7 @@ static void usage(void)
|
|||
"Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ tunnel_info id TUNNEL_ID ]\n"
|
||||
" [ pvid ] [ untagged ]\n"
|
||||
" [ self ] [ master ]\n"
|
||||
" bridge vlan { set } vid VLAN_ID dev DEV [ state STP_STATE ]\n"
|
||||
" bridge vlan { show } [ dev DEV ] [ vid VLAN_ID ]\n"
|
||||
" bridge vlan { tunnelshow } [ dev DEV ] [ vid VLAN_ID ]\n");
|
||||
exit(-1);
|
||||
|
|
@ -241,6 +243,100 @@ static int vlan_modify(int cmd, int argc, char **argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int vlan_option_set(int argc, char **argv)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct br_vlan_msg bvm;
|
||||
char buf[1024];
|
||||
} req = {
|
||||
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_vlan_msg)),
|
||||
.n.nlmsg_flags = NLM_F_REQUEST,
|
||||
.n.nlmsg_type = RTM_NEWVLAN,
|
||||
.bvm.family = PF_BRIDGE,
|
||||
};
|
||||
struct bridge_vlan_info vinfo = {};
|
||||
struct rtattr *afspec;
|
||||
short vid_end = -1;
|
||||
char *d = NULL;
|
||||
short vid = -1;
|
||||
int state = -1;
|
||||
|
||||
while (argc > 0) {
|
||||
if (strcmp(*argv, "dev") == 0) {
|
||||
NEXT_ARG();
|
||||
d = *argv;
|
||||
} else if (strcmp(*argv, "vid") == 0) {
|
||||
char *p;
|
||||
|
||||
NEXT_ARG();
|
||||
p = strchr(*argv, '-');
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
p++;
|
||||
vid = atoi(*argv);
|
||||
vid_end = atoi(p);
|
||||
if (vid >= vid_end || vid_end >= 4096) {
|
||||
fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n",
|
||||
vid, vid_end);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
vid = atoi(*argv);
|
||||
}
|
||||
} else if (strcmp(*argv, "state") == 0) {
|
||||
char *endptr;
|
||||
|
||||
NEXT_ARG();
|
||||
state = strtol(*argv, &endptr, 10);
|
||||
if (!(**argv != '\0' && *endptr == '\0'))
|
||||
state = parse_stp_state(*argv);
|
||||
if (state == -1) {
|
||||
fprintf(stderr, "Error: invalid STP state\n");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (matches(*argv, "help") == 0)
|
||||
NEXT_ARG();
|
||||
}
|
||||
argc--; argv++;
|
||||
}
|
||||
|
||||
if (d == NULL || vid == -1) {
|
||||
fprintf(stderr, "Device and VLAN ID are required arguments.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
req.bvm.ifindex = ll_name_to_index(d);
|
||||
if (req.bvm.ifindex == 0) {
|
||||
fprintf(stderr, "Cannot find network device \"%s\"\n", d);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vid >= 4096) {
|
||||
fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid);
|
||||
return -1;
|
||||
}
|
||||
afspec = addattr_nest(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY);
|
||||
afspec->rta_type |= NLA_F_NESTED;
|
||||
|
||||
vinfo.flags = BRIDGE_VLAN_INFO_ONLY_OPTS;
|
||||
vinfo.vid = vid;
|
||||
addattr_l(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_INFO, &vinfo,
|
||||
sizeof(vinfo));
|
||||
if (vid_end != -1)
|
||||
addattr16(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_RANGE,
|
||||
vid_end);
|
||||
if (state >= 0)
|
||||
addattr8(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_STATE, state);
|
||||
addattr_nest_end(&req.n, afspec);
|
||||
|
||||
if (rtnl_talk(&rth, &req.n, NULL) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* In order to use this function for both filtering and non-filtering cases
|
||||
* we need to make it a tristate:
|
||||
* return -1 - if filtering we've gone over so don't continue
|
||||
|
|
@ -422,14 +518,8 @@ static void print_vlan_flags(__u16 flags)
|
|||
close_json_array(PRINT_JSON, NULL);
|
||||
}
|
||||
|
||||
static void print_one_vlan_stats(const struct bridge_vlan_xstats *vstats)
|
||||
static void __print_one_vlan_stats(const struct bridge_vlan_xstats *vstats)
|
||||
{
|
||||
open_json_object(NULL);
|
||||
|
||||
print_hu(PRINT_ANY, "vid", "%hu", vstats->vid);
|
||||
print_vlan_flags(vstats->flags);
|
||||
print_nl();
|
||||
|
||||
print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
|
||||
print_lluint(PRINT_ANY, "rx_bytes", "RX: %llu bytes",
|
||||
vstats->rx_bytes);
|
||||
|
|
@ -441,6 +531,16 @@ static void print_one_vlan_stats(const struct bridge_vlan_xstats *vstats)
|
|||
vstats->tx_bytes);
|
||||
print_lluint(PRINT_ANY, "tx_packets", " %llu packets\n",
|
||||
vstats->tx_packets);
|
||||
}
|
||||
|
||||
static void print_one_vlan_stats(const struct bridge_vlan_xstats *vstats)
|
||||
{
|
||||
open_json_object(NULL);
|
||||
|
||||
print_hu(PRINT_ANY, "vid", "%hu", vstats->vid);
|
||||
print_vlan_flags(vstats->flags);
|
||||
print_nl();
|
||||
__print_one_vlan_stats(vstats);
|
||||
|
||||
close_json_object();
|
||||
}
|
||||
|
|
@ -521,6 +621,116 @@ static int print_vlan_stats(struct nlmsghdr *n, void *arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor)
|
||||
{
|
||||
struct rtattr *vtb[BRIDGE_VLANDB_ENTRY_MAX + 1], *a;
|
||||
struct br_vlan_msg *bvm = NLMSG_DATA(n);
|
||||
int len = n->nlmsg_len;
|
||||
bool newport = false;
|
||||
int rem;
|
||||
|
||||
if (n->nlmsg_type != RTM_NEWVLAN && n->nlmsg_type != RTM_DELVLAN &&
|
||||
n->nlmsg_type != RTM_GETVLAN) {
|
||||
fprintf(stderr, "Unknown vlan rtm message: %08x %08x %08x\n",
|
||||
n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
len -= NLMSG_LENGTH(sizeof(*bvm));
|
||||
if (len < 0) {
|
||||
fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bvm->family != AF_BRIDGE)
|
||||
return 0;
|
||||
|
||||
if (filter_index && filter_index != bvm->ifindex)
|
||||
return 0;
|
||||
|
||||
if (n->nlmsg_type == RTM_DELVLAN)
|
||||
print_bool(PRINT_ANY, "deleted", "Deleted ", true);
|
||||
|
||||
if (monitor)
|
||||
vlan_rtm_cur_ifidx = -1;
|
||||
|
||||
if (vlan_rtm_cur_ifidx == -1 || vlan_rtm_cur_ifidx != bvm->ifindex) {
|
||||
if (vlan_rtm_cur_ifidx != -1)
|
||||
close_vlan_port();
|
||||
open_vlan_port(bvm->ifindex, VLAN_SHOW_VLAN);
|
||||
vlan_rtm_cur_ifidx = bvm->ifindex;
|
||||
newport = true;
|
||||
}
|
||||
|
||||
rem = len;
|
||||
for (a = BRVLAN_RTA(bvm); RTA_OK(a, rem); a = RTA_NEXT(a, rem)) {
|
||||
struct bridge_vlan_xstats vstats;
|
||||
struct bridge_vlan_info *vinfo;
|
||||
__u32 vrange = 0;
|
||||
__u8 state = 0;
|
||||
|
||||
parse_rtattr_flags(vtb, BRIDGE_VLANDB_ENTRY_MAX, RTA_DATA(a),
|
||||
RTA_PAYLOAD(a), NLA_F_NESTED);
|
||||
vinfo = RTA_DATA(vtb[BRIDGE_VLANDB_ENTRY_INFO]);
|
||||
|
||||
memset(&vstats, 0, sizeof(vstats));
|
||||
if (vtb[BRIDGE_VLANDB_ENTRY_RANGE])
|
||||
vrange = rta_getattr_u16(vtb[BRIDGE_VLANDB_ENTRY_RANGE]);
|
||||
else
|
||||
vrange = vinfo->vid;
|
||||
|
||||
if (vtb[BRIDGE_VLANDB_ENTRY_STATE])
|
||||
state = rta_getattr_u8(vtb[BRIDGE_VLANDB_ENTRY_STATE]);
|
||||
|
||||
if (vtb[BRIDGE_VLANDB_ENTRY_STATS]) {
|
||||
struct rtattr *stb[BRIDGE_VLANDB_STATS_MAX+1];
|
||||
struct rtattr *attr;
|
||||
|
||||
attr = vtb[BRIDGE_VLANDB_ENTRY_STATS];
|
||||
parse_rtattr(stb, BRIDGE_VLANDB_STATS_MAX, RTA_DATA(attr),
|
||||
RTA_PAYLOAD(attr));
|
||||
|
||||
if (stb[BRIDGE_VLANDB_STATS_RX_BYTES]) {
|
||||
attr = stb[BRIDGE_VLANDB_STATS_RX_BYTES];
|
||||
vstats.rx_bytes = rta_getattr_u64(attr);
|
||||
}
|
||||
if (stb[BRIDGE_VLANDB_STATS_RX_PACKETS]) {
|
||||
attr = stb[BRIDGE_VLANDB_STATS_RX_PACKETS];
|
||||
vstats.rx_packets = rta_getattr_u64(attr);
|
||||
}
|
||||
if (stb[BRIDGE_VLANDB_STATS_TX_PACKETS]) {
|
||||
attr = stb[BRIDGE_VLANDB_STATS_TX_PACKETS];
|
||||
vstats.tx_packets = rta_getattr_u64(attr);
|
||||
}
|
||||
if (stb[BRIDGE_VLANDB_STATS_TX_BYTES]) {
|
||||
attr = stb[BRIDGE_VLANDB_STATS_TX_BYTES];
|
||||
vstats.tx_bytes = rta_getattr_u64(attr);
|
||||
}
|
||||
}
|
||||
open_json_object(NULL);
|
||||
if (!newport)
|
||||
print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
|
||||
else
|
||||
newport = false;
|
||||
print_range("vlan", vinfo->vid, vrange);
|
||||
print_vlan_flags(vinfo->flags);
|
||||
print_nl();
|
||||
print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
|
||||
print_stp_state(state);
|
||||
print_nl();
|
||||
if (show_stats)
|
||||
__print_one_vlan_stats(&vstats);
|
||||
close_json_object();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_vlan_rtm_filter(struct nlmsghdr *n, void *arg)
|
||||
{
|
||||
return print_vlan_rtm(n, arg, false);
|
||||
}
|
||||
|
||||
static int vlan_show(int argc, char **argv, int subject)
|
||||
{
|
||||
char *filter_dev = NULL;
|
||||
|
|
@ -549,6 +759,34 @@ static int vlan_show(int argc, char **argv, int subject)
|
|||
|
||||
new_json_obj(json);
|
||||
|
||||
/* if show_details is true then use the new bridge vlan dump format */
|
||||
if (show_details && subject == VLAN_SHOW_VLAN) {
|
||||
__u32 dump_flags = show_stats ? BRIDGE_VLANDB_DUMPF_STATS : 0;
|
||||
|
||||
if (rtnl_brvlandump_req(&rth, PF_BRIDGE, dump_flags) < 0) {
|
||||
perror("Cannot send dump request");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!is_json_context()) {
|
||||
printf("%-" __stringify(IFNAMSIZ) "s %-"
|
||||
__stringify(VLAN_ID_LEN) "s", "port",
|
||||
"vlan-id");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
ret = rtnl_dump_filter(&rth, print_vlan_rtm_filter, &subject);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Dump terminated\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (vlan_rtm_cur_ifidx != -1)
|
||||
close_vlan_port();
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!show_stats) {
|
||||
if (rtnl_linkdump_req_filter(&rth, PF_BRIDGE,
|
||||
(compress_vlans ?
|
||||
|
|
@ -602,6 +840,7 @@ static int vlan_show(int argc, char **argv, int subject)
|
|||
}
|
||||
}
|
||||
|
||||
out:
|
||||
delete_json_obj();
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
|
|
@ -667,6 +906,8 @@ int do_vlan(int argc, char **argv)
|
|||
if (matches(*argv, "tunnelshow") == 0) {
|
||||
return vlan_show(argc-1, argv+1, VLAN_SHOW_TUNNELINFO);
|
||||
}
|
||||
if (matches(*argv, "set") == 0)
|
||||
return vlan_option_set(argc-1, argv+1);
|
||||
if (matches(*argv, "help") == 0)
|
||||
usage();
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@ int rtnl_neightbldump_req(struct rtnl_handle *rth, int family)
|
|||
__attribute__((warn_unused_result));
|
||||
int rtnl_mdbdump_req(struct rtnl_handle *rth, int family)
|
||||
__attribute__((warn_unused_result));
|
||||
int rtnl_brvlandump_req(struct rtnl_handle *rth, int family, __u32 dump_flags)
|
||||
__attribute__((warn_unused_result));
|
||||
int rtnl_netconfdump_req(struct rtnl_handle *rth, int family)
|
||||
__attribute__((warn_unused_result));
|
||||
|
||||
|
|
@ -283,6 +285,11 @@ int rtnl_from_file(FILE *, rtnl_listen_filter_t handler,
|
|||
((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct if_stats_msg))))
|
||||
#endif
|
||||
|
||||
#ifndef BRVLAN_RTA
|
||||
#define BRVLAN_RTA(r) \
|
||||
((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct br_vlan_msg))))
|
||||
#endif
|
||||
|
||||
/* User defined nlmsg_type which is used mostly for logging netlink
|
||||
* messages from dump file */
|
||||
#define NLMSG_TSTAMP 15
|
||||
|
|
|
|||
|
|
@ -450,6 +450,25 @@ int rtnl_mdbdump_req(struct rtnl_handle *rth, int family)
|
|||
return send(rth->fd, &req, sizeof(req), 0);
|
||||
}
|
||||
|
||||
int rtnl_brvlandump_req(struct rtnl_handle *rth, int family, __u32 dump_flags)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
struct br_vlan_msg bvm;
|
||||
char buf[256];
|
||||
} req = {
|
||||
.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_vlan_msg)),
|
||||
.nlh.nlmsg_type = RTM_GETVLAN,
|
||||
.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
|
||||
.nlh.nlmsg_seq = rth->dump = ++rth->seq,
|
||||
.bvm.family = family,
|
||||
};
|
||||
|
||||
addattr32(&req.nlh, sizeof(req), BRIDGE_VLANDB_DUMP_FLAGS, dump_flags);
|
||||
|
||||
return send(rth->fd, &req, sizeof(req), 0);
|
||||
}
|
||||
|
||||
int rtnl_netconfdump_req(struct rtnl_handle *rth, int family)
|
||||
{
|
||||
struct {
|
||||
|
|
|
|||
|
|
@ -138,13 +138,22 @@ bridge \- show / manipulate bridge addresses and devices
|
|||
.BR pvid " ] [ " untagged " ] [ "
|
||||
.BR self " ] [ " master " ] "
|
||||
|
||||
.ti -8
|
||||
.BR "bridge vlan set"
|
||||
.B dev
|
||||
.I DEV
|
||||
.B vid
|
||||
.IR VID " [ "
|
||||
.B state
|
||||
.IR STP_STATE " ] "
|
||||
|
||||
.ti -8
|
||||
.BR "bridge vlan" " [ " show " | " tunnelshow " ] [ "
|
||||
.B dev
|
||||
.IR DEV " ]"
|
||||
|
||||
.ti -8
|
||||
.BR "bridge monitor" " [ " all " | " neigh " | " link " | " mdb " ]"
|
||||
.BR "bridge monitor" " [ " all " | " neigh " | " link " | " mdb " | " vlan " ]"
|
||||
|
||||
.SH OPTIONS
|
||||
|
||||
|
|
@ -162,7 +171,7 @@ As a rule, the information is statistics or some time values.
|
|||
|
||||
.TP
|
||||
.BR "\-d" , " \-details"
|
||||
print detailed information about MDB router ports.
|
||||
print detailed information about bridge vlan filter entries or MDB router ports.
|
||||
|
||||
.TP
|
||||
.BR "\-n" , " \-net" , " \-netns " <NETNS>
|
||||
|
|
@ -813,10 +822,70 @@ The
|
|||
.BR "pvid " and " untagged"
|
||||
flags are ignored.
|
||||
|
||||
.SS bridge vlan set - change vlan filter entry's options
|
||||
|
||||
This command changes vlan filter entry's options.
|
||||
|
||||
.TP
|
||||
.BI dev " NAME"
|
||||
the interface with which this vlan is associated.
|
||||
|
||||
.TP
|
||||
.BI vid " VID"
|
||||
the VLAN ID that identifies the vlan.
|
||||
|
||||
.TP
|
||||
.BI state " STP_STATE "
|
||||
the operation state of the vlan. One may enter STP state name (case insensitive), or one of the
|
||||
numbers below. Negative inputs are ignored, and unrecognized names return an
|
||||
error. Note that the state is set only for the vlan of the specified device, e.g. if it is
|
||||
a bridge port then the state will be set only for the vlan of the port.
|
||||
|
||||
.B 0
|
||||
- vlan is in STP
|
||||
.B DISABLED
|
||||
state. Make this vlan completely inactive for STP. This is also called
|
||||
BPDU filter and could be used to disable STP on an untrusted vlan.
|
||||
.sp
|
||||
|
||||
.B 1
|
||||
- vlan is in STP
|
||||
.B LISTENING
|
||||
state. Only valid if STP is enabled on the bridge. In this
|
||||
state the vlan listens for STP BPDUs and drops all other traffic frames.
|
||||
.sp
|
||||
|
||||
.B 2
|
||||
- vlan is in STP
|
||||
.B LEARNING
|
||||
state. Only valid if STP is enabled on the bridge. In this
|
||||
state the vlan will accept traffic only for the purpose of updating MAC
|
||||
address tables.
|
||||
.sp
|
||||
|
||||
.B 3
|
||||
- vlan is in STP
|
||||
.B FORWARDING
|
||||
state. This is the default vlan state.
|
||||
.sp
|
||||
|
||||
.B 4
|
||||
- vlan is in STP
|
||||
.B BLOCKING
|
||||
state. Only valid if STP is enabled on the bridge. This state
|
||||
is used during the STP election process. In this state, the vlan will only process
|
||||
STP BPDUs.
|
||||
.sp
|
||||
|
||||
.SS bridge vlan show - list vlan configuration.
|
||||
|
||||
This command displays the current VLAN filter table.
|
||||
|
||||
.PP
|
||||
With the
|
||||
.B -details
|
||||
option, the command becomes verbose. It displays the per-vlan options.
|
||||
|
||||
.PP
|
||||
With the
|
||||
.B -statistics
|
||||
|
|
@ -842,7 +911,7 @@ command is the first in the command line and then the object list follows:
|
|||
.I OBJECT-LIST
|
||||
is the list of object types that we want to monitor.
|
||||
It may contain
|
||||
.BR link ", " fdb ", and " mdb "."
|
||||
.BR link ", " fdb ", " vlan " and " mdb "."
|
||||
If no
|
||||
.B file
|
||||
argument is given,
|
||||
|
|
|
|||
Loading…
Reference in New Issue