bridge: Add a vlanfilter bridge option

vlanfilter was originally a per-interface flag to allow more flexible
configurations where some interfaces had VLAN filtering enabled and
some didn't.  In practice, this just makes the configuration more
confusing without any real benefit, so remove it, and make vlanfilter
a bridge flag instead.

Add a new bridge option "defuntagged", which sets the automatically
assigned PVID for new members.  If set to 0 (the default) then no
PVID is assigned, which matches the current behaviour.

While here, add some more atf_checks to the bridge VLAN tests to
make debugging easier.

Differential Revision:	https://reviews.freebsd.org/D51600
This commit is contained in:
Lexi Winter 2025-08-03 23:54:59 +01:00
parent d733bca670
commit ce06c1921e
8 changed files with 299 additions and 98 deletions

View file

@ -69,6 +69,8 @@ struct ifconfig_bridge_status {
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 {

View file

@ -92,6 +92,18 @@ ifconfig_bridge_get_bridge_status(ifconfig_handle_t *h,
}
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;

View file

@ -223,6 +223,11 @@ bridge_status(if_ctx *ctx)
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 @@ setbridge_deladdr(if_ctx *ctx, int argc, const char *const *argv)
static void
setbridge_addr(if_ctx *ctx, const char *val __unused, int dummy __unused)
{
bridge_addresses(ctx, "");
}
@ -735,18 +739,6 @@ unsetbridge_private(if_ctx *ctx, const char *val, int dummy __unused)
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 @@ delbridge_tagged(if_ctx *ctx, const char *ifn, const char *vlans)
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 @@ 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_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 @@ static struct cmd bridge_cmds[] = {
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,

View file

@ -2710,18 +2710,23 @@ The behaviour of these options is described in the
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 @@ meaning the empty set,
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:

View file

@ -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 @@ interface on the bridge and (if necessary) assign IP addresses there.
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.

View file

@ -300,6 +300,8 @@ struct bridge_softc {
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_grte(struct bridge_softc *, void *);
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 @@ static const struct bridge_control bridge_control_table[] = {
{ 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 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
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 @@ bridge_ioctl_sifpvid(struct bridge_softc *sc, void *arg)
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 @@ bridge_ioctl_sifpvid(struct bridge_softc *sc, void *arg)
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 @@ bridge_ioctl_sifvlanset(struct bridge_softc *sc, void *arg)
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 @@ bridge_ioctl_sifvlanset(struct bridge_softc *sc, void *arg)
"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 @@ bridge_ioctl_stxhc(struct bridge_softc *sc, void *arg)
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 @@ bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m,
* 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 @@ bridge_vfilter_in(const struct bridge_iflist *sbif, struct mbuf *m)
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 @@ bridge_vfilter_out(const struct bridge_iflist *dbif, const struct mbuf *m)
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);

View file

@ -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 @@ struct ifbreq {
#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 @@ struct ifbrparam {
#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.
*/

View file

@ -919,7 +919,7 @@ vlan_pvid_body()
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 @@ vlan_pvid_filtered_body()
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 @@ vlan_pvid_tagged_body()
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 @@ vlan_pvid_1q_body()
# 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 @@ vlan_filtering_body()
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 @@ vlan_filtering_body()
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 @@ vlan_ifconfig_tagged_body()
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 @@ vlan_svi_body()
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 @@ bridge_svi_in_bridge_cleanup()
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_init_test_cases()
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"
}