diff --git a/docs/schemas/nwfilter.rng b/docs/schemas/nwfilter.rng
index c81e410bd1..46b8d4f0b9 100644
--- a/docs/schemas/nwfilter.rng
+++ b/docs/schemas/nwfilter.rng
@@ -28,6 +28,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -286,6 +296,9 @@
root
+
+ vlan[a-zA-Z0-9_\.:-]{0,8}
+
arp[a-zA-Z0-9_\.:-]{0,9}
@@ -557,6 +570,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -762,10 +790,29 @@
rarp
ipv4
ipv6
+ vlan
+
+
+
+
+ $[a-zA-Z0-9_]+
+
+
+
+ 0x([0-9a-fA-F]{1,3})
+
+
+
+ 0
+ 4095
+
+
+
+
diff --git a/src/conf/nwfilter_conf.c b/src/conf/nwfilter_conf.c
index fd027e3cf1..59132d9a69 100644
--- a/src/conf/nwfilter_conf.c
+++ b/src/conf/nwfilter_conf.c
@@ -82,6 +82,7 @@ VIR_ENUM_IMPL(virNWFilterEbtablesTable, VIR_NWFILTER_EBTABLES_TABLE_LAST,
VIR_ENUM_IMPL(virNWFilterChainSuffix, VIR_NWFILTER_CHAINSUFFIX_LAST,
"root",
+ "vlan",
"arp",
"rarp",
"ipv4",
@@ -90,6 +91,7 @@ VIR_ENUM_IMPL(virNWFilterChainSuffix, VIR_NWFILTER_CHAINSUFFIX_LAST,
VIR_ENUM_IMPL(virNWFilterRuleProtocol, VIR_NWFILTER_RULE_PROTOCOL_LAST,
"none",
"mac",
+ "vlan",
"arp",
"rarp",
"ip",
@@ -126,6 +128,7 @@ struct int_map {
static const struct int_map chain_priorities[] = {
INTMAP_ENTRY(NWFILTER_ROOT_FILTER_PRI, "root"),
+ INTMAP_ENTRY(NWFILTER_VLAN_FILTER_PRI, "vlan"),
INTMAP_ENTRY(NWFILTER_IPV4_FILTER_PRI, "ipv4"),
INTMAP_ENTRY(NWFILTER_IPV6_FILTER_PRI, "ipv6"),
INTMAP_ENTRY(NWFILTER_ARP_FILTER_PRI , "arp" ),
@@ -459,6 +462,7 @@ static const struct int_map macProtoMap[] = {
INTMAP_ENTRY(ETHERTYPE_REVARP, "rarp"),
INTMAP_ENTRY(ETHERTYPE_IP , "ipv4"),
INTMAP_ENTRY(ETHERTYPE_IPV6 , "ipv6"),
+ INTMAP_ENTRY(ETHERTYPE_VLAN , "vlan"),
INTMAP_ENTRY_LAST
};
@@ -513,6 +517,75 @@ macProtocolIDFormatter(virBufferPtr buf,
}
+static bool
+checkVlanVlanID(enum attrDatatype datatype, union data *value,
+ virNWFilterRuleDefPtr nwf,
+ nwItemDesc *item ATTRIBUTE_UNUSED)
+{
+ int32_t res;
+
+ res = value->ui;
+ if (res < 0 || res > 4095) {
+ res = -1;
+ }
+
+ if (res != -1) {
+ nwf->p.vlanHdrFilter.dataVlanID.u.u16 = res;
+ nwf->p.vlanHdrFilter.dataVlanID.datatype = datatype;
+ return true;
+ }
+
+ return false;
+}
+
+static bool
+checkVlanProtocolID(enum attrDatatype datatype, union data *value,
+ virNWFilterRuleDefPtr nwf,
+ nwItemDesc *item ATTRIBUTE_UNUSED)
+{
+ int32_t res = -1;
+
+ if (datatype == DATATYPE_STRING) {
+ if (intMapGetByString(macProtoMap, value->c, 1, &res) == 0)
+ res = -1;
+ datatype = DATATYPE_UINT16;
+ } else if (datatype == DATATYPE_UINT16 ||
+ datatype == DATATYPE_UINT16_HEX) {
+ res = value->ui;
+ if (res < 0x3c)
+ res = -1;
+ }
+
+ if (res != -1) {
+ nwf->p.vlanHdrFilter.dataVlanEncap.u.u16 = res;
+ nwf->p.vlanHdrFilter.dataVlanEncap.datatype = datatype;
+ return true;
+ }
+
+ return false;
+}
+
+static bool
+vlanProtocolIDFormatter(virBufferPtr buf,
+ virNWFilterRuleDefPtr nwf,
+ nwItemDesc *item ATTRIBUTE_UNUSED)
+{
+ const char *str = NULL;
+ bool asHex = true;
+
+ if (intMapGetByInt(macProtoMap,
+ nwf->p.vlanHdrFilter.dataVlanEncap.u.u16,
+ &str)) {
+ virBufferAdd(buf, str, -1);
+ } else {
+ if (nwf->p.vlanHdrFilter.dataVlanEncap.datatype == DATATYPE_UINT16)
+ asHex = false;
+ virBufferAsprintf(buf, asHex ? "0x%x" : "%d",
+ nwf->p.vlanHdrFilter.dataVlanEncap.u.u16);
+ }
+ return true;
+}
+
/* generic function to check for a valid (ipv4,ipv6, mac) mask
* A mask is valid of there is a sequence of 1's followed by a sequence
* of 0s or only 1s or only 0s
@@ -951,6 +1024,27 @@ static const virXMLAttr2Struct macAttributes[] = {
}
};
+static const virXMLAttr2Struct vlanAttributes[] = {
+ COMMON_MAC_PROPS(ethHdrFilter),
+ {
+ .name = "vlanid",
+ .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.vlanHdrFilter.dataVlanID),
+ .validator = checkVlanVlanID,
+ },
+ {
+ .name = "encap-protocol",
+ .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX | DATATYPE_STRING,
+ .dataIdx = offsetof(virNWFilterRuleDef, p.vlanHdrFilter.dataVlanEncap),
+ .validator = checkVlanProtocolID,
+ .formatter = vlanProtocolIDFormatter,
+ },
+ COMMENT_PROP(vlanHdrFilter),
+ {
+ .name = NULL,
+ }
+};
+
static const virXMLAttr2Struct arpAttributes[] = {
COMMON_MAC_PROPS(arpHdrFilter),
{
@@ -1408,6 +1502,7 @@ static const virAttributes virAttr[] = {
PROTOCOL_ENTRY("arp" , arpAttributes , VIR_NWFILTER_RULE_PROTOCOL_ARP),
PROTOCOL_ENTRY("rarp" , arpAttributes , VIR_NWFILTER_RULE_PROTOCOL_RARP),
PROTOCOL_ENTRY("mac" , macAttributes , VIR_NWFILTER_RULE_PROTOCOL_MAC),
+ PROTOCOL_ENTRY("vlan" , vlanAttributes , VIR_NWFILTER_RULE_PROTOCOL_VLAN),
PROTOCOL_ENTRY("ip" , ipAttributes , VIR_NWFILTER_RULE_PROTOCOL_IP),
PROTOCOL_ENTRY("ipv6" , ipv6Attributes , VIR_NWFILTER_RULE_PROTOCOL_IPV6),
PROTOCOL_ENTRY("tcp" , tcpAttributes , VIR_NWFILTER_RULE_PROTOCOL_TCP),
@@ -1735,6 +1830,13 @@ virNWFilterRuleDefFixup(virNWFilterRuleDefPtr rule)
rule->p.ethHdrFilter.ethHdr.dataDstMACAddr);
break;
+ case VIR_NWFILTER_RULE_PROTOCOL_VLAN:
+ COPY_NEG_SIGN(rule->p.vlanHdrFilter.ethHdr.dataSrcMACMask,
+ rule->p.vlanHdrFilter.ethHdr.dataSrcMACAddr);
+ COPY_NEG_SIGN(rule->p.vlanHdrFilter.ethHdr.dataDstMACMask,
+ rule->p.vlanHdrFilter.ethHdr.dataDstMACAddr);
+ break;
+
case VIR_NWFILTER_RULE_PROTOCOL_IP:
COPY_NEG_SIGN(rule->p.ipHdrFilter.ipHdr.dataSrcIPMask,
rule->p.ipHdrFilter.ipHdr.dataSrcIPAddr);
diff --git a/src/conf/nwfilter_conf.h b/src/conf/nwfilter_conf.h
index 23475c44cf..1d568dc3ff 100644
--- a/src/conf/nwfilter_conf.h
+++ b/src/conf/nwfilter_conf.h
@@ -55,6 +55,9 @@
# ifndef ETHERTYPE_IPV6
# define ETHERTYPE_IPV6 0x86dd
# endif
+# ifndef ETHERTYPE_VLAN
+# define ETHERTYPE_VLAN 0x8100
+# endif
/**
* Chain suffix size is:
@@ -151,6 +154,16 @@ struct _ethHdrFilterDef {
};
+typedef struct _vlanHdrFilterDef vlanHdrFilterDef;
+typedef vlanHdrFilterDef *vlanHdrFilterDefPtr;
+struct _vlanHdrFilterDef {
+ ethHdrDataDef ethHdr;
+ nwItemDesc dataVlanID;
+ nwItemDesc dataVlanEncap;
+ nwItemDesc dataComment;
+};
+
+
typedef struct _arpHdrFilterDef arpHdrFilterDef;
typedef arpHdrFilterDef *arpHdrFilterDefPtr;
struct _arpHdrFilterDef {
@@ -323,6 +336,7 @@ enum virNWFilterChainPolicyType {
enum virNWFilterRuleProtocolType {
VIR_NWFILTER_RULE_PROTOCOL_NONE = 0,
VIR_NWFILTER_RULE_PROTOCOL_MAC,
+ VIR_NWFILTER_RULE_PROTOCOL_VLAN,
VIR_NWFILTER_RULE_PROTOCOL_ARP,
VIR_NWFILTER_RULE_PROTOCOL_RARP,
VIR_NWFILTER_RULE_PROTOCOL_IP,
@@ -364,6 +378,7 @@ enum virNWFilterEbtablesTableType {
# define NWFILTER_MAX_FILTER_PRIORITY MAX_RULE_PRIORITY
# define NWFILTER_ROOT_FILTER_PRI 0
+# define NWFILTER_VLAN_FILTER_PRI -750
# define NWFILTER_IPV4_FILTER_PRI -700
# define NWFILTER_IPV6_FILTER_PRI -600
# define NWFILTER_ARP_FILTER_PRI -500
@@ -401,6 +416,7 @@ struct _virNWFilterRuleDef {
enum virNWFilterRuleProtocolType prtclType;
union {
ethHdrFilterDef ethHdrFilter;
+ vlanHdrFilterDef vlanHdrFilter;
arpHdrFilterDef arpHdrFilter; /* also used for rarp */
ipHdrFilterDef ipHdrFilter;
ipv6HdrFilterDef ipv6HdrFilter;
@@ -440,6 +456,7 @@ struct _virNWFilterEntry {
enum virNWFilterChainSuffixType {
VIR_NWFILTER_CHAINSUFFIX_ROOT = 0,
+ VIR_NWFILTER_CHAINSUFFIX_VLAN,
VIR_NWFILTER_CHAINSUFFIX_ARP,
VIR_NWFILTER_CHAINSUFFIX_RARP,
VIR_NWFILTER_CHAINSUFFIX_IPv4,
diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c
index b7819788c4..ec7f4f03ce 100644
--- a/src/nwfilter/nwfilter_ebiptables_driver.c
+++ b/src/nwfilter/nwfilter_ebiptables_driver.c
@@ -188,6 +188,7 @@ enum l3_proto_idx {
L3_PROTO_IPV6_IDX,
L3_PROTO_ARP_IDX,
L3_PROTO_RARP_IDX,
+ L2_PROTO_VLAN_IDX,
L3_PROTO_LAST_IDX
};
@@ -203,6 +204,7 @@ static const struct ushort_map l3_protocols[] = {
USHORTMAP_ENTRY_IDX(L3_PROTO_IPV6_IDX, ETHERTYPE_IPV6 , "ipv6"),
USHORTMAP_ENTRY_IDX(L3_PROTO_ARP_IDX , ETHERTYPE_ARP , "arp"),
USHORTMAP_ENTRY_IDX(L3_PROTO_RARP_IDX, ETHERTYPE_REVARP, "rarp"),
+ USHORTMAP_ENTRY_IDX(L2_PROTO_VLAN_IDX, ETHERTYPE_VLAN , "vlan"),
USHORTMAP_ENTRY_IDX(L3_PROTO_LAST_IDX, 0 , NULL),
};
@@ -1996,6 +1998,38 @@ ebtablesCreateRuleInstance(char chainPrefix,
}
break;
+ case VIR_NWFILTER_RULE_PROTOCOL_VLAN:
+
+ virBufferAsprintf(&buf,
+ CMD_DEF_PRE "%s -t %s -%%c %s %%s",
+ ebtables_cmd_path, EBTABLES_DEFAULT_TABLE, chain);
+
+
+ if (ebtablesHandleEthHdr(&buf,
+ vars,
+ &rule->p.vlanHdrFilter.ethHdr,
+ reverse))
+ goto err_exit;
+
+ virBufferAddLit(&buf,
+ " -p 0x8100");
+
+#define INST_ITEM(STRUCT, ITEM, CLI) \
+ if (HAS_ENTRY_ITEM(&rule->p.STRUCT.ITEM)) { \
+ if (printDataType(vars, \
+ number, sizeof(number), \
+ &rule->p.STRUCT.ITEM)) \
+ goto err_exit; \
+ virBufferAsprintf(&buf, \
+ " " CLI " %s %s", \
+ ENTRY_GET_NEG_SIGN(&rule->p.STRUCT.ITEM), \
+ number); \
+ }
+
+ INST_ITEM(vlanHdrFilter, dataVlanID, "--vlan-id")
+ INST_ITEM(vlanHdrFilter, dataVlanEncap, "--vlan-encap")
+ break;
+
case VIR_NWFILTER_RULE_PROTOCOL_ARP:
case VIR_NWFILTER_RULE_PROTOCOL_RARP:
@@ -2443,6 +2477,7 @@ ebiptablesCreateRuleInstance(virConnectPtr conn ATTRIBUTE_UNUSED,
switch (rule->prtclType) {
case VIR_NWFILTER_RULE_PROTOCOL_IP:
case VIR_NWFILTER_RULE_PROTOCOL_MAC:
+ case VIR_NWFILTER_RULE_PROTOCOL_VLAN:
case VIR_NWFILTER_RULE_PROTOCOL_ARP:
case VIR_NWFILTER_RULE_PROTOCOL_RARP:
case VIR_NWFILTER_RULE_PROTOCOL_NONE: