The branch stable/14 has been updated by ivy:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=c064ee9d7d974d5626e43f7817db940cefe9dead

commit c064ee9d7d974d5626e43f7817db940cefe9dead
Author:     Lexi Winter <i...@freebsd.org>
AuthorDate: 2025-07-31 15:56:51 +0000
Commit:     Lexi Winter <i...@freebsd.org>
CommitDate: 2025-08-23 00:10:15 +0000

    ifconfig: Support VLAN ID in static/deladdr
    
    Add an optional "vlan <n>" argument to the bridge static and deladdr
    commands to allow addresses to be added to / removed from a particular
    vlan.  No changes to if_bridge are required as the kernel API already
    supports this, it just wasn't exposed in ifconfig.
    
    Add tests for the new functionality, and improve the test for the
    existing "static" command.
    
    Reviewed by:            kevans
    Differential Revision:  https://reviews.freebsd.org/D51243
    
    (cherry picked from commit 3650722abf2922893540361a1369b54abc5ff8d2)
---
 sbin/ifconfig/ifbridge.c        | 71 +++++++++++++++++++++++++++++++----------
 sbin/ifconfig/ifconfig.8        | 18 ++++++++---
 tests/sys/net/if_bridge_test.sh | 70 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 136 insertions(+), 23 deletions(-)

diff --git a/sbin/ifconfig/ifbridge.c b/sbin/ifconfig/ifbridge.c
index 973c4f9cfe6e..9d3296ea6a3e 100644
--- a/sbin/ifconfig/ifbridge.c
+++ b/sbin/ifconfig/ifbridge.c
@@ -401,43 +401,80 @@ setbridge_flushall(if_ctx *ctx, const char *val __unused, 
int dummy __unused)
                err(1, "BRDGFLUSH");
 }
 
-static void
-setbridge_static(if_ctx *ctx, const char *val, const char *mac)
+static int
+setbridge_static(if_ctx *ctx, int argc, const char *const *argv)
 {
        struct ifbareq req;
        struct ether_addr *ea;
+       int arg;
+
+       if (argc < 2)
+               errx(1, "usage: static <interface> <address> [vlan <id>]");
+       arg = 0;
 
        memset(&req, 0, sizeof(req));
-       strlcpy(req.ifba_ifsname, val, sizeof(req.ifba_ifsname));
+       req.ifba_flags = IFBAF_STATIC;
 
-       ea = ether_aton(mac);
-       if (ea == NULL)
-               errx(1, "%s: invalid address: %s", val, mac);
+       strlcpy(req.ifba_ifsname, argv[arg], sizeof(req.ifba_ifsname));
+       ++arg;
 
+       ea = ether_aton(argv[arg]);
+       if (ea == NULL)
+               errx(1, "invalid address: %s", argv[arg]);
        memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
-       req.ifba_flags = IFBAF_STATIC;
-       req.ifba_vlan = 0; /* XXX allow user to specify */
+       ++arg;
+
+       req.ifba_vlan = 0;
+       if (argc > 2 && strcmp(argv[arg], "vlan") == 0) {
+               if (argc < 3)
+                       errx(1, "usage: static <interface> <address> "
+                           "[vlan <id>]");
+               ++arg;
+
+               if (get_vlan_id(argv[arg], &req.ifba_vlan) < 0)
+                       errx(1, "invalid vlan id: %s", argv[arg]);
+               ++arg;
+       }
 
        if (do_cmd(ctx, BRDGSADDR, &req, sizeof(req), 1) < 0)
-               err(1, "BRDGSADDR %s",  val);
+               err(1, "BRDGSADDR");
+       return arg;
 }
 
-static void
-setbridge_deladdr(if_ctx *ctx, const char *val, int dummy __unused)
+static int
+setbridge_deladdr(if_ctx *ctx, int argc, const char *const *argv)
 {
        struct ifbareq req;
        struct ether_addr *ea;
+       int arg;
+
+       if (argc < 1)
+               errx(1, "usage: deladdr <address> [vlan <id>]");
+       arg = 0;
 
        memset(&req, 0, sizeof(req));
 
-       ea = ether_aton(val);
+       ea = ether_aton(argv[arg]);
        if (ea == NULL)
-               errx(1, "invalid address: %s",  val);
-
+               errx(1, "invalid address: %s", argv[arg]);
        memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
+       ++arg;
+
+       req.ifba_vlan = 0;
+       if (argc >= 2 && strcmp(argv[arg], "vlan") == 0) {
+               if (argc < 3)
+                       errx(1, "usage: deladdr <address> [vlan <id>]");
+               ++arg;
+
+               if (get_vlan_id(argv[arg], &req.ifba_vlan) < 0)
+                       errx(1, "invalid vlan id: %s", argv[arg]);
+               ++arg;
+       }
 
        if (do_cmd(ctx, BRDGDADDR, &req, sizeof(req), 1) < 0)
-               err(1, "BRDGDADDR %s",  val);
+               err(1, "BRDGDADDR");
+
+       return arg;
 }
 
 static void
