VIR_ENUM_IMPL(virNWFilterChainSuffix, VIR_NWFILTER_CHAINSUFFIX_LAST,
"root",
+ "vlan",
"arp",
"rarp",
"ipv4",
VIR_ENUM_IMPL(virNWFilterRuleProtocol, VIR_NWFILTER_RULE_PROTOCOL_LAST,
"none",
"mac",
+ "vlan",
"arp",
"rarp",
"ip",
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" ),
INTMAP_ENTRY(ETHERTYPE_REVARP, "rarp"),
INTMAP_ENTRY(ETHERTYPE_IP , "ipv4"),
INTMAP_ENTRY(ETHERTYPE_IPV6 , "ipv6"),
+ INTMAP_ENTRY(ETHERTYPE_VLAN , "vlan"),
INTMAP_ENTRY_LAST
};
}
+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
}
};
+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),
{
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),
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);
# ifndef ETHERTYPE_IPV6
# define ETHERTYPE_IPV6 0x86dd
# endif
+# ifndef ETHERTYPE_VLAN
+# define ETHERTYPE_VLAN 0x8100
+# endif
/**
* Chain suffix size is:
};
+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 {
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,
# 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
enum virNWFilterRuleProtocolType prtclType;
union {
ethHdrFilterDef ethHdrFilter;
+ vlanHdrFilterDef vlanHdrFilter;
arpHdrFilterDef arpHdrFilter; /* also used for rarp */
ipHdrFilterDef ipHdrFilter;
ipv6HdrFilterDef ipv6HdrFilter;
enum virNWFilterChainSuffixType {
VIR_NWFILTER_CHAINSUFFIX_ROOT = 0,
+ VIR_NWFILTER_CHAINSUFFIX_VLAN,
VIR_NWFILTER_CHAINSUFFIX_ARP,
VIR_NWFILTER_CHAINSUFFIX_RARP,
VIR_NWFILTER_CHAINSUFFIX_IPv4,
L3_PROTO_IPV6_IDX,
L3_PROTO_ARP_IDX,
L3_PROTO_RARP_IDX,
+ L2_PROTO_VLAN_IDX,
L3_PROTO_LAST_IDX
};
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),
};
}
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:
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: