bridge: add per-interface vlan access list

The new ifconfig options 'tagged', '+tagged' and '-tagged' allow the
vlan access list of a bridge interface to be configured:

- Incoming tagged frames will be dropped if the vlan tag isn't in the
  interface's access list.

- Outgoing frames will be dropped if the vlan tag isn't in the
  interface's access list (e.g., for BUM traffic).

This has no effect if vlan filtering is not enabled on the interface.

Since we now add a tag to untagged frames at ingress, remove the
vlan argument from bridge_vfilter_out() and use VLANTAGOF instead.

Reviewed by:	des, kp, adrian
Approved by:	des (mentor)
Differential Revision:	https://reviews.freebsd.org/D50503
This commit is contained in:
Lexi Winter
2025-05-28 08:57:33 +01:00
parent 877a7a325b
commit 032d32c2c2
8 changed files with 503 additions and 49 deletions
+2
View File
@@ -29,6 +29,7 @@
#include <sys/types.h>
#include <net/if.h>
#include <net/if_bridgevar.h> /* for ifbvlan_set_t */
#include <netinet/in.h>
#include <netinet/ip_carp.h>
@@ -64,6 +65,7 @@ struct lagg_reqport;
struct ifconfig_bridge_status {
struct ifbropreq *params; /**< current operational parameters */
struct ifbreq *members; /**< list of bridge members */
ifbvlan_set_t *member_vlans; /**< bridge member vlan sets */
size_t members_count; /**< how many member interfaces */
uint32_t cache_size; /**< size of address cache */
uint32_t cache_lifetime; /**< address cache entry lifetime */
+38 -16
View File
@@ -66,40 +66,37 @@ ifconfig_bridge_get_bridge_status(ifconfig_handle_t *h,
{
struct ifbifconf members;
struct ifbrparam cache_param;
struct _ifconfig_bridge_status *bridge;
char *buf;
struct _ifconfig_bridge_status *bridge = NULL;
char *buf = NULL;
members.ifbic_buf = NULL;
*bridgep = NULL;
bridge = calloc(1, sizeof(struct _ifconfig_bridge_status));
if (bridge == NULL) {
h->error.errtype = OTHER;
h->error.errcode = ENOMEM;
return (-1);
goto err;
}
bridge->inner.params = &bridge->params;
if (ifconfig_bridge_ioctlwrap(h, name, BRDGGCACHE,
&cache_param, sizeof(cache_param), false) != 0) {
free(bridge);
return (-1);
goto err;
}
bridge->inner.cache_size = cache_param.ifbrp_csize;
if (ifconfig_bridge_ioctlwrap(h, name, BRDGGTO,
&cache_param, sizeof(cache_param), false) != 0) {
free(bridge);
return (-1);
goto err;
}
bridge->inner.cache_lifetime = cache_param.ifbrp_ctime;
if (ifconfig_bridge_ioctlwrap(h, name, BRDGPARAM,
&bridge->params, sizeof(bridge->params), false) != 0) {
free(bridge);
return (-1);
goto err;
}
members.ifbic_buf = NULL;
for (size_t len = 8192;
(buf = realloc(members.ifbic_buf, len)) != NULL;
len *= 2) {
@@ -107,27 +104,52 @@ ifconfig_bridge_get_bridge_status(ifconfig_handle_t *h,
members.ifbic_len = len;
if (ifconfig_bridge_ioctlwrap(h, name, BRDGGIFS,
&members, sizeof(members), false) != 0) {
free(buf);
free(bridge);
return (-1);
goto err;
}
if ((members.ifbic_len + sizeof(*members.ifbic_req)) < len)
break;
}
if (buf == NULL) {
free(members.ifbic_buf);
free(bridge);
h->error.errtype = OTHER;
h->error.errcode = ENOMEM;
return (-1);
goto err;
}
bridge->inner.members = members.ifbic_req;
bridge->inner.members_count =
members.ifbic_len / sizeof(*members.ifbic_req);
bridge->inner.member_vlans = calloc(bridge->inner.members_count,
sizeof(ifbvlan_set_t));
if (bridge->inner.member_vlans == NULL) {
h->error.errtype = OTHER;
h->error.errcode = ENOMEM;
goto err;
}
for (size_t i = 0; i < bridge->inner.members_count; ++i) {
struct ifbif_vlan_req vreq;
memset(&vreq, 0, sizeof(vreq));
strlcpy(vreq.bv_ifname, bridge->inner.members[i].ifbr_ifsname,
sizeof(vreq.bv_ifname));
if (ifconfig_bridge_ioctlwrap(h, name, BRDGGIFVLANSET, &vreq,
sizeof(vreq), false) != 0) {
goto err;
}
__BIT_COPY(BRVLAN_SETSIZE, &vreq.bv_set,
&bridge->inner.member_vlans[i]);
}
*bridgep = &bridge->inner;
return (0);
err:
free(members.ifbic_buf);
if (bridge)
free(bridge->inner.member_vlans);
free(bridge);
return (-1);
}
void
+125
View File
@@ -146,6 +146,36 @@ bridge_addresses(if_ctx *ctx, const char *prefix)
free(inbuf);
}
static void
print_vlans(ifbvlan_set_t *vlans)
{
unsigned printed = 0;
for (unsigned vlan = DOT1Q_VID_MIN; vlan <= DOT1Q_VID_MAX;) {
unsigned last;
if (!BRVLAN_TEST(vlans, vlan)) {
++vlan;
continue;
}
last = vlan;
while (last < DOT1Q_VID_MAX && BRVLAN_TEST(vlans, last + 1))
++last;
if (printed == 0)
printf(" tagged ");
else
printf(",");
printf("%u", vlan);
if (last != vlan)
printf("-%u", last);
++printed;
vlan = last + 1;
}
}
static void
bridge_status(if_ctx *ctx)
{
@@ -213,6 +243,7 @@ bridge_status(if_ctx *ctx)
}
if (member->ifbr_untagged != 0)
printf(" untagged %u", (unsigned)member->ifbr_untagged);
print_vlans(&bridge->member_vlans[i]);
printf("\n");
}
@@ -674,6 +705,97 @@ 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)
{
char *s, *token;
/* "none" means the empty vlan set */
if (strcmp(str, "none") == 0) {
__BIT_ZERO(BRVLAN_SETSIZE, set);
return (0);
}
/* "all" means all vlans, except for 0 and 4095 which are reserved */
if (strcmp(str, "all") == 0) {
__BIT_FILL(BRVLAN_SETSIZE, set);
BRVLAN_CLR(set, DOT1Q_VID_NULL);
BRVLAN_CLR(set, DOT1Q_VID_RSVD_IMPL);
return (0);
}
if ((s = strdup(str)) == NULL)
return (-1);
while ((token = strsep(&s, ",")) != NULL) {
unsigned long first, last;
char *p, *lastp;
if ((lastp = strchr(token, '-')) != NULL)
*lastp++ = '\0';
first = last = strtoul(token, &p, 10);
if (*p != '\0')
goto err;
if (first < DOT1Q_VID_MIN || first > DOT1Q_VID_MAX)
goto err;
if (lastp) {
last = strtoul(lastp, &p, 10);
if (*p != '\0')
goto err;
if (last < DOT1Q_VID_MIN || last > DOT1Q_VID_MAX ||
last < first)
goto err;
}
for (unsigned vlan = first; vlan <= last; ++vlan)
BRVLAN_SET(set, vlan);
}
free(s);
return (0);
err:
free(s);
return (-1);
}
static void
set_bridge_vlanset(if_ctx *ctx, const char *ifn, const char *vlans, int op)
{
struct ifbif_vlan_req req;
memset(&req, 0, sizeof(req));
if (parse_vlans(&req.bv_set, vlans) != 0)
errx(1, "invalid vlan set: %s", vlans);
strlcpy(req.bv_ifname, ifn, sizeof(req.bv_ifname));
req.bv_op = op;
if (do_cmd(ctx, BRDGSIFVLANSET, &req, sizeof(req), 1) < 0)
err(1, "BRDGSIFVLANSET %s", vlans);
}
static void
setbridge_tagged(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)
{
set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_ADD);
}
static void
delbridge_tagged(if_ctx *ctx, const char *ifn, const char *vlans)
{
set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_DEL);
}
static struct cmd bridge_cmds[] = {
DEF_CMD_ARG("addm", setbridge_add),
DEF_CMD_ARG("deletem", setbridge_delete),
@@ -714,6 +836,9 @@ static struct cmd bridge_cmds[] = {
DEF_CMD_ARG("-vlanfilter", unsetbridge_vlanfilter),
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_ARG("timeout", setbridge_timeout),
DEF_CMD_ARG("private", setbridge_private),
DEF_CMD_ARG("-private", unsetbridge_private),
+32
View File
@@ -2714,6 +2714,38 @@ Setting
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 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
or ranges formatted as
.Ar first-last ,
the value
.Dq none
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:
+12 -1
View File
@@ -289,7 +289,8 @@ VLAN filtering may be enabled on an interface using the
.Cm vlanfilter
option.
When VLAN filtering is enabled, an interface may only send and receive
untagged frames.
frames based on its configured VLAN access list.
.Pp
The interface's untagged VLAN ID may be configured using the
.Xr ifconfig 8
.Cm untagged
@@ -298,6 +299,16 @@ If an untagged VLAN ID is configured, incoming frames will be assigned
to that VLAN, and the interface may receive outgoing untagged frames
in that VLAN.
.Pp
The tagged VLAN access list may be configured using the
.Cm tagged ,
.Cm +tagged
and
.Cm -tagged
options to
.Xr ifconfig 8 .
An interface may send and receive tagged frames for any VLAN in its
access list.
.Pp
The bridge will automatically insert or remove 802.1q tags as needed,
based on the interface configuration, when forwarding frames between
interfaces.
+141 -32
View File
@@ -255,6 +255,7 @@ struct bridge_iflist {
uint32_t bif_addrexceeded;/* # of address violations */
struct epoch_context bif_epoch_ctx;
ether_vlanid_t bif_untagged; /* untagged vlan id */
ifbvlan_set_t bif_vlan_set; /* allowed tagged vlans */
};
/*
@@ -353,8 +354,9 @@ static void bridge_rtage(struct bridge_softc *);
static void bridge_rtflush(struct bridge_softc *, int);
static int bridge_rtdaddr(struct bridge_softc *, const uint8_t *,
ether_vlanid_t);
static bool bridge_vfilter_in(const struct bridge_iflist *, struct mbuf *);
static bool bridge_vfilter_out(const struct bridge_iflist *,
const struct mbuf *, ether_vlanid_t);
const struct mbuf *);
static void bridge_rtable_init(struct bridge_softc *);
static void bridge_rtable_fini(struct bridge_softc *);
@@ -403,6 +405,8 @@ static int bridge_ioctl_sifprio(struct bridge_softc *, void *);
static int bridge_ioctl_sifcost(struct bridge_softc *, void *);
static int bridge_ioctl_sifmaxaddr(struct bridge_softc *, void *);
static int bridge_ioctl_sifuntagged(struct bridge_softc *, void *);
static int bridge_ioctl_sifvlanset(struct bridge_softc *, void *);
static int bridge_ioctl_gifvlanset(struct bridge_softc *, void *);
static int bridge_ioctl_addspan(struct bridge_softc *, void *);
static int bridge_ioctl_delspan(struct bridge_softc *, void *);
static int bridge_ioctl_gbparam(struct bridge_softc *, void *);
@@ -623,6 +627,12 @@ static const struct bridge_control bridge_control_table[] = {
{ bridge_ioctl_sifuntagged, sizeof(struct ifbreq),
BC_F_COPYIN|BC_F_SUSER },
{ bridge_ioctl_sifvlanset, sizeof(struct ifbif_vlan_req),
BC_F_COPYIN|BC_F_SUSER },
{ bridge_ioctl_gifvlanset, sizeof(struct ifbif_vlan_req),
BC_F_COPYIN|BC_F_COPYOUT },
};
static const int bridge_control_table_size = nitems(bridge_control_table);
@@ -959,6 +969,7 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct ifbaconf ifbaconf;
struct ifbrparam ifbrparam;
struct ifbropreq ifbropreq;
struct ifbif_vlan_req ifvlanreq;
} args;
struct ifdrv *ifd = (struct ifdrv *) data;
const struct bridge_control *bc;
@@ -1897,6 +1908,65 @@ bridge_ioctl_sifuntagged(struct bridge_softc *sc, void *arg)
return (0);
}
static int
bridge_ioctl_sifvlanset(struct bridge_softc *sc, void *arg)
{
struct ifbif_vlan_req *req = arg;
struct bridge_iflist *bif;
bif = bridge_lookup_member(sc, req->bv_ifname);
if (bif == NULL)
return (ENOENT);
/* Reject invalid VIDs. */
if (BRVLAN_TEST(&req->bv_set, DOT1Q_VID_NULL) ||
BRVLAN_TEST(&req->bv_set, DOT1Q_VID_RSVD_IMPL))
return (EINVAL);
switch (req->bv_op) {
/* Replace the existing vlan set with the new set */
case BRDG_VLAN_OP_SET:
BIT_COPY(BRVLAN_SETSIZE, &req->bv_set, &bif->bif_vlan_set);
break;
/* Modify the existing vlan set to add the given vlans */
case BRDG_VLAN_OP_ADD:
BIT_OR(BRVLAN_SETSIZE, &bif->bif_vlan_set, &req->bv_set);
break;
/* Modify the existing vlan set to remove the given vlans */
case BRDG_VLAN_OP_DEL:
BIT_ANDNOT(BRVLAN_SETSIZE, &bif->bif_vlan_set, &req->bv_set);
break;
/* Invalid or unknown operation */
default:
return (EINVAL);
}
/*
* 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);
}
static int
bridge_ioctl_gifvlanset(struct bridge_softc *sc, void *arg)
{
struct ifbif_vlan_req *req = arg;
struct bridge_iflist *bif;
bif = bridge_lookup_member(sc, req->bv_ifname);
if (bif == NULL)
return (ENOENT);
BIT_COPY(BRVLAN_SETSIZE, &bif->bif_vlan_set, &req->bv_set);
return (0);
}
static int
bridge_ioctl_addspan(struct bridge_softc *sc, void *arg)
{
@@ -2606,7 +2676,7 @@ bridge_forward(struct bridge_softc *sc, struct bridge_iflist *sbif,
goto drop;
/* Do VLAN filtering. */
if (!bridge_vfilter_out(dbif, m, vlan))
if (!bridge_vfilter_out(dbif, m))
goto drop;
if ((dbif->bif_flags & IFBIF_STP) &&
@@ -2691,27 +2761,13 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
}
/* Do VLAN filtering. */
if (bif->bif_flags & IFBIF_VLANFILTER) {
/*
* If the frame was received with a tag, drop it, since we only
* support untagged ports which shouldn't be receiving tagged
* frames.
*
* If the frame was received without a tag, and the port doesn't
* have an untagged vlan configured, drop it.
*/
if (vlan != DOT1Q_VID_NULL ||
bif->bif_untagged == DOT1Q_VID_NULL) {
if_inc_counter(sc->sc_ifp, IFCOUNTER_IERRORS, 1);
m_freem(m);
return (NULL);
}
/* Otherwise, assign the untagged frame to the correct vlan. */
vlan = bif->bif_untagged;
m->m_pkthdr.ether_vtag = bif->bif_untagged;
m->m_flags |= M_VLANTAG;
if (!bridge_vfilter_in(bif, m)) {
if_inc_counter(sc->sc_ifp, IFCOUNTER_IERRORS, 1);
m_freem(m);
return (NULL);
}
/* bridge_vfilter_in() may add a tag */
vlan = VLANTAGOF(m);
bridge_span(sc, m);
@@ -2922,12 +2978,10 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if,
struct mbuf *mc;
struct ifnet *dst_if;
int used = 0, i;
ether_vlanid_t vlan;
NET_EPOCH_ASSERT();
sbif = bridge_lookup_member_if(sc, src_if);
vlan = VLANTAGOF(m);
/* Filter on the bridge interface before broadcasting */
if (runfilt && PFIL_HOOKED_OUT_46) {
@@ -2947,7 +3001,7 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if,
continue;
/* Do VLAN filtering. */
if (!bridge_vfilter_out(dbif, m, vlan))
if (!bridge_vfilter_out(dbif, m))
continue;
if ((dbif->bif_flags & IFBIF_STP) &&
@@ -3033,16 +3087,63 @@ bridge_span(struct bridge_softc *sc, struct mbuf *m)
}
}
/*
* Incoming VLAN filtering. Given a frame and the member interface it was
* received on, decide whether the port configuration allows it.
*/
static bool
bridge_vfilter_in(const struct bridge_iflist *sbif, struct mbuf *m)
{
ether_vlanid_t vlan;
vlan = VLANTAGOF(m);
/* Make sure the vlan id is reasonable. */
if (vlan > DOT1Q_VID_MAX)
return (false);
/* If VLAN filtering isn't enabled, pass everything. */
if ((sbif->bif_flags & IFBIF_VLANFILTER) == 0)
return (true);
if (vlan == DOT1Q_VID_NULL) {
/*
* The frame doesn't have a tag. If the interface does not
* have an untagged vlan configured, drop the frame.
*/
if (sbif->bif_untagged == DOT1Q_VID_NULL)
return (false);
/*
* Otherwise, insert a new tag based on the interface's
* untagged vlan id.
*/
m->m_pkthdr.ether_vtag = sbif->bif_untagged;
m->m_flags |= M_VLANTAG;
} else {
/*
* The frame has a tag, so check it matches the interface's
* vlan access list. We explicitly do not accept tagged
* frames for the untagged vlan id here (unless it's also
* in the access list).
*/
if (!BRVLAN_TEST(&sbif->bif_vlan_set, vlan))
return (false);
}
/* Accept the frame. */
return (true);
}
/*
* Outgoing VLAN filtering. Given a frame, its vlan, and the member interface
* we intend to send it to, decide whether the port configuration allows it to
* be sent.
*/
static bool
bridge_vfilter_out(const struct bridge_iflist *dbif, const struct mbuf *m,
ether_vlanid_t vlan)
bridge_vfilter_out(const struct bridge_iflist *dbif, const struct mbuf *m)
{
struct ether_header *eh;
ether_vlanid_t vlan;
NET_EPOCH_ASSERT();
@@ -3050,6 +3151,8 @@ bridge_vfilter_out(const struct bridge_iflist *dbif, const struct mbuf *m,
if ((dbif->bif_flags & IFBIF_VLANFILTER) == 0)
return (true);
vlan = VLANTAGOF(m);
/*
* Always allow untagged 802.1D STP frames, even if they would
* otherwise be dropped. This is required for STP to work on
@@ -3072,15 +3175,21 @@ bridge_vfilter_out(const struct bridge_iflist *dbif, const struct mbuf *m,
return (false);
/*
* Make sure the frame's vlan matches the port's untagged vlan.
* If the frame's vlan matches the interfaces's untagged vlan,
* allow it.
*/
if (vlan != dbif->bif_untagged)
return (false);
if (vlan == dbif->bif_untagged)
return (true);
/*
* Everything looks fine, so pass this frame.
* If the frame's vlan is on the interface's tagged access list,
* allow it.
*/
return (true);
if (BRVLAN_TEST(&dbif->bif_vlan_set, vlan))
return (true);
/* The frame was not permitted, so drop it. */
return (false);
}
/*
+24
View File
@@ -78,6 +78,8 @@
#define _NET_IF_BRIDGEVAR_H_
#include <sys/types.h>
#include <sys/_bitset.h>
#include <sys/bitset.h>
#include <sys/callout.h>
#include <sys/queue.h>
#include <sys/condvar.h>
@@ -123,6 +125,8 @@
#define BRDGSTXHC 29 /* set tx hold count (ifbrparam) */
#define BRDGSIFAMAX 30 /* set max interface addrs (ifbreq) */
#define BRDGSIFUNTAGGED 31 /* set if untagged vlan */
#define BRDGSIFVLANSET 32 /* set if vlan set */
#define BRDGGIFVLANSET 33 /* get if vlan set */
/*
* Generic bridge control request.
@@ -307,6 +311,26 @@ struct ifbpstpconf {
eaddr[5] = pv >> 0; \
} while (0)
/*
* Bridge VLAN access request.
*/
#define BRVLAN_SETSIZE 4096
typedef __BITSET_DEFINE(ifbvlan_set, BRVLAN_SETSIZE) ifbvlan_set_t;
#define BRVLAN_SET(set, bit) __BIT_SET(BRVLAN_SETSIZE, (bit), set)
#define BRVLAN_CLR(set, bit) __BIT_CLR(BRVLAN_SETSIZE, (bit), set)
#define BRVLAN_TEST(set, bit) __BIT_ISSET(BRVLAN_SETSIZE, (bit), set)
#define BRDG_VLAN_OP_SET 1 /* replace current vlan set */
#define BRDG_VLAN_OP_ADD 2 /* add vlans to current set */
#define BRDG_VLAN_OP_DEL 3 /* remove vlans from current set */
struct ifbif_vlan_req {
char bv_ifname[IFNAMSIZ];
uint8_t bv_op;
ifbvlan_set_t bv_set;
};
#ifdef _KERNEL
#define BRIDGE_INPUT(_ifp, _m) do { \
+129
View File
@@ -997,6 +997,133 @@ vlan_pvid_1q_cleanup()
vnet_cleanup
}
#
# Test vlan filtering.
#
atf_test_case "vlan_filtering" "cleanup"
vlan_filtering_head()
{
atf_set descr 'tagged traffic with filtering'
atf_set require.user root
}
vlan_filtering_body()
{
vnet_init
vnet_init_bridge
epone=$(vnet_mkepair)
eptwo=$(vnet_mkepair)
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
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
# Right now there are no VLANs on the access list, so everything
# should be blocked.
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
# 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: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
# 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 -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: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
}
vlan_filtering_cleanup()
{
vnet_cleanup
}
#
# Test the ifconfig 'tagged' option.
#
atf_test_case "vlan_ifconfig_tagged" "cleanup"
vlan_ifconfig_tagged_head()
{
atf_set descr 'test the ifconfig tagged option'
atf_set require.user root
}
vlan_ifconfig_tagged_body()
{
vnet_init
vnet_init_bridge
ep=$(vnet_mkepair)
bridge=$(vnet_mkbridge)
ifconfig ${bridge} addm ${ep}a vlanfilter ${ep}a up
ifconfig ${ep}a up
# To start with, no vlans should be configured.
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 -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 -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 -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 -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 -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"
done
}
vlan_ifconfig_tagged_cleanup()
{
vnet_cleanup
}
atf_init_test_cases()
{
atf_add_test_case "bridge_transmit_ipv4_unicast"
@@ -1019,4 +1146,6 @@ atf_init_test_cases()
atf_add_test_case "vlan_pvid_1q"
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"
}