Use the previously introduced chain priorities to sort the chains for access
from the 'root' table and have them created in the proper order. This gets
rid of a lot of code that was previously creating the chains in a more
hardcoded way.
To detmerine what protocol a filter is used for evaluation do prefix-
matching, i.e., the filter 'arp' is used to filter for the 'arp'
protocol,
'ipv4' for the 'ipv4' protocol and 'arp-xyz' will also be used to
filter
for the 'arp' protocol.
---
src/nwfilter/nwfilter_ebiptables_driver.c | 130 ++++++++++++++++++++++--------
1 file changed, 98 insertions(+), 32 deletions(-)
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
@@ -2774,6 +2774,7 @@ ebtablesCreateTmpSubChain(virBufferPtr b
int incoming,
const char *ifname,
enum l3_proto_idx protoidx,
+ const char *filtername,
int stopOnError)
{
char rootchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
@@ -2781,7 +2782,8 @@ ebtablesCreateTmpSubChain(virBufferPtr b
: CHAINPREFIX_HOST_OUT_TEMP;
PRINT_ROOT_CHAIN(rootchain, chainPrefix, ifname);
- PRINT_CHAIN(chain, chainPrefix, ifname, l3_protocols[protoidx].val);
+ PRINT_CHAIN(chain, chainPrefix, ifname,
+ (filtername) ? filtername : l3_protocols[protoidx].val);
virBufferAsprintf(buf,
CMD_DEF("%s -t %s -N %s") CMD_SEPARATOR
@@ -3288,6 +3290,13 @@ ebiptablesRuleOrderSort(const void *a, c
return ((*insta)->priority - (*instb)->priority);
}
+static int
+ebiptablesFilterOrderSort(const virHashKeyValuePairPtr a,
+ const virHashKeyValuePairPtr b)
+{
+ return *(virNWFilterChainPriority *)a->value -
+ *(virNWFilterChainPriority *)b->value;
+}
static void
iptablesCheckBridgeNFCallEnabled(bool isIPv6)
@@ -3327,6 +3336,56 @@ iptablesCheckBridgeNFCallEnabled(bool is
}
}
+/*
+ * Given a filtername determine the protocol it is used for evaluating
+ * We do prefix-matching to determine the protocol.
+ */
+static enum l3_proto_idx
+ebtablesGetProtoIdxByFiltername(const char *filtername)
+{
+ enum l3_proto_idx idx;
+
+ for (idx = 0; idx < L3_PROTO_LAST_IDX; idx++) {
+ if (STRPREFIX(filtername, l3_protocols[idx].val)) {
+ return idx;
+ }
+ }
+
+ return -1;
+}
+
+static int
+ebtablesCreateTmpRootAndSubChains(virBufferPtr buf,
+ const char *ifname,
+ virHashTablePtr chains, int direction)
+{
+ int rc = 0, i;
+
+ if (virHashSize(chains) != 0) {
+ char **filter_names;
+
+ ebtablesCreateTmpRootChain(buf, direction, ifname, 1);
+ filter_names = (char **)virHashGetKeys(chains,
+ ebiptablesFilterOrderSort);
+ if (filter_names == NULL) {
+ virReportOOMError();
+ rc = 1;
+ goto err_exit;
+ }
+ for (i = 0; filter_names[i]; i++) {
+ enum l3_proto_idx idx = ebtablesGetProtoIdxByFiltername(
+ filter_names[i]);
+ if ((int)idx < 0)
+ continue;
+ ebtablesCreateTmpSubChain(buf, direction, ifname, idx,
+ filter_names[i], 1);
+ }
+ virHashFreeKeys(chains, (void **)filter_names);
+ }
+
+ err_exit:
+ return rc;
+}
static int
ebiptablesApplyNewRules(virConnectPtr conn ATTRIBUTE_UNUSED,
@@ -3337,24 +3396,43 @@ ebiptablesApplyNewRules(virConnectPtr co
int i;
int cli_status;
ebiptablesRuleInstPtr *inst = (ebiptablesRuleInstPtr *)_inst;
- int chains_in = 0, chains_out = 0;
virBuffer buf = VIR_BUFFER_INITIALIZER;
+ virHashTablePtr chains_in_set = virHashCreate(10, NULL),
+ chains_out_set = virHashCreate(10, NULL);
bool haveIptables = false;
bool haveIp6tables = false;
+ if (!chains_in_set || !chains_out_set) {
+ virReportOOMError();
+ goto exit_free_sets;
+ }
+
if (nruleInstances > 1 && inst)
qsort(inst, nruleInstances, sizeof(inst[0]), ebiptablesRuleOrderSort);
+ /* scan the rules to see which chains need to be created */
for (i = 0; i < nruleInstances; i++) {
sa_assert (inst);
if (inst[i]->ruleType == RT_EBTABLES) {
- if (inst[i]->chainprefix == CHAINPREFIX_HOST_IN_TEMP)
- chains_in |= (1 << inst[i]->neededProtocolChain);
- else
- chains_out |= (1 << inst[i]->neededProtocolChain);
+ const char *name = virNWFilterChainSuffixTypeToString(
+ inst[i]->neededProtocolChain);
+ if (inst[i]->chainprefix == CHAINPREFIX_HOST_IN_TEMP) {
+ if (virHashUpdateEntry(chains_in_set, name,
+ &inst[i]->chainPriority)) {
+ virReportOOMError();
+ goto exit_free_sets;
+ }
+ } else {
+ if (virHashUpdateEntry(chains_out_set, name,
+ &inst[i]->chainPriority)) {
+ virReportOOMError();
+ goto exit_free_sets;
+ }
+ }
}
}
+ /* cleanup whatever may exist */
if (ebtables_cmd_path) {
ebtablesUnlinkTmpRootChain(&buf, 1, ifname);
ebtablesUnlinkTmpRootChain(&buf, 0, ifname);
@@ -3364,30 +3442,11 @@ ebiptablesApplyNewRules(virConnectPtr co
ebiptablesExecCLI(&buf, &cli_status);
}
- if (chains_in != 0)
- ebtablesCreateTmpRootChain(&buf, 1, ifname, 1);
- if (chains_out != 0)
- ebtablesCreateTmpRootChain(&buf, 0, ifname, 1);
-
- if (chains_in & (1 << VIR_NWFILTER_CHAINSUFFIX_IPv4))
- ebtablesCreateTmpSubChain(&buf, 1, ifname, L3_PROTO_IPV4_IDX, 1);
- if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_IPv4))
- ebtablesCreateTmpSubChain(&buf, 0, ifname, L3_PROTO_IPV4_IDX, 1);
-
- if (chains_in & (1 << VIR_NWFILTER_CHAINSUFFIX_IPv6))
- ebtablesCreateTmpSubChain(&buf, 1, ifname, L3_PROTO_IPV6_IDX, 1);
- if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_IPv6))
- ebtablesCreateTmpSubChain(&buf, 0, ifname, L3_PROTO_IPV6_IDX, 1);
-
- /* keep arp,rarp as last */
- if (chains_in & (1 << VIR_NWFILTER_CHAINSUFFIX_ARP))
- ebtablesCreateTmpSubChain(&buf, 1, ifname, L3_PROTO_ARP_IDX, 1);
- if (chains_out & (1 << VIR_NWFILTER_CHAINSUFFIX_ARP))
- 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);
+ /* create needed chains */
+ if (ebtablesCreateTmpRootAndSubChains(&buf, ifname, chains_in_set , 1) ||
+ ebtablesCreateTmpRootAndSubChains(&buf, ifname, chains_out_set, 0)) {
+ goto tear_down_tmpebchains;
+ }
if (ebiptablesExecCLI(&buf, &cli_status) || cli_status != 0)
goto tear_down_tmpebchains;
@@ -3477,14 +3536,17 @@ ebiptablesApplyNewRules(virConnectPtr co
iptablesCheckBridgeNFCallEnabled(true);
}
- if (chains_in != 0)
+ if (virHashSize(chains_in_set) != 0)
ebtablesLinkTmpRootChain(&buf, 1, ifname, 1);
- if (chains_out != 0)
+ if (virHashSize(chains_out_set) != 0)
ebtablesLinkTmpRootChain(&buf, 0, ifname, 1);
if (ebiptablesExecCLI(&buf, &cli_status) || cli_status != 0)
goto tear_down_ebsubchains_and_unlink;
+ virHashFree(chains_in_set);
+ virHashFree(chains_out_set);
+
return 0;
tear_down_ebsubchains_and_unlink:
@@ -3519,6 +3581,10 @@ tear_down_tmpebchains:
"interface %s."),
ifname);
+exit_free_sets:
+ virHashFree(chains_in_set);
+ virHashFree(chains_out_set);
+
return 1;
}