Blob Blame History Raw
From 0be286b3062fc2ff8718cbbc914eb596506d9fac Mon Sep 17 00:00:00 2001
From: Laine Stump <laine@laine.org>
Date: Wed, 7 Oct 2015 13:49:45 -0400
Subject: [PATCH 2/2] optimize aug_match() query for all ifcfg files related to
 an interface

This resolves:

 https://bugzilla.redhat.com/show_bug.cgi?id=1269613

The original augeas search term used by netcf to find, for example, all the
ifcfg files associated with device "br1" was:

     "/files/etc/sysconfig/network-scripts/*[ "
     "DEVICE = 'br1' or BRIDGE = 'br1' or MASTER = 'br1' or MASTER = "
     "../*[BRIDGE = 'br1']/DEVICE ]/DEVICE"

This is *extremely* inefficient - on a test host with 514 host
bridges, each with an attached vlan interface, a dumpxml of all
toplevel interfaces took 6m40s (*after* installing an augeas that
included augeas upstream commits a659f09a, 41e989ca, and 23d5e480
which were all pushed after the augeas-1.4.0 release).

In these two messages:

 https://www.redhat.com/archives/augeas-devel/2015-October/msg00003.html
 https://www.redhat.com/archives/augeas-devel/2015-October/msg00004.html

David Lutterkort suggested changing the search term to:

  "(/files/etc/sysconfig/network-scripts/*[(DEVICE|BRIDGE|MASTER) = 'br1']"
  "|/files/etc/sysconfig/network-scripts/*[MASTER]"
  "[MASTER = ../*[BRIDGE = 'br1']/DEVICE ])/DEVICE

That's what this patch does. Testing shows that it is functionally
equivalent, and reduces the dumpxml time in the previously described
test from 6m40s down to 17 seconds.

(cherry picked from commit 396e4e0698d9fb542f2eb8b32790a069e1c0df61)
---
 src/drv_redhat.c | 44 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 34 insertions(+), 10 deletions(-)

diff --git a/src/drv_redhat.c b/src/drv_redhat.c
index 4935f98..092ef5c 100644
--- a/src/drv_redhat.c
+++ b/src/drv_redhat.c
@@ -88,6 +88,38 @@ static const struct augeas_xfm_table augeas_xfm_common =
     { .size = ARRAY_CARDINALITY(augeas_xfm_common_pv),
       .pv = augeas_xfm_common_pv };
 
+/* aug_all_related_ifcfgs() - return the count of (and optionally a list
+ * of, if matches != NULL) the paths for all ifcfg files that are
+ * related to the interface "name".
+ */
+static
+int aug_all_related_ifcfgs(struct netcf *ncf, char ***matches, const char *name) {
+    int nmatches;
+
+    /* this includes the ifcfg files for:
+     *
+     * 1) the named interface itself (DEVICE=$name)
+     *
+     * 2) any interface naming $name as a bridge it is attached to
+     *    (BRIDGE=$name)
+     *
+     * 3) any interface naming $name as the master of a bond it is
+     *    enslaved to (MASTER=$name)
+     *
+     * 4) any interface with a MASTER, where the device named as
+     *    MASTER contains a BRIDGE=$name *and* DEVICE=$itself (thus
+     *    catching ethernet devices that are enslaved to a bond that
+     *    is attached to a bridge).
+     */
+    nmatches = aug_fmt_match(ncf, matches,
+                             "(%s[(DEVICE|BRIDGE|MASTER) = '%s']"
+                             "|%s[MASTER][MASTER = ../*[BRIDGE = '%s']/DEVICE "
+                             "])/DEVICE",
+                             ifcfg_path, name, ifcfg_path, name);
+    return nmatches;
+
+}
+
 /* Entries in a ifcfg file that tell us that the interface
  * is not a toplevel interface
  */
@@ -108,12 +140,7 @@ static int is_slave(struct netcf *ncf, const char *intf) {
 static bool has_ifcfg_file(struct netcf *ncf, const char *name) {
     int nmatches;
 
-    nmatches = aug_fmt_match(ncf, NULL,
-                             "%s[ DEVICE = '%s'"
-                             "    or BRIDGE = '%s'"
-                             "    or MASTER = '%s'"
-                             "    or MASTER = ../*[BRIDGE = '%s']/DEVICE ]/DEVICE",
-                             ifcfg_path, name, name, name, name);
+    nmatches = aug_all_related_ifcfgs(ncf, NULL, name);
     return nmatches > 0;
 }
 
@@ -588,10 +615,7 @@ static xmlDocPtr aug_get_xml_for_nif(struct netcf_if *nif) {
     int ndevs = 0, nint = 0;
 
     ncf = nif->ncf;
-    ndevs = aug_fmt_match(ncf, &devs,
-              "%s[ DEVICE = '%s' or BRIDGE = '%s' or MASTER = '%s'"
-              "    or MASTER = ../*[BRIDGE = '%s']/DEVICE ]/DEVICE",
-              ifcfg_path, nif->name, nif->name, nif->name, nif->name);
+    ndevs = aug_all_related_ifcfgs(ncf, &devs, nif->name);
     ERR_BAIL(ncf);
 
     nint = uniq_ifcfg_paths(ncf, ndevs, devs, &intf);
-- 
1.8.3.1