]> xenbits.xensource.com Git - libvirt.git/commitdiff
Add support for VLAN filtering
authorStefan Berger <stefanb@linux.vnet.ibm.com>
Sat, 19 Nov 2011 12:26:56 +0000 (07:26 -0500)
committerStefan Berger <stefanb@us.ibm.com>
Sat, 19 Nov 2011 12:26:56 +0000 (07:26 -0500)
This patch adds support for filtering of VLAN (802.1Q) traffic to the
parser and makes us of the ebtables support for VLAN filtering. This code
now enables the filtering of traffic in chains with prefix 'vlan'.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
docs/schemas/nwfilter.rng
src/conf/nwfilter_conf.c
src/conf/nwfilter_conf.h
src/nwfilter/nwfilter_ebiptables_driver.c

index c81e410bd1a14602785b6a1d296709eeb7f5eeb7..46b8d4f0b9ba93d40b09a786a0a7a37069848cef 100644 (file)
                 </element>
               </zeroOrMore>
             </optional>
+            <optional>
+              <zeroOrMore>
+                <element name="vlan">
+                  <ref name="match-attribute"/>
+                  <ref name="common-l2-attributes"/>
+                  <ref name="vlan-attributes"/>
+                  <ref name="comment-attribute"/>
+                </element>
+              </zeroOrMore>
+            </optional>
             <optional>
               <zeroOrMore>
                 <element name="arp">
       <attribute name="chain">
         <choice>
           <value>root</value>
+          <data type="string">
+            <param name="pattern">vlan[a-zA-Z0-9_\.:-]{0,8}</param>
+          </data>
           <data type="string">
             <param name="pattern">arp[a-zA-Z0-9_\.:-]{0,9}</param>
           </data>
     </interleave>
   </define>
 
+  <define name="vlan-attributes">
+    <interleave>
+      <optional>
+        <attribute name="vlanid">
+          <ref name="vlan-vlanid"/>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="encap-protocol">
+          <ref name="mac-protocolid"/>
+        </attribute>
+      </optional>
+    </interleave>
+  </define>
+
   <define name="arp-attributes">
     <interleave>
       <optional>
         <value>rarp</value>
         <value>ipv4</value>
         <value>ipv6</value>
+        <value>vlan</value>
       </choice>
     </choice>
   </define>
 
+  <define name="vlan-vlanid">
+    <choice>
+      <!-- variable -->
+      <data type="string">
+        <param name="pattern">$[a-zA-Z0-9_]+</param>
+      </data>
+
+      <data type="string">
+        <param name="pattern">0x([0-9a-fA-F]{1,3})</param>
+      </data>
+
+      <data type="int">
+        <param name="minInclusive">0</param>
+        <param name="maxInclusive">4095</param>
+      </data>
+    </choice>
+  </define>
+
   <define name="uint8range">
     <choice>
       <!-- variable -->
index fd027e3cf1b2a0f0af55a93b9217af4befc91ad4..59132d9a6947eb95e7c874b1ea6e04a335d48e0c 100644 (file)
@@ -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);
index 23475c44cf826764c74a33b0a4f40fb5813cd49c..1d568dc3ffa11fd38a98c1667c0879dfd71e0632 100644 (file)
@@ -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,
index b7819788c442fe9f41cfed710fc1ceccfd842434..ec7f4f03ce3f6a1213ed33b81fb143c6bd804176 100644 (file)
@@ -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: