File netcf-suse.patch of Package netcf

From:Patrick Mullaney <pmullaney@novell.com>

From: root <root@novy.(none)>

netcf: Suse backend for netcf

    These changes address basic ethernet physical interface configuration.
    Bridging and vlan configuration needs to be tested and addressed still.

Signed-off-by: Patrick Mullaney <pmullaney@novell.com>
---

 Makefile.am                  |    2 
 data/xml/initscripts-get.xsl |   51 +++-
 data/xml/initscripts-put.xsl |    7 -
 src/Makefile.am              |    1 
 src/drv_initscripts.c        |  570 ++++++++++++++++++++++++++----------------
 src/dutil.c                  |   32 ++
 src/dutil.h                  |    3 
 7 files changed, 432 insertions(+), 234 deletions(-)


diff --git a/Makefile.am b/Makefile.am
index 416a9ad..f4f8cb6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -15,7 +15,7 @@ dist_xml_DATA=data/xml/augeas.rng data/xml/interface.rng \
 	data/xml/util-get.xsl data/xml/util-put.xsl \
 	data/xml/initscripts-get.xsl data/xml/initscripts-put.xsl
 dist_netcf_DATA=data/iptables-forward-bridged
-dist_lens_DATA=data/lenses/netcf.aug data/lenses/sysconfig.aug
+dist_lens_DATA=data/lenses/netcf.aug data/lenses/sysconfig.aug data/lenses/persist_net_rules.aug data/lenses/routes.aug
 
 # This requires that trang is installed, but we don't want to require
 # that, even for building, since the .rnc files are only a convenience
diff --git a/data/xml/initscripts-get.xsl b/data/xml/initscripts-get.xsl
index fab8ecb..dd5dff6 100644
--- a/data/xml/initscripts-get.xsl
+++ b/data/xml/initscripts-get.xsl
@@ -47,9 +47,10 @@
   <xsl:template name="vlan-interface-common">
     <xsl:variable name="iface" select="concat(vlan/interface/@name, '.', vlan/@tag)"/>
 
-    <xsl:attribute name="path">/files/etc/sysconfig/network-scripts/ifcfg-<xsl:value-of select="$iface"/></xsl:attribute>
+    <xsl:attribute name="path">/files/etc/sysconfig/network/ifcfg-<xsl:value-of select="$iface"/></xsl:attribute>
     <node label="DEVICE" value="{$iface}"/>
-    <node label="VLAN" value="yes"/>
+    <node label="ETHERDEVICE" value="{vlan/interface/@name}"/>
+    <!-- <node label="VLAN" value="yes"/> -->
   </xsl:template>
 
   <xsl:template name='bare-vlan-interface'>
@@ -67,15 +68,21 @@
       <xsl:call-template name="name-attr"/>
       <xsl:call-template name="startmode"/>
       <xsl:call-template name="mtu"/>
-      <node label="TYPE" value="Bridge"/>
+      <node label="BRIDGE" value="yes"/>
       <xsl:call-template name="interface-addressing"/>
       <xsl:if test="bridge/@stp">
-        <node label="STP" value="{bridge/@stp}"/>
+        <node label="BRIDGE_STP" value="{bridge/@stp}"/>
       </xsl:if>
       <xsl:if test="bridge/@delay">
-        <node label="DELAY" value="{bridge/@delay}"/>
+        <node label="BRIDGE_FORWARDDELAY" value="{bridge/@delay}"/>
       </xsl:if>
-    </tree>
+      <xsl:variable name="bridges">
+        <xsl:for-each select="//bridge/interface">
+        <xsl:text> </xsl:text><xsl:value-of select="@name"/>
+        </xsl:for-each>
+      </xsl:variable>
+      <node label="BRIDGE_PORTS"> <xsl:attribute name="value"> <xsl:value-of select="$bridges"/></xsl:attribute></node>
+      </tree>
     <xsl:for-each select='bridge/interface'>
       <tree>
         <xsl:if test="@type = 'ethernet'">
@@ -87,7 +94,6 @@
         <xsl:if test="@type = 'bond'">
           <xsl:call-template name="bare-bond-interface"/>
         </xsl:if>
-        <node label="BRIDGE" value="{../../@name}"/>
       </tree>
       <xsl:if test="@type = 'bond'">
         <xsl:call-template name="bond-slaves"/>
@@ -102,8 +108,6 @@
     <xsl:for-each select='bond/interface'>
       <tree>
         <xsl:call-template name="bare-ethernet-interface"/>
-        <node label="MASTER" value="{../../@name}"/>
-        <node label="SLAVE" value="yes"/>
       </tree>
     </xsl:for-each>
   </xsl:template>
@@ -129,6 +133,13 @@
       <xsl:call-template name="startmode"/>
       <xsl:call-template name="mtu"/>
       <xsl:call-template name="interface-addressing"/>
+      <node label="BONDING_MASTER" value="yes"/>
+      <xsl:for-each select="//bond/interface">
+        <node>
+          <xsl:attribute name="label">BONDING_SLAVE_<xsl:copy-of select='position()-1'/></xsl:attribute>
+          <xsl:attribute name="value"><xsl:value-of select="@name"/></xsl:attribute>
+      </node>
+      </xsl:for-each>
       <xsl:call-template name="bonding-opts-node"/>
     </tree>
     <xsl:call-template name="bond-slaves"/>
@@ -138,7 +149,7 @@
        Named templates, following the Relax NG syntax
   -->
   <xsl:template name="name-attr">
-    <xsl:attribute name="path">/files/etc/sysconfig/network-scripts/ifcfg-<xsl:value-of select="@name"/></xsl:attribute>
+    <xsl:attribute name="path">/files/etc/sysconfig/network/ifcfg-<xsl:value-of select="@name"/></xsl:attribute>
     <node label="DEVICE" value="{@name}"/>
   </xsl:template>
 
