This patch adds support for the RARP protocol. This may be needed due to qemu sending out a RARP packet (at least that's what it seems to want to do even though the protocol id is wrong) when migration finishes and we'd need a rule to let the packets pass. Unfortunately my installation of ebtables does not understand -p RARP and also seems to otherwise depend on strings in /etc/ethertype translated to protocol identifiers. Therefore I need to pass -p 0x8035 for RARP. To generally get rid of the dependency of that file I switch all so far supported protocols to use their protocol identifier in the -p parameter rather than the string. I am also extending the schema and added a test case. changes from v1 to v2: - added test case into patch Signed-off-by: Stefan Berger <stefanb@xxxxxxxxxx> --- docs/schemas/nwfilter.rng | 9 ++ src/conf/nwfilter_conf.c | 29 ++----- src/conf/nwfilter_conf.h | 22 +++++- src/nwfilter/nwfilter_ebiptables_driver.c | 109 ++++++++++++++++++------------ tests/nwfilterxml2xmlin/rarp-test.xml | 33 +++++++++ tests/nwfilterxml2xmlout/rarp-test.xml | 18 ++++ tests/nwfilterxml2xmltest.c | 1 7 files changed, 158 insertions(+), 63 deletions(-) Index: libvirt-acl/docs/schemas/nwfilter.rng =================================================================== --- libvirt-acl.orig/docs/schemas/nwfilter.rng +++ libvirt-acl/docs/schemas/nwfilter.rng @@ -39,6 +39,15 @@ </optional> <optional> <zeroOrMore> + <element name="rarp"> + <ref name="match-attribute"/> + <ref name="common-l2-attributes"/> + <ref name="arp-attributes"/> <!-- same as arp --> + </element> + </zeroOrMore> + </optional> + <optional> + <zeroOrMore> <element name="ip"> <ref name="match-attribute"/> <ref name="common-l2-attributes"/> Index: libvirt-acl/src/conf/nwfilter_conf.c =================================================================== --- libvirt-acl.orig/src/conf/nwfilter_conf.c +++ libvirt-acl/src/conf/nwfilter_conf.c @@ -46,22 +46,6 @@ #include "domain_conf.h" -/* XXX - * The config parser/structs should not be using platform specific - * constants. Win32 lacks these constants, breaking the parser, - * so temporarily define them until this can be re-written to use - * locally defined enums for all constants - */ -#ifndef ETHERTYPE_IP -# define ETHERTYPE_IP 0x0800 -#endif -#ifndef ETHERTYPE_ARP -# define ETHERTYPE_ARP 0x0806 -#endif -#ifndef ETHERTYPE_IPV6 -# define ETHERTYPE_IPV6 0x86dd -#endif - #define VIR_FROM_THIS VIR_FROM_NWFILTER @@ -90,6 +74,7 @@ VIR_ENUM_IMPL(virNWFilterEbtablesTable, VIR_ENUM_IMPL(virNWFilterChainSuffix, VIR_NWFILTER_CHAINSUFFIX_LAST, "root", "arp", + "rarp", "ipv4", "ipv6"); @@ -97,6 +82,7 @@ VIR_ENUM_IMPL(virNWFilterRuleProtocol, V "none", "mac", "arp", + "rarp", "ip", "ipv6", "tcp", @@ -412,11 +398,10 @@ struct _virXMLAttr2Struct static const struct int_map macProtoMap[] = { - INTMAP_ENTRY(ETHERTYPE_ARP , "arp"), - INTMAP_ENTRY(ETHERTYPE_IP , "ipv4"), -#ifdef ETHERTYPE_IPV6 - INTMAP_ENTRY(ETHERTYPE_IPV6, "ipv6"), -#endif + INTMAP_ENTRY(ETHERTYPE_ARP , "arp"), + INTMAP_ENTRY(ETHERTYPE_REVARP, "rarp"), + INTMAP_ENTRY(ETHERTYPE_IP , "ipv4"), + INTMAP_ENTRY(ETHERTYPE_IPV6 , "ipv6"), INTMAP_ENTRY_LAST }; @@ -1096,6 +1081,7 @@ struct _virAttributes { 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("ip" , ipAttributes , VIR_NWFILTER_RULE_PROTOCOL_IP), PROTOCOL_ENTRY("ipv6" , ipv6Attributes , VIR_NWFILTER_RULE_PROTOCOL_IPV6), @@ -1450,6 +1436,7 @@ virNWFilterRuleDefFixup(virNWFilterRuleD break; case VIR_NWFILTER_RULE_PROTOCOL_ARP: + case VIR_NWFILTER_RULE_PROTOCOL_RARP: case VIR_NWFILTER_RULE_PROTOCOL_NONE: break; Index: libvirt-acl/src/conf/nwfilter_conf.h =================================================================== --- libvirt-acl.orig/src/conf/nwfilter_conf.h +++ libvirt-acl/src/conf/nwfilter_conf.h @@ -35,6 +35,24 @@ # include "xml.h" # include "network.h" +/* XXX + * The config parser/structs should not be using platform specific + * constants. Win32 lacks these constants, breaking the parser, + * so temporarily define them until this can be re-written to use + * locally defined enums for all constants + */ +# ifndef ETHERTYPE_IP +# define ETHERTYPE_IP 0x0800 +# endif +# ifndef ETHERTYPE_ARP +# define ETHERTYPE_ARP 0x0806 +# endif +# ifndef ETHERTYPE_REVARP +# define ETHERTYPE_REVARP 0x8035 +# endif +# ifndef ETHERTYPE_IPV6 +# define ETHERTYPE_IPV6 0x86dd +# endif /** * Chain suffix size is: @@ -292,6 +310,7 @@ enum virNWFilterRuleProtocolType { VIR_NWFILTER_RULE_PROTOCOL_NONE = 0, VIR_NWFILTER_RULE_PROTOCOL_MAC, VIR_NWFILTER_RULE_PROTOCOL_ARP, + VIR_NWFILTER_RULE_PROTOCOL_RARP, VIR_NWFILTER_RULE_PROTOCOL_IP, VIR_NWFILTER_RULE_PROTOCOL_IPV6, VIR_NWFILTER_RULE_PROTOCOL_TCP, @@ -336,7 +355,7 @@ struct _virNWFilterRuleDef { enum virNWFilterRuleProtocolType prtclType; union { ethHdrFilterDef ethHdrFilter; - arpHdrFilterDef arpHdrFilter; + arpHdrFilterDef arpHdrFilter; /* also used for rarp */ ipHdrFilterDef ipHdrFilter; ipv6HdrFilterDef ipv6HdrFilter; tcpHdrFilterDef tcpHdrFilter; @@ -373,6 +392,7 @@ struct _virNWFilterEntry { enum virNWFilterChainSuffixType { VIR_NWFILTER_CHAINSUFFIX_ROOT = 0, VIR_NWFILTER_CHAINSUFFIX_ARP, + VIR_NWFILTER_CHAINSUFFIX_RARP, VIR_NWFILTER_CHAINSUFFIX_IPv4, VIR_NWFILTER_CHAINSUFFIX_IPv6, Index: libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c =================================================================== --- libvirt-acl.orig/src/nwfilter/nwfilter_ebiptables_driver.c +++ libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c @@ -32,6 +32,7 @@ #include "logging.h" #include "virterror_internal.h" #include "domain_conf.h" +#include "nwfilter_conf.h" #include "nwfilter_gentech_driver.h" #include "nwfilter_ebiptables_driver.h" @@ -103,11 +104,28 @@ static int ebiptablesDriverInit(void); static void ebiptablesDriverShutdown(void); -static const char *supported_protocols[] = { - "ipv4", - "ipv6", - "arp", - NULL, +struct ushort_map { + unsigned short attr; + const char *val; +}; + + +enum l3_proto_idx { + L3_PROTO_IPV4_IDX = 0, + L3_PROTO_IPV6_IDX, + L3_PROTO_ARP_IDX, + L3_PROTO_RARP_IDX, + L3_PROTO_LAST_IDX +}; + +#define USHORTMAP_ENTRY_IDX(IDX, ATT, VAL) [IDX] = { .attr = ATT, .val = VAL } + +static const struct ushort_map l3_protocols[] = { + USHORTMAP_ENTRY_IDX(L3_PROTO_IPV4_IDX, ETHERTYPE_IP , "ipv4"), + 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(L3_PROTO_LAST_IDX, 0 , NULL), }; @@ -1611,6 +1629,7 @@ ebtablesCreateRuleInstance(char chainPre break; case VIR_NWFILTER_RULE_PROTOCOL_ARP: + case VIR_NWFILTER_RULE_PROTOCOL_RARP: virBufferVSprintf(&buf, CMD_DEF_PRE "%s -t %s -%%c %s %%s", @@ -1622,7 +1641,10 @@ ebtablesCreateRuleInstance(char chainPre reverse)) goto err_exit; - virBufferAddLit(&buf, " -p arp"); + virBufferVSprintf(&buf, " -p 0x%x", + (rule->prtclType == VIR_NWFILTER_RULE_PROTOCOL_ARP) + ? l3_protocols[L3_PROTO_ARP_IDX].attr + : l3_protocols[L3_PROTO_RARP_IDX].attr); if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataHWType)) { if (printDataType(vars, @@ -2036,6 +2058,7 @@ ebiptablesCreateRuleInstance(virConnectP case VIR_NWFILTER_RULE_PROTOCOL_IP: case VIR_NWFILTER_RULE_PROTOCOL_MAC: case VIR_NWFILTER_RULE_PROTOCOL_ARP: + case VIR_NWFILTER_RULE_PROTOCOL_RARP: case VIR_NWFILTER_RULE_PROTOCOL_NONE: case VIR_NWFILTER_RULE_PROTOCOL_IPV6: @@ -2427,7 +2450,7 @@ static int ebtablesCreateTmpSubChain(virBufferPtr buf, int incoming, const char *ifname, - const char *protocol, + enum l3_proto_idx protoidx, int stopOnError) { char rootchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH]; @@ -2435,13 +2458,13 @@ ebtablesCreateTmpSubChain(virBufferPtr b : CHAINPREFIX_HOST_OUT_TEMP; PRINT_ROOT_CHAIN(rootchain, chainPrefix, ifname); - PRINT_CHAIN(chain, chainPrefix, ifname, protocol); + PRINT_CHAIN(chain, chainPrefix, ifname, l3_protocols[protoidx].val); virBufferVSprintf(buf, CMD_DEF("%s -t %s -N %s") CMD_SEPARATOR CMD_EXEC "%s" - CMD_DEF("%s -t %s -A %s -p %s -j %s") CMD_SEPARATOR + CMD_DEF("%s -t %s -A %s -p 0x%x -j %s") CMD_SEPARATOR CMD_EXEC "%s", @@ -2450,7 +2473,7 @@ ebtablesCreateTmpSubChain(virBufferPtr b CMD_STOPONERR(stopOnError), ebtables_cmd_path, EBTABLES_DEFAULT_TABLE, - rootchain, protocol, chain, + rootchain, l3_protocols[protoidx].attr, chain, CMD_STOPONERR(stopOnError)); @@ -2462,11 +2485,12 @@ static int _ebtablesRemoveSubChain(virBufferPtr buf, int incoming, const char *ifname, - const char *protocol, + enum l3_proto_idx protoidx, int isTempChain) { char rootchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH]; char chainPrefix; + if (isTempChain) { chainPrefix =(incoming) ? CHAINPREFIX_HOST_IN_TEMP : CHAINPREFIX_HOST_OUT_TEMP; @@ -2476,14 +2500,14 @@ _ebtablesRemoveSubChain(virBufferPtr buf } PRINT_ROOT_CHAIN(rootchain, chainPrefix, ifname); - PRINT_CHAIN(chain, chainPrefix, ifname, protocol); + PRINT_CHAIN(chain, chainPrefix, ifname, l3_protocols[protoidx].val); virBufferVSprintf(buf, - "%s -t %s -D %s -p %s -j %s" CMD_SEPARATOR + "%s -t %s -D %s -p 0x%x -j %s" CMD_SEPARATOR "%s -t %s -F %s" CMD_SEPARATOR "%s -t %s -X %s" CMD_SEPARATOR, ebtables_cmd_path, EBTABLES_DEFAULT_TABLE, - rootchain, protocol, chain, + rootchain, l3_protocols[protoidx].attr, chain, ebtables_cmd_path, EBTABLES_DEFAULT_TABLE, chain, @@ -2497,10 +2521,10 @@ static int ebtablesRemoveSubChain(virBufferPtr buf, int incoming, const char *ifname, - const char *protocol) + enum l3_proto_idx protoidx) { return _ebtablesRemoveSubChain(buf, - incoming, ifname, protocol, 0); + incoming, ifname, protoidx, 0); } @@ -2508,10 +2532,11 @@ static int ebtablesRemoveSubChains(virBufferPtr buf, const char *ifname) { - int i; - for (i = 0; supported_protocols[i]; i++) { - ebtablesRemoveSubChain(buf, 1, ifname, supported_protocols[i]); - ebtablesRemoveSubChain(buf, 0, ifname, supported_protocols[i]); + enum l3_proto_idx i; + + for (i = 0; i < L3_PROTO_LAST_IDX; i++) { + ebtablesRemoveSubChain(buf, 1, ifname, i); + ebtablesRemoveSubChain(buf, 0, ifname, i); } return 0; @@ -2522,10 +2547,10 @@ static int ebtablesRemoveTmpSubChain(virBufferPtr buf, int incoming, const char *ifname, - const char *protocol) + enum l3_proto_idx protoidx) { return _ebtablesRemoveSubChain(buf, - incoming, ifname, protocol, 1); + incoming, ifname, protoidx, 1); } @@ -2533,12 +2558,11 @@ static int ebtablesRemoveTmpSubChains(virBufferPtr buf, const char *ifname) { - int i; - for (i = 0; supported_protocols[i]; i++) { - ebtablesRemoveTmpSubChain(buf, 1, ifname, - supported_protocols[i]); - ebtablesRemoveTmpSubChain(buf, 0, ifname, - supported_protocols[i]); + enum l3_proto_idx i; + + for (i = 0; i < L3_PROTO_LAST_IDX; i++) { + ebtablesRemoveTmpSubChain(buf, 1, ifname, i); + ebtablesRemoveTmpSubChain(buf, 0, ifname, i); } return 0; @@ -2576,12 +2600,11 @@ static int ebtablesRenameTmpSubChains(virBufferPtr buf, const char *ifname) { - int i; - for (i = 0; supported_protocols[i]; i++) { - ebtablesRenameTmpSubChain (buf, 1, ifname, - supported_protocols[i]); - ebtablesRenameTmpSubChain (buf, 0, ifname, - supported_protocols[i]); + enum l3_proto_idx i; + + for (i = 0; i < L3_PROTO_LAST_IDX; i++) { + ebtablesRenameTmpSubChain (buf, 1, ifname, l3_protocols[i].val); + ebtablesRenameTmpSubChain (buf, 0, ifname, l3_protocols[i].val); } return 0; @@ -2911,20 +2934,24 @@ ebiptablesApplyNewRules(virConnectPtr co ebtablesCreateTmpRootChain(&buf, 0, ifname, 1); if (chains_in & (1 << VIR_NWFILTER_CHAINSUFFIX_IPv4)) - ebtablesCreateTmpSubChain(&buf, 1, ifname, "ipv4", 1); + ebtablesCreateTmpSubChain(&buf, 1, ifname, L3_PROTO_IPV4_IDX, 1); if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_IPv4)) - ebtablesCreateTmpSubChain(&buf, 0, ifname, "ipv4", 1); + ebtablesCreateTmpSubChain(&buf, 0, ifname, L3_PROTO_IPV4_IDX, 1); if (chains_in & (1 << VIR_NWFILTER_CHAINSUFFIX_IPv6)) - ebtablesCreateTmpSubChain(&buf, 1, ifname, "ipv6", 1); + ebtablesCreateTmpSubChain(&buf, 1, ifname, L3_PROTO_IPV6_IDX, 1); if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_IPv6)) - ebtablesCreateTmpSubChain(&buf, 0, ifname, "ipv6", 1); + ebtablesCreateTmpSubChain(&buf, 0, ifname, L3_PROTO_IPV6_IDX, 1); - // keep arp as last + // keep arp,rarp as last if (chains_in & (1 << VIR_NWFILTER_CHAINSUFFIX_ARP)) - ebtablesCreateTmpSubChain(&buf, 1, ifname, "arp", 1); + ebtablesCreateTmpSubChain(&buf, 1, ifname, L3_PROTO_ARP_IDX, 1); if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_ARP)) - ebtablesCreateTmpSubChain(&buf, 0, ifname, "arp", 1); + ebtablesCreateTmpSubChain(&buf, 0, ifname, L3_PROTO_ARP_IDX, 1); + if (chains_in & (1 << VIR_NWFILTER_CHAINSUFFIX_RARP)) + ebtablesCreateTmpSubChain(&buf, 1, ifname, L3_PROTO_RARP_IDX, 1); + if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_RARP)) + ebtablesCreateTmpSubChain(&buf, 0, ifname, L3_PROTO_RARP_IDX, 1); if (ebiptablesExecCLI(&buf, &cli_status) || cli_status != 0) goto tear_down_tmpebchains; Index: libvirt-acl/tests/nwfilterxml2xmlin/rarp-test.xml =================================================================== --- /dev/null +++ libvirt-acl/tests/nwfilterxml2xmlin/rarp-test.xml @@ -0,0 +1,33 @@ +<filter name='testcase'> + <uuid>5c6d49af-b071-6127-b4ec-6f8ed4b55335</uuid> + <rule action='accept' direction='out'> + <rarp srcmacaddr='1:2:3:4:5:6' srcmacmask='ff:ff:ff:ff:ff:ff' + protocolid='rarp' + dstmacaddr='aa:bb:cc:dd:ee:ff' dstmacmask='ff:ff:ff:ff:ff:ff' + hwtype='12' + protocoltype='34' + opcode='Request' + arpsrcmacaddr='1:2:3:4:5:6' + arpdstmacaddr='a:b:c:d:e:f'/> + </rule> + + <rule action='accept' direction='out'> + <rarp srcmacaddr='1:2:3:4:5:6' srcmacmask='ff:ff:ff:ff:ff:ff' + opcode='1' hwtype='255' protocoltype='255'/> + </rule> + + <rule action='accept' direction='out'> + <rarp srcmacaddr='1:2:3:4:5:6' srcmacmask='ff:ff:ff:ff:ff:ff' + opcode='11' hwtype='256' protocoltype='256'/> + </rule> + + <rule action='accept' direction='out'> + <rarp srcmacaddr='1:2:3:4:5:6' srcmacmask='ff:ff:ff:ff:ff:ff' + opcode='65535' hwtype='65535' protocoltype='65535' /> + </rule> + + <rule action='accept' direction='out'> + <rarp srcmacaddr='1:2:3:4:5:6' srcmacmask='ff:ff:ff:ff:ff:ff' + opcode='65536' hwtype='65536' protocoltype='65536' /> + </rule> +</filter> Index: libvirt-acl/tests/nwfilterxml2xmlout/rarp-test.xml =================================================================== --- /dev/null +++ libvirt-acl/tests/nwfilterxml2xmlout/rarp-test.xml @@ -0,0 +1,18 @@ +<filter name='testcase' chain='root'> + <uuid>5c6d49af-b071-6127-b4ec-6f8ed4b55335</uuid> + <rule action='accept' direction='out' priority='500'> + <rarp srcmacaddr='01:02:03:04:05:06' srcmacmask='ff:ff:ff:ff:ff:ff' dstmacaddr='aa:bb:cc:dd:ee:ff' dstmacmask='ff:ff:ff:ff:ff:ff' hwtype='12' protocoltype='34' opcode='Request' arpsrcmacaddr='01:02:03:04:05:06' arpdstmacaddr='0a:0b:0c:0d:0e:0f'/> + </rule> + <rule action='accept' direction='out' priority='500'> + <rarp srcmacaddr='01:02:03:04:05:06' srcmacmask='ff:ff:ff:ff:ff:ff' hwtype='255' protocoltype='255' opcode='Request'/> + </rule> + <rule action='accept' direction='out' priority='500'> + <rarp srcmacaddr='01:02:03:04:05:06' srcmacmask='ff:ff:ff:ff:ff:ff' hwtype='256' protocoltype='256' opcode='11'/> + </rule> + <rule action='accept' direction='out' priority='500'> + <rarp srcmacaddr='01:02:03:04:05:06' srcmacmask='ff:ff:ff:ff:ff:ff' hwtype='65535' protocoltype='65535' opcode='65535'/> + </rule> + <rule action='accept' direction='out' priority='500'> + <rarp srcmacaddr='01:02:03:04:05:06' srcmacmask='ff:ff:ff:ff:ff:ff'/> + </rule> +</filter> Index: libvirt-acl/tests/nwfilterxml2xmltest.c =================================================================== --- libvirt-acl.orig/tests/nwfilterxml2xmltest.c +++ libvirt-acl/tests/nwfilterxml2xmltest.c @@ -90,6 +90,7 @@ mymain(int argc, char **argv) DO_TEST("mac-test"); DO_TEST("arp-test"); + DO_TEST("rarp-test"); DO_TEST("ip-test"); DO_TEST("ipv6-test"); -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list