@@ -660,8 +697,8 @@ static struct cmd bridge_cmds[] = {
        DEF_CMD_ARG("-autoptp",         unsetbridge_autoptp),
        DEF_CMD("flush", 0,             setbridge_flush),
        DEF_CMD("flushall", 0,          setbridge_flushall),
-       DEF_CMD_ARG2("static",          setbridge_static),
-       DEF_CMD_ARG("deladdr",          setbridge_deladdr),
+       DEF_CMD_VARG("static",          setbridge_static),
+       DEF_CMD_VARG("deladdr",         setbridge_deladdr),
        DEF_CMD("addr",  1,             setbridge_addr),
        DEF_CMD_ARG("maxaddr",          setbridge_maxaddr),
        DEF_CMD_ARG("hellotime",        setbridge_hellotime),
diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8
index ce15e3a68abc..85dad643f588 100644
--- a/sbin/ifconfig/ifconfig.8
+++ b/sbin/ifconfig/ifconfig.8
@@ -28,7 +28,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd July 11, 2025
+.Dd July 30, 2025
 .Dt IFCONFIG 8
 .Os
 .Sh NAME
@@ -2521,15 +2521,23 @@ is zero, then address cache entries will not be expired.
 The default is 1200 seconds.
 .It Cm addr
 Display the addresses that have been learned by the bridge.
-.It Cm static Ar interface-name Ar address
-Add a static entry into the address cache pointing to
+.It Cm static Ar interface-name Ar address Op Cm vlan Ar vlan-id
+Add a static entry into the address cache for pointing to
 .Ar interface-name .
+If
+.Ar vlan-id
+is specified, the entry is added for that VLAN, otherwise it is added
+for VLAN 0.
+.Pp
 Static entries are never aged out of the cache or re-placed, even if the
 address is seen on a different interface.
-.It Cm deladdr Ar address
+.It Cm deladdr Ar address Op Cm vlan Ar vlan-id
 Delete
 .Ar address
-from the address cache.
+from the address cache.  If
+.Ar vlan-id
+is specified, the entry is deleted from that VLAN's address table,
+otherwise it is deleted from the VLAN 0 address table.
 .It Cm flush
 Delete all dynamically-learned addresses from the address cache.
 .It Cm flushall
diff --git a/tests/sys/net/if_bridge_test.sh b/tests/sys/net/if_bridge_test.sh
index 5438f67cf637..264a8986fcf9 100755
--- a/tests/sys/net/if_bridge_test.sh
+++ b/tests/sys/net/if_bridge_test.sh
@@ -245,7 +245,8 @@ static_body()
            jexec one ifconfig ${bridge} static ${epair}a 00:01:02:03:04:05
 
        # List addresses
-       atf_check -s exit:0 -o ignore \
+       atf_check -s exit:0 \
+           -o match:"00:01:02:03:04:05 Vlan0 ${epair}a 0 flags=1<STATIC>" \
            jexec one ifconfig ${bridge} addr
 
        # Delete with bad address format
@@ -266,6 +267,72 @@ static_cleanup()
        vnet_cleanup
 }
 
+atf_test_case "vstatic" "cleanup"
+vstatic_head()
+{
+       atf_set descr 'Bridge VLAN static address test'
+       atf_set require.user root
+}
+
+vstatic_body()
+{
+       vnet_init
+       vnet_init_bridge
+
+       epair=$(vnet_mkepair)
+       bridge=$(vnet_mkbridge)
+
+       vnet_mkjail one ${bridge} ${epair}a
+
+       ifconfig ${epair}b up
+
+       jexec one ifconfig ${bridge} up
+       jexec one ifconfig ${epair}a up
+       jexec one ifconfig ${bridge} addm ${epair}a
+
+       # Wrong interface
+       atf_check -s exit:1 -o ignore -e ignore jexec one \
+           ifconfig ${bridge} static ${epair}b 00:01:02:03:04:05 vlan 10
+
+       # Bad address format
+       atf_check -s exit:1 -o ignore -e ignore jexec one \
+           ifconfig ${bridge} static ${epair}a 00:01:02:03:04 vlan 10
+
+       # Invalid VLAN ID
+       atf_check -s exit:1 -o ignore -e ignore jexec one \
+           ifconfig ${bridge} static ${epair}a 00:01:02:03:04:05 vlan 5000
+
+       # Correct add
+       atf_check -s exit:0 -o ignore jexec one \
+           ifconfig ${bridge} static ${epair}a 00:01:02:03:04:05 vlan 10
+
+       # List addresses
+       atf_check -s exit:0 \
+           -o match:"00:01:02:03:04:05 Vlan10 ${epair}a 0 flags=1<STATIC>" \
+           jexec one ifconfig ${bridge} addr
+
+       # Delete with bad address format
+       atf_check -s exit:1 -o ignore -e ignore jexec one \
+           ifconfig ${bridge} deladdr 00:01:02:03:04 vlan 10
+
+       # Delete with unlisted address
+       atf_check -s exit:1 -o ignore -e ignore jexec one \
+           ifconfig ${bridge} deladdr 00:01:02:03:04:06 vlan 10
+
+       # Delete with wrong vlan id
+       atf_check -s exit:1 -o ignore -e ignore jexec one \
+           ifconfig ${bridge} deladdr 00:01:02:03:04:05 vlan 20
+
+       # Correct delete
+       atf_check -s exit:0 -o ignore jexec one \
+           ifconfig ${bridge} deladdr 00:01:02:03:04:05 vlan 10
+}
+
+vstatic_cleanup()
+{
+       vnet_cleanup
+}
+
 atf_test_case "span" "cleanup"
 span_head()
 {
@@ -835,6 +902,7 @@ atf_init_test_cases()
        atf_add_test_case "stp"
        atf_add_test_case "stp_vlan"
        atf_add_test_case "static"
+       atf_add_test_case "vstatic"
        atf_add_test_case "span"
        atf_add_test_case "inherit_mac"
        atf_add_test_case "delete_with_members"

Reply via email to