@@ -155,20 +166,23 @@
     </xsl:if>
     <xsl:call-template name="startmode"/>
     <xsl:call-template name="mtu"/>
+      <node label="BOOTPROTO" value="none"/>
   </xsl:template>
 
   <xsl:template name="startmode">
     <xsl:choose>
       <xsl:when test="$g_startmode = 'onboot'">
-        <node label="ONBOOT" value="yes"/>
+        <node label="STARTMODE" value="auto"/>
       </xsl:when>
       <xsl:when test="$g_startmode = 'none'">
-        <node label="ONBOOT" value="no"/>
+        <node label="STARTMODE" value="manual"/>
       </xsl:when>
       <xsl:when test="$g_startmode = 'hotplug'">
-        <node label="ONBOOT" value="no"/>
-        <node label="HOTPLUG" value="yes"/>
+        <node label="STARTMODE" value="ifplugd"/>
       </xsl:when>
+      <xsl:otherwise>
+        <node label="STARTMODE" value="manual"/>
+      </xsl:otherwise>
     </xsl:choose>
   </xsl:template>
 
@@ -185,12 +199,12 @@
     <xsl:choose>
       <xsl:when test="dhcp">
         <node label="BOOTPROTO" value="dhcp"/>
-        <xsl:if test="dhcp/@peerdns">
+        <!-- <xsl:if test="dhcp/@peerdns">
           <node label="PEERDNS" value="{dhcp/@peerdns}"/>
-        </xsl:if>
+        </xsl:if> -->
       </xsl:when>
       <xsl:when test="ip">
-        <node label="BOOTPROTO" value="none"/>
+        <node label="BOOTPROTO" value="static"/>
         <node label="IPADDR" value="{ip/@address}"/>
         <xsl:if test="ip/@prefix">
           <node label="NETMASK" value="{ipcalc:netmask(ip/@prefix)}"/>
@@ -199,6 +213,9 @@
           <node label="GATEWAY" value="{route/@gateway}"/>
         </xsl:if>
       </xsl:when>
+      <xsl:otherwise>
+        <node label="BOOTPROTO" value="none"/>
+      </xsl:otherwise>
     </xsl:choose>
   </xsl:template>
 
diff --git a/data/xml/initscripts-put.xsl b/data/xml/initscripts-put.xsl
index 267d9cd..1b5145a 100644
--- a/data/xml/initscripts-put.xsl
+++ b/data/xml/initscripts-put.xsl
@@ -140,12 +140,15 @@
   -->
   <xsl:template name="startmode">
     <xsl:choose>
-      <xsl:when test="node[@label ='HOTPLUG']/@value = 'yes'">
+      <xsl:when test="node[@label ='STARTMODE']/@value = 'yes'">
         <start mode='hotplug'/>
       </xsl:when>
-      <xsl:when test="node[@label = 'ONBOOT']/@value = 'yes'">
+      <xsl:when test="node[@label = 'STARTMODE']/@value = 'auto'">
         <start mode='onboot'/>
       </xsl:when>
+      <xsl:when test="node[@label = 'STARTMODE']/@value = 'manual'">
+        <start mode='manual'/>
+      </xsl:when>
       <xsl:otherwise>
         <start mode='none'/>
       </xsl:otherwise>
diff --git a/src/Makefile.am b/src/Makefile.am
index 9d8a3d7..daa54d9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -31,7 +31,6 @@ libnetcf_la_SOURCES = netcf.h netcf.c internal.h \
 libnetcf_la_LDFLAGS = -Wl,--version-script=netcf.syms \
      -version-info $(LIBNETCF_VERSION_INFO)
 libnetcf_la_LIBADD = $(NETCF_LIBDEPS) $(GNULIB)
-libnetcf_la_DEPENDENCIES = $(libnetcf_la_LIBADD) netcf.syms
 
 ncftool_SOURCES = ncftool.c
 ncftool_LDADD = libnetcf.la $(READLINE_LIBS) $(GNULIB)
diff --git a/src/drv_initscripts.c b/src/drv_initscripts.c
index d5bbd44..1878875 100644
--- a/src/drv_initscripts.c
+++ b/src/drv_initscripts.c
@@ -1,6 +1,7 @@
 /*
- * drv_initscripts.c: the initscripts backend for netcf
+ * drv_initscripts.c: the initscripts backend for suse
  *
+ * Copyright (C) 2010 Novell Inc.
  * Copyright (C) 2009 Red Hat Inc.
  *
  * This library is free software; you can redistribute it and/or
@@ -17,7 +18,10 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
  *
- * Author: David Lutterkort <lutter@redhat.com>
+ * Derived from the drv_initscripts.c for the Redhat backend authored
+ * by David Lutterkort.
+ *
+ * Author: Patrick Mullaney <pmullaney@novell.com>
  */
 
 #include <config.h>
@@ -30,6 +34,9 @@
 #include <stdbool.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+
 
 #include "safe-alloc.h"
 #include "ref.h"
@@ -47,18 +54,44 @@
 
 #include <libexslt/exslt.h>
 
+#define NETRULE_PATH "/etc/udev/rules.d/70-persistent-net.rules"
+
+static const char *const aug_files =
+    "/files";
+
 static const char *const network_scripts_path =
-    "/files/etc/sysconfig/network-scripts";
+    "/etc/sysconfig/network";
 
 static const char *const ifcfg_path =
-    "/files/etc/sysconfig/network-scripts/*";
+    "/files/etc/sysconfig/network/*";
+
+static const char *const udev_netrule_path =
+    NETRULE_PATH;
+
+static const char *const ifcfg_prefix =
+    "ifcfg-";
 
 /* Augeas should only load the files we are interested in */
 static const struct augeas_pv augeas_xfm_common_pv[] = {
+    /* Netrule files */
+    { "/augeas/load/Persist_Net_Rules/lens", "Persist_Net_Rules.lns" },
+    { "/augeas/load/Persist_Net_Rules/incl", NETRULE_PATH },
+    { "/augeas/load/Persist_Net_Rules/excl[1]", "*.augnew" },
+    { "/augeas/load/Persist_Net_Rules/excl[2]", "*.augsave" },
+    { "/augeas/load/Persist_Net_Rules/excl[3]", "*.rpmsave" },
+    { "/augeas/load/Persist_Net_Rules/excl[4]", "*.rpmnew" },
+    { "/augeas/load/Persist_Net_Rules/excl[5]", "*~" },
+    /* Routes files */
+    { "/augeas/load/Routes/lens", "Routes.lns" },
+    { "/augeas/load/Routes/incl", "/etc/sysconfig/network/routes" },
+    { "/augeas/load/Routes/excl[1]", "*.augnew" },
+    { "/augeas/load/Routes/excl[2]", "*.augsave" },
+    { "/augeas/load/Routes/excl[3]", "*.rpmsave" },
+    { "/augeas/load/Routes/excl[4]", "*.rpmnew" },
+    { "/augeas/load/Routes/excl[5]", "*~" },
     /* Ifcfg files */
     { "/augeas/load/Ifcfg/lens", "Sysconfig.lns" },
-    { "/augeas/load/Ifcfg/incl",
-      "/etc/sysconfig/network-scripts/ifcfg-*" },
+    { "/augeas/load/Ifcfg/incl", "/etc/sysconfig/network/ifcfg-*" },
     { "/augeas/load/Ifcfg/excl[1]", "*~" },
     { "/augeas/load/Ifcfg/excl[2]", "*.bak" },
     { "/augeas/load/Ifcfg/excl[3]", "*.orig" },
@@ -108,13 +141,14 @@ static const char *const prog_rc_d_iptables = "/etc/init.d/iptables";
  * is not a toplevel interface
  */
 static const char *const subif_paths[] = {
-    "MASTER", "BRIDGE"
+    "BONDING_MASTER", "BRIDGE"
 };
 
 static int is_slave(struct netcf *ncf, const char *intf) {
     for (int s = 0; s < ARRAY_CARDINALITY(subif_paths); s++) {
         int r;
-        r = aug_fmt_match(ncf, NULL, "%s/%s", intf, subif_paths[s]);
+        r = aug_fmt_match(ncf, NULL, "%s%s/ifcfg-%s/%s",
+                          aug_files, network_scripts_path, intf, subif_paths[s]);
         if (r != 0)
             return r;
     }
@@ -122,14 +156,23 @@ static int is_slave(struct netcf *ncf, const char *intf) {
 }
 
 static bool has_ifcfg_file(struct netcf *ncf, const char *name) {
-    int nmatches;
+    struct augeas *aug = NULL;
+    char *path = NULL;
+    int nmatches = 0, r;
 
-    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);
+    aug = get_augeas(ncf);
+    ERR_BAIL(ncf);
+
+    /* if ifcfg-NAME exists, true */
+    r = xasprintf(&path, "%s/%s/ifcfg-%s", aug_files, network_scripts_path, name);
+    ERR_NOMEM(r < 0, ncf);
+
+    nmatches = aug_match(aug, path, NULL);
+    ERR_COND_BAIL(nmatches < 0, ncf, EOTHER);
+
+    FREE(path);
+
+error:
     return nmatches > 0;
 }
 
@@ -139,76 +182,114 @@ static int cmpstrp(const void *p1, const void *p2) {
     return strcmp(s1, s2);
 }
 
-/* Find the path to the ifcfg file that has the configuration for the
- * interface with MAC address MAC.
- */
-static char *find_ifcfg_path_by_hwaddr(struct netcf *ncf, const char *mac) {
-    static const char *const hwaddr_str = "/HWADDR";
+static int
+find_ifcfg_file_by_name(struct netcf *ncf, const char *name, char ***intf)
+{
+    DIR *dp;
+    struct dirent *ent;
+    const char *ifprefix = "ifcfg-";
+    const char *ifdir = network_scripts_path;
+    int found=-1, result=0, r=0;
+
+    dp = opendir (ifdir);
+    ERR_COND_BAIL(dp == NULL, ncf, EOTHER);
+    r = ALLOC_N(*intf, 1);
+    while ((ent = readdir (dp)))
+        if (ent->d_type == DT_REG &&
+            !strncmp(ifprefix, ent->d_name, strlen(ifprefix)) &&
+            strlen(ent->d_name + strlen(ifprefix)) == strlen(name) &&
+            !strncmp((ent->d_name + strlen(ifprefix)),name, strlen(name))) {
+            result = xasprintf( &(*intf)[0], "%s",
+                                ent->d_name + strlen(ifprefix));
+            ERR_NOMEM(result < 0, ncf);
+            found = 1;
+        }
+    closedir (dp);
 
-    int nhwaddr = 0, r;
-    char **hwaddr = NULL;
-    struct augeas *aug = NULL;
+    return found;
 
-    aug = get_augeas(ncf);
-    ERR_BAIL(ncf);
+error:
+    FREE((*intf)[0]);
+    FREE((*intf));
+    return -1;
+}
 
-    // It would be nice if Augeas provided a way to do case-insensitive
-    // matching. For now, we just write it out
-    nhwaddr = aug_fmt_match(ncf, &hwaddr, "%s%s", ifcfg_path, hwaddr_str);
-    ERR_COND_BAIL(nhwaddr < 0, ncf, EOTHER);
-
-    /* Sort because need_config will return the last match in case
-     * of multiple matches */
-    qsort(hwaddr, nhwaddr, sizeof(*hwaddr), cmpstrp);
-    int match = -1;
-    for (int i=0; i < nhwaddr; i++) {
-        const char *addr;
-        r = aug_get(aug, hwaddr[i], &addr);
-        ERR_COND_BAIL(r != 1, ncf, EOTHER);
-        if (STRCASEEQ(addr, mac))
-            match = i;
-    }
-    if (match != -1) {
-        char *path = hwaddr[match];
-        hwaddr[match] = NULL;
-        path[strlen(path) - strlen(hwaddr_str)] = '\0';
-        free_matches(nhwaddr, &hwaddr);
-        return path;
+static int
+find_ifcfg_files(struct netcf *ncf, char ***intf)
+{
+    DIR *dp;
+    struct dirent *ent;
+    const char *ifprefix = "ifcfg-";
+    const char *ifdir = network_scripts_path;
+    int count = 0, result =0, r =0;;
+
+    dp = opendir (ifdir);
+    ERR_COND_BAIL(dp == NULL, ncf, EOTHER);
+    while ((ent = readdir (dp)))
+        if (ent->d_type == DT_REG &&
+            !strncmp(ifprefix, ent->d_name, strlen(ifprefix))) {
+            count++;
+        }
+    closedir (dp);
+
+    dp = opendir (ifdir);
+    ERR_COND_BAIL(dp == NULL, ncf, EOTHER);
+    r = ALLOC_N(*intf, count);
+    ERR_NOMEM(r < 0, ncf);
+    count = 0;
+    while ((ent = readdir (dp))) {
+        if (ent->d_type == DT_REG &&
+            !strncmp(ifprefix, ent->d_name, strlen(ifprefix))) {
+            result = xasprintf( &(*intf)[count], "%s",
+                                ent->d_name + strlen(ifprefix));
+            ERR_NOMEM(result < 0, ncf);
+            count++;
+        }
     }
- error:
-    free_matches(nhwaddr, &hwaddr);
-    return NULL;
+    closedir (dp);
+
+    qsort(*intf, count, sizeof(**intf), cmpstrp);
+
+    return count;
+
+error:
+    for(;count>=0;count--)
+        FREE((*intf)[count]);
+    FREE((*intf));
+    return -1;
 }
 
-/* Find the path to the ifcfg file that has the configuration for the
- * interface by checking for an entry 'DEVICE=NAME'
+/* Find the mac address given the interface name in the udev persistent
+ * netrule file.
  */
-static char *find_ifcfg_path_by_device(struct netcf *ncf, const char *name) {
+static int find_hwaddr_by_device(struct netcf *ncf, const char *name,
+                                 const char **addr) {
+    int nmatches = 0, r;
+    char **matches = NULL;
     struct augeas *aug = NULL;
-    int ndevs = 0;
-    char **devs = NULL;
+    char *path = NULL;
 
     aug = get_augeas(ncf);
     ERR_BAIL(ncf);
 
-    ndevs = aug_fmt_match(ncf, &devs, "%s[DEVICE = '%s']",
-                          ifcfg_path, name);
-    ERR_COND_BAIL(ndevs < 0, ncf, EOTHER);
-
-    if (ndevs == 0)
-        return NULL;
+    nmatches = aug_fmt_match(ncf, &matches, "%s/%s/*[ NAME = '%s']",
+                             aug_files, udev_netrule_path, name);
+    ERR_COND_BAIL(nmatches < 0 , ncf, EOTHER);
 
-    qsort(devs, ndevs, sizeof(*devs), cmpstrp);
-
-    char *path = devs[ndevs - 1];
-    devs[ndevs - 1] = NULL;
-
-    free_matches(ndevs, &devs);
+    if (nmatches == 1 ) {
+        r = xasprintf(&path, "%s/%s", matches[0], "ATTR{address}");
+        ERR_NOMEM(r < 0, ncf);
+        *addr = NULL; /* ensure that addr is NULL */
+        r = aug_get(aug, path, addr);
+        FREE(path);
+    } else
+        goto error;
 
-    return path;
+    free_matches(nmatches, &matches);
+    return nmatches;
  error:
-    free_matches(ndevs, &devs);
-    return NULL;
+    free_matches(nmatches, &matches);
+    return 0;
 }
 
 /* Find the path to the ifcfg file that has the configuration for
@@ -218,14 +299,13 @@ static char *find_ifcfg_path_by_device(struct netcf *ncf, const char *name) {
 static char *find_ifcfg_path(struct netcf *ncf, const char *name) {
     struct augeas *aug = NULL;
     char *path = NULL;
-    const char *mac = NULL;
     int r, nmatches;
 
     aug = get_augeas(ncf);
     ERR_BAIL(ncf);
 
     /* if ifcfg-NAME exists, use that */
-    r = xasprintf(&path, "%s/ifcfg-%s", network_scripts_path, name);
+    r = xasprintf(&path, "%s/%s/ifcfg-%s", aug_files, network_scripts_path, name);
     ERR_NOMEM(r < 0, ncf);
 
     nmatches = aug_match(aug, path, NULL);
@@ -234,98 +314,10 @@ static char *find_ifcfg_path(struct netcf *ncf, const char *name) {
     if (nmatches == 1)
         return path;
 
-    FREE(path);
-
-    /* Now find the config by MAC, matching on HWADDR */
-    r = aug_get_mac(ncf, name, &mac);
-    ERR_COND_BAIL(r < 0, ncf, EOTHER);
-    if (r > 0) {
-        path = find_ifcfg_path_by_hwaddr(ncf, mac);
-        ERR_BAIL(ncf);
-        if (path != NULL)
-            return path;
-    }
-
-    path = find_ifcfg_path_by_device(ncf, name);
-    ERR_BAIL(ncf);
-
-    return path;
  error:
     FREE(path);
-    return NULL;
-}
-
-/* Given NDEVS path to DEVICE entries which may contain duplicate devices,
- * produce a list of canonical paths to the interfaces in INTF and return
- * the number of entries. Return -1 on error
- */
-static int uniq_ifcfg_paths(struct netcf *ncf,
-                            int ndevs, char **devs,
-                            char ***intf) {
-    struct augeas *aug;
-    int r;
-    int ndevnames = 0;
-    const char **devnames = NULL;
 
-    aug = get_augeas(ncf);
-    ERR_BAIL(ncf);
-
-    /* List unique device names */
-    r = ALLOC_N(devnames, ndevs);
-    ERR_NOMEM(r < 0, ncf);
-
-    for (int i=0; i < ndevs; i++) {
-        const char *name = NULL;
-        r = aug_get(aug, devs[i], &name);
-        ERR_COND_BAIL(r != 1, ncf, EOTHER);
-        int exists = 0;
-        for (int j = 0; j < ndevnames; j++)
-            if (STREQ(name, devnames[j])) {
-                exists = 1;
-                break;
-            }
-        if (!exists)
-            devnames[ndevnames++] = name;
-    }
-    qsort(devnames, ndevnames, sizeof(*devnames), cmpstrp);
-
-    /* Find canonical config for each device name */
-    r = ALLOC_N(*intf, ndevnames);
-    ERR_NOMEM(r < 0, ncf);
-    for (int i= 0; i < ndevnames; i++) {
-        (*intf)[i] = find_ifcfg_path(ncf, devnames[i]);
-        ERR_BAIL(ncf);
-    }
-
-    FREE(devnames);
-    return ndevnames;
-
- error:
-    FREE(devnames);
-    free_matches(ndevnames, intf);
-    return -1;
-}
-
-/* List all configured network devices; returns the number of devices or -1
- * on error. On success, the path to the config file for each interface
- * is returned in INTF
- */
-static int list_ifcfg_paths(struct netcf *ncf, char ***intf) {
-    int result = 0, ndevs;
-    char **devs = NULL;
-
-    ndevs = aug_fmt_match(ncf, &devs, "%s/DEVICE", ifcfg_path);
-    ERR_COND_BAIL(ndevs < 0, ncf, EOTHER);
-
-    result = uniq_ifcfg_paths(ncf, ndevs, devs, intf);
-    ERR_BAIL(ncf);
-
-    free_matches(ndevs, &devs);
-    return result;
-
- error:
-    free_matches(ndevs, &devs);
-    return -1;
+    return NULL;
 }
 
 static int list_interfaces(struct netcf *ncf, char ***intf) {
@@ -335,8 +327,8 @@ static int list_interfaces(struct netcf *ncf, char ***intf) {
     aug = get_augeas(ncf);
     ERR_BAIL(ncf);
 
-    /* Look in augeas for all interfaces */
-    nint = list_ifcfg_paths(ncf, intf);
+    /* Look for all interfaces */
+    nint = find_ifcfg_files(ncf, intf);
     ERR_BAIL(ncf);
     result = nint;
 
@@ -491,6 +483,7 @@ int drv_init(struct netcf *ncf) {
         goto error;
 
     // FIXME: Check for errors
+
     xsltInit();
     exsltStrRegister();
     ncf->driver->get = parse_stylesheet(ncf, "initscripts-get.xsl");
@@ -498,8 +491,10 @@ int drv_init(struct netcf *ncf) {
     ncf->driver->rng = rng_parse(ncf, "interface.rng");
     ERR_BAIL(ncf);
 
+#ifdef NCF_CHECK_BRIDGING_RULES
     bridge_physdevs(ncf);
     ERR_BAIL(ncf);
+#endif
 
     /* open a socket for interface ioctls */
     ncf->driver->ioctl_fd = init_ioctl_fd(ncf);
@@ -534,11 +529,10 @@ void drv_entry(struct netcf *ncf) {
 
 static int list_interface_ids(struct netcf *ncf,
                               int maxnames, char **names,
-                              unsigned int flags,
-                              const char *id_attr) {
+                              unsigned int flags) {
     struct augeas *aug = NULL;
-    int nint = 0, nmatches = 0, nqualified = 0, result = 0, r;
-    char **intf = NULL, **matches = NULL;
+    int nint = 0, nqualified = 0, result = 0;
+    char **intf = NULL;
 
     aug = get_augeas(ncf);
     ERR_BAIL(ncf);
@@ -547,17 +541,13 @@ static int list_interface_ids(struct netcf *ncf,
     if (!names) {
         maxnames = nint;    /* if not returning list, ignore maxnames too */
     }
+
     for (result = 0; (result < nint) && (nqualified < maxnames); result++) {
-        nmatches = aug_fmt_match(ncf, &matches,
-                                 "%s/%s", intf[result], id_attr);
-        ERR_BAIL(ncf);
-        if (nmatches > 0) {
             const char *name;
             int is_qualified = ((flags & (NETCF_IFACE_ACTIVE|NETCF_IFACE_INACTIVE))
-                                == (NETCF_IFACE_ACTIVE|NETCF_IFACE_INACTIVE));
+                             == (NETCF_IFACE_ACTIVE|NETCF_IFACE_INACTIVE));
 
-            r = aug_get(aug, matches[nmatches-1], &name);
-            ERR_COND_BAIL(r < 0, ncf, EOTHER);
+            name = intf[result];
 
             if (!is_qualified) {
                 int is_active = if_is_active(ncf, name);
@@ -575,24 +565,21 @@ static int list_interface_ids(struct netcf *ncf,
                 }
                 nqualified++;
             }
-        }
-        free_matches(nmatches, &matches);
     }
     free_matches(nint, &intf);
     return nqualified;
  error:
-    free_matches(nmatches, &matches);
     free_matches(nint, &intf);
     return -1;
 }
 
 int drv_list_interfaces(struct netcf *ncf, int maxnames, char **names,
         unsigned int flags) {
-    return list_interface_ids(ncf, maxnames, names, flags, "DEVICE");
+    return list_interface_ids(ncf, maxnames, names, flags);
 }
 
 int drv_num_of_interfaces(struct netcf *ncf, unsigned int flags) {
-    return list_interface_ids(ncf, 0, NULL, flags, "DEVICE");
+    return list_interface_ids(ncf, 0, NULL, flags);
 }
 
 struct netcf_if *drv_lookup_by_name(struct netcf *ncf, const char *name) {
@@ -607,7 +594,7 @@ struct netcf_if *drv_lookup_by_name(struct netcf *ncf, const char *name) {
     pathx = find_ifcfg_path(ncf, name);
     ERR_BAIL(ncf);
 
-    if (pathx == NULL || is_slave(ncf, pathx))
+    if (pathx == NULL || is_slave(ncf, name))
         goto done;
 
     name_dup = strdup(name);
@@ -629,12 +616,15 @@ struct netcf_if *drv_lookup_by_name(struct netcf *ncf, const char *name) {
  * The format is a very simple representation of the Augeas tree (see
  * xml/augeas.rng)
  */
-static xmlDocPtr aug_get_xml(struct netcf *ncf, int nint, char **intf) {
+static xmlDocPtr aug_get_xml(struct netcf_if *nif, int nint, char **intf) {
     struct augeas *aug;
     xmlDocPtr result = NULL;
     xmlNodePtr root = NULL, tree = NULL;
     char **matches = NULL;
+    struct netcf *ncf = nif->ncf;
     int nmatches, r;
+    int pathoffset = strlen(aug_files) + strlen(network_scripts_path)
+                     + strlen(ifcfg_prefix) + 1;
 
     aug = get_augeas(ncf);
     ERR_BAIL(ncf);
@@ -646,17 +636,33 @@ static xmlDocPtr aug_get_xml(struct netcf *ncf, int nint, char **intf) {
     for (int i=0; i < nint; i++) {
         tree = xmlNewChild(root, NULL, BAD_CAST "tree", NULL);
         xmlNewProp(tree, BAD_CAST "path", BAD_CAST intf[i]);
-        nmatches = aug_fmt_match(ncf, &matches, "%s/%s", intf[i], "*");
+        nmatches = aug_fmt_match(ncf, &matches, "%s%s/ifcfg-%s/%s",
+                                 aug_files, network_scripts_path, intf[i], "*");
         ERR_COND_BAIL(nint < 0, ncf, EOTHER);
         for (int j = 0; j < nmatches; j++) {
             xmlNodePtr node = xmlNewChild(tree, NULL, BAD_CAST "node", NULL);
             const char *value;
             xmlNewProp(node, BAD_CAST "label",
-                       BAD_CAST matches[j] + strlen(intf[i]) + 1);
+                       BAD_CAST matches[j] + pathoffset + strlen(intf[i]) + 1);
             r = aug_get(aug, matches[j], &value);
             ERR_COND_BAIL(r < 0, ncf, EOTHER);
             xmlNewProp(node, BAD_CAST "value", BAD_CAST value);
         }
+        {
+            xmlNodePtr node = xmlNewChild(tree, NULL, BAD_CAST "node", NULL);
+            xmlNewProp(node, BAD_CAST "label",
+                       BAD_CAST "DEVICE" );
+            xmlNewProp(node, BAD_CAST "value", BAD_CAST nif->name);
+        }
+        {
+            const char *mac = NULL;
+            if( find_hwaddr_by_device(ncf, nif->name, &mac) > 0 ) {
+                xmlNodePtr node = xmlNewChild(tree, NULL, BAD_CAST "node", NULL);
+                xmlNewProp(node, BAD_CAST "label",
+                           BAD_CAST "HWADDR" );
+                xmlNewProp(node, BAD_CAST "value", BAD_CAST mac);
+            }
+        }
         free_matches(nmatches, &matches);
     }
 
@@ -672,8 +678,11 @@ static xmlDocPtr aug_get_xml(struct netcf *ncf, int nint, char **intf) {
 static int aug_put_xml(struct netcf *ncf, xmlDocPtr xml) {
     xmlNodePtr forest;
     char *path = NULL, *lpath = NULL, *label = NULL, *value = NULL;
+    char *device = NULL, *mac = NULL, *gateway = NULL;
+    char **rules = NULL;
     struct augeas *aug = NULL;
-    int result = -1;
+    int result = -1, nrules = 0, ethphysical = 0;
+    int toplevel = 1;
     int r;
 
     aug = get_augeas(ncf);
@@ -689,7 +698,7 @@ static int aug_put_xml(struct netcf *ncf, xmlDocPtr xml) {
                   EINTERNAL, "expected node labeled 'tree', not '%s'",
                   tree->name);
         path = xml_prop(tree, "path");
-        int toplevel = 1;
+        /*int toplevel = 1;*/
         /* This is a little drastic, since it clears out the file entirely */
         r = aug_rm(aug, path);
         ERR_THROW(r < 0, ncf, EINTERNAL, "aug_rm of '%s' failed", path);
@@ -697,23 +706,154 @@ static int aug_put_xml(struct netcf *ncf, xmlDocPtr xml) {
             label = xml_prop(node, "label");
             value = xml_prop(node, "value");
             /* We should mark the toplevel interface from the XSLT */
-            if (STREQ(label, "BRIDGE") || STREQ(label, "MASTER")) {
+            if (STREQ(label, "BRIDGE") || STREQ(label, "BONDING_MASTER")) {
                 toplevel = 0;
             }
-            r = xasprintf(&lpath, "%s/%s", path, label);
-            ERR_NOMEM(r < 0, ncf);
-
-            r = aug_set(aug, lpath, value);
-            ERR_THROW(r < 0, ncf, EOTHER,
-                      "aug_set of '%s' failed", lpath);
-            FREE(lpath);
-            xmlFree(label);
-            xmlFree(value);
+            if (STREQ(label, "DEVICE")) {
+		device = value;
+                if(!strchr(value, '.') && !strncmp("eth", value, strlen("eth")))
+                   ethphysical = 1;
+                xmlFree(label);
+            } else if(STREQ(label, "HWADDR")) {
+		mac = value;
+                xmlFree(label);
+		//continue;
+            } else if(STREQ(label, "GATEWAY")) {
+		gateway = value;
+                xmlFree(label);
+		//continue;
+            } else {
+                r = xasprintf(&lpath, "%s/%s", path, label);
+                ERR_NOMEM(r < 0, ncf);
+
+                r = aug_set(aug, lpath, value);
+                ERR_THROW(r < 0, ncf, EOTHER,
+                          "aug_set of '%s' failed", lpath);
+                FREE(lpath);
+                xmlFree(label);
+                xmlFree(value);
+            }
             label = value = NULL;
         }
         xmlFree(path);
         path = NULL;
     }
+    if( device && !mac && ethphysical && toplevel ){
+        mac = malloc(20);
+        if( if_hwaddr(ncf, device, mac, 20) ){
+            free(mac);
+            mac = NULL;
+        }
+    }
+    if( device && gateway && ethphysical && toplevel ) {
+
+        r = xasprintf(&lpath, "%s%s/%s/%s", aug_files,
+                       network_scripts_path, "routes/default", "gateway");
+        ERR_NOMEM(r < 0, ncf);
+
+        r = aug_set(aug, lpath, gateway);
+        ERR_THROW(r < 0, ncf, EOTHER,
+              "aug_set of '%s' failed", lpath);
+
+        FREE(lpath);
+
+        r = xasprintf(&lpath, "%s%s/%s/%s", aug_files,
+                       network_scripts_path, "routes/default", "netmask");
+        ERR_NOMEM(r < 0, ncf);
+
+        r = aug_set(aug, lpath, "-");
+        ERR_THROW(r < 0, ncf, EOTHER,
+              "aug_set of '%s' failed", lpath);
+
+        FREE(lpath);
+
+        r = xasprintf(&lpath, "%s%s/%s/%s", aug_files,
+                       network_scripts_path, "routes/default", "device");
+        ERR_NOMEM(r < 0, ncf);
+
+        r = aug_set(aug, lpath, device );
+        ERR_THROW(r < 0, ncf, EOTHER,
+              "aug_set of '%s' failed", lpath);
+
+        FREE(lpath);
+    }
+    if( device && mac && ethphysical && toplevel ) {
+
+        r = xasprintf(&lpath, "%s%s/%s/%s", aug_files,
+                       udev_netrule_path, device, "SUBSYSTEM");
+        ERR_NOMEM(r < 0, ncf);
+
+        r = aug_set(aug, lpath, "net");
+        ERR_THROW(r < 0, ncf, EOTHER,
+              "aug_set of '%s' failed", lpath);
+
+        FREE(lpath);
+
+        r = xasprintf(&lpath, "%s%s/%s/%s", aug_files,
+                       udev_netrule_path, device, "ACTION");
+        ERR_NOMEM(r < 0, ncf);
+
+        r = aug_set(aug, lpath, "add");
+        ERR_THROW(r < 0, ncf, EOTHER,
+              "aug_set of '%s' failed", lpath);
+
+        FREE(lpath);
+
+        r = xasprintf(&lpath, "%s%s/%s/%s", aug_files,
+                       udev_netrule_path, device, "DRIVERS");
+        ERR_NOMEM(r < 0, ncf);
+
+        r = aug_set(aug, lpath, "?*");
+        ERR_THROW(r < 0, ncf, EOTHER,
+              "aug_set of '%s' failed", lpath);
+
+        FREE(lpath);
+
+        r = xasprintf(&lpath, "%s%s/%s/%s", aug_files,
+                       udev_netrule_path, device, "ATTR{address}");
+        ERR_NOMEM(r < 0, ncf);
+
+        r = aug_set(aug, lpath, mac);
+        ERR_THROW(r < 0, ncf, EOTHER,
+                  "aug_set of '%s' failed", lpath);
+
+        FREE(lpath);
+
+#ifdef OS113
+        r = xasprintf(&lpath, "%s%s/%s/%s", aug_files,
+                       udev_netrule_path, device, "ATTR{dev_id}");
+        ERR_NOMEM(r < 0, ncf);
+
+        r = aug_set(aug, lpath, "0x0");
+        ERR_THROW(r < 0, ncf, EOTHER,
+                  "aug_set of '%s' failed", lpath);
+
+        FREE(lpath);
+#endif
+
+            r = xasprintf(&lpath, "%s%s/%s/%s", aug_files,
+                           udev_netrule_path, device, "ATTR{type}");
+            ERR_NOMEM(r < 0, ncf);
+
+            r = aug_set(aug, lpath, "1");
+            ERR_THROW(r < 0, ncf, EOTHER,
+                  "aug_set of '%s' failed", lpath);
+
+            FREE(lpath);
+
+            r = xasprintf(&lpath, "%s%s/%s/%s", aug_files,
+                           udev_netrule_path, device, "KERNEL");
+            ERR_NOMEM(r < 0, ncf);
+
+            r = aug_set(aug, lpath, "eth*");
+            ERR_THROW(r < 0, ncf, EOTHER,
+                  "aug_set of '%s' failed", lpath);
+
+            FREE(lpath);
+    }
+    xmlFree(device);
+    xmlFree(mac);
+    xmlFree(gateway);
     result = 0;
  error:
     xmlFree(label);
@@ -728,24 +868,17 @@ static int aug_put_xml(struct netcf *ncf, xmlDocPtr xml) {
  */
 static xmlDocPtr aug_get_xml_for_nif(struct netcf_if *nif) {
     struct netcf *ncf;
-    char **devs = NULL, **intf = NULL;
+    char **intf = NULL;
     xmlDocPtr aug_xml = NULL;
-    int ndevs = 0, nint = 0;
+    int 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);
-    ERR_BAIL(ncf);
-
-    nint = uniq_ifcfg_paths(ncf, ndevs, devs, &intf);
+    nint = find_ifcfg_file_by_name(ncf, nif->name, &intf);
     ERR_BAIL(ncf);
 
-    aug_xml = aug_get_xml(ncf, nint, intf);
+    aug_xml = aug_get_xml(nif, nint, intf);
 
  error:
-    free_matches(ndevs, &devs);
     free_matches(nint, &intf);
     return aug_xml;
 }
@@ -871,7 +1004,7 @@ static bool is_bond(struct netcf *ncf, const char *name) {
     int nmatches = 0;
 
     nmatches = aug_fmt_match(ncf, NULL,
-                             "%s[ MASTER = '%s']", ifcfg_path, name);
+                             "%s[ BONDING_MASTER = '%s']", ifcfg_path, name);
     return nmatches > 0;
 }
 
@@ -880,8 +1013,8 @@ static bool is_bridge(struct netcf *ncf, const char *name) {
     int nmatches = 0;
 
     nmatches = aug_fmt_match(ncf, NULL,
-                             "%s[ DEVICE = '%s' and TYPE = 'Bridge']",
-                             ifcfg_path, name);
+                             "%s%s/ifcfg-%s[ BRIDGE = 'yes' ]",
+                             aug_files, network_scripts_path, name);
     return nmatches > 0;
 }
 
@@ -917,21 +1050,32 @@ static int bridge_slaves(struct netcf *ncf, const char *name, char ***slaves) {
 static void rm_interface(struct netcf *ncf, const char *name) {
     int r;
     char *path = NULL;
+    char **rules = NULL;
     struct augeas *aug = NULL;
+    int nrules = 0;
 
     aug = get_augeas(ncf);
     ERR_BAIL(ncf);
 
     /* The last or clause catches slaves of a bond that are enslaved to
      * a bridge NAME */
-    r = xasprintf(&path,
-          "%s[ DEVICE = '%s' or BRIDGE = '%s' or MASTER = '%s' "
-          "    or MASTER = ../*[BRIDGE = '%s']/DEVICE ]",
-                  ifcfg_path, name, name, name, name);
+    r = xasprintf(&path, "%s/%s/ifcfg-%s",
+                  aug_files, network_scripts_path, name);
     ERR_NOMEM(r < 0, ncf);
 
     r = aug_rm(aug, path);
     ERR_COND_BAIL(r < 0, ncf, EOTHER);
+
+    nrules = aug_fmt_match(ncf, &rules, "%s/%s/%s",
+                           aug_files, udev_netrule_path, name);
+    ERR_COND_BAIL(nrules < 0, ncf, EINTERNAL);
+
+    while(nrules > 0) {
+        nrules--;
+        r = aug_rm(aug, rules[nrules]);
+    }
+    free_matches(nrules, &rules);
+
  error:
     FREE(path);
 }
diff --git a/src/dutil.c b/src/dutil.c
index 2a6eaa0..05ec95a 100644
--- a/src/dutil.c
+++ b/src/dutil.c
@@ -547,6 +547,38 @@ int netlink_close(struct netcf *ncf) {
     return 0;
 }
 
+static size_t format_mac_addr(unsigned char *buf, int buflen,
+                                const unsigned char *addr, int len)
+{
+        int i;
+        char *cp = (char *)buf;
+
+        for (i = 0; i < len; i++) {
+                cp += snprintf(cp, buflen - (cp - (char *)buf), "%02x", addr[i]);
+                if (i == len - 1) {
+			*cp = '\0';
+                        break;
+                }
+                strncpy(cp, ":", 1);
+		cp++;
+        }
+        return cp - (char *)buf;
+}
+
+int if_hwaddr(struct netcf *ncf, const char *intf,
+              unsigned char *mac, int buflen) {
+    struct ifreq ifr;
+    int ret;
+
+    MEMZERO(&ifr, 1);
+    strncpy(ifr.ifr_name, intf, sizeof(ifr.ifr_name));
+    ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
+    ret = ioctl(ncf->driver->ioctl_fd, SIOCGIFHWADDR, &ifr);
+    memcpy(mac,ifr.ifr_hwaddr.sa_data,6);
+    format_mac_addr(mac,buflen, (unsigned char *)ifr.ifr_hwaddr.sa_data,6);
+    return ret;
+}
+
 int if_is_active(struct netcf *ncf, const char *intf) {
     struct ifreq ifr;
 
diff --git a/src/dutil.h b/src/dutil.h
index 90dc59a..c1dfbb7 100644
--- a/src/dutil.h
+++ b/src/dutil.h
@@ -122,6 +122,9 @@ int netlink_close(struct netcf *ncf);
 /* Check if the interface INTF is up using an ioctl call */
 int if_is_active(struct netcf *ncf, const char *intf);
 
+/* Retrieve the hw mac address of the interface INTF */
+int if_hwaddr(struct netcf *ncf, const char *intf, unsigned char *mac, int len);
+
 /* Interface types recognized by netcf. */
 typedef enum {
     NETCF_IFACE_TYPE_NONE = 0,  /* not yet determined */
openSUSE Build Service is sponsored by