bridge: Allow VLAN protocol to be configured
Add a new per-interface option "ifvlanproto", which can be either "802.1q" (the default) or "802.1ad". This controls what type of tag we attach to outgoing packets on the interface. Reviewed by: pauamma_gundo.com (manpages) Differential Revision: https://reviews.freebsd.org/D51231
This commit is contained in:
@@ -190,6 +190,21 @@ print_vlans(ifbvlan_set_t *vlans)
|
||||
}
|
||||
}
|
||||
|
||||
static char const *
|
||||
vlan_proto_name(uint16_t proto)
|
||||
{
|
||||
switch (proto) {
|
||||
case 0:
|
||||
return "none";
|
||||
case ETHERTYPE_VLAN:
|
||||
return "802.1q";
|
||||
case ETHERTYPE_QINQ:
|
||||
return "802.1ad";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bridge_status(if_ctx *ctx)
|
||||
{
|
||||
@@ -261,6 +276,9 @@ bridge_status(if_ctx *ctx)
|
||||
else
|
||||
printf(" <unknown state %d>", state);
|
||||
}
|
||||
if (member->ifbr_vlanproto != 0)
|
||||
printf(" vlan protocol %s",
|
||||
vlan_proto_name(member->ifbr_vlanproto));
|
||||
if (member->ifbr_pvid != 0)
|
||||
printf(" untagged %u", (unsigned)member->ifbr_pvid);
|
||||
print_vlans(&bridge->member_vlans[i]);
|
||||
@@ -895,6 +913,25 @@ unsetbridge_qinq(if_ctx *ctx, const char *val, int dummy __unused)
|
||||
do_bridgeflag(ctx, val, IFBIF_QINQ, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
setbridge_ifvlanproto(if_ctx *ctx, const char *ifname, const char *proto)
|
||||
{
|
||||
struct ifbreq req;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
strlcpy(req.ifbr_ifsname, ifname, sizeof(req.ifbr_ifsname));
|
||||
|
||||
if (strcmp(proto, "802.1q") == 0)
|
||||
req.ifbr_vlanproto = ETHERTYPE_VLAN;
|
||||
else if (strcmp(proto, "802.1ad") == 0)
|
||||
req.ifbr_vlanproto = ETHERTYPE_QINQ;
|
||||
else
|
||||
errx(1, "unrecognised VLAN protocol: %s", proto);
|
||||
|
||||
if (do_cmd(ctx, BRDGSIFVLANPROTO, &req, sizeof(req), 1) < 0)
|
||||
err(1, "BRDGSIFVLANPROTO");
|
||||
}
|
||||
|
||||
static struct cmd bridge_cmds[] = {
|
||||
DEF_CMD_ARG("addm", setbridge_add),
|
||||
DEF_CMD_ARG("deletem", setbridge_delete),
|
||||
@@ -936,6 +973,7 @@ static struct cmd bridge_cmds[] = {
|
||||
DEF_CMD_ARG2("tagged", setbridge_tagged),
|
||||
DEF_CMD_ARG2("+tagged", addbridge_tagged),
|
||||
DEF_CMD_ARG2("-tagged", delbridge_tagged),
|
||||
DEF_CMD_ARG2("ifvlanproto", setbridge_ifvlanproto),
|
||||
DEF_CMD_ARG("timeout", setbridge_timeout),
|
||||
DEF_CMD_ARG("private", setbridge_private),
|
||||
DEF_CMD_ARG("-private", unsetbridge_private),
|
||||
|
||||
@@ -2765,6 +2765,17 @@ Do not enable the
|
||||
.Cm qinq
|
||||
option by default on newly added members.
|
||||
This is the default behavior.
|
||||
.It Cm ifvlanproto Ar interface Ar proto
|
||||
Set the VLAN encapsulation protocol on
|
||||
.Ar interface
|
||||
to
|
||||
.Ar proto ,
|
||||
which must be either
|
||||
.Dq 802.1q
|
||||
or
|
||||
.Dq 802.1ad .
|
||||
The default is
|
||||
.Dq 802.1q .
|
||||
.El
|
||||
.Ss Link Aggregation and Link Failover Parameters
|
||||
The following parameters are specific to lagg interfaces:
|
||||
|
||||
+32
-4
@@ -259,6 +259,7 @@ struct bridge_iflist {
|
||||
struct epoch_context bif_epoch_ctx;
|
||||
ether_vlanid_t bif_pvid; /* port vlan id */
|
||||
ifbvlan_set_t bif_vlan_set; /* if allowed tagged vlans */
|
||||
uint16_t bif_vlanproto; /* vlan protocol */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -423,6 +424,7 @@ 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_ioctl_svlanproto(struct bridge_softc *, void *);
|
||||
static int bridge_pfil(struct mbuf **, struct ifnet *, struct ifnet *,
|
||||
int);
|
||||
#ifdef INET
|
||||
@@ -654,6 +656,9 @@ static const struct bridge_control bridge_control_table[] = {
|
||||
|
||||
{ bridge_ioctl_sdefpvid, sizeof(struct ifbrparam),
|
||||
BC_F_COPYIN|BC_F_SUSER },
|
||||
|
||||
{ bridge_ioctl_svlanproto, sizeof(struct ifbreq),
|
||||
BC_F_COPYIN|BC_F_SUSER },
|
||||
};
|
||||
static const int bridge_control_table_size = nitems(bridge_control_table);
|
||||
|
||||
@@ -1494,6 +1499,7 @@ 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;
|
||||
bif->bif_vlanproto = ETHERTYPE_VLAN;
|
||||
if (sc->sc_flags & IFBRF_VLANFILTER)
|
||||
bif->bif_pvid = sc->sc_defpvid;
|
||||
if (sc->sc_flags & IFBRF_DEFQINQ)
|
||||
@@ -1579,6 +1585,7 @@ bridge_ioctl_gifflags(struct bridge_softc *sc, void *arg)
|
||||
req->ifbr_addrmax = bif->bif_addrmax;
|
||||
req->ifbr_addrexceeded = bif->bif_addrexceeded;
|
||||
req->ifbr_pvid = bif->bif_pvid;
|
||||
req->ifbr_vlanproto = bif->bif_vlanproto;
|
||||
|
||||
/* Copy STP state options as flags */
|
||||
if (bp->bp_operedge)
|
||||
@@ -2254,6 +2261,24 @@ bridge_ioctl_sdefpvid(struct bridge_softc *sc, void *arg)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
bridge_ioctl_svlanproto(struct bridge_softc *sc, void *arg)
|
||||
{
|
||||
struct ifbreq *req = arg;
|
||||
struct bridge_iflist *bif;
|
||||
|
||||
bif = bridge_lookup_member(sc, req->ifbr_ifsname);
|
||||
if (bif == NULL)
|
||||
return (EXTERROR(ENOENT, "Interface is not a bridge member"));
|
||||
|
||||
if (req->ifbr_vlanproto != ETHERTYPE_VLAN &&
|
||||
req->ifbr_vlanproto != ETHERTYPE_QINQ)
|
||||
return (EXTERROR(EINVAL, "Invalid VLAN protocol"));
|
||||
|
||||
bif->bif_vlanproto = req->ifbr_vlanproto;
|
||||
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
* bridge_ifdetach:
|
||||
*
|
||||
@@ -2397,12 +2422,15 @@ bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m,
|
||||
}
|
||||
|
||||
/*
|
||||
* If underlying interface can not do VLAN tag insertion itself
|
||||
* then attach a packet tag that holds it.
|
||||
* There are two cases where we have to insert our own tag:
|
||||
* if the member interface doesn't support hardware tagging,
|
||||
* or if the tag proto is not 802.1q.
|
||||
*/
|
||||
if ((m->m_flags & M_VLANTAG) &&
|
||||
(dst_ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0) {
|
||||
m = ether_vlanencap(m, m->m_pkthdr.ether_vtag);
|
||||
((dst_ifp->if_capenable & IFCAP_VLAN_HWTAGGING) == 0 ||
|
||||
bif->bif_vlanproto != ETHERTYPE_VLAN)) {
|
||||
m = ether_vlanencap_proto(m, m->m_pkthdr.ether_vtag,
|
||||
bif->bif_vlanproto);
|
||||
if (m == NULL) {
|
||||
if_printf(dst_ifp,
|
||||
"unable to prepend VLAN header\n");
|
||||
|
||||
@@ -131,6 +131,7 @@
|
||||
#define BRDGSFLAGS 35 /* set bridge flags (ifbrparam) */
|
||||
#define BRDGGDEFPVID 36 /* get default pvid (ifbrparam) */
|
||||
#define BRDGSDEFPVID 37 /* set default pvid (ifbrparam) */
|
||||
#define BRDGSIFVLANPROTO 38 /* set if vlan protocol (ifbreq) */
|
||||
|
||||
/* BRDGSFLAGS, Bridge flags (non-interface-specific) */
|
||||
typedef uint32_t ifbr_flags_t;
|
||||
@@ -157,6 +158,7 @@ struct ifbreq {
|
||||
uint32_t ifbr_addrmax; /* member if addr max */
|
||||
uint32_t ifbr_addrexceeded; /* member if addr violations */
|
||||
ether_vlanid_t ifbr_pvid; /* member if PVID */
|
||||
uint16_t ifbr_vlanproto; /* member if VLAN protocol */
|
||||
uint8_t pad[32];
|
||||
};
|
||||
|
||||
@@ -252,6 +254,7 @@ struct ifbrparam {
|
||||
* addresses */
|
||||
#define ifbrp_flags ifbrp_ifbrpu.ifbrpu_int32 /* bridge flags */
|
||||
#define ifbrp_defpvid ifbrp_ifbrpu.ifbrpu_int16 /* default pvid */
|
||||
#define ifbrp_vlanproto ifbrp_ifbrpu.ifbrpu_int8 /* vlan protocol */
|
||||
|
||||
/*
|
||||
* Bridge current operational parameters structure.
|
||||
|
||||
Reference in New Issue
Block a user