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: