aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Ahern <dsahern@kernel.org>2022-06-10 09:02:29 -0600
committerDavid Ahern <dsahern@kernel.org>2022-06-10 09:02:29 -0600
commitf84e3f8cced949e7d81cba1e67e1a6d3ec92d317 (patch)
tree229683c0b9bd605415b704a193ee03af3024b49a
parentcef46213d5ddbaa507b277878394d6a535dc22cc (diff)
parent4a4e32a92b56a94c9192dbdcb6e504edf58d11d6 (diff)
downloadiproute2-f84e3f8cced949e7d81cba1e67e1a6d3ec92d317.tar.gz
Merge branch 'bridge-fdb-flush' into next
Nikolay Aleksandrov says: ==================== Hi, This set adds support for the new bulk delete flag to allow fdb flushing for specific entries which are matched based on the supplied options. The new bridge fdb subcommand is "flush", and as can be seen from the commits it allows to delete entries based on many different criteria: - matching vlan - matching port - matching all sorts of flags (combinations are allowed) There are also examples for each option in the respective commit messages. Examples: $ bridge fdb flush dev swp2 master vlan 100 dynamic [ delete all dynamic entries with port swp2 and vlan 100 ] $ bridge fdb flush dev br0 vlan 1 static [ delete all static entries in br0's fdb table ] $ bridge fdb flush dev swp2 master extern_learn nosticky [ delete all entries with port swp2 which have extern_learn set and don't have the sticky flag set ] $ bridge fdb flush dev br0 brport br0 vlan 100 permanent [ delete all entries pointing to the bridge itself with vlan 100 ] $ bridge fdb flush dev swp2 master nostatic nooffloaded [ delete all entries with port swp2 which are not static and not offloaded ] If keyword is specified and after that nokeyword is specified obviously the nokeyword would override keyword. ==================== Signed-off-by: David Ahern <dsahern@kernel.org>
-rw-r--r--bridge/fdb.c142
-rw-r--r--man/man8/bridge.883
2 files changed, 224 insertions, 1 deletions
diff --git a/bridge/fdb.c b/bridge/fdb.c
index 8912f092c..b71b20c8b 100644
--- a/bridge/fdb.c
+++ b/bridge/fdb.c
@@ -44,7 +44,11 @@ static void usage(void)
" bridge fdb [ show [ br BRDEV ] [ brport DEV ] [ vlan VID ]\n"
" [ state STATE ] [ dynamic ] ]\n"
" bridge fdb get [ to ] LLADDR [ br BRDEV ] { brport | dev } DEV\n"
- " [ vlan VID ] [ vni VNI ] [ self ] [ master ] [ dynamic ]\n");
+ " [ vlan VID ] [ vni VNI ] [ self ] [ master ] [ dynamic ]\n"
+ " bridge fdb flush dev DEV [ brport DEV ] [ vlan VID ]\n"
+ " [ self ] [ master ] [ [no]permanent | [no]static | [no]dynamic ]\n"
+ " [ [no]added_by_user ] [ [no]extern_learn ] [ [no]sticky ]\n"
+ " [ [no]offloaded ]\n");
exit(-1);
}
@@ -666,6 +670,140 @@ static int fdb_get(int argc, char **argv)
return 0;
}
+static int fdb_flush(int argc, char **argv)
+{
+ struct {
+ struct nlmsghdr n;
+ struct ndmsg ndm;
+ char buf[256];
+ } req = {
+ .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
+ .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_BULK,
+ .n.nlmsg_type = RTM_DELNEIGH,
+ .ndm.ndm_family = PF_BRIDGE,
+ };
+ unsigned short ndm_state_mask = 0;
+ unsigned short ndm_flags_mask = 0;
+ short vid = -1, port_ifidx = -1;
+ unsigned short ndm_flags = 0;
+ unsigned short ndm_state = 0;
+ char *d = NULL, *port = NULL;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "dev") == 0) {
+ NEXT_ARG();
+ d = *argv;
+ } else if (strcmp(*argv, "master") == 0) {
+ ndm_flags |= NTF_MASTER;
+ } else if (strcmp(*argv, "self") == 0) {
+ ndm_flags |= NTF_SELF;
+ } else if (strcmp(*argv, "permanent") == 0) {
+ ndm_state |= NUD_PERMANENT;
+ ndm_state_mask |= NUD_PERMANENT;
+ } else if (strcmp(*argv, "nopermanent") == 0) {
+ ndm_state &= ~NUD_PERMANENT;
+ ndm_state_mask |= NUD_PERMANENT;
+ } else if (strcmp(*argv, "static") == 0) {
+ ndm_state |= NUD_NOARP;
+ ndm_state_mask |= NUD_NOARP | NUD_PERMANENT;
+ } else if (strcmp(*argv, "nostatic") == 0) {
+ ndm_state &= ~NUD_NOARP;
+ ndm_state_mask |= NUD_NOARP;
+ } else if (strcmp(*argv, "dynamic") == 0) {
+ ndm_state &= ~NUD_NOARP | NUD_PERMANENT;
+ ndm_state_mask |= NUD_NOARP | NUD_PERMANENT;
+ } else if (strcmp(*argv, "nodynamic") == 0) {
+ ndm_state |= NUD_NOARP;
+ ndm_state_mask |= NUD_NOARP;
+ } else if (strcmp(*argv, "added_by_user") == 0) {
+ ndm_flags |= NTF_USE;
+ ndm_flags_mask |= NTF_USE;
+ } else if (strcmp(*argv, "noadded_by_user") == 0) {
+ ndm_flags &= ~NTF_USE;
+ ndm_flags_mask |= NTF_USE;
+ } else if (strcmp(*argv, "extern_learn") == 0) {
+ ndm_flags |= NTF_EXT_LEARNED;
+ ndm_flags_mask |= NTF_EXT_LEARNED;
+ } else if (strcmp(*argv, "noextern_learn") == 0) {
+ ndm_flags &= ~NTF_EXT_LEARNED;
+ ndm_flags_mask |= NTF_EXT_LEARNED;
+ } else if (strcmp(*argv, "sticky") == 0) {
+ ndm_flags |= NTF_STICKY;
+ ndm_flags_mask |= NTF_STICKY;
+ } else if (strcmp(*argv, "nosticky") == 0) {
+ ndm_flags &= ~NTF_STICKY;
+ ndm_flags_mask |= NTF_STICKY;
+ } else if (strcmp(*argv, "offloaded") == 0) {
+ ndm_flags |= NTF_OFFLOADED;
+ ndm_flags_mask |= NTF_OFFLOADED;
+ } else if (strcmp(*argv, "nooffloaded") == 0) {
+ ndm_flags &= ~NTF_OFFLOADED;
+ ndm_flags_mask |= NTF_OFFLOADED;
+ } else if (strcmp(*argv, "brport") == 0) {
+ if (port)
+ duparg2("brport", *argv);
+ NEXT_ARG();
+ port = *argv;
+ } else if (strcmp(*argv, "vlan") == 0) {
+ if (vid >= 0)
+ duparg2("vlan", *argv);
+ NEXT_ARG();
+ vid = atoi(*argv);
+ } else {
+ if (strcmp(*argv, "help") == 0)
+ NEXT_ARG();
+ }
+ argc--; argv++;
+ }
+
+ if (d == NULL) {
+ fprintf(stderr, "Device is a required argument.\n");
+ return -1;
+ }
+
+ req.ndm.ndm_ifindex = ll_name_to_index(d);
+ if (req.ndm.ndm_ifindex == 0) {
+ fprintf(stderr, "Cannot find bridge device \"%s\"\n", d);
+ return -1;
+ }
+
+ if (port) {
+ port_ifidx = ll_name_to_index(port);
+ if (port_ifidx == 0) {
+ fprintf(stderr, "Cannot find bridge port device \"%s\"\n",
+ port);
+ return -1;
+ }
+ }
+
+ if (vid >= 4096) {
+ fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid);
+ return -1;
+ }
+
+ /* if self and master were not specified assume self */
+ if (!(ndm_flags & (NTF_SELF | NTF_MASTER)))
+ ndm_flags |= NTF_SELF;
+
+ req.ndm.ndm_flags = ndm_flags;
+ req.ndm.ndm_state = ndm_state;
+ if (port_ifidx > -1)
+ addattr32(&req.n, sizeof(req), NDA_IFINDEX, port_ifidx);
+ if (vid > -1)
+ addattr16(&req.n, sizeof(req), NDA_VLAN, vid);
+ if (ndm_flags_mask)
+ addattr8(&req.n, sizeof(req), NDA_NDM_FLAGS_MASK,
+ ndm_flags_mask);
+ if (ndm_state_mask)
+ addattr16(&req.n, sizeof(req), NDA_NDM_STATE_MASK,
+ ndm_state_mask);
+
+ if (rtnl_talk(&rth, &req.n, NULL) < 0)
+ return -1;
+
+ return 0;
+}
+
int do_fdb(int argc, char **argv)
{
ll_init_map(&rth);
@@ -685,6 +823,8 @@ int do_fdb(int argc, char **argv)
matches(*argv, "lst") == 0 ||
matches(*argv, "list") == 0)
return fdb_show(argc-1, argv+1);
+ if (strcmp(*argv, "flush") == 0)
+ return fdb_flush(argc-1, argv+1);
if (matches(*argv, "help") == 0)
usage();
} else
diff --git a/man/man8/bridge.8 b/man/man8/bridge.8
index d8923d2eb..d4df772ea 100644
--- a/man/man8/bridge.8
+++ b/man/man8/bridge.8
@@ -113,6 +113,19 @@ bridge \- show / manipulate bridge addresses and devices
.BR self " ] [ " master " ] [ " dynamic " ]"
.ti -8
+.BR "bridge fdb flush"
+.B dev
+.IR DEV " [ "
+.B brport
+.IR DEV " ] [ "
+.B vlan
+.IR VID " ] [ "
+.BR self " ] [ " master " ] [ "
+.BR [no]permanent " | " [no]static " | " [no]dynamic " ] [ "
+.BR [no]added_by_user " ] [ " [no]extern_learn " ] [ "
+.BR [no]sticky " ] [ " [no]offloaded " ]"
+
+.ti -8
.BR "bridge mdb" " { " add " | " del " } "
.B dev
.I DEV
@@ -782,6 +795,76 @@ the bridge to which this address is associated.
.TP
.B master
- the address is associated with master devices fdb. Usually software (default).
+
+.SS bridge fdb flush - flush bridge forwarding table entries.
+
+flush the matching bridge forwarding table entries. Some options below have a negated
+form when "no" is prepended to them (e.g. permanent and nopermanent).
+
+.TP
+.BI dev " DEV"
+the target device for the operation. If the device is a bridge port and "master"
+is set then the operation will be fulfilled by its master device's driver and
+all entries pointing to that port will be deleted.
+
+.TP
+.BI brport " DEV"
+the target bridge port for the operation. If the bridge device is specified then only
+entries pointing to the bridge itself will be deleted. Note that the target device
+specified by this option will override the one specified by dev above.
+
+.TP
+.BI vlan " VID"
+the target VLAN ID for the operation. Match forwarding table entries only with the
+specified VLAN ID.
+
+.TP
+.B self
+the operation is fulfilled directly by the driver for the specified network
+device. If the network device belongs to a master like a bridge, then the
+bridge is bypassed and not notified of this operation. The "bridge fdb flush"
+command can also be used on the bridge device itself. The flag is set by default if
+"master" is not specified.
+
+.TP
+.B master
+if the specified network device is a port that belongs to a master device
+such as a bridge, the operation is fulfilled by the master device's driver.
+
+.TP
+.B [no]permanent
+if specified then only permanent entries will be deleted or respectively if "no"
+is prepended then only non-permanent entries will be deleted.
+
+.TP
+.B [no]static
+if specified then only static entries will be deleted or respectively if "no"
+is prepended then only non-static entries will be deleted.
+
+.TP
+.B [no]dynamic
+if specified then only dynamic entries will be deleted or respectively if "no"
+is prepended then only non-dynamic (static or permanent) entries will be deleted.
+
+.TP
+.B [no]added_by_user
+if specified then only entries with added_by_user flag will be deleted or respectively
+if "no" is prepended then only entries without added_by_user flag will be deleted.
+
+.TP
+.B [no]extern_learn
+if specified then only entries with extern_learn flag will be deleted or respectively
+if "no" is prepended then only entries without extern_learn flag will be deleted.
+
+.TP
+.B [no]sticky
+if specified then only entries with sticky flag will be deleted or respectively
+if "no" is prepended then only entries without sticky flag will be deleted.
+
+.TP
+.B [no]offloaded
+if specified then only entries with offloaded flag will be deleted or respectively
+if "no" is prepended then only entries without offloaded flag will be deleted.
.sp
.SH bridge mdb - multicast group database management