diff --git a/lib/libifconfig/libifconfig.h b/lib/libifconfig/libifconfig.h --- a/lib/libifconfig/libifconfig.h +++ b/lib/libifconfig/libifconfig.h @@ -69,6 +69,8 @@ size_t members_count; /**< how many member interfaces */ uint32_t cache_size; /**< size of address cache */ uint32_t cache_lifetime; /**< address cache entry lifetime */ + ifbr_flags_t flags; /**< bridge flags */ + ether_vlanid_t defpvid; /**< default pvid */ }; struct ifconfig_capabilities { diff --git a/lib/libifconfig/libifconfig_bridge.c b/lib/libifconfig/libifconfig_bridge.c --- a/lib/libifconfig/libifconfig_bridge.c +++ b/lib/libifconfig/libifconfig_bridge.c @@ -92,6 +92,18 @@ } bridge->inner.cache_lifetime = cache_param.ifbrp_ctime; + if (ifconfig_bridge_ioctlwrap(h, name, BRDGGFLAGS, + &cache_param, sizeof(cache_param), false) != 0) { + goto err; + } + bridge->inner.flags = cache_param.ifbrp_flags; + + if (ifconfig_bridge_ioctlwrap(h, name, BRDGGDEFPVID, + &cache_param, sizeof(cache_param), false) != 0) { + goto err; + } + bridge->inner.defpvid = cache_param.ifbrp_defpvid; + if (ifconfig_bridge_ioctlwrap(h, name, BRDGPARAM, &bridge->params, sizeof(bridge->params), false) != 0) { goto err; diff --git a/sbin/ifconfig/ifbridge.c b/sbin/ifconfig/ifbridge.c --- a/sbin/ifconfig/ifbridge.c +++ b/sbin/ifconfig/ifbridge.c @@ -223,6 +223,11 @@ params->ifbop_root_path_cost, params->ifbop_root_port & 0xfff); + printb("\tbridge flags", bridge->flags, IFBRFBITS); + if (bridge->defpvid) + printf(" defuntagged=%u", (unsigned) bridge->defpvid); + printf("\n"); + prefix = "\tmember: "; pad = "\t "; for (size_t i = 0; i < bridge->members_count; ++i) { @@ -514,7 +519,6 @@ static void setbridge_addr(if_ctx *ctx, const char *val __unused, int dummy __unused) { - bridge_addresses(ctx, ""); } @@ -735,18 +739,6 @@ do_bridgeflag(ctx, val, IFBIF_PRIVATE, 0); } -static void -setbridge_vlanfilter(if_ctx *ctx, const char *val, int dummy __unused) -{ - do_bridgeflag(ctx, val, IFBIF_VLANFILTER, 1); -} - -static void -unsetbridge_vlanfilter(if_ctx *ctx, const char *val, int dummy __unused) -{ - do_bridgeflag(ctx, val, IFBIF_VLANFILTER, 0); -} - static int parse_vlans(ifbvlan_set_t *set, const char *str) { @@ -838,6 +830,59 @@ set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_DEL); } +static void +setbridge_flags(if_ctx *ctx, const char *val __unused, int newflags) +{ + struct ifbrparam req; + + if (do_cmd(ctx, BRDGGFLAGS, &req, sizeof(req), 0) < 0) + err(1, "BRDGGFLAGS"); + + req.ifbrp_flags |= (uint32_t)newflags; + + if (do_cmd(ctx, BRDGSFLAGS, &req, sizeof(req), 1) < 0) + err(1, "BRDGSFLAGS"); +} + +static void +unsetbridge_flags(if_ctx *ctx, const char *val __unused, int newflags) +{ + struct ifbrparam req; + + if (do_cmd(ctx, BRDGGFLAGS, &req, sizeof(req), 0) < 0) + err(1, "BRDGGFLAGS"); + + req.ifbrp_flags &= ~(uint32_t)newflags; + + if (do_cmd(ctx, BRDGSFLAGS, &req, sizeof(req), 1) < 0) + err(1, "BRDGSFLAGS"); +} + +static void +setbridge_defuntagged(if_ctx *ctx, const char *arg, int dummy __unused) +{ + struct ifbrparam req; + + memset(&req, 0, sizeof(req)); + if (get_vlan_id(arg, &req.ifbrp_defpvid) < 0) + errx(1, "invalid vlan id: %s", arg); + + if (do_cmd(ctx, BRDGSDEFPVID, &req, sizeof(req), 1) < 0) + err(1, "BRDGSDEFPVID"); +} + +static void +unsetbridge_defuntagged(if_ctx *ctx, const char *val __unused, int dummy __unused) +{ + struct ifbrparam req; + + memset(&req, 0, sizeof(req)); + req.ifbrp_defpvid = 0; + + if (do_cmd(ctx, BRDGSDEFPVID, &req, sizeof(req), 1) < 0) + err(1, "BRDGSDEFPVID"); +} + static struct cmd bridge_cmds[] = { DEF_CMD_ARG("addm", setbridge_add), DEF_CMD_ARG("deletem", setbridge_delete), @@ -874,8 +919,6 @@ DEF_CMD_ARG2("ifpriority", setbridge_ifpriority), DEF_CMD_ARG2("ifpathcost", setbridge_ifpathcost), DEF_CMD_ARG2("ifmaxaddr", setbridge_ifmaxaddr), - DEF_CMD_ARG("vlanfilter", setbridge_vlanfilter), - DEF_CMD_ARG("-vlanfilter", unsetbridge_vlanfilter), DEF_CMD_ARG2("untagged", setbridge_untagged), DEF_CMD_ARG("-untagged", unsetbridge_untagged), DEF_CMD_ARG2("tagged", setbridge_tagged), @@ -884,7 +927,14 @@ DEF_CMD_ARG("timeout", setbridge_timeout), DEF_CMD_ARG("private", setbridge_private), DEF_CMD_ARG("-private", unsetbridge_private), + DEF_CMD("vlanfilter", (int32_t)IFBRF_VLANFILTER, + setbridge_flags), + DEF_CMD("-vlanfilter", (int32_t)IFBRF_VLANFILTER, + unsetbridge_flags), + DEF_CMD_ARG("defuntagged", setbridge_defuntagged), + DEF_CMD("-defuntagged", 0, unsetbridge_defuntagged), }; + static struct afswtch af_bridge = { .af_name = "af_bridge", .af_af = AF_UNSPEC, diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8 --- a/sbin/ifconfig/ifconfig.8 +++ b/sbin/ifconfig/ifconfig.8 @@ -2710,18 +2710,23 @@ section of .Xr bridge 4 . .Bl -tag -width indent -.It Cm vlanfilter Ar interface -Enable VLAN filtering on an interface. -.It Cm -vlanfilter Ar interface -Disable VLAN filtering on an interface. +.It Cm vlanfilter +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 Set the untagged VLAN identifier for an interface. -.Pp -Setting -.Cm untagged -will automatically enable VLAN filtering on the interface. .It Cm -untagged Ar interface Ar vlan-id Clear the untagged VLAN identifier for an interface. +.It Cm defuntagged Ar vlan-id +Enable the +.Cm untagged +option by default on newly added members. +.It Cm -defuntagged +Do not enable the +.Cm untagged +option by default on newly added members. .It Cm tagged 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 @@ -2733,27 +2738,15 @@ or the value .Dq all meaning all VLANs (1-4094). -.Pp -Setting -.Cm tagged -will automatically enable VLAN filtering on the interface. .It Cm +tagged 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 . -.Pp -Setting -.Cm +tagged -will automatically enable VLAN filtering on the interface. .It Cm -tagged 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 . -.Pp -Setting -.Cm -tagged -will automatically enable VLAN filtering on the interface. .El .Ss Link Aggregation and Link Failover Parameters The following parameters are specific to lagg interfaces: diff --git a/share/man/man4/bridge.4 b/share/man/man4/bridge.4 --- a/share/man/man4/bridge.4 +++ b/share/man/man4/bridge.4 @@ -36,7 +36,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd July 5, 2025 +.Dd July 28, 2025 .Dt IF_BRIDGE 4 .Os .Sh NAME @@ -289,7 +289,7 @@ By default no access control is enabled, so any interface may participate in any VLAN. .Pp -VLAN filtering may be enabled on an interface using the +VLAN filtering may be enabled on a bridge using the .Xr ifconfig 8 .Cm vlanfilter option. diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -300,6 +300,8 @@ struct ether_addr sc_defaddr; /* Default MAC address */ if_input_fn_t sc_if_input; /* Saved copy of if_input */ struct epoch_context sc_epoch_ctx; + ifbr_flags_t sc_flags; /* bridge flags */ + ether_vlanid_t sc_defpvid; /* default PVID */ }; VNET_DEFINE_STATIC(struct sx, bridge_list_sx); @@ -417,6 +419,10 @@ static int bridge_ioctl_gifsstp(struct bridge_softc *, void *); static int bridge_ioctl_sproto(struct bridge_softc *, void *); static int bridge_ioctl_stxhc(struct bridge_softc *, void *); +static int bridge_ioctl_gflags(struct bridge_softc *, void *); +static int bridge_ioctl_sflags(struct bridge_softc *, void *); +static int bridge_ioctl_gdefpvid(struct bridge_softc *, void *); +static int bridge_ioctl_sdefpvid(struct bridge_softc *, void *); static int bridge_pfil(struct mbuf **, struct ifnet *, struct ifnet *, int); #ifdef INET @@ -636,6 +642,18 @@ { bridge_ioctl_gifvlanset, sizeof(struct ifbif_vlan_req), BC_F_COPYIN|BC_F_COPYOUT }, + + { bridge_ioctl_gflags, sizeof(struct ifbrparam), + BC_F_COPYOUT }, + + { bridge_ioctl_sflags, sizeof(struct ifbrparam), + BC_F_COPYIN|BC_F_SUSER }, + + { bridge_ioctl_gdefpvid, sizeof(struct ifbrparam), + BC_F_COPYOUT }, + + { bridge_ioctl_sdefpvid, sizeof(struct ifbrparam), + BC_F_COPYIN|BC_F_SUSER }, }; static const int bridge_control_table_size = nitems(bridge_control_table); @@ -1476,6 +1494,8 @@ bif->bif_ifp = ifs; bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER; bif->bif_savedcaps = ifs->if_capenable; + if (sc->sc_flags & IFBRF_VLANFILTER) + bif->bif_pvid = sc->sc_defpvid; /* * Assign the interface's MAC address to the bridge if it's the first @@ -1941,6 +1961,9 @@ struct ifbreq *req = arg; struct bridge_iflist *bif; + if ((sc->sc_flags & IFBRF_VLANFILTER) == 0) + return (EXTERROR(EINVAL, "VLAN filtering not enabled")); + bif = bridge_lookup_member(sc, req->ifbr_ifsname); if (bif == NULL) return (EXTERROR(ENOENT, "Interface is not a bridge member")); @@ -1948,8 +1971,6 @@ if (req->ifbr_pvid > DOT1Q_VID_MAX) return (EXTERROR(EINVAL, "Invalid VLAN ID")); - if (req->ifbr_pvid != DOT1Q_VID_NULL) - bif->bif_flags |= IFBIF_VLANFILTER; bif->bif_pvid = req->ifbr_pvid; return (0); } @@ -1960,6 +1981,9 @@ struct ifbif_vlan_req *req = arg; struct bridge_iflist *bif; + if ((sc->sc_flags & IFBRF_VLANFILTER) == 0) + return (EXTERROR(EINVAL, "VLAN filtering not enabled")); + bif = bridge_lookup_member(sc, req->bv_ifname); if (bif == NULL) return (EXTERROR(ENOENT, "Interface is not a bridge member")); @@ -1991,12 +2015,6 @@ "Unsupported BRDGSIFVLANSET operation")); } - /* - * The only reason to modify the VLAN access list is to use VLAN - * filtering on this interface, so enable it automatically. - */ - bif->bif_flags |= IFBIF_VLANFILTER; - return (0); } @@ -2190,6 +2208,50 @@ return (bstp_set_holdcount(&sc->sc_stp, param->ifbrp_txhc)); } +static int +bridge_ioctl_gflags(struct bridge_softc *sc, void *arg) +{ + struct ifbrparam *param = arg; + + param->ifbrp_flags = sc->sc_flags; + + return (0); +} + +static int +bridge_ioctl_sflags(struct bridge_softc *sc, void *arg) +{ + struct ifbrparam *param = arg; + + sc->sc_flags = param->ifbrp_flags; + + return (0); +} + +static int +bridge_ioctl_gdefpvid(struct bridge_softc *sc, void *arg) +{ + struct ifbrparam *param = arg; + + param->ifbrp_defpvid = sc->sc_defpvid; + + return (0); +} + +static int +bridge_ioctl_sdefpvid(struct bridge_softc *sc, void *arg) +{ + struct ifbrparam *param = arg; + + /* Reject invalid VIDs, but allow 0 to mean 'none'. */ + if (param->ifbrp_defpvid > DOT1Q_VID_MAX) + return (EINVAL); + + sc->sc_defpvid = param->ifbrp_defpvid; + + return (0); +} + /* * bridge_ifdetach: * @@ -2325,7 +2387,7 @@ * outgoing interface matches the VLAN ID of the frame, remove * the VLAN header. */ - if ((bif->bif_flags & IFBIF_VLANFILTER) && + if ((sc->sc_flags & IFBRF_VLANFILTER) && bif->bif_pvid != DOT1Q_VID_NULL && VLANTAGOF(m) == bif->bif_pvid) { m->m_flags &= ~M_VLANTAG; @@ -3185,7 +3247,7 @@ return (false); /* If VLAN filtering isn't enabled, pass everything. */ - if ((sbif->bif_flags & IFBIF_VLANFILTER) == 0) + if ((sbif->bif_sc->sc_flags & IFBRF_VLANFILTER) == 0) return (true); if (vlan == DOT1Q_VID_NULL) { @@ -3231,7 +3293,7 @@ NET_EPOCH_ASSERT(); /* If VLAN filtering isn't enabled, pass everything. */ - if ((dbif->bif_flags & IFBIF_VLANFILTER) == 0) + if ((dbif->bif_sc->sc_flags & IFBRF_VLANFILTER) == 0) return (true); vlan = VLANTAGOF(m); diff --git a/sys/net/if_bridgevar.h b/sys/net/if_bridgevar.h --- a/sys/net/if_bridgevar.h +++ b/sys/net/if_bridgevar.h @@ -127,6 +127,17 @@ #define BRDGSIFPVID 31 /* set if PVID */ #define BRDGSIFVLANSET 32 /* set if vlan set */ #define BRDGGIFVLANSET 33 /* get if vlan set */ +#define BRDGGFLAGS 34 /* get bridge flags (ifbrparam) */ +#define BRDGSFLAGS 35 /* set bridge flags (ifbrparam) */ +#define BRDGGDEFPVID 36 /* get default pvid (ifbrparam) */ +#define BRDGSDEFPVID 37 /* set default pvid (ifbrparam) */ + +/* BRDGSFLAGS, Bridge flags (non-interface-specific) */ +typedef uint32_t ifbr_flags_t; + +#define IFBRF_VLANFILTER (1U<<0) /* VLAN filtering enabled */ + +#define IFBRFBITS "\020\01VLANFILTER" /* * Generic bridge control request. @@ -161,11 +172,12 @@ #define IFBIF_BSTP_ADMEDGE 0x0200 /* member stp admin edge enabled */ #define IFBIF_BSTP_ADMCOST 0x0400 /* member stp admin path cost */ #define IFBIF_PRIVATE 0x0800 /* if is a private segment */ -#define IFBIF_VLANFILTER 0x1000 /* if does vlan filtering */ +/* was IFBIF_VLANFILTER 0x1000 */ +#define IFBIF_QINQ 0x2000 /* if allows 802.1ad Q-in-Q */ #define IFBIFBITS "\020\001LEARNING\002DISCOVER\003STP\004SPAN" \ "\005STICKY\014PRIVATE\006EDGE\007AUTOEDGE\010PTP" \ - "\011AUTOPTP\015VLANFILTER" + "\011AUTOPTP" #define IFBIFMASK ~(IFBIF_BSTP_EDGE|IFBIF_BSTP_AUTOEDGE|IFBIF_BSTP_PTP| \ IFBIF_BSTP_AUTOPTP|IFBIF_BSTP_ADMEDGE| \ IFBIF_BSTP_ADMCOST) /* not saved */ @@ -237,7 +249,10 @@ #define ifbrp_fwddelay ifbrp_ifbrpu.ifbrpu_int8 /* fwd time (sec) */ #define ifbrp_maxage ifbrp_ifbrpu.ifbrpu_int8 /* max age (sec) */ #define ifbrp_cexceeded ifbrp_ifbrpu.ifbrpu_int32 /* # of cache dropped - * adresses */ + * addresses */ +#define ifbrp_flags ifbrp_ifbrpu.ifbrpu_int32 /* bridge flags */ +#define ifbrp_defpvid ifbrp_ifbrpu.ifbrpu_int16 /* default pvid */ + /* * Bridge current operational parameters structure. */ diff --git a/tests/sys/net/if_bridge_test.sh b/tests/sys/net/if_bridge_test.sh --- a/tests/sys/net/if_bridge_test.sh +++ b/tests/sys/net/if_bridge_test.sh @@ -919,7 +919,7 @@ bridge=$(vnet_mkbridge) - ifconfig ${bridge} up + ifconfig ${bridge} vlanfilter up ifconfig ${epone}a up ifconfig ${eptwo}a up ifconfig ${bridge} addm ${epone}a untagged ${epone}a 20 @@ -958,16 +958,18 @@ vnet_mkjail one ${epone}b vnet_mkjail two ${eptwo}b - jexec one ifconfig ${epone}b 192.0.2.1/24 up - jexec two ifconfig ${eptwo}b 192.0.2.2/24 up + atf_check -s exit:0 jexec one ifconfig ${epone}b 192.0.2.1/24 up + atf_check -s exit:0 jexec two ifconfig ${eptwo}b 192.0.2.2/24 up bridge=$(vnet_mkbridge) - ifconfig ${bridge} 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 30 + 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: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 @@ -997,18 +999,22 @@ vnet_mkjail two ${eptwo}b # Create two tagged interfaces on the appropriate VLANs - jexec one ifconfig ${epone}b up - jexec one ifconfig ${epone}b.20 create 192.0.2.1/24 up - jexec two ifconfig ${eptwo}b up - jexec two ifconfig ${eptwo}b.20 create 192.0.2.2/24 up + atf_check -s exit:0 jexec one ifconfig ${epone}b up + atf_check -s exit:0 jexec one ifconfig ${epone}b.20 \ + create 192.0.2.1/24 up + atf_check -s exit:0 jexec two ifconfig ${eptwo}b up + atf_check -s exit:0 jexec two ifconfig ${eptwo}b.20 \ + create 192.0.2.2/24 up bridge=$(vnet_mkbridge) - ifconfig ${bridge} 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 + 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 # Tagged frames should not be passed. atf_check -s exit:2 -o ignore jexec one ping -c 3 -t 1 192.0.2.2 @@ -1042,18 +1048,20 @@ # This forces the bridge to add and remove .1q tags to bridge the # traffic. - jexec one ifconfig ${epone}b 192.0.2.1/24 up - jexec two ifconfig ${eptwo}b up - jexec two ifconfig ${eptwo}b.20 create 192.0.2.2/24 up + atf_check -s exit:0 jexec one ifconfig ${epone}b 192.0.2.1/24 up + atf_check -s exit:0 jexec two ifconfig ${eptwo}b up + atf_check -s exit:0 jexec two ifconfig ${eptwo}b.20 create 192.0.2.2/24 up bridge=$(vnet_mkbridge) - ifconfig ${bridge} addm ${epone}a untagged ${epone}a 20 - ifconfig ${bridge} addm ${eptwo}a + 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 - ifconfig ${bridge} up - ifconfig ${epone}a up - ifconfig ${eptwo}a up + atf_check -s exit:0 ifconfig ${epone}a up + atf_check -s exit:0 ifconfig ${eptwo}a up 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 @@ -1085,18 +1093,20 @@ vnet_mkjail one ${epone}b vnet_mkjail two ${eptwo}b - jexec one ifconfig ${epone}b up - jexec one ifconfig ${epone}b.20 create 192.0.2.1/24 up - jexec two ifconfig ${eptwo}b up - jexec two ifconfig ${eptwo}b.20 create 192.0.2.2/24 up + atf_check -s exit:0 jexec one ifconfig ${epone}b up + atf_check -s exit:0 jexec one ifconfig ${epone}b.20 \ + create 192.0.2.1/24 up + atf_check -s exit:0 jexec two ifconfig ${eptwo}b up + atf_check -s exit:0 jexec two ifconfig ${eptwo}b.20 \ + create 192.0.2.2/24 up bridge=$(vnet_mkbridge) - ifconfig ${bridge} up - ifconfig ${epone}a up - ifconfig ${eptwo}a up - ifconfig ${bridge} addm ${epone}a vlanfilter ${epone}a - ifconfig ${bridge} addm ${eptwo}a vlanfilter ${eptwo}a + 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 + atf_check -s exit:0 ifconfig ${bridge} addm ${eptwo}a # Right now there are no VLANs on the access list, so everything # should be blocked. @@ -1116,15 +1126,15 @@ atf_check -s exit:0 ifconfig ${bridge} -untagged ${eptwo}a # Add VLANs 10-30 to the access list; now access should be allowed. - ifconfig ${bridge} +tagged ${epone}a 10-30 - ifconfig ${bridge} +tagged ${eptwo}a 10-30 + 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 -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. - ifconfig ${bridge} -tagged ${epone}a 20 - ifconfig ${bridge} -tagged ${eptwo}a 20 + 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: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 } @@ -1151,9 +1161,10 @@ ep=$(vnet_mkepair) bridge=$(vnet_mkbridge) + atf_check -s exit:0 ifconfig ${bridge} vlanfilter up - ifconfig ${bridge} addm ${ep}a vlanfilter ${ep}a up - ifconfig ${ep}a up + atf_check -s exit:0 ifconfig ${bridge} addm ${ep}a + atf_check -s exit:0 ifconfig ${ep}a up # To start with, no vlans should be configured. atf_check -s exit:0 -o not-match:"tagged" ifconfig ${bridge} @@ -1210,18 +1221,20 @@ vnet_mkjail one ${epone}b - jexec one ifconfig ${epone}b up - jexec one ifconfig ${epone}b.20 create 192.0.2.1/24 up + atf_check -s exit:0 jexec one ifconfig ${epone}b up + atf_check -s exit:0 jexec one ifconfig ${epone}b.20 \ + create 192.0.2.1/24 up bridge=$(vnet_mkbridge) - ifconfig ${bridge} up - ifconfig ${epone}a up - ifconfig ${bridge} addm ${epone}a tagged ${epone}a 20 + 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 svi=$(vnet_mkvlan) - ifconfig ${svi} vlan 20 vlandev ${bridge} - ifconfig ${svi} inet 192.0.2.2/24 up + atf_check -s exit:0 ifconfig ${svi} vlan 20 vlandev ${bridge} + atf_check -s exit:0 ifconfig ${svi} inet 192.0.2.2/24 up atf_check -s exit:0 -o ignore ping -c 3 -t 1 192.0.2.1 } @@ -1311,6 +1324,59 @@ vnet_cleanup } +atf_test_case "vlan_defuntagged" "cleanup" +vlan_defuntagged_head() +{ + atf_set descr 'defuntagged (defpvid) bridge option' + atf_set require.user root +} + +vlan_defuntagged_body() +{ + vnet_init + vnet_init_bridge + + bridge=$(vnet_mkbridge) + atf_check -s exit:0 ifconfig ${bridge} vlanfilter + + # Invalid VLAN IDs + atf_check -s exit:1 -ematch:"invalid vlan id: 0" \ + ifconfig ${bridge} defuntagged 0 + atf_check -s exit:1 -ematch:"invalid vlan id: 4095" \ + ifconfig ${bridge} defuntagged 4095 + atf_check -s exit:1 -ematch:"invalid vlan id: 5000" \ + ifconfig ${bridge} defuntagged 5000 + + # Check the bridge option is set and cleared correctly + atf_check -s exit:0 -onot-match:"defuntagged=" \ + ifconfig ${bridge} + + atf_check -s exit:0 ifconfig ${bridge} defuntagged 10 + atf_check -s exit:0 -omatch:"defuntagged=10$" \ + ifconfig ${bridge} + + atf_check -s exit:0 ifconfig ${bridge} -defuntagged + atf_check -s exit:0 -onot-match:"defuntagged=" \ + ifconfig ${bridge} + + # Check the untagged option is correctly set on a member + atf_check -s exit:0 ifconfig ${bridge} defuntagged 10 + + epair=$(vnet_mkepair) + atf_check -s exit:0 ifconfig ${bridge} addm ${epair}a + + tag=$(ifconfig ${bridge} | sed -Ene \ + "/member: ${epair}a/ { N;s/.*untagged ([0-9]+).*/\\1/p;q; }") + if [ "$tag" != "10" ]; then + atf_fail "wrong untagged vlan: ${tag}" + fi +} + +vlan_defuntagged_cleanup() +{ + vnet_cleanup +} + atf_init_test_cases() { atf_add_test_case "bridge_transmit_ipv4_unicast" @@ -1338,5 +1404,6 @@ atf_add_test_case "vlan_ifconfig_tagged" atf_add_test_case "vlan_svi" atf_add_test_case "vlan_qinq" + atf_add_test_case "vlan_defuntagged" atf_add_test_case "bridge_svi_in_bridge" }