The branch main has been updated by ivy: URL: https://cgit.FreeBSD.org/src/commit/?id=c41469a89f74e921ccbab09074c7b24edacbcc85
commit c41469a89f74e921ccbab09074c7b24edacbcc85 Author: Lexi Winter <i...@freebsd.org> AuthorDate: 2025-08-05 18:27:09 +0000 Commit: Lexi Winter <i...@freebsd.org> CommitDate: 2025-08-05 19:25:37 +0000 ifconfig: Improve bridge vlan filtering syntax The current syntax to add an interface to a filtering bridge requires repeating the interface name up to three times: ifconfig bridge0 addm ix0 untagged ix0 10 tagged ix0 100-199 Since at least one of these options nearly always needs to be set, this results in excessively verbose configuration. Extend "addm" to support optional arguments, and add two arguments, "untagged" and "tagged", which infer the interface name from the addm command. Now the interface only has to be given once: ifconfig bridge0 addm ix0 untagged 10 tagged 100-199 To avoid confusion with the existing untagged and tagged commands, rename those to ifuntagged and iftagged. In future, this syntax will make it possible to add an interface and set its vlan configuration atomically (once the API supports that), but switching to the new syntax now means we don't need to change it after 15.0. Differential Revision: https://reviews.freebsd.org/D51707 --- sbin/ifconfig/ifbridge.c | 81 +++++++++++++++++++++++++++++++++-------- sbin/ifconfig/ifconfig.8 | 31 ++++++++++++---- tests/sys/net/if_bridge_test.sh | 73 +++++++++++++++++-------------------- 3 files changed, 122 insertions(+), 63 deletions(-) diff --git a/sbin/ifconfig/ifbridge.c b/sbin/ifconfig/ifbridge.c index d02d92d10b59..eff443447c13 100644 --- a/sbin/ifconfig/ifbridge.c +++ b/sbin/ifconfig/ifbridge.c @@ -60,6 +60,10 @@ #include "ifconfig.h" +static int parse_vlans(ifbvlan_set_t *set, const char *str); +static int get_val(const char *cp, u_long *valp); +static int get_vlan_id(const char *cp, ether_vlanid_t *valp); + static const char *stpstates[] = { STP_STATES }; static const char *stpproto[] = { STP_PROTOS }; static const char *stproles[] = { STP_ROLES }; @@ -288,15 +292,62 @@ bridge_status(if_ctx *ctx) ifconfig_bridge_free_bridge_status(bridge); } -static void -setbridge_add(if_ctx *ctx, const char *val, int dummy __unused) +static int +setbridge_add(if_ctx *ctx, int argc, const char *const *argv) { struct ifbreq req; + struct ifbif_vlan_req vlreq; + int oargc = argc; memset(&req, 0, sizeof(req)); - strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname)); + memset(&vlreq, 0, sizeof(vlreq)); + + if (argc < 1) + errx(1, "usage: addm <interface> [opts ...]"); + + strlcpy(req.ifbr_ifsname, argv[0], sizeof(req.ifbr_ifsname)); + --argc; ++argv; + + while (argc) { + if (strcmp(argv[0], "untagged") == 0) { + if (argc < 2) + errx(1, "usage: untagged <vlan id>"); + + if (get_vlan_id(argv[1], &req.ifbr_pvid) < 0) + errx(1, "invalid VLAN identifier: %s", argv[1]); + + argc -= 2; + argv += 2; + } else if (strcmp(argv[0], "tagged") == 0) { + if (argc < 2) + errx(1, "usage: tagged <vlan set>"); + + vlreq.bv_op = BRDG_VLAN_OP_SET; + strlcpy(vlreq.bv_ifname, req.ifbr_ifsname, + sizeof(vlreq.bv_ifname)); + if (parse_vlans(&vlreq.bv_set, argv[1]) != 0) + errx(1, "invalid vlan set: %s", argv[1]); + + argc -= 2; + argv += 2; + } else { + break; + } + } + if (do_cmd(ctx, BRDGADD, &req, sizeof(req), 1) < 0) - err(1, "BRDGADD %s", val); + err(1, "BRDGADD %s", req.ifbr_ifsname); + + if (req.ifbr_pvid != 0 && + do_cmd(ctx, BRDGSIFPVID, &req, sizeof(req), 1) < 0) + err(1, "BRDGSIFPVID %s %u", req.ifbr_ifsname, + (unsigned)req.ifbr_pvid); + + if (vlreq.bv_op != 0 && + do_cmd(ctx, BRDGSIFVLANSET, &vlreq, sizeof(vlreq), 1) < 0) + err(1, "BRDGSIFVLANSET %s", req.ifbr_ifsname); + + return (oargc - argc); } static void @@ -684,7 +735,7 @@ setbridge_ifpathcost(if_ctx *ctx, const char *ifn, const char *cost) } static void -setbridge_untagged(if_ctx *ctx, const char *ifn, const char *vlanid) +setbridge_ifuntagged(if_ctx *ctx, const char *ifn, const char *vlanid) { struct ifbreq req; @@ -699,7 +750,7 @@ setbridge_untagged(if_ctx *ctx, const char *ifn, const char *vlanid) } static void -unsetbridge_untagged(if_ctx *ctx, const char *ifn, int dummy __unused) +unsetbridge_ifuntagged(if_ctx *ctx, const char *ifn, int dummy __unused) { struct ifbreq req; @@ -831,19 +882,19 @@ set_bridge_vlanset(if_ctx *ctx, const char *ifn, const char *vlans, int op) } static void -setbridge_tagged(if_ctx *ctx, const char *ifn, const char *vlans) +setbridge_iftagged(if_ctx *ctx, const char *ifn, const char *vlans) { set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_SET); } static void -addbridge_tagged(if_ctx *ctx, const char *ifn, const char *vlans) +addbridge_iftagged(if_ctx *ctx, const char *ifn, const char *vlans) { set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_ADD); } static void -delbridge_tagged(if_ctx *ctx, const char *ifn, const char *vlans) +delbridge_iftagged(if_ctx *ctx, const char *ifn, const char *vlans) { set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_DEL); } @@ -933,7 +984,7 @@ setbridge_ifvlanproto(if_ctx *ctx, const char *ifname, const char *proto) } static struct cmd bridge_cmds[] = { - DEF_CMD_ARG("addm", setbridge_add), + DEF_CMD_VARG("addm", setbridge_add), DEF_CMD_ARG("deletem", setbridge_delete), DEF_CMD_ARG("discover", setbridge_discover), DEF_CMD_ARG("-discover", unsetbridge_discover), @@ -968,11 +1019,11 @@ static struct cmd bridge_cmds[] = { DEF_CMD_ARG2("ifpriority", setbridge_ifpriority), DEF_CMD_ARG2("ifpathcost", setbridge_ifpathcost), DEF_CMD_ARG2("ifmaxaddr", setbridge_ifmaxaddr), - DEF_CMD_ARG2("untagged", setbridge_untagged), - DEF_CMD_ARG("-untagged", unsetbridge_untagged), - DEF_CMD_ARG2("tagged", setbridge_tagged), - DEF_CMD_ARG2("+tagged", addbridge_tagged), - DEF_CMD_ARG2("-tagged", delbridge_tagged), + DEF_CMD_ARG2("ifuntagged", setbridge_ifuntagged), + DEF_CMD_ARG("-ifuntagged", unsetbridge_ifuntagged), + DEF_CMD_ARG2("iftagged", setbridge_iftagged), + DEF_CMD_ARG2("+iftagged", addbridge_iftagged), + DEF_CMD_ARG2("-iftagged", delbridge_iftagged), DEF_CMD_ARG2("ifvlanproto", setbridge_ifvlanproto), DEF_CMD_ARG("timeout", setbridge_timeout), DEF_CMD_ARG("private", setbridge_private), diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8 index d7b2570ab20d..b562f9e4c0c5 100644 --- a/sbin/ifconfig/ifconfig.8 +++ b/sbin/ifconfig/ifconfig.8 @@ -2494,12 +2494,27 @@ compatibility. .Ss Bridge Interface Parameters The following parameters are specific to bridge interfaces: .Bl -tag -width indent -.It Cm addm Ar interface +.It Cm addm Ar interface Op Ar options ... Add the interface named by .Ar interface as a member of the bridge. The interface is put into promiscuous mode so that it can receive every packet sent on the network. +.Pp +The interface name may be followed by one or more of the following +.Ar options : +.Bl -tag -width ".Cm untagged Ar vlan-id" +.It Cm untagged Ar vlan-id +Set the untagged VLAN identifier for the interface. +This is equivalent to the +.Cm ifuntagged +command. +.It Cm tagged Ar vlan-set +Set the allowed VLAN list for the interface. +This is equivalent to the +.Cm iftagged +command. +.El .It Cm deletem Ar interface Remove the interface named by .Ar interface @@ -2715,9 +2730,9 @@ Enable VLAN filtering on the bridge. .It Cm -vlanfilter Disable VLAN filtering on the bridge. This is the default. -.It Cm untagged Ar interface Ar vlan-id +.It Cm ifuntagged Ar interface Ar vlan-id Set the untagged VLAN identifier for an interface. -.It Cm -untagged Ar interface Ar vlan-id +.It Cm -ifuntagged Ar interface Ar vlan-id Clear the untagged VLAN identifier for an interface. .It Cm defuntagged Ar vlan-id Enable the @@ -2727,7 +2742,7 @@ option by default on newly added members. Do not enable the .Cm untagged option by default on newly added members. -.It Cm tagged Ar interface Ar vlan-list +.It Cm iftagged Ar interface Ar vlan-list Set the interface's VLAN access list to the provided list of VLANs. The list should be a comma-separated list of one or more VLAN IDs or ranges formatted as @@ -2738,15 +2753,15 @@ meaning the empty set, or the value .Dq all meaning all VLANs (1-4094). -.It Cm +tagged Ar interface Ar vlan-list +.It Cm +iftagged Ar interface Ar vlan-list Add the provided list of VLAN IDs to the interface's VLAN access list. The list should be formatted as described for -.Cm tagged . -.It Cm -tagged Ar interface Ar vlan-list +.Cm iftagged . +.It Cm -iftagged Ar interface Ar vlan-list Remove the provided list of VLAN IDs from the interface's VLAN access list. The list should be formatted as described for -.Cm tagged . +.Cm iftagged . .It Cm qinq Ar interface Allow this interface to send 802.1ad .Dq Q-in-Q diff --git a/tests/sys/net/if_bridge_test.sh b/tests/sys/net/if_bridge_test.sh index 8a6c730014ce..906f586d2483 100755 --- a/tests/sys/net/if_bridge_test.sh +++ b/tests/sys/net/if_bridge_test.sh @@ -922,15 +922,15 @@ vlan_pvid_body() ifconfig ${bridge} vlanfilter up ifconfig ${epone}a up ifconfig ${eptwo}a up - ifconfig ${bridge} addm ${epone}a untagged ${epone}a 20 - ifconfig ${bridge} addm ${eptwo}a untagged ${eptwo}a 20 + ifconfig ${bridge} addm ${epone}a untagged 20 + ifconfig ${bridge} addm ${eptwo}a untagged 20 # With VLAN filtering enabled, traffic should be passed. atf_check -s exit:0 -o ignore jexec one ping -c 3 -t 1 192.0.2.2 atf_check -s exit:0 -o ignore jexec two ping -c 3 -t 1 192.0.2.1 # Removed the untagged VLAN on one port; traffic should not be passed. - ifconfig ${bridge} -untagged ${epone}a + ifconfig ${bridge} -ifuntagged ${epone}a atf_check -s exit:2 -o ignore jexec one ping -c 3 -t 1 192.0.2.2 atf_check -s exit:2 -o ignore jexec two ping -c 3 -t 1 192.0.2.1 } @@ -966,10 +966,8 @@ vlan_pvid_filtered_body() atf_check -s exit:0 ifconfig ${bridge} vlanfilter up atf_check -s exit:0 ifconfig ${epone}a up atf_check -s exit:0 ifconfig ${eptwo}a up - atf_check -s exit:0 ifconfig ${bridge} \ - addm ${epone}a untagged ${epone}a 20 - atf_check -s exit:0 ifconfig ${bridge} \ - addm ${eptwo}a untagged ${eptwo}a 30 + atf_check -s exit:0 ifconfig ${bridge} addm ${epone}a untagged 20 + atf_check -s exit:0 ifconfig ${bridge} addm ${eptwo}a untagged 30 atf_check -s exit:2 -o ignore jexec one ping -c 3 -t 1 192.0.2.2 atf_check -s exit:2 -o ignore jexec two ping -c 3 -t 1 192.0.2.1 @@ -1011,10 +1009,8 @@ vlan_pvid_tagged_body() atf_check -s exit:0 ifconfig ${bridge} vlanfilter up atf_check -s exit:0 ifconfig ${epone}a up atf_check -s exit:0 ifconfig ${eptwo}a up - atf_check -s exit:0 ifconfig ${bridge} \ - addm ${epone}a untagged ${epone}a 20 - atf_check -s exit:0 ifconfig ${bridge} \ - addm ${eptwo}a untagged ${eptwo}a 20 + atf_check -s exit:0 ifconfig ${bridge} addm ${epone}a untagged 20 + atf_check -s exit:0 ifconfig ${bridge} addm ${eptwo}a untagged 20 # Tagged frames should not be passed. atf_check -s exit:2 -o ignore jexec one ping -c 3 -t 1 192.0.2.2 @@ -1055,10 +1051,8 @@ vlan_pvid_1q_body() bridge=$(vnet_mkbridge) atf_check -s exit:0 ifconfig ${bridge} vlanfilter up - atf_check -s exit:0 ifconfig ${bridge} \ - addm ${epone}a untagged ${epone}a 20 - atf_check -s exit:0 ifconfig ${bridge} addm ${eptwo}a \ - tagged ${eptwo}a 20 + atf_check -s exit:0 ifconfig ${bridge} addm ${epone}a untagged 20 + atf_check -s exit:0 ifconfig ${bridge} addm ${eptwo}a tagged 20 atf_check -s exit:0 ifconfig ${epone}a up atf_check -s exit:0 ifconfig ${eptwo}a up @@ -1116,25 +1110,25 @@ vlan_filtering_body() # Set the untagged vlan on both ports to 20 and make sure traffic is # still blocked. We intentionally do not pass tagged traffic for the # untagged vlan. - atf_check -s exit:0 ifconfig ${bridge} untagged ${epone}a 20 - atf_check -s exit:0 ifconfig ${bridge} untagged ${eptwo}a 20 + atf_check -s exit:0 ifconfig ${bridge} ifuntagged ${epone}a 20 + atf_check -s exit:0 ifconfig ${bridge} ifuntagged ${eptwo}a 20 atf_check -s exit:2 -o ignore jexec one ping -c 3 -t 1 192.0.2.2 atf_check -s exit:2 -o ignore jexec two ping -c 3 -t 1 192.0.2.1 - atf_check -s exit:0 ifconfig ${bridge} -untagged ${epone}a - atf_check -s exit:0 ifconfig ${bridge} -untagged ${eptwo}a + atf_check -s exit:0 ifconfig ${bridge} -ifuntagged ${epone}a + atf_check -s exit:0 ifconfig ${bridge} -ifuntagged ${eptwo}a # Add VLANs 10-30 to the access list; now access should be allowed. - atf_check -s exit:0 ifconfig ${bridge} +tagged ${epone}a 10-30 - atf_check -s exit:0 ifconfig ${bridge} +tagged ${eptwo}a 10-30 + atf_check -s exit:0 ifconfig ${bridge} +iftagged ${epone}a 10-30 + atf_check -s exit:0 ifconfig ${bridge} +iftagged ${eptwo}a 10-30 atf_check -s exit:0 -o ignore jexec one ping -c 3 -t 1 192.0.2.2 atf_check -s exit:0 -o ignore jexec two ping -c 3 -t 1 192.0.2.1 # Remove vlan 20 from the access list, now access should be blocked # again. - atf_check -s exit:0 ifconfig ${bridge} -tagged ${epone}a 20 - atf_check -s exit:0 ifconfig ${bridge} -tagged ${eptwo}a 20 + atf_check -s exit:0 ifconfig ${bridge} -iftagged ${epone}a 20 + atf_check -s exit:0 ifconfig ${bridge} -iftagged ${eptwo}a 20 atf_check -s exit:2 -o ignore jexec one ping -c 3 -t 1 192.0.2.2 atf_check -s exit:2 -o ignore jexec two ping -c 3 -t 1 192.0.2.1 } @@ -1145,16 +1139,16 @@ vlan_filtering_cleanup() } # -# Test the ifconfig 'tagged' option. +# Test the ifconfig 'iftagged' option. # -atf_test_case "vlan_ifconfig_tagged" "cleanup" -vlan_ifconfig_tagged_head() +atf_test_case "vlan_ifconfig_iftagged" "cleanup" +vlan_ifconfig_iftagged_head() { - atf_set descr 'test the ifconfig tagged option' + atf_set descr 'test the ifconfig iftagged option' atf_set require.user root } -vlan_ifconfig_tagged_body() +vlan_ifconfig_iftagged_body() { vnet_init vnet_init_bridge @@ -1170,34 +1164,34 @@ vlan_ifconfig_tagged_body() atf_check -s exit:0 -o not-match:"tagged" ifconfig ${bridge} # Add vlans 100-149. - atf_check -s exit:0 ifconfig ${bridge} tagged ${ep}a 100-149 + atf_check -s exit:0 ifconfig ${bridge} iftagged ${ep}a 100-149 atf_check -s exit:0 -o match:"tagged 100-149" ifconfig ${bridge} # Replace the vlan list with 139-199. - atf_check -s exit:0 ifconfig ${bridge} tagged ${ep}a 139-199 + atf_check -s exit:0 ifconfig ${bridge} iftagged ${ep}a 139-199 atf_check -s exit:0 -o match:"tagged 139-199" ifconfig ${bridge} # Add vlans 100-170. - atf_check -s exit:0 ifconfig ${bridge} +tagged ${ep}a 100-170 + atf_check -s exit:0 ifconfig ${bridge} +iftagged ${ep}a 100-170 atf_check -s exit:0 -o match:"tagged 100-199" ifconfig ${bridge} # Remove vlans 104, 105, and 150-159 - atf_check -s exit:0 ifconfig ${bridge} -tagged ${ep}a 104,105,150-159 + atf_check -s exit:0 ifconfig ${bridge} -iftagged ${ep}a 104,105,150-159 atf_check -s exit:0 -o match:"tagged 100-103,106-149,160-199" \ ifconfig ${bridge} # Remove the entire vlan list. - atf_check -s exit:0 ifconfig ${bridge} tagged ${ep}a none + atf_check -s exit:0 ifconfig ${bridge} iftagged ${ep}a none atf_check -s exit:0 -o not-match:"tagged" ifconfig ${bridge} # Test some invalid vlans sets. for bad_vlan in -1 0 4096 4097 foo 0-10 4000-5000 foo-40 40-foo; do atf_check -s exit:1 -e ignore \ - ifconfig ${bridge} tagged "$bad_vlan" + ifconfig ${bridge} iftagged "$bad_vlan" done } -vlan_ifconfig_tagged_cleanup() +vlan_ifconfig_iftagged_cleanup() { vnet_cleanup } @@ -1229,8 +1223,7 @@ vlan_svi_body() atf_check -s exit:0 ifconfig ${bridge} vlanfilter up atf_check -s exit:0 ifconfig ${epone}a up - atf_check -s exit:0 ifconfig ${bridge} addm ${epone}a \ - tagged ${epone}a 20 + atf_check -s exit:0 ifconfig ${bridge} addm ${epone}a tagged 20 svi=$(vnet_mkvlan) atf_check -s exit:0 ifconfig ${svi} vlan 20 vlandev ${bridge} @@ -1294,8 +1287,8 @@ vlan_qinq_body() atf_check -s exit:2 -o ignore jexec two ping -c 3 -t 1 192.0.2.1 # Add the provider tag to the access list; now traffic should be passed. - atf_check -s exit:0 ifconfig ${bridge} +tagged ${epone}a 5 - atf_check -s exit:0 ifconfig ${bridge} +tagged ${eptwo}a 5 + atf_check -s exit:0 ifconfig ${bridge} +iftagged ${epone}a 5 + atf_check -s exit:0 ifconfig ${bridge} +iftagged ${eptwo}a 5 atf_check -s exit:0 -o ignore jexec one ping -c 3 -t 1 192.0.2.2 atf_check -s exit:0 -o ignore jexec two ping -c 3 -t 1 192.0.2.1 @@ -1411,7 +1404,7 @@ atf_init_test_cases() atf_add_test_case "vlan_pvid_filtered" atf_add_test_case "vlan_pvid_tagged" atf_add_test_case "vlan_filtering" - atf_add_test_case "vlan_ifconfig_tagged" + atf_add_test_case "vlan_ifconfig_iftagged" atf_add_test_case "vlan_svi" atf_add_test_case "vlan_qinq" atf_add_test_case "vlan_defuntagged"