aboutsummaryrefslogtreecommitdiff
path: root/sbin/ifconfig
diff options
context:
space:
mode:
authorAlexander V. Chernikov <melifaro@FreeBSD.org>2020-10-21 21:28:20 +0000
committerAlexander V. Chernikov <melifaro@FreeBSD.org>2020-10-21 21:28:20 +0000
commitc7cffd65c5d858425e90b847d2e8e583e3b13bf7 (patch)
tree43a36ae6b443b446902f50162ee514f2429996e8 /sbin/ifconfig
parent37d411338e9de344d53ea7d55c4f886978bd8171 (diff)
downloadsrc-c7cffd65c5d858425e90b847d2e8e583e3b13bf7.tar.gz
src-c7cffd65c5d858425e90b847d2e8e583e3b13bf7.zip
Add support for stacked VLANs (IEEE 802.1ad, AKA Q-in-Q).
802.1ad interfaces are created with ifconfig using the "vlanproto" parameter. Eg., the following creates a 802.1Q VLAN (id #42) over a 802.1ad S-VLAN (id #5) over a physical Ethernet interface (em0). ifconfig vlan5 create vlandev em0 vlan 5 vlanproto 802.1ad up ifconfig vlan42 create vlandev vlan5 vlan 42 inet 10.5.42.1/24 VLAN_MTU, VLAN_HWCSUM and VLAN_TSO capabilities should be properly supported. VLAN_HWTAGGING is only partially supported, as there is currently no IFCAP_VLAN_* denoting the possibility to set the VLAN EtherType to anything else than 0x8100 (802.1ad uses 0x88A8). Submitted by: Olivier Piras Sponsored by: RG Nets Differential Revision: https://reviews.freebsd.org/D26436
Notes
Notes: svn path=/head/; revision=366917
Diffstat (limited to 'sbin/ifconfig')
-rw-r--r--sbin/ifconfig/ifclone.c36
-rw-r--r--sbin/ifconfig/ifconfig.815
-rw-r--r--sbin/ifconfig/ifconfig.h4
-rw-r--r--sbin/ifconfig/ifieee80211.c2
-rw-r--r--sbin/ifconfig/ifvlan.c78
-rw-r--r--sbin/ifconfig/ifvxlan.c2
6 files changed, 126 insertions, 11 deletions
diff --git a/sbin/ifconfig/ifclone.c b/sbin/ifconfig/ifclone.c
index 134bb0af3efa..58bc3b3103ee 100644
--- a/sbin/ifconfig/ifclone.c
+++ b/sbin/ifconfig/ifclone.c
@@ -49,6 +49,11 @@ static const char rcsid[] =
#include "ifconfig.h"
+typedef enum {
+ MT_PREFIX,
+ MT_FILTER,
+} clone_match_type;
+
static void
list_cloners(void)
{
@@ -76,7 +81,11 @@ list_cloners(void)
}
struct clone_defcb {
- char ifprefix[IFNAMSIZ];
+ union {
+ char ifprefix[IFNAMSIZ];
+ clone_match_func *ifmatch;
+ };
+ clone_match_type clone_mt;
clone_callback_func *clone_cb;
SLIST_ENTRY(clone_defcb) next;
};
@@ -85,12 +94,25 @@ static SLIST_HEAD(, clone_defcb) clone_defcbh =
SLIST_HEAD_INITIALIZER(clone_defcbh);
void
-clone_setdefcallback(const char *ifprefix, clone_callback_func *p)
+clone_setdefcallback_prefix(const char *ifprefix, clone_callback_func *p)
{
struct clone_defcb *dcp;
dcp = malloc(sizeof(*dcp));
strlcpy(dcp->ifprefix, ifprefix, IFNAMSIZ-1);
+ dcp->clone_mt = MT_PREFIX;
+ dcp->clone_cb = p;
+ SLIST_INSERT_HEAD(&clone_defcbh, dcp, next);
+}
+
+void
+clone_setdefcallback_filter(clone_match_func *filter, clone_callback_func *p)
+{
+ struct clone_defcb *dcp;
+
+ dcp = malloc(sizeof(*dcp));
+ dcp->ifmatch = filter;
+ dcp->clone_mt = MT_FILTER;
dcp->clone_cb = p;
SLIST_INSERT_HEAD(&clone_defcbh, dcp, next);
}
@@ -114,8 +136,14 @@ ifclonecreate(int s, void *arg)
if (clone_cb == NULL) {
/* Try to find a default callback */
SLIST_FOREACH(dcp, &clone_defcbh, next) {
- if (strncmp(dcp->ifprefix, ifr.ifr_name,
- strlen(dcp->ifprefix)) == 0) {
+ if ((dcp->clone_mt == MT_PREFIX) &&
+ (strncmp(dcp->ifprefix, ifr.ifr_name,
+ strlen(dcp->ifprefix)) == 0)) {
+ clone_cb = dcp->clone_cb;
+ break;
+ }
+ if ((dcp->clone_mt == MT_FILTER) &&
+ dcp->ifmatch(ifr.ifr_name)) {
clone_cb = dcp->clone_cb;
break;
}
diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8
index 701bc763a859..2978fbdb5691 100644
--- a/sbin/ifconfig/ifconfig.8
+++ b/sbin/ifconfig/ifconfig.8
@@ -582,7 +582,7 @@ they support in their capabilities.
is a synonym for enabling all available WOL mechanisms.
To disable WOL use
.Fl wol .
-.It Cm vlanmtu , vlanhwtag, vlanhwfilter, vlanhwcsum, vlanhwtso
+.It Cm vlanmtu , vlanhwtag , vlanhwfilter , vlanhwcsum , vlanhwtso
If the driver offers user-configurable VLAN support, enable
reception of extended frames, tag processing in hardware,
frame filtering in hardware, checksum offloading, or TSO on VLAN,
@@ -592,7 +592,7 @@ Note that this must be configured on a physical interface associated with
not on a
.Xr vlan 4
interface itself.
-.It Fl vlanmtu , vlanhwtag , vlanhwfilter , vlanhwtso
+.It Fl vlanmtu , vlanhwtag, vlanhwfilter, vlanhwtso
If the driver offers user-configurable VLAN support, disable
reception of extended frames, tag processing in hardware,
frame filtering in hardware, or TSO on VLAN,
@@ -2696,7 +2696,7 @@ interfaces:
Set the VLAN tag value to
.Ar vlan_tag .
This value is a 12-bit VLAN Identifier (VID) which is used to create an 802.1Q
-VLAN header for packets sent from the
+or 802.1ad VLAN header for packets sent from the
.Xr vlan 4
interface.
Note that
@@ -2704,6 +2704,15 @@ Note that
and
.Cm vlandev
must both be set at the same time.
+.It Cm vlanproto Ar vlan_proto
+Set the VLAN encapsulation protocol to
+.Ar vlan_proto .
+Supported encapsulation protocols are currently
+.Dq 802.1Q
+and
+.Dq 802.1ad .
+The default encapsulation protocol is
+.Dq 802.1Q .
.It Cm vlanpcp Ar priority_code_point
Priority code point
.Pq Dv PCP
diff --git a/sbin/ifconfig/ifconfig.h b/sbin/ifconfig/ifconfig.h
index 5b5a839aec0e..f91ee2fd23bb 100644
--- a/sbin/ifconfig/ifconfig.h
+++ b/sbin/ifconfig/ifconfig.h
@@ -145,8 +145,10 @@ void printb(const char *s, unsigned value, const char *bits);
void ifmaybeload(const char *name);
+typedef int clone_match_func(const char *);
typedef void clone_callback_func(int, struct ifreq *);
-void clone_setdefcallback(const char *, clone_callback_func *);
+void clone_setdefcallback_prefix(const char *, clone_callback_func *);
+void clone_setdefcallback_filter(clone_match_func *, clone_callback_func *);
void sfp_status(int s, struct ifreq *ifr, int verbose);
diff --git a/sbin/ifconfig/ifieee80211.c b/sbin/ifconfig/ifieee80211.c
index b2032127c3f7..d3f1c3e3aea6 100644
--- a/sbin/ifconfig/ifieee80211.c
+++ b/sbin/ifconfig/ifieee80211.c
@@ -6069,5 +6069,5 @@ ieee80211_ctor(void)
for (i = 0; i < nitems(ieee80211_cmds); i++)
cmd_register(&ieee80211_cmds[i]);
af_register(&af_ieee80211);
- clone_setdefcallback("wlan", wlan_create);
+ clone_setdefcallback_prefix("wlan", wlan_create);
}
diff --git a/sbin/ifconfig/ifvlan.c b/sbin/ifconfig/ifvlan.c
index a29c50f11efa..bbf9d0324cde 100644
--- a/sbin/ifconfig/ifvlan.c
+++ b/sbin/ifconfig/ifvlan.c
@@ -66,8 +66,12 @@ static const char rcsid[] =
#define NOTAG ((u_short) -1)
+static const char proto_8021Q[] = "802.1q";
+static const char proto_8021ad[] = "802.1ad";
+
static struct vlanreq params = {
.vlr_tag = NOTAG,
+ .vlr_proto = ETHERTYPE_VLAN,
};
static int
@@ -87,6 +91,17 @@ vlan_status(int s)
if (getvlan(s, &ifr, &vreq) == -1)
return;
printf("\tvlan: %d", vreq.vlr_tag);
+ printf(" vlanproto: ");
+ switch (vreq.vlr_proto) {
+ case ETHERTYPE_VLAN:
+ printf(proto_8021Q);
+ break;
+ case ETHERTYPE_QINQ:
+ printf(proto_8021ad);
+ break;
+ default:
+ printf("0x%04x", vreq.vlr_proto);
+ }
if (ioctl(s, SIOCGVLANPCP, (caddr_t)&ifr) != -1)
printf(" vlanpcp: %u", ifr.ifr_vlan_pcp);
printf(" parent interface: %s", vreq.vlr_parent[0] == '\0' ?
@@ -94,9 +109,49 @@ vlan_status(int s)
printf("\n");
}
+static int
+vlan_match_ethervid(const char *name)
+{
+ return (strchr(name, '.') != NULL);
+}
+
+static void
+vlan_parse_ethervid(const char *name)
+{
+ char ifname[IFNAMSIZ];
+ char *cp;
+ int vid;
+
+ strlcpy(ifname, name, IFNAMSIZ);
+ if ((cp = strrchr(ifname, '.')) == NULL)
+ return;
+ /*
+ * Don't mix vlan/vlandev parameters with dot notation.
+ */
+ if (params.vlr_tag != NOTAG || params.vlr_parent[0] != '\0')
+ errx(1, "ambiguous vlan specification");
+ /*
+ * Derive params from interface name: "parent.vid".
+ */
+ *cp++ = '\0';
+ if ((*cp < '1') || (*cp > '9'))
+ errx(1, "invalid vlan tag");
+
+ vid = *cp++ - '0';
+ while ((*cp >= '0') && (*cp <= '9'))
+ vid = (vid * 10) + (*cp++ - '0');
+ if ((*cp != '\0') || (vid & ~0xFFF))
+ errx(1, "invalid vlan tag");
+
+ strlcpy(params.vlr_parent, ifname, IFNAMSIZ);
+ params.vlr_tag = (vid & 0xFFF);
+}
+
static void
vlan_create(int s, struct ifreq *ifr)
{
+ vlan_parse_ethervid(ifr->ifr_name);
+
if (params.vlr_tag != NOTAG || params.vlr_parent[0] != '\0') {
/*
* One or both parameters were specified, make sure both.
@@ -159,6 +214,24 @@ DECL_CMD_FUNC(setvlandev, val, d)
}
static
+DECL_CMD_FUNC(setvlanproto, val, d)
+{
+ struct vlanreq vreq;
+
+ if (strncasecmp(proto_8021Q, val,
+ strlen(proto_8021Q)) == 0) {
+ params.vlr_proto = ETHERTYPE_VLAN;
+ } else if (strncasecmp(proto_8021ad, val,
+ strlen(proto_8021ad)) == 0) {
+ params.vlr_proto = ETHERTYPE_QINQ;
+ } else
+ errx(1, "invalid value for vlanproto");
+
+ if (getvlan(s, &ifr, &vreq) != -1)
+ vlan_set(s, &ifr);
+}
+
+static
DECL_CMD_FUNC(setvlanpcp, val, d)
{
u_long ul;
@@ -195,10 +268,12 @@ DECL_CMD_FUNC(unsetvlandev, val, d)
static struct cmd vlan_cmds[] = {
DEF_CLONE_CMD_ARG("vlan", setvlantag),
DEF_CLONE_CMD_ARG("vlandev", setvlandev),
+ DEF_CLONE_CMD_ARG("vlanproto", setvlanproto),
DEF_CMD_ARG("vlanpcp", setvlanpcp),
/* NB: non-clone cmds */
DEF_CMD_ARG("vlan", setvlantag),
DEF_CMD_ARG("vlandev", setvlandev),
+ DEF_CMD_ARG("vlanproto", setvlanproto),
/* XXX For compatibility. Should become DEF_CMD() some day. */
DEF_CMD_OPTARG("-vlandev", unsetvlandev),
DEF_CMD("vlanmtu", IFCAP_VLAN_MTU, setifcap),
@@ -227,5 +302,6 @@ vlan_ctor(void)
cmd_register(&vlan_cmds[i]);
af_register(&af_vlan);
callback_register(vlan_cb, NULL);
- clone_setdefcallback("vlan", vlan_create);
+ clone_setdefcallback_prefix("vlan", vlan_create);
+ clone_setdefcallback_filter(vlan_match_ethervid, vlan_create);
}
diff --git a/sbin/ifconfig/ifvxlan.c b/sbin/ifconfig/ifvxlan.c
index 32c7ecbffe63..e9ccc0f4fb2e 100644
--- a/sbin/ifconfig/ifvxlan.c
+++ b/sbin/ifconfig/ifvxlan.c
@@ -642,5 +642,5 @@ vxlan_ctor(void)
cmd_register(&vxlan_cmds[i]);
af_register(&af_vxlan);
callback_register(vxlan_cb, NULL);
- clone_setdefcallback("vxlan", vxlan_create);
+ clone_setdefcallback_prefix("vxlan", vxlan_create);
}