[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH V2 03/10] Make filter creation in root table more flexible



Use the previously introduced chain priorities to sort the chains for access
from an interface's '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 determine 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 following the prefix 'arp' in its name.

Signed-off-by: Stefan Berger <stefanb linux vnet ibm com>

---
 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;
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]