diff --git a/docs/schemas/nwfilter.rng b/docs/schemas/nwfilter.rng index 5fd4860b26..6a9c7bc108 100644 --- a/docs/schemas/nwfilter.rng +++ b/docs/schemas/nwfilter.rng @@ -38,6 +38,16 @@ + + + + + + + + + + @@ -299,6 +309,9 @@ mac[a-zA-Z0-9_\.:-]{0,9} + + stp[a-zA-Z0-9_\.:-]{0,9} + vlan[a-zA-Z0-9_\.:-]{0,8} @@ -382,7 +395,7 @@ - + @@ -390,6 +403,12 @@ + + + + + + @@ -588,6 +607,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -852,6 +984,24 @@ + + + + + $[a-zA-Z0-9_]+ + + + + 0x[0-9a-fA-F]{1,8} + + + + 0 + 4294967295 + + + + yes diff --git a/src/conf/nwfilter_conf.c b/src/conf/nwfilter_conf.c index 1321f8b1c0..9a97dae776 100644 --- a/src/conf/nwfilter_conf.c +++ b/src/conf/nwfilter_conf.c @@ -84,6 +84,7 @@ VIR_ENUM_IMPL(virNWFilterChainSuffix, VIR_NWFILTER_CHAINSUFFIX_LAST, "root", "mac", "vlan", + "stp", "arp", "rarp", "ipv4", @@ -93,6 +94,7 @@ VIR_ENUM_IMPL(virNWFilterRuleProtocol, VIR_NWFILTER_RULE_PROTOCOL_LAST, "none", "mac", "vlan", + "stp", "arp", "rarp", "ip", @@ -1047,6 +1049,138 @@ static const virXMLAttr2Struct vlanAttributes[] = { } }; +/* STP is documented by IEEE 802.1D; for a synopsis, + * see http://www.javvin.com/protocolSTP.html */ +static const virXMLAttr2Struct stpAttributes[] = { + /* spanning tree uses a special destination MAC address */ + { + .name = SRCMACADDR, + .datatype = DATATYPE_MACADDR, + .dataIdx = offsetof(virNWFilterRuleDef, + p.stpHdrFilter.ethHdr.dataSrcMACAddr), + }, + { + .name = SRCMACMASK, + .datatype = DATATYPE_MACMASK, + .dataIdx = offsetof(virNWFilterRuleDef, + p.stpHdrFilter.ethHdr.dataSrcMACMask), + }, + { + .name = "type", + .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataType), + }, + { + .name = "flags", + .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataFlags), + }, + { + .name = "root-priority", + .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataRootPri), + }, + { + .name = "root-priority-hi", + .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataRootPriHi), + }, + { + .name = "root-address", + .datatype = DATATYPE_MACADDR, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataRootAddr), + }, + { + .name = "root-address-mask", + .datatype = DATATYPE_MACMASK, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataRootAddrMask), + }, + { + .name = "root-cost", + .datatype = DATATYPE_UINT32 | DATATYPE_UINT32_HEX, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataRootCost), + }, + { + .name = "root-cost-hi", + .datatype = DATATYPE_UINT32 | DATATYPE_UINT32_HEX, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataRootCostHi), + }, + { + .name = "sender-priority", + .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataSndrPrio), + }, + { + .name = "sender-priority-hi", + .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataSndrPrioHi), + }, + { + .name = "sender-address", + .datatype = DATATYPE_MACADDR, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataSndrAddr), + }, + { + .name = "sender-address-mask", + .datatype = DATATYPE_MACMASK, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataSndrAddrMask), + }, + { + .name = "port", + .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataPort), + }, + { + .name = "port-hi", + .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataPortHi), + }, + { + .name = "age", + .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataAge), + }, + { + .name = "age-hi", + .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataAgeHi), + }, + { + .name = "max-age", + .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataMaxAge), + }, + { + .name = "max-age-hi", + .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataMaxAgeHi), + }, + { + .name = "hello-time", + .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataHelloTime), + }, + { + .name = "hello-time-hi", + .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataHelloTimeHi), + }, + { + .name = "forward-delay", + .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataFwdDelay), + }, + { + .name = "forward-delay-hi", + .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX, + .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataFwdDelayHi), + }, + COMMENT_PROP(stpHdrFilter), + { + .name = NULL, + } +}; + static const virXMLAttr2Struct arpAttributes[] = { COMMON_MAC_PROPS(arpHdrFilter), { @@ -1505,6 +1639,7 @@ static const virAttributes virAttr[] = { 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("stp" , stpAttributes , VIR_NWFILTER_RULE_PROTOCOL_STP), 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), @@ -1628,6 +1763,18 @@ virNWFilterRuleDetailsParse(xmlNodePtr node, rc = -1; break; + case DATATYPE_UINT32_HEX: + base = 16; + /* fallthrough */ + case DATATYPE_UINT32: + if (virStrToLong_ui(prop, NULL, base, &uint_val) >= 0) { + item->u.u32 = uint_val; + found = 1; + data.ui = uint_val; + } else + rc = -1; + break; + case DATATYPE_IPADDR: if (virSocketAddrParseIPv4(&item->u.ipaddr, prop) < 0) rc = -1; @@ -1839,6 +1986,31 @@ virNWFilterRuleDefFixup(virNWFilterRuleDefPtr rule) rule->p.vlanHdrFilter.ethHdr.dataDstMACAddr); break; + case VIR_NWFILTER_RULE_PROTOCOL_STP: + COPY_NEG_SIGN(rule->p.stpHdrFilter.ethHdr.dataSrcMACMask, + rule->p.stpHdrFilter.ethHdr.dataSrcMACAddr); + COPY_NEG_SIGN(rule->p.stpHdrFilter.dataRootPriHi, + rule->p.stpHdrFilter.dataRootPri); + COPY_NEG_SIGN(rule->p.stpHdrFilter.dataRootAddrMask, + rule->p.stpHdrFilter.dataRootAddr); + COPY_NEG_SIGN(rule->p.stpHdrFilter.dataRootCostHi, + rule->p.stpHdrFilter.dataRootCost); + COPY_NEG_SIGN(rule->p.stpHdrFilter.dataSndrPrioHi, + rule->p.stpHdrFilter.dataSndrPrio); + COPY_NEG_SIGN(rule->p.stpHdrFilter.dataSndrAddrMask, + rule->p.stpHdrFilter.dataSndrAddr); + COPY_NEG_SIGN(rule->p.stpHdrFilter.dataPortHi, + rule->p.stpHdrFilter.dataPort); + COPY_NEG_SIGN(rule->p.stpHdrFilter.dataAgeHi, + rule->p.stpHdrFilter.dataAge); + COPY_NEG_SIGN(rule->p.stpHdrFilter.dataMaxAgeHi, + rule->p.stpHdrFilter.dataMaxAge); + COPY_NEG_SIGN(rule->p.stpHdrFilter.dataHelloTimeHi, + rule->p.stpHdrFilter.dataHelloTime); + COPY_NEG_SIGN(rule->p.stpHdrFilter.dataFwdDelayHi, + rule->p.stpHdrFilter.dataFwdDelay); + break; + case VIR_NWFILTER_RULE_PROTOCOL_IP: COPY_NEG_SIGN(rule->p.ipHdrFilter.ipHdr.dataSrcIPMask, rule->p.ipHdrFilter.ipHdr.dataSrcIPAddr); @@ -2921,6 +3093,14 @@ virNWFilterRuleDefDetailsFormat(virBufferPtr buf, item->u.u16); break; + case DATATYPE_UINT32_HEX: + asHex = true; + /* fallthrough */ + case DATATYPE_UINT32: + virBufferAsprintf(buf, asHex ? "0x%x" : "%u", + item->u.u32); + break; + case DATATYPE_IPADDR: case DATATYPE_IPV6ADDR: virNWIPAddressFormat(buf, diff --git a/src/conf/nwfilter_conf.h b/src/conf/nwfilter_conf.h index a7e7a13dc2..61923aa5a4 100644 --- a/src/conf/nwfilter_conf.h +++ b/src/conf/nwfilter_conf.h @@ -101,10 +101,14 @@ enum attrDatatype { DATATYPE_IPV6MASK = (1 << 10), DATATYPE_STRINGCOPY = (1 << 11), DATATYPE_BOOLEAN = (1 << 12), + DATATYPE_UINT32 = (1 << 13), + DATATYPE_UINT32_HEX = (1 << 14), - DATATYPE_LAST = (1 << 13), + DATATYPE_LAST = (1 << 15), }; +# define NWFILTER_MAC_BGA "01:80:c2:00:00:00" + typedef struct _nwMACAddress nwMACAddress; typedef nwMACAddress *nwMACAddressPtr; @@ -125,6 +129,7 @@ struct _nwItemDesc { bool boolean; uint8_t u8; uint16_t u16; + uint32_t u32; char protocolID[10]; char *string; struct { @@ -164,6 +169,36 @@ struct _vlanHdrFilterDef { }; +typedef struct _stpHdrFilterDef stpHdrFilterDef; +typedef stpHdrFilterDef *stpHdrFilterDefPtr; +struct _stpHdrFilterDef { + ethHdrDataDef ethHdr; + nwItemDesc dataType; + nwItemDesc dataFlags; + nwItemDesc dataRootPri; + nwItemDesc dataRootPriHi; + nwItemDesc dataRootAddr; + nwItemDesc dataRootAddrMask; + nwItemDesc dataRootCost; + nwItemDesc dataRootCostHi; + nwItemDesc dataSndrPrio; + nwItemDesc dataSndrPrioHi; + nwItemDesc dataSndrAddr; + nwItemDesc dataSndrAddrMask; + nwItemDesc dataPort; + nwItemDesc dataPortHi; + nwItemDesc dataAge; + nwItemDesc dataAgeHi; + nwItemDesc dataMaxAge; + nwItemDesc dataMaxAgeHi; + nwItemDesc dataHelloTime; + nwItemDesc dataHelloTimeHi; + nwItemDesc dataFwdDelay; + nwItemDesc dataFwdDelayHi; + nwItemDesc dataComment; +}; + + typedef struct _arpHdrFilterDef arpHdrFilterDef; typedef arpHdrFilterDef *arpHdrFilterDefPtr; struct _arpHdrFilterDef { @@ -337,6 +372,7 @@ enum virNWFilterRuleProtocolType { VIR_NWFILTER_RULE_PROTOCOL_NONE = 0, VIR_NWFILTER_RULE_PROTOCOL_MAC, VIR_NWFILTER_RULE_PROTOCOL_VLAN, + VIR_NWFILTER_RULE_PROTOCOL_STP, VIR_NWFILTER_RULE_PROTOCOL_ARP, VIR_NWFILTER_RULE_PROTOCOL_RARP, VIR_NWFILTER_RULE_PROTOCOL_IP, @@ -378,6 +414,7 @@ enum virNWFilterEbtablesTableType { # define NWFILTER_MAX_FILTER_PRIORITY MAX_RULE_PRIORITY # define NWFILTER_ROOT_FILTER_PRI 0 +# define NWFILTER_STP_FILTER_PRI -810 # define NWFILTER_MAC_FILTER_PRI -800 # define NWFILTER_VLAN_FILTER_PRI -750 # define NWFILTER_IPV4_FILTER_PRI -700 @@ -418,6 +455,7 @@ struct _virNWFilterRuleDef { union { ethHdrFilterDef ethHdrFilter; vlanHdrFilterDef vlanHdrFilter; + stpHdrFilterDef stpHdrFilter; arpHdrFilterDef arpHdrFilter; /* also used for rarp */ ipHdrFilterDef ipHdrFilter; ipv6HdrFilterDef ipv6HdrFilter; @@ -459,6 +497,7 @@ enum virNWFilterChainSuffixType { VIR_NWFILTER_CHAINSUFFIX_ROOT = 0, VIR_NWFILTER_CHAINSUFFIX_MAC, VIR_NWFILTER_CHAINSUFFIX_VLAN, + VIR_NWFILTER_CHAINSUFFIX_STP, VIR_NWFILTER_CHAINSUFFIX_ARP, VIR_NWFILTER_CHAINSUFFIX_RARP, VIR_NWFILTER_CHAINSUFFIX_IPv4, diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 2cf50d30b0..1c64311e55 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -830,6 +830,7 @@ virNWFilterPrintStateMatchFlags; virNWFilterPrintTCPFlags; virNWFilterRegisterCallbackDriver; virNWFilterRuleActionTypeToString; +virNWFilterRuleDirectionTypeToString; virNWFilterRuleProtocolTypeToString; virNWFilterTestUnassignDef; virNWFilterUnlockFilterUpdates; diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c index 73b62f43e1..54f76562ad 100644 --- a/src/nwfilter/nwfilter_ebiptables_driver.c +++ b/src/nwfilter/nwfilter_ebiptables_driver.c @@ -41,6 +41,7 @@ #include "virfile.h" #include "command.h" #include "configmake.h" +#include "intprops.h" #define VIR_FROM_THIS VIR_FROM_NWFILTER @@ -190,6 +191,7 @@ enum l3_proto_idx { L3_PROTO_RARP_IDX, L2_PROTO_MAC_IDX, L2_PROTO_VLAN_IDX, + L2_PROTO_STP_IDX, L3_PROTO_LAST_IDX }; @@ -206,6 +208,7 @@ static const struct ushort_map l3_protocols[] = { 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(L2_PROTO_STP_IDX, 0 , "stp"), USHORTMAP_ENTRY_IDX(L2_PROTO_MAC_IDX, 0 , "mac"), USHORTMAP_ENTRY_IDX(L3_PROTO_LAST_IDX, 0 , NULL), }; @@ -306,6 +309,16 @@ _printDataType(virNWFilterVarCombIterPtr vars, } break; + case DATATYPE_UINT32: + case DATATYPE_UINT32_HEX: + if (snprintf(buf, bufsize, asHex ? "0x%x" : "%u", + item->u.u32) >= bufsize) { + virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Buffer too small for uint32 type")); + return 1; + } + break; + case DATATYPE_UINT16: case DATATYPE_UINT16_HEX: if (snprintf(buf, bufsize, asHex ? "0x%x" : "%d", @@ -937,7 +950,8 @@ iptablesHandleIpHdr(virBufferPtr buf, virBufferPtr prefix) { char ipaddr[INET6_ADDRSTRLEN], - number[20]; + number[MAX(INT_BUFSIZE_BOUND(uint32_t), + INT_BUFSIZE_BOUND(int))]; const char *src = "--source"; const char *dst = "--destination"; const char *srcrange = "--src-range"; @@ -1218,7 +1232,8 @@ _iptablesCreateRuleInstance(int directionIn, bool maySkipICMP) { char chain[MAX_CHAINNAME_LENGTH]; - char number[20]; + char number[MAX(INT_BUFSIZE_BOUND(uint32_t), + INT_BUFSIZE_BOUND(int))]; virBuffer prefix = VIR_BUFFER_INITIALIZER; virBuffer buf = VIR_BUFFER_INITIALIZER; virBuffer afterStateMatch = VIR_BUFFER_INITIALIZER; @@ -1953,7 +1968,9 @@ ebtablesCreateRuleInstance(char chainPrefix, char macaddr[VIR_MAC_STRING_BUFLEN], ipaddr[INET_ADDRSTRLEN], ipv6addr[INET6_ADDRSTRLEN], - number[20]; + number[MAX(INT_BUFSIZE_BOUND(uint32_t), + INT_BUFSIZE_BOUND(int))], + field[MAX(VIR_MAC_STRING_BUFLEN, INET6_ADDRSTRLEN)]; char chain[MAX_CHAINNAME_LENGTH]; virBuffer buf = VIR_BUFFER_INITIALIZER; const char *target; @@ -2019,19 +2036,91 @@ ebtablesCreateRuleInstance(char chainPrefix, #define INST_ITEM(STRUCT, ITEM, CLI) \ if (HAS_ENTRY_ITEM(&rule->p.STRUCT.ITEM)) { \ if (printDataType(vars, \ - number, sizeof(number), \ + field, sizeof(field), \ &rule->p.STRUCT.ITEM)) \ goto err_exit; \ virBufferAsprintf(&buf, \ " " CLI " %s %s", \ ENTRY_GET_NEG_SIGN(&rule->p.STRUCT.ITEM), \ - number); \ + field); \ } +#define INST_ITEM_2PARMS(STRUCT, ITEM, ITEM_HI, CLI, SEP) \ + if (HAS_ENTRY_ITEM(&rule->p.STRUCT.ITEM)) { \ + if (printDataType(vars, \ + field, sizeof(field), \ + &rule->p.STRUCT.ITEM)) \ + goto err_exit; \ + virBufferAsprintf(&buf, \ + " " CLI " %s %s", \ + ENTRY_GET_NEG_SIGN(&rule->p.STRUCT.ITEM), \ + field); \ + if (HAS_ENTRY_ITEM(&rule->p.STRUCT.ITEM_HI)) { \ + if (printDataType(vars, \ + field, sizeof(field), \ + &rule->p.STRUCT.ITEM_HI)) \ + goto err_exit; \ + virBufferAsprintf(&buf, SEP "%s", field); \ + } \ + } +#define INST_ITEM_RANGE(S, I, I_HI, C) \ + INST_ITEM_2PARMS(S, I, I_HI, C, ":") +#define INST_ITEM_MASK(S, I, MASK, C) \ + INST_ITEM_2PARMS(S, I, MASK, C, "/") + INST_ITEM(vlanHdrFilter, dataVlanID, "--vlan-id") INST_ITEM(vlanHdrFilter, dataVlanEncap, "--vlan-encap") break; + case VIR_NWFILTER_RULE_PROTOCOL_STP: + + /* cannot handle inout direction with srcmask set in reverse dir. + since this clashes with -d below... */ + if (reverse && + HAS_ENTRY_ITEM(&rule->p.stpHdrFilter.ethHdr.dataSrcMACAddr)) { + virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, + _("STP filtering in %s direction with " + "source MAC address set is not supported"), + virNWFilterRuleDirectionTypeToString( + VIR_NWFILTER_RULE_DIRECTION_INOUT)); + return -1; + } + + virBufferAsprintf(&buf, + CMD_DEF_PRE "%s -t %s -%%c %s %%s", + ebtables_cmd_path, EBTABLES_DEFAULT_TABLE, chain); + + + if (ebtablesHandleEthHdr(&buf, + vars, + &rule->p.stpHdrFilter.ethHdr, + reverse)) + goto err_exit; + + virBufferAddLit(&buf, " -d " NWFILTER_MAC_BGA); + + INST_ITEM(stpHdrFilter, dataType, "--stp-type") + INST_ITEM(stpHdrFilter, dataFlags, "--stp-flags") + INST_ITEM_RANGE(stpHdrFilter, dataRootPri, dataRootPriHi, + "--stp-root-pri"); + INST_ITEM_MASK( stpHdrFilter, dataRootAddr, dataRootAddrMask, + "--stp-root-addr"); + INST_ITEM_RANGE(stpHdrFilter, dataRootCost, dataRootCostHi, + "--stp-root-cost"); + INST_ITEM_RANGE(stpHdrFilter, dataSndrPrio, dataSndrPrioHi, + "--stp-sender-prio"); + INST_ITEM_MASK( stpHdrFilter, dataSndrAddr, dataSndrAddrMask, + "--stp-sender-addr"); + INST_ITEM_RANGE(stpHdrFilter, dataPort, dataPortHi, "--stp-port"); + INST_ITEM_RANGE(stpHdrFilter, dataAge, dataAgeHi, "--stp-msg-age"); + INST_ITEM_RANGE(stpHdrFilter, dataMaxAge, dataMaxAgeHi, + "--stp-max-age"); + INST_ITEM_RANGE(stpHdrFilter, dataHelloTime, dataHelloTimeHi, + "--stp-hello-time"); + INST_ITEM_RANGE(stpHdrFilter, dataFwdDelay, dataFwdDelayHi, + "--stp-forward-delay"); + break; + case VIR_NWFILTER_RULE_PROTOCOL_ARP: case VIR_NWFILTER_RULE_PROTOCOL_RARP: @@ -2480,6 +2569,7 @@ ebiptablesCreateRuleInstance(virConnectPtr conn ATTRIBUTE_UNUSED, case VIR_NWFILTER_RULE_PROTOCOL_IP: case VIR_NWFILTER_RULE_PROTOCOL_MAC: case VIR_NWFILTER_RULE_PROTOCOL_VLAN: + case VIR_NWFILTER_RULE_PROTOCOL_STP: case VIR_NWFILTER_RULE_PROTOCOL_ARP: case VIR_NWFILTER_RULE_PROTOCOL_RARP: case VIR_NWFILTER_RULE_PROTOCOL_NONE: @@ -2818,6 +2908,9 @@ ebtablesCreateTmpSubChain(ebiptablesRuleInstPtr *inst, case L2_PROTO_MAC_IDX: protostr = strdup(""); break; + case L2_PROTO_STP_IDX: + virAsprintf(&protostr, "-d " NWFILTER_MAC_BGA " "); + break; default: virAsprintf(&protostr, "-p 0x%04x ", l3_protocols[protoidx].attr); break;