File cloud-init-mix-static-dhcp.patch of Package cloud-init.14164

From 263d8be627431001b8fd27d520340f280ed2d5f9 Mon Sep 17 00:00:00 2001
From: Robert Schweikert <rjschwei@suse.com>
Date: Thu, 9 Jan 2020 14:47:46 -0500
Subject: [PATCH] - Handle different values for the common BOOTPROTO
 configuration option   + Introduce the "flavor" configuration option for the
 sysconfig renderer     this is necessary to account for differences in the
 handling of the     BOOTPROTO setting between distributions (lp#1858808)   +
 Thanks to Petr Pavlu for the idea - Network config clean up for sysconfig
 renderer   + The introduction of the "flavor" renderer configuration allows
 us     to only write values that are pertinent for the given distro - Set the
 DHCPv6 client mode on SUSE (lp#1800854)

---
 cloudinit/distros/opensuse.py                  |   1 +
 cloudinit/net/sysconfig.py                     | 295 ++++++++++++------
 tests/unittests/test_distros/test_netconfig.py |  39 +--
 tests/unittests/test_net.py                    | 405 +++++++++++++++----------
 4 files changed, 450 insertions(+), 290 deletions(-)

--- cloudinit/distros/opensuse.py.orig
+++ cloudinit/distros/opensuse.py
@@ -38,6 +38,7 @@ class Distro(distros.Distro):
     renderer_configs = {
         'sysconfig': {
             'control': 'etc/sysconfig/network/config',
+            'flavor': 'suse',
             'iface_templates': '%(base)s/network/ifcfg-%(name)s',
             'netrules_path': (
                 'etc/udev/rules.d/85-persistent-net-cloud-init.rules'),
--- cloudinit/net/sysconfig.py.orig
+++ cloudinit/net/sysconfig.py
@@ -86,6 +86,9 @@ class ConfigMap(object):
     def __getitem__(self, key):
         return self._conf[key]
 
+    def get(self, key):
+        return self._conf.get(key, None)
+
     def __contains__(self, key):
         return key in self._conf
 
@@ -269,11 +272,15 @@ class Renderer(renderer.Renderer):
     #      s1-networkscripts-interfaces.html (or other docs for
     #                                         details about this)
 
-    iface_defaults = tuple([
+    iface_defaults_rh = tuple([
         ('ONBOOT', True),
         ('USERCTL', False),
         ('NM_CONTROLLED', False),
         ('BOOTPROTO', 'none'),
+    ])
+
+    iface_defaults_suse = tuple([
+        ('BOOTPROTO', 'static'),
         ('STARTMODE', 'auto'),
     ])
 
@@ -297,12 +304,18 @@ class Renderer(renderer.Renderer):
         ('bond_primary_reselect', "primary_reselect=%s"),
     ])
 
-    bridge_opts_keys = tuple([
+    bridge_opts_keys_rh = tuple([
         ('bridge_stp', 'STP'),
         ('bridge_ageing', 'AGEING'),
         ('bridge_bridgeprio', 'PRIO'),
     ])
 
+    bridge_opts_keys_suse = tuple([
+        ('bridge_stp', 'BRIDGE_STP'),
+        ('bridge_ageing', 'BRIDGE_AGEINGTIME'),
+        ('bridge_bridgeprio', 'BRIDGE_PRIORITY'),
+    ])
+
     templates = {}
 
     def __init__(self, config=None):
@@ -320,13 +333,21 @@ class Renderer(renderer.Renderer):
             'iface_templates': config.get('iface_templates'),
             'route_templates': config.get('route_templates'),
         }
+        self.flavor = config.get('flavor', 'rh')
 
     @classmethod
-    def _render_iface_shared(cls, iface, iface_cfg):
-        for k, v in cls.iface_defaults:
+    def _render_iface_shared(cls, iface, iface_cfg, flavor):
+        if flavor == 'suse':
+            iface_defaults = cls.iface_defaults_suse
+            mac_map = ('mac_address', 'LLADDR')
+        else:
+            iface_defaults = cls.iface_defaults_rh
+            mac_map = ('mac_address', 'HWADDR')
+
+        for k, v in iface_defaults:
             iface_cfg[k] = v
 
-        for (old_key, new_key) in [('mac_address', 'HWADDR'), ('mtu', 'MTU')]:
+        for (old_key, new_key) in [mac_map, ('mtu', 'MTU')]:
             old_value = iface.get(old_key)
             if old_value is not None:
                 # only set HWADDR on physical interfaces
@@ -335,50 +356,86 @@ class Renderer(renderer.Renderer):
                     continue
                 iface_cfg[new_key] = old_value
 
-        if iface['accept-ra'] is not None:
+        if iface['accept-ra'] is not None and flavor != 'suse':
             iface_cfg['IPV6_FORCE_ACCEPT_RA'] = iface['accept-ra']
 
     @classmethod
-    def _render_subnets(cls, iface_cfg, subnets, has_default_route):
+    def _render_subnets(cls, iface_cfg, subnets, has_default_route, flavor):
         # setting base values
-        iface_cfg['BOOTPROTO'] = 'none'
+        if flavor == 'suse':
+            iface_cfg['BOOTPROTO'] = 'static'
+            if 'BRIDGE' in iface_cfg:
+                iface_cfg['BOOTPROTO'] = 'dhcp'
+                iface_cfg.drop('BRIDGE')
+        else:
+            iface_cfg['BOOTPROTO'] = 'none'
 
         # modifying base values according to subnets
         for i, subnet in enumerate(subnets, start=len(iface_cfg.children)):
             mtu_key = 'MTU'
             subnet_type = subnet.get('type')
             if subnet_type == 'dhcp6' or subnet_type == 'ipv6_dhcpv6-stateful':
-                # TODO need to set BOOTPROTO to dhcp6 on SUSE
-                iface_cfg['IPV6INIT'] = True
-                # Configure network settings using DHCPv6
-                iface_cfg['DHCPV6C'] = True
+                if flavor == 'suse':
+                    # User wants dhcp for both protocols
+                    if iface_cfg['BOOTPROTO'] == 'dhcp4':
+                        iface_cfg['BOOTPROTO'] = 'dhcp'
+                    else:
+                        # Only IPv6 is DHCP, IPv4 may be static
+                        iface_cfg['BOOTPROTO'] = 'dhcp6'
+                    iface_cfg['DHCLIENT6_MODE'] = 'managed'
+                else:
+                    iface_cfg['IPV6INIT'] = True
+                    # Configure network settings using DHCPv6
+                    iface_cfg['DHCPV6C'] = True
             elif subnet_type == 'ipv6_dhcpv6-stateless':
-                iface_cfg['IPV6INIT'] = True
-                # Configure network settings using SLAAC from RAs and optional
-                # info from dhcp server using DHCPv6
-                iface_cfg['IPV6_AUTOCONF'] = True
-                iface_cfg['DHCPV6C'] = True
-                # Use Information-request to get only stateless configuration
-                # parameters (i.e., without address).
-                iface_cfg['DHCPV6C_OPTIONS'] = '-S'
+                if flavor == 'suse':
+                    # User wants dhcp for both protocols
+                    if iface_cfg['BOOTPROTO'] == 'dhcp4':
+                        iface_cfg['BOOTPROTO'] = 'dhcp'
+                    else:
+                        # Only IPv6 is DHCP, IPv4 may be static
+                        iface_cfg['BOOTPROTO'] = 'dhcp6'
+                    iface_cfg['DHCLIENT6_MODE'] = 'info'
+                else:
+                    iface_cfg['IPV6INIT'] = True
+                    # Configure network settings using SLAAC from RAs and
+                    # optional info from dhcp server using DHCPv6
+                    iface_cfg['IPV6_AUTOCONF'] = True
+                    iface_cfg['DHCPV6C'] = True
+                    # Use Information-request to get only stateless
+                    # configuration parameters (i.e., without address).
+                    iface_cfg['DHCPV6C_OPTIONS'] = '-S'
             elif subnet_type == 'ipv6_slaac':
-                iface_cfg['IPV6INIT'] = True
-                # Configure network settings using SLAAC from RAs
-                iface_cfg['IPV6_AUTOCONF'] = True
+                if flavor == 'suse':
+                    # User wants dhcp for both protocols
+                    if iface_cfg['BOOTPROTO'] == 'dhcp4':
+                        iface_cfg['BOOTPROTO'] = 'dhcp'
+                    else:
+                        # Only IPv6 is DHCP, IPv4 may be static
+                        iface_cfg['BOOTPROTO'] = 'dhcp6'
+                    iface_cfg['DHCLIENT6_MODE'] = 'info'
+                else:
+                    iface_cfg['IPV6INIT'] = True
+                    # Configure network settings using SLAAC from RAs
+                    iface_cfg['IPV6_AUTOCONF'] = True
             elif subnet_type in ['dhcp4', 'dhcp']:
+                bootproto_in = iface_cfg['BOOTPROTO']
                 iface_cfg['BOOTPROTO'] = 'dhcp'
+                if flavor == 'suse' and subnet_type == 'dhcp4':
+                    # If dhcp6 is already specified the user wants dhcp
+                    # for both protocols
+                    if bootproto_in != 'dhcp6':
+                        # Only IPv4 is DHCP, IPv6 may be static
+                        iface_cfg['BOOTPROTO'] = 'dhcp4'
             elif subnet_type == 'static':
+                # RH info
                 # grep BOOTPROTO sysconfig.txt -A2 | head -3
                 # BOOTPROTO=none|bootp|dhcp
                 # 'bootp' or 'dhcp' cause a DHCP client
                 # to run on the device. Any other
                 # value causes any static configuration
                 # in the file to be applied.
-                # ==> the following should not be set to 'static'
-                # but should remain 'none'
-                # if iface_cfg['BOOTPROTO'] == 'none':
-                #    iface_cfg['BOOTPROTO'] = 'static'
-                if subnet_is_ipv6(subnet):
+                if subnet_is_ipv6(subnet) and flavor != 'suse':
                     mtu_key = 'IPV6_MTU'
                     iface_cfg['IPV6INIT'] = True
                 if 'mtu' in subnet:
@@ -389,18 +446,31 @@ class Renderer(renderer.Renderer):
                             'Network config: ignoring %s device-level mtu:%s'
                             ' because ipv4 subnet-level mtu:%s provided.',
                             iface_cfg.name, iface_cfg[mtu_key], subnet['mtu'])
-                    iface_cfg[mtu_key] = subnet['mtu']
+                    if subnet_is_ipv6(subnet):
+                        if flavor == 'suse':
+                            # TODO(rjschwei) write mtu setting to
+                            # /etc/sysctl.d/
+                            pass
+                        else:
+                            iface_cfg[mtu_key] = subnet['mtu']
+                    else:
+                        iface_cfg[mtu_key] = subnet['mtu']
             elif subnet_type == 'manual':
-                # If the subnet has an MTU setting, then ONBOOT=True
-                # to apply the setting
-                iface_cfg['ONBOOT'] = mtu_key in iface_cfg
+                if flavor == 'suse':
+                    LOG.debug('Unknown subnet type setting "%s"', subnet_type)
+                else:
+                    # If the subnet has an MTU setting, then ONBOOT=True
+                    # to apply the setting
+                    iface_cfg['ONBOOT'] = mtu_key in iface_cfg
             else:
                 raise ValueError("Unknown subnet type '%s' found"
                                  " for interface '%s'" % (subnet_type,
                                                           iface_cfg.name))
             if subnet.get('control') == 'manual':
-                iface_cfg['ONBOOT'] = False
-                iface_cfg['STARTMODE'] = 'manual'
+                if flavor == 'suse':
+                    iface_cfg['STARTMODE'] = 'manual'
+                else:
+                    iface_cfg['ONBOOT'] = False
 
         # set IPv4 and IPv6 static addresses
         ipv4_index = -1
@@ -409,13 +479,14 @@ class Renderer(renderer.Renderer):
             subnet_type = subnet.get('type')
             # metric may apply to both dhcp and static config
             if 'metric' in subnet:
-                iface_cfg['METRIC'] = subnet['metric']
-            # TODO(hjensas): Including dhcp6 here is likely incorrect. DHCPv6
-            # does not ever provide a default gateway, the default gateway
-            # come from RA's. (https://github.com/openSUSE/wicked/issues/570)
-            if subnet_type in ['dhcp', 'dhcp4', 'dhcp6']:
-                if has_default_route and iface_cfg['BOOTPROTO'] != 'none':
-                    iface_cfg['DHCLIENT_SET_DEFAULT_ROUTE'] = False
+                if flavor != 'suse':
+                    iface_cfg['METRIC'] = subnet['metric']
+            if subnet_type in ['dhcp', 'dhcp4']:
+                # On SUSE distros 'DHCLIENT_SET_DEFAULT_ROUTE' is a global
+                # setting in /etc/sysconfig/network/dhcp
+                if flavor != 'suse':
+                    if has_default_route and iface_cfg['BOOTPROTO'] != 'none':
+                        iface_cfg['DHCLIENT_SET_DEFAULT_ROUTE'] = False
                 continue
             elif subnet_type in IPV6_DYNAMIC_TYPES:
                 continue
@@ -424,14 +495,21 @@ class Renderer(renderer.Renderer):
                     ipv6_index = ipv6_index + 1
                     ipv6_cidr = "%s/%s" % (subnet['address'], subnet['prefix'])
                     if ipv6_index == 0:
-                        iface_cfg['IPV6ADDR'] = ipv6_cidr
-                        iface_cfg['IPADDR6'] = ipv6_cidr
+                        if flavor == 'suse':
+                            iface_cfg['IPADDR6'] = ipv6_cidr
+                        else:
+                            iface_cfg['IPV6ADDR'] = ipv6_cidr
                     elif ipv6_index == 1:
-                        iface_cfg['IPV6ADDR_SECONDARIES'] = ipv6_cidr
-                        iface_cfg['IPADDR6_0'] = ipv6_cidr
+                        if flavor == 'suse':
+                            iface_cfg['IPADDR6_1'] = ipv6_cidr
+                        else:
+                            iface_cfg['IPV6ADDR_SECONDARIES'] = ipv6_cidr
                     else:
-                        iface_cfg['IPV6ADDR_SECONDARIES'] += " " + ipv6_cidr
-                        iface_cfg['IPADDR6_%d' % ipv6_index] = ipv6_cidr
+                        if flavor == 'suse':
+                            iface_cfg['IPADDR6_%d' % ipv6_index] = ipv6_cidr
+                        else:
+                            iface_cfg['IPV6ADDR_SECONDARIES'] += \
+                                                        " " + ipv6_cidr
                 else:
                     ipv4_index = ipv4_index + 1
                     suff = "" if ipv4_index == 0 else str(ipv4_index)
@@ -439,17 +517,17 @@ class Renderer(renderer.Renderer):
                     iface_cfg['NETMASK' + suff] = \
                         net_prefix_to_ipv4_mask(subnet['prefix'])
 
-                if 'gateway' in subnet:
+                if 'gateway' in subnet and flavor != 'suse':
                     iface_cfg['DEFROUTE'] = True
                     if is_ipv6_addr(subnet['gateway']):
                         iface_cfg['IPV6_DEFAULTGW'] = subnet['gateway']
                     else:
                         iface_cfg['GATEWAY'] = subnet['gateway']
 
-                if 'dns_search' in subnet:
+                if 'dns_search' in subnet and flavor != 'suse':
                     iface_cfg['DOMAIN'] = ' '.join(subnet['dns_search'])
 
-                if 'dns_nameservers' in subnet:
+                if 'dns_nameservers' in subnet and flavor != 'suse':
                     if len(subnet['dns_nameservers']) > 3:
                         # per resolv.conf(5) MAXNS sets this to 3.
                         LOG.debug("%s has %d entries in dns_nameservers. "
@@ -459,7 +537,12 @@ class Renderer(renderer.Renderer):
                         iface_cfg['DNS' + str(i)] = k
 
     @classmethod
-    def _render_subnet_routes(cls, iface_cfg, route_cfg, subnets):
+    def _render_subnet_routes(cls, iface_cfg, route_cfg, subnets, flavor):
+        # TODO(rjschwei): route configuration on SUSE distro happens via
+        # ifroute-* files, see lp#1812117. SUSE currently carries a local
+        # patch in their package.
+        if flavor == 'suse':
+            return
         for _, subnet in enumerate(subnets, start=len(iface_cfg.children)):
             subnet_type = subnet.get('type')
             for route in subnet.get('routes', []):
@@ -487,14 +570,7 @@ class Renderer(renderer.Renderer):
                     # TODO(harlowja): add validation that no other iface has
                     # also provided the default route?
                     iface_cfg['DEFROUTE'] = True
-                    # TODO(hjensas): Including dhcp6 here is likely incorrect.
-                    # DHCPv6 does not ever provide a default gateway, the
-                    # default gateway come from RA's.
-                    # (https://github.com/openSUSE/wicked/issues/570)
-                    if iface_cfg['BOOTPROTO'] in ('dhcp', 'dhcp4', 'dhcp6'):
-                        # NOTE(hjensas): DHCLIENT_SET_DEFAULT_ROUTE is SuSE
-                        # only. RHEL, CentOS, Fedora does not implement this
-                        # option.
+                    if iface_cfg['BOOTPROTO'] in ('dhcp', 'dhcp4'):
                         iface_cfg['DHCLIENT_SET_DEFAULT_ROUTE'] = True
                     if 'gateway' in route:
                         if is_ipv6:
@@ -538,7 +614,9 @@ class Renderer(renderer.Renderer):
             iface_cfg['BONDING_OPTS'] = " ".join(bond_opts)
 
     @classmethod
-    def _render_physical_interfaces(cls, network_state, iface_contents):
+    def _render_physical_interfaces(
+            cls, network_state, iface_contents, flavor
+    ):
         physical_filter = renderer.filter_by_physical
         for iface in network_state.iter_interfaces(physical_filter):
             iface_name = iface['name']
@@ -547,12 +625,15 @@ class Renderer(renderer.Renderer):
             route_cfg = iface_cfg.routes
 
             cls._render_subnets(
-                iface_cfg, iface_subnets, network_state.has_default_route
+                iface_cfg, iface_subnets, network_state.has_default_route,
+                flavor
+            )
+            cls._render_subnet_routes(
+                iface_cfg, route_cfg, iface_subnets, flavor
             )
-            cls._render_subnet_routes(iface_cfg, route_cfg, iface_subnets)
 
     @classmethod
-    def _render_bond_interfaces(cls, network_state, iface_contents):
+    def _render_bond_interfaces(cls, network_state, iface_contents, flavor):
         bond_filter = renderer.filter_by_type('bond')
         slave_filter = renderer.filter_by_attr('bond-master')
         for iface in network_state.iter_interfaces(bond_filter):
@@ -566,17 +647,24 @@ class Renderer(renderer.Renderer):
             master_cfgs.extend(iface_cfg.children)
             for master_cfg in master_cfgs:
                 master_cfg['BONDING_MASTER'] = True
-                master_cfg.kind = 'bond'
+                if flavor != 'suse':
+                    master_cfg.kind = 'bond'
 
             if iface.get('mac_address'):
-                iface_cfg['MACADDR'] = iface.get('mac_address')
+                if flavor == 'suse':
+                    iface_cfg['LLADDR'] = iface.get('mac_address')
+                else:
+                    iface_cfg['MACADDR'] = iface.get('mac_address')
 
             iface_subnets = iface.get("subnets", [])
             route_cfg = iface_cfg.routes
             cls._render_subnets(
-                iface_cfg, iface_subnets, network_state.has_default_route
+                iface_cfg, iface_subnets, network_state.has_default_route,
+                flavor
+            )
+            cls._render_subnet_routes(
+                iface_cfg, route_cfg, iface_subnets, flavor
             )
-            cls._render_subnet_routes(iface_cfg, route_cfg, iface_subnets)
 
             # iter_interfaces on network-state is not sorted to produce
             # consistent numbers we need to sort.
@@ -586,28 +674,44 @@ class Renderer(renderer.Renderer):
                  if slave_iface['bond-master'] == iface_name])
 
             for index, bond_slave in enumerate(bond_slaves):
-                slavestr = 'BONDING_SLAVE%s' % index
+                if flavor == 'suse':
+                    slavestr = 'BONDING_SLAVE_%s' % index
+                else:
+                    slavestr = 'BONDING_SLAVE%s' % index
                 iface_cfg[slavestr] = bond_slave
 
                 slave_cfg = iface_contents[bond_slave]
-                slave_cfg['MASTER'] = iface_name
-                slave_cfg['SLAVE'] = True
+                if flavor == 'suse':
+                    slave_cfg['BOOTPROTO'] = 'none'
+                    slave_cfg['STARTMODE'] = 'hotplug'
+                else:
+                    slave_cfg['MASTER'] = iface_name
+                    slave_cfg['SLAVE'] = True
 
     @classmethod
-    def _render_vlan_interfaces(cls, network_state, iface_contents):
+    def _render_vlan_interfaces(cls, network_state, iface_contents, flavor):
         vlan_filter = renderer.filter_by_type('vlan')
         for iface in network_state.iter_interfaces(vlan_filter):
             iface_name = iface['name']
             iface_cfg = iface_contents[iface_name]
-            iface_cfg['VLAN'] = True
-            iface_cfg['PHYSDEV'] = iface_name[:iface_name.rfind('.')]
+            if flavor == 'suse':
+                vlan_id = iface.get('vlan_id')
+                if vlan_id:
+                    iface_cfg['VLAN_ID'] = vlan_id
+                iface_cfg['ETHERDEVICE'] = iface_name[:iface_name.rfind('.')]
+            else:
+                iface_cfg['VLAN'] = True
+                iface_cfg['PHYSDEV'] = iface_name[:iface_name.rfind('.')]
 
             iface_subnets = iface.get("subnets", [])
             route_cfg = iface_cfg.routes
             cls._render_subnets(
-                iface_cfg, iface_subnets, network_state.has_default_route
+                iface_cfg, iface_subnets, network_state.has_default_route,
+                flavor
+            )
+            cls._render_subnet_routes(
+                iface_cfg, route_cfg, iface_subnets, flavor
             )
-            cls._render_subnet_routes(iface_cfg, route_cfg, iface_subnets)
 
     @staticmethod
     def _render_dns(network_state, existing_dns_path=None):
@@ -644,19 +748,39 @@ class Renderer(renderer.Renderer):
         return out
 
     @classmethod
-    def _render_bridge_interfaces(cls, network_state, iface_contents):
+    def _render_bridge_interfaces(cls, network_state, iface_contents, flavor):
+        if flavor == 'suse':
+            bridge_opts_keys = cls.bridge_opts_keys_suse
+        else:
+            bridge_opts_keys = cls.bridge_opts_keys_rh
         bridge_filter = renderer.filter_by_type('bridge')
         for iface in network_state.iter_interfaces(bridge_filter):
             iface_name = iface['name']
             iface_cfg = iface_contents[iface_name]
-            iface_cfg.kind = 'bridge'
-            for old_key, new_key in cls.bridge_opts_keys:
+            if flavor != 'suse':
+                iface_cfg.kind = 'bridge'
+            for old_key, new_key in bridge_opts_keys:
                 if old_key in iface:
                     iface_cfg[new_key] = iface[old_key]
 
-            if iface.get('mac_address'):
-                iface_cfg['MACADDR'] = iface.get('mac_address')
+            if flavor == 'suse':
+                if 'BRIDGE_STP' in iface_cfg:
+                    if iface_cfg.get('BRIDGE_STP'):
+                        iface_cfg['BRIDGE_STP'] = 'on'
+                    else:
+                        iface_cfg['BRIDGE_STP'] = 'off'
 
+            if iface.get('mac_address'):
+                key = 'MACADDR'
+                if flavor == 'suse':
+                    key = 'LLADDRESS'
+                iface_cfg[key] = iface.get('mac_address')
+
+            if flavor == 'suse':
+                if iface.get('bridge_ports', []):
+                    iface_cfg['BRIDGE_PORTS'] = '%s' % " ".join(
+                        iface.get('bridge_ports')
+                    )
             # Is this the right key to get all the connected interfaces?
             for bridged_iface_name in iface.get('bridge_ports', []):
                 # Ensure all bridged interfaces are correctly tagged
@@ -665,17 +789,23 @@ class Renderer(renderer.Renderer):
                 bridged_cfgs = [bridged_cfg]
                 bridged_cfgs.extend(bridged_cfg.children)
                 for bridge_cfg in bridged_cfgs:
-                    bridge_cfg['BRIDGE'] = iface_name
+                    bridge_value = iface_name
+                    if flavor == 'suse':
+                        bridge_value = 'yes'
+                    bridge_cfg['BRIDGE'] = bridge_value
 
             iface_subnets = iface.get("subnets", [])
             route_cfg = iface_cfg.routes
             cls._render_subnets(
-                iface_cfg, iface_subnets, network_state.has_default_route
+                iface_cfg, iface_subnets, network_state.has_default_route,
+                flavor
+            )
+            cls._render_subnet_routes(
+                iface_cfg, route_cfg, iface_subnets, flavor
             )
-            cls._render_subnet_routes(iface_cfg, route_cfg, iface_subnets)
 
     @classmethod
-    def _render_ib_interfaces(cls, network_state, iface_contents):
+    def _render_ib_interfaces(cls, network_state, iface_contents, flavor):
         ib_filter = renderer.filter_by_type('infiniband')
         for iface in network_state.iter_interfaces(ib_filter):
             iface_name = iface['name']
@@ -684,12 +814,15 @@ class Renderer(renderer.Renderer):
             iface_subnets = iface.get("subnets", [])
             route_cfg = iface_cfg.routes
             cls._render_subnets(
-                iface_cfg, iface_subnets, network_state.has_default_route
+                iface_cfg, iface_subnets, network_state.has_default_route,
+                flavor
+            )
+            cls._render_subnet_routes(
+                iface_cfg, route_cfg, iface_subnets, flavor
             )
-            cls._render_subnet_routes(iface_cfg, route_cfg, iface_subnets)
 
     @classmethod
-    def _render_sysconfig(cls, base_sysconf_dir, network_state,
+    def _render_sysconfig(cls, base_sysconf_dir, network_state, flavor,
                           templates=None):
         '''Given state, return /etc/sysconfig files + contents'''
         if not templates:
@@ -700,13 +833,17 @@ class Renderer(renderer.Renderer):
                 continue
             iface_name = iface['name']
             iface_cfg = NetInterface(iface_name, base_sysconf_dir, templates)
-            cls._render_iface_shared(iface, iface_cfg)
+            if flavor == 'suse':
+                iface_cfg.drop('DEVICE')
+                # If type detection fails it is considered a bug in SUSE
+                iface_cfg.drop('TYPE')
+            cls._render_iface_shared(iface, iface_cfg, flavor)
             iface_contents[iface_name] = iface_cfg
-        cls._render_physical_interfaces(network_state, iface_contents)
-        cls._render_bond_interfaces(network_state, iface_contents)
-        cls._render_vlan_interfaces(network_state, iface_contents)
-        cls._render_bridge_interfaces(network_state, iface_contents)
-        cls._render_ib_interfaces(network_state, iface_contents)
+        cls._render_physical_interfaces(network_state, iface_contents, flavor)
+        cls._render_bond_interfaces(network_state, iface_contents, flavor)
+        cls._render_vlan_interfaces(network_state, iface_contents, flavor)
+        cls._render_bridge_interfaces(network_state, iface_contents, flavor)
+        cls._render_ib_interfaces(network_state, iface_contents, flavor)
         contents = {}
         for iface_name, iface_cfg in iface_contents.items():
             if iface_cfg or iface_cfg.children:
@@ -728,7 +865,7 @@ class Renderer(renderer.Renderer):
         file_mode = 0o644
         base_sysconf_dir = util.target_path(target, self.sysconf_dir)
         for path, data in self._render_sysconfig(base_sysconf_dir,
-                                                 network_state,
+                                                 network_state, self.flavor,
                                                  templates=templates).items():
             util.write_file(path, data, file_mode)
         if self.dns_path:
--- tests/unittests/test_distros/test_netconfig.py.orig
+++ tests/unittests/test_distros/test_netconfig.py
@@ -468,7 +468,6 @@ class TestNetCfgDistroRedhat(TestNetCfgD
                 NETMASK=255.255.255.0
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no
                 """),
@@ -477,7 +476,6 @@ class TestNetCfgDistroRedhat(TestNetCfgD
                 DEVICE=eth1
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no
                 """),
@@ -496,13 +494,11 @@ class TestNetCfgDistroRedhat(TestNetCfgD
                 BOOTPROTO=none
                 DEFROUTE=yes
                 DEVICE=eth0
-                IPADDR6=2607:f0d0:1002:0011::2/64
                 IPV6ADDR=2607:f0d0:1002:0011::2/64
                 IPV6INIT=yes
                 IPV6_DEFAULTGW=2607:f0d0:1002:0011::1
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no
                 """),
@@ -511,7 +507,6 @@ class TestNetCfgDistroRedhat(TestNetCfgD
                 DEVICE=eth1
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no
                 """),
@@ -556,26 +551,14 @@ class TestNetCfgDistroOpensuse(TestNetCf
         """Opensuse uses apply_network_config and renders sysconfig"""
         expected_cfgs = {
             self.ifcfg_path('eth0'): dedent("""\
-                BOOTPROTO=none
-                DEFROUTE=yes
-                DEVICE=eth0
-                GATEWAY=192.168.1.254
+                BOOTPROTO=static
                 IPADDR=192.168.1.5
                 NETMASK=255.255.255.0
-                NM_CONTROLLED=no
-                ONBOOT=yes
                 STARTMODE=auto
-                TYPE=Ethernet
-                USERCTL=no
                 """),
             self.ifcfg_path('eth1'): dedent("""\
-                BOOTPROTO=dhcp
-                DEVICE=eth1
-                NM_CONTROLLED=no
-                ONBOOT=yes
+                BOOTPROTO=dhcp4
                 STARTMODE=auto
-                TYPE=Ethernet
-                USERCTL=no
                 """),
         }
         self._apply_and_verify(self.distro.apply_network_config,
@@ -586,27 +569,13 @@ class TestNetCfgDistroOpensuse(TestNetCf
         """Opensuse uses apply_network_config and renders sysconfig w/ipv6"""
         expected_cfgs = {
             self.ifcfg_path('eth0'): dedent("""\
-                BOOTPROTO=none
-                DEFROUTE=yes
-                DEVICE=eth0
+                BOOTPROTO=static
                 IPADDR6=2607:f0d0:1002:0011::2/64
-                IPV6ADDR=2607:f0d0:1002:0011::2/64
-                IPV6INIT=yes
-                IPV6_DEFAULTGW=2607:f0d0:1002:0011::1
-                NM_CONTROLLED=no
-                ONBOOT=yes
                 STARTMODE=auto
-                TYPE=Ethernet
-                USERCTL=no
             """),
             self.ifcfg_path('eth1'): dedent("""\
-                BOOTPROTO=dhcp
-                DEVICE=eth1
-                NM_CONTROLLED=no
-                ONBOOT=yes
+                BOOTPROTO=dhcp4
                 STARTMODE=auto
-                TYPE=Ethernet
-                USERCTL=no
             """),
         }
         self._apply_and_verify(self.distro.apply_network_config,
--- tests/unittests/test_net.py.orig
+++ tests/unittests/test_net.py
@@ -489,18 +489,11 @@ OS_SAMPLES = [
              """
 # Created by cloud-init on instance boot automatically, do not edit.
 #
-BOOTPROTO=none
-DEFROUTE=yes
-DEVICE=eth0
-GATEWAY=172.19.3.254
-HWADDR=fa:16:3e:ed:9a:59
+BOOTPROTO=static
 IPADDR=172.19.1.34
+LLADDR=fa:16:3e:ed:9a:59
 NETMASK=255.255.252.0
-NM_CONTROLLED=no
-ONBOOT=yes
 STARTMODE=auto
-TYPE=Ethernet
-USERCTL=no
 """.lstrip()),
             ('etc/resolv.conf',
              """
@@ -532,7 +525,6 @@ IPADDR=172.19.1.34
 NETMASK=255.255.252.0
 NM_CONTROLLED=no
 ONBOOT=yes
-STARTMODE=auto
 TYPE=Ethernet
 USERCTL=no
 """.lstrip()),
@@ -591,20 +583,13 @@ dns = none
              """
 # Created by cloud-init on instance boot automatically, do not edit.
 #
-BOOTPROTO=none
-DEFROUTE=yes
-DEVICE=eth0
-GATEWAY=172.19.3.254
-HWADDR=fa:16:3e:ed:9a:59
+BOOTPROTO=static
 IPADDR=172.19.1.34
 IPADDR1=10.0.0.10
+LLADDR=fa:16:3e:ed:9a:59
 NETMASK=255.255.252.0
 NETMASK1=255.255.255.0
-NM_CONTROLLED=no
-ONBOOT=yes
 STARTMODE=auto
-TYPE=Ethernet
-USERCTL=no
 """.lstrip()),
             ('etc/resolv.conf',
              """
@@ -638,7 +623,6 @@ NETMASK=255.255.252.0
 NETMASK1=255.255.255.0
 NM_CONTROLLED=no
 ONBOOT=yes
-STARTMODE=auto
 TYPE=Ethernet
 USERCTL=no
 """.lstrip()),
@@ -717,25 +701,14 @@ dns = none
              """
 # Created by cloud-init on instance boot automatically, do not edit.
 #
-BOOTPROTO=none
-DEFROUTE=yes
-DEVICE=eth0
-GATEWAY=172.19.3.254
-HWADDR=fa:16:3e:ed:9a:59
+BOOTPROTO=static
 IPADDR=172.19.1.34
 IPADDR6=2001:DB8::10/64
-IPADDR6_0=2001:DB9::10/64
+IPADDR6_1=2001:DB9::10/64
 IPADDR6_2=2001:DB10::10/64
-IPV6ADDR=2001:DB8::10/64
-IPV6ADDR_SECONDARIES="2001:DB9::10/64 2001:DB10::10/64"
-IPV6INIT=yes
-IPV6_DEFAULTGW=2001:DB8::1
+LLADDR=fa:16:3e:ed:9a:59
 NETMASK=255.255.252.0
-NM_CONTROLLED=no
-ONBOOT=yes
 STARTMODE=auto
-TYPE=Ethernet
-USERCTL=no
 """.lstrip()),
             ('etc/resolv.conf',
              """
@@ -764,9 +737,6 @@ DEVICE=eth0
 GATEWAY=172.19.3.254
 HWADDR=fa:16:3e:ed:9a:59
 IPADDR=172.19.1.34
-IPADDR6=2001:DB8::10/64
-IPADDR6_0=2001:DB9::10/64
-IPADDR6_2=2001:DB10::10/64
 IPV6ADDR=2001:DB8::10/64
 IPV6ADDR_SECONDARIES="2001:DB9::10/64 2001:DB10::10/64"
 IPV6INIT=yes
@@ -774,7 +744,6 @@ IPV6_DEFAULTGW=2001:DB8::1
 NETMASK=255.255.252.0
 NM_CONTROLLED=no
 ONBOOT=yes
-STARTMODE=auto
 TYPE=Ethernet
 USERCTL=no
 """.lstrip()),
@@ -884,14 +853,25 @@ NETWORK_CONFIGS = {
                             via: 65.61.151.37
                         set-name: eth99
         """).rstrip(' '),
-        'expected_sysconfig': {
+        'expected_sysconfig_opensuse': {
+            'ifcfg-eth1': textwrap.dedent("""\
+                BOOTPROTO=static
+                LLADDR=cf:d6:af:48:e8:80
+                STARTMODE=auto"""),
+            'ifcfg-eth99': textwrap.dedent("""\
+                BOOTPROTO=dhcp4
+                LLADDR=c0:d6:9f:2c:e8:80
+                IPADDR=192.168.21.3
+                NETMASK=255.255.255.0
+                STARTMODE=auto"""),
+        },
+        'expected_sysconfig_rhel': {
             'ifcfg-eth1': textwrap.dedent("""\
                 BOOTPROTO=none
                 DEVICE=eth1
                 HWADDR=cf:d6:af:48:e8:80
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no"""),
             'ifcfg-eth99': textwrap.dedent("""\
@@ -909,7 +889,6 @@ NETWORK_CONFIGS = {
                 METRIC=10000
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no"""),
         },
@@ -1013,18 +992,28 @@ NETWORK_CONFIGS = {
                     address: 2001:1::1/64
                     mtu: 1500
         """).rstrip(' '),
-        'expected_sysconfig': {
+        'expected_sysconfig_opensuse': {
+            # TODO(rjschwei): what should MTU be, RHEL has 2 for IPv6 and
+            # IPv4 but SUSE only has 1, pick the smaller of the values?
+            'ifcfg-iface0': textwrap.dedent("""\
+                BOOTPROTO=static
+                IPADDR=192.168.14.2
+                IPADDR6=2001:1::1/64
+                NETMASK=255.255.255.0
+                STARTMODE=auto
+                MTU=1500
+                """),
+        },
+        'expected_sysconfig_rhel': {
             'ifcfg-iface0': textwrap.dedent("""\
                 BOOTPROTO=none
                 DEVICE=iface0
                 IPADDR=192.168.14.2
-                IPADDR6=2001:1::1/64
                 IPV6ADDR=2001:1::1/64
                 IPV6INIT=yes
                 NETMASK=255.255.255.0
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no
                 MTU=9000
@@ -1055,7 +1044,14 @@ NETWORK_CONFIGS = {
                 subnets:
                 - {'type': 'dhcp6'}
         """).rstrip(' '),
-        'expected_sysconfig': {
+        'expected_sysconfig_opensuse': {
+            'ifcfg-iface0': textwrap.dedent("""\
+                BOOTPROTO=dhcp6
+                DHCLIENT6_MODE=managed
+                STARTMODE=auto
+                """),
+        },
+        'expected_sysconfig_rhel': {
             'ifcfg-iface0': textwrap.dedent("""\
                 BOOTPROTO=none
                 DEVICE=iface0
@@ -1064,7 +1060,6 @@ NETWORK_CONFIGS = {
                 DEVICE=iface0
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no
                 """),
@@ -1103,7 +1098,14 @@ NETWORK_CONFIGS = {
                     dhcp6: true
                     accept-ra: true
         """).rstrip(' '),
-        'expected_sysconfig': {
+        'expected_sysconfig_opensuse': {
+            'ifcfg-iface0': textwrap.dedent("""\
+                BOOTPROTO=dhcp6
+                DHCLIENT6_MODE=managed
+                STARTMODE=auto
+            """),
+        },
+        'expected_sysconfig_rhel': {
             'ifcfg-iface0': textwrap.dedent("""\
                 BOOTPROTO=none
                 DEVICE=iface0
@@ -1113,7 +1115,6 @@ NETWORK_CONFIGS = {
                 DEVICE=iface0
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no
             """),
@@ -1152,7 +1153,14 @@ NETWORK_CONFIGS = {
                     dhcp6: true
                     accept-ra: false
         """).rstrip(' '),
-        'expected_sysconfig': {
+        'expected_sysconfig_opensuse': {
+            'ifcfg-iface0': textwrap.dedent("""\
+                BOOTPROTO=dhcp6
+                DHCLIENT6_MODE=managed
+                STARTMODE=auto
+            """),
+        },
+        'expected_sysconfig_rhel': {
             'ifcfg-iface0': textwrap.dedent("""\
                 BOOTPROTO=none
                 DEVICE=iface0
@@ -1162,7 +1170,6 @@ NETWORK_CONFIGS = {
                 DEVICE=iface0
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no
             """),
@@ -1192,7 +1199,14 @@ NETWORK_CONFIGS = {
               subnets:
               - {'type': 'ipv6_slaac'}
         """).rstrip(' '),
-        'expected_sysconfig': {
+        'expected_sysconfig_opensuse': {
+            'ifcfg-iface0': textwrap.dedent("""\
+                BOOTPROTO=dhcp6
+                DHCLIENT6_MODE=managed
+                STARTMODE=auto
+            """),
+        },
+        'expected_sysconfig_rhel': {
             'ifcfg-iface0': textwrap.dedent("""\
                 BOOTPROTO=none
                 DEVICE=iface0
@@ -1201,7 +1215,6 @@ NETWORK_CONFIGS = {
                 DEVICE=iface0
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no
             """),
@@ -1231,7 +1244,14 @@ NETWORK_CONFIGS = {
             subnets:
             - {'type': 'ipv6_dhcpv6-stateless'}
     """).rstrip(' '),
-        'expected_sysconfig': {
+        'expected_sysconfig_opensuse': {
+            'ifcfg-iface0': textwrap.dedent("""\
+            BOOTPROTO=dhcp6
+            DHCLIENT6_MODE=managed
+            STARTMODE=auto
+            """),
+        },
+        'expected_sysconfig_rhel': {
             'ifcfg-iface0': textwrap.dedent("""\
             BOOTPROTO=none
             DEVICE=iface0
@@ -1242,7 +1262,6 @@ NETWORK_CONFIGS = {
             DEVICE=iface0
             NM_CONTROLLED=no
             ONBOOT=yes
-            STARTMODE=auto
             TYPE=Ethernet
             USERCTL=no
             """),
@@ -1273,7 +1292,14 @@ NETWORK_CONFIGS = {
             - {'type': 'ipv6_dhcpv6-stateful'}
             accept-ra: true
     """).rstrip(' '),
-        'expected_sysconfig': {
+        'expected_sysconfig_opensuse': {
+            'ifcfg-iface0': textwrap.dedent("""\
+            BOOTPROTO=dhcp6
+            DHCLIENT6_MODE=managed
+            STARTMODE=auto
+            """),
+        },
+        'expected_sysconfig_rhel': {
             'ifcfg-iface0': textwrap.dedent("""\
             BOOTPROTO=none
             DEVICE=iface0
@@ -1283,7 +1309,6 @@ NETWORK_CONFIGS = {
             DEVICE=iface0
             NM_CONTROLLED=no
             ONBOOT=yes
-            STARTMODE=auto
             TYPE=Ethernet
             USERCTL=no
             """),
@@ -1478,7 +1503,80 @@ pre-down route del -net 10.0.0.0/8 gw 11
                             - sacchromyces.maas
                             - brettanomyces.maas
         """).rstrip(' '),
-        'expected_sysconfig': {
+        'expected_sysconfig_opensuse': {
+            'ifcfg-bond0': textwrap.dedent("""\
+                BONDING_MASTER=yes
+                BONDING_OPTS="mode=active-backup """
+                                           """xmit_hash_policy=layer3+4 """
+                                           """miimon=100"
+                BONDING_SLAVE_0=eth1
+                BONDING_SLAVE_1=eth2
+                BOOTPROTO=dhcp6
+                DHCLIENT6_MODE=managed
+                LLADDR=aa:bb:cc:dd:ee:ff
+                STARTMODE=auto"""),
+            'ifcfg-bond0.200': textwrap.dedent("""\
+                BOOTPROTO=dhcp4
+                ETHERDEVICE=bond0
+                STARTMODE=auto
+                VLAN_ID=200"""),
+            'ifcfg-br0': textwrap.dedent("""\
+                BRIDGE_AGEINGTIME=250
+                BOOTPROTO=static
+                IPADDR=192.168.14.2
+                IPADDR6=2001:1::1/64
+                LLADDRESS=bb:bb:bb:bb:bb:aa
+                NETMASK=255.255.255.0
+                BRIDGE_PRIORITY=22
+                BRIDGE_PORTS='eth3 eth4'
+                STARTMODE=auto
+                BRIDGE_STP=off"""),
+            'ifcfg-eth0': textwrap.dedent("""\
+                BOOTPROTO=static
+                LLADDR=c0:d6:9f:2c:e8:80
+                STARTMODE=auto"""),
+            'ifcfg-eth0.101': textwrap.dedent("""\
+                BOOTPROTO=static
+                IPADDR=192.168.0.2
+                IPADDR1=192.168.2.10
+                MTU=1500
+                NETMASK=255.255.255.0
+                NETMASK1=255.255.255.0
+                ETHERDEVICE=eth0
+                STARTMODE=auto
+                VLAN_ID=101"""),
+            'ifcfg-eth1': textwrap.dedent("""\
+                BOOTPROTO=none
+                LLADDR=aa:d6:9f:2c:e8:80
+                STARTMODE=hotplug"""),
+            'ifcfg-eth2': textwrap.dedent("""\
+                BOOTPROTO=none
+                LLADDR=c0:bb:9f:2c:e8:80
+                STARTMODE=hotplug"""),
+            'ifcfg-eth3': textwrap.dedent("""\
+                BOOTPROTO=static
+                BRIDGE=yes
+                LLADDR=66:bb:9f:2c:e8:80
+                STARTMODE=auto"""),
+            'ifcfg-eth4': textwrap.dedent("""\
+                BOOTPROTO=static
+                BRIDGE=yes
+                LLADDR=98:bb:9f:2c:e8:80
+                STARTMODE=auto"""),
+            'ifcfg-eth5': textwrap.dedent("""\
+                BOOTPROTO=dhcp
+                LLADDR=98:bb:9f:2c:e8:8a
+                STARTMODE=manual"""),
+            'ifcfg-ib0': textwrap.dedent("""\
+                BOOTPROTO=static
+                LLADDR=a0:00:02:20:fe:80:00:00:00:00:00:00:ec:0d:9a:03:00:15:e2:c1
+                IPADDR=192.168.200.7
+                MTU=9000
+                NETMASK=255.255.255.0
+                STARTMODE=auto
+                TYPE=InfiniBand"""),
+        },
+        'expected_sysconfig_rhel': {
             'ifcfg-bond0': textwrap.dedent("""\
                 BONDING_MASTER=yes
                 BONDING_OPTS="mode=active-backup """
@@ -1493,7 +1591,6 @@ pre-down route del -net 10.0.0.0/8 gw 11
                 MACADDR=aa:bb:cc:dd:ee:ff
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Bond
                 USERCTL=no"""),
             'ifcfg-bond0.200': textwrap.dedent("""\
@@ -1503,7 +1600,6 @@ pre-down route del -net 10.0.0.0/8 gw 11
                 NM_CONTROLLED=no
                 ONBOOT=yes
                 PHYSDEV=bond0
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no
                 VLAN=yes"""),
@@ -1513,7 +1609,6 @@ pre-down route del -net 10.0.0.0/8 gw 11
                 DEFROUTE=yes
                 DEVICE=br0
                 IPADDR=192.168.14.2
-                IPADDR6=2001:1::1/64
                 IPV6ADDR=2001:1::1/64
                 IPV6INIT=yes
                 IPV6_DEFAULTGW=2001:4800:78ff:1b::1
@@ -1522,7 +1617,6 @@ pre-down route del -net 10.0.0.0/8 gw 11
                 NM_CONTROLLED=no
                 ONBOOT=yes
                 PRIO=22
-                STARTMODE=auto
                 STP=no
                 TYPE=Bridge
                 USERCTL=no"""),
@@ -1532,7 +1626,6 @@ pre-down route del -net 10.0.0.0/8 gw 11
                 HWADDR=c0:d6:9f:2c:e8:80
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no"""),
             'ifcfg-eth0.101': textwrap.dedent("""\
@@ -1551,7 +1644,6 @@ pre-down route del -net 10.0.0.0/8 gw 11
                 NM_CONTROLLED=no
                 ONBOOT=yes
                 PHYSDEV=eth0
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no
                 VLAN=yes"""),
@@ -1562,7 +1654,6 @@ pre-down route del -net 10.0.0.0/8 gw 11
                 MASTER=bond0
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 SLAVE=yes
                 TYPE=Ethernet
                 USERCTL=no"""),
@@ -1573,7 +1664,6 @@ pre-down route del -net 10.0.0.0/8 gw 11
                 MASTER=bond0
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 SLAVE=yes
                 TYPE=Ethernet
                 USERCTL=no"""),
@@ -1584,7 +1674,6 @@ pre-down route del -net 10.0.0.0/8 gw 11
                 HWADDR=66:bb:9f:2c:e8:80
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no"""),
             'ifcfg-eth4': textwrap.dedent("""\
@@ -1594,7 +1683,6 @@ pre-down route del -net 10.0.0.0/8 gw 11
                 HWADDR=98:bb:9f:2c:e8:80
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no"""),
             'ifcfg-eth5': textwrap.dedent("""\
@@ -1604,7 +1692,6 @@ pre-down route del -net 10.0.0.0/8 gw 11
                 HWADDR=98:bb:9f:2c:e8:8a
                 NM_CONTROLLED=no
                 ONBOOT=no
-                STARTMODE=manual
                 TYPE=Ethernet
                 USERCTL=no"""),
             'ifcfg-ib0': textwrap.dedent("""\
@@ -1616,7 +1703,6 @@ pre-down route del -net 10.0.0.0/8 gw 11
                 NETMASK=255.255.255.0
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=InfiniBand
                 USERCTL=no"""),
         },
@@ -2012,58 +2098,29 @@ iface bond0 inet6 static
                                            """fail_over_mac=active """
                                            """primary=bond0s0 """
                                            """primary_reselect=always"
-        BONDING_SLAVE0=bond0s0
-        BONDING_SLAVE1=bond0s1
-        BOOTPROTO=none
-        DEFROUTE=yes
-        DEVICE=bond0
-        GATEWAY=192.168.0.1
-        MACADDR=aa:bb:cc:dd:e8:ff
+        BONDING_SLAVE_0=bond0s0
+        BONDING_SLAVE_1=bond0s1
+        BOOTPROTO=static
+        LLADDR=aa:bb:cc:dd:e8:ff
         IPADDR=192.168.0.2
         IPADDR1=192.168.1.2
         IPADDR6=2001:1::1/92
-        IPV6ADDR=2001:1::1/92
-        IPV6INIT=yes
         MTU=9000
         NETMASK=255.255.255.0
         NETMASK1=255.255.255.0
-        NM_CONTROLLED=no
-        ONBOOT=yes
         STARTMODE=auto
-        TYPE=Bond
-        USERCTL=no
         """),
             'ifcfg-bond0s0': textwrap.dedent("""\
         BOOTPROTO=none
-        DEVICE=bond0s0
-        HWADDR=aa:bb:cc:dd:e8:00
-        MASTER=bond0
-        NM_CONTROLLED=no
-        ONBOOT=yes
-        SLAVE=yes
-        STARTMODE=auto
-        TYPE=Ethernet
-        USERCTL=no
-        """),
-            'ifroute-bond0': textwrap.dedent("""\
-        ADDRESS0=10.1.3.0
-        GATEWAY0=192.168.0.3
-        NETMASK0=255.255.255.0
+        LLADDR=aa:bb:cc:dd:e8:00
+        STARTMODE=hotplug
         """),
             'ifcfg-bond0s1': textwrap.dedent("""\
         BOOTPROTO=none
-        DEVICE=bond0s1
-        HWADDR=aa:bb:cc:dd:e8:01
-        MASTER=bond0
-        NM_CONTROLLED=no
-        ONBOOT=yes
-        SLAVE=yes
-        STARTMODE=auto
-        TYPE=Ethernet
-        USERCTL=no
+        LLADDR=aa:bb:cc:dd:e8:01
+        STARTMODE=hotplug
         """),
         },
-
         'expected_sysconfig_rhel': {
             'ifcfg-bond0': textwrap.dedent("""\
         BONDING_MASTER=yes
@@ -2082,7 +2139,6 @@ iface bond0 inet6 static
         MACADDR=aa:bb:cc:dd:e8:ff
         IPADDR=192.168.0.2
         IPADDR1=192.168.1.2
-        IPADDR6=2001:1::1/92
         IPV6ADDR=2001:1::1/92
         IPV6INIT=yes
         MTU=9000
@@ -2090,7 +2146,6 @@ iface bond0 inet6 static
         NETMASK1=255.255.255.0
         NM_CONTROLLED=no
         ONBOOT=yes
-        STARTMODE=auto
         TYPE=Bond
         USERCTL=no
         """),
@@ -2102,7 +2157,6 @@ iface bond0 inet6 static
         NM_CONTROLLED=no
         ONBOOT=yes
         SLAVE=yes
-        STARTMODE=auto
         TYPE=Ethernet
         USERCTL=no
         """),
@@ -2125,7 +2179,6 @@ iface bond0 inet6 static
         NM_CONTROLLED=no
         ONBOOT=yes
         SLAVE=yes
-        STARTMODE=auto
         TYPE=Ethernet
         USERCTL=no
         """),
@@ -2156,14 +2209,32 @@ iface bond0 inet6 static
                        netmask: '::'
                        network: '::'
             """),
-        'expected_sysconfig': {
+        'expected_sysconfig_opensuse': {
+            # TODO RJS: unknown proper BOOTPROTO setting ask Marius
+            'ifcfg-en0': textwrap.dedent("""\
+                BOOTPROTO=static
+                LLADDR=aa:bb:cc:dd:e8:00
+                STARTMODE=auto"""),
+            'ifcfg-en0.99': textwrap.dedent("""\
+                BOOTPROTO=static
+                IPADDR=192.168.2.2
+                IPADDR1=192.168.1.2
+                IPADDR6=2001:1::bbbb/96
+                MTU=2222
+                NETMASK=255.255.255.0
+                NETMASK1=255.255.255.0
+                STARTMODE=auto
+                ETHERDEVICE=en0
+                VLAN_ID=99
+            """),
+        },
+        'expected_sysconfig_rhel': {
             'ifcfg-en0': textwrap.dedent("""\
                 BOOTPROTO=none
                 DEVICE=en0
                 HWADDR=aa:bb:cc:dd:e8:00
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no"""),
             'ifcfg-en0.99': textwrap.dedent("""\
@@ -2173,7 +2244,6 @@ iface bond0 inet6 static
                 GATEWAY=192.168.1.1
                 IPADDR=192.168.2.2
                 IPADDR1=192.168.1.2
-                IPADDR6=2001:1::bbbb/96
                 IPV6ADDR=2001:1::bbbb/96
                 IPV6INIT=yes
                 IPV6_DEFAULTGW=2001:1::1
@@ -2183,7 +2253,6 @@ iface bond0 inet6 static
                 NM_CONTROLLED=no
                 ONBOOT=yes
                 PHYSDEV=en0
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no
                 VLAN=yes"""),
@@ -2216,7 +2285,32 @@ iface bond0 inet6 static
                 subnets:
                   - type: static
                     address: 192.168.2.2/24"""),
-        'expected_sysconfig': {
+        'expected_sysconfig_opensuse': {
+            'ifcfg-br0': textwrap.dedent("""\
+                BOOTPROTO=static
+                IPADDR=192.168.2.2
+                NETMASK=255.255.255.0
+                STARTMODE=auto
+                BRIDGE_STP=off
+                BRIDGE_PRIORITY=22
+                BRIDGE_PORTS='eth0 eth1'
+                """),
+            'ifcfg-eth0': textwrap.dedent("""\
+                BOOTPROTO=static
+                BRIDGE=yes
+                LLADDR=52:54:00:12:34:00
+                IPADDR6=2001:1::100/96
+                STARTMODE=auto
+                """),
+            'ifcfg-eth1': textwrap.dedent("""\
+                BOOTPROTO=static
+                BRIDGE=yes
+                LLADDR=52:54:00:12:34:01
+                IPADDR6=2001:1::101/96
+                STARTMODE=auto
+                """),
+        },
+        'expected_sysconfig_rhel': {
             'ifcfg-br0': textwrap.dedent("""\
                 BOOTPROTO=none
                 DEVICE=br0
@@ -2225,7 +2319,6 @@ iface bond0 inet6 static
                 NM_CONTROLLED=no
                 ONBOOT=yes
                 PRIO=22
-                STARTMODE=auto
                 STP=no
                 TYPE=Bridge
                 USERCTL=no
@@ -2235,12 +2328,10 @@ iface bond0 inet6 static
                 BRIDGE=br0
                 DEVICE=eth0
                 HWADDR=52:54:00:12:34:00
-                IPADDR6=2001:1::100/96
                 IPV6ADDR=2001:1::100/96
                 IPV6INIT=yes
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no
                 """),
@@ -2249,12 +2340,10 @@ iface bond0 inet6 static
                 BRIDGE=br0
                 DEVICE=eth1
                 HWADDR=52:54:00:12:34:01
-                IPADDR6=2001:1::101/96
                 IPV6ADDR=2001:1::101/96
                 IPV6INIT=yes
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no
                 """),
@@ -2320,7 +2409,27 @@ iface bond0 inet6 static
                             macaddress: 52:54:00:12:34:ff
                         set-name: eth2
             """),
-        'expected_sysconfig': {
+        'expected_sysconfig_opensuse': {
+            'ifcfg-eth0': textwrap.dedent("""\
+                BOOTPROTO=static
+                LLADDR=52:54:00:12:34:00
+                IPADDR=192.168.1.2
+                NETMASK=255.255.255.0
+                STARTMODE=manual
+                """),
+            'ifcfg-eth1': textwrap.dedent("""\
+                BOOTPROTO=static
+                LLADDR=52:54:00:12:34:aa
+                MTU=1480
+                STARTMODE=auto
+                """),
+            'ifcfg-eth2': textwrap.dedent("""\
+                BOOTPROTO=static
+                LLADDR=52:54:00:12:34:ff
+                STARTMODE=manual
+                """),
+        },
+        'expected_sysconfig_rhel': {
             'ifcfg-eth0': textwrap.dedent("""\
                 BOOTPROTO=none
                 DEVICE=eth0
@@ -2329,7 +2438,6 @@ iface bond0 inet6 static
                 NETMASK=255.255.255.0
                 NM_CONTROLLED=no
                 ONBOOT=no
-                STARTMODE=manual
                 TYPE=Ethernet
                 USERCTL=no
                 """),
@@ -2340,7 +2448,6 @@ iface bond0 inet6 static
                 MTU=1480
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no
                 """),
@@ -2350,7 +2457,6 @@ iface bond0 inet6 static
                 HWADDR=52:54:00:12:34:ff
                 NM_CONTROLLED=no
                 ONBOOT=no
-                STARTMODE=manual
                 TYPE=Ethernet
                 USERCTL=no
                 """),
@@ -2681,7 +2787,7 @@ class TestRhelSysConfigRendering(CiTestC
     header = ('# Created by cloud-init on instance boot automatically, '
               'do not edit.\n#\n')
 
-    expected_name = 'expected_sysconfig'
+    expected_name = 'expected_sysconfig_rhel'
 
     def _get_renderer(self):
         distro_cls = distros.fetch('rhel')
@@ -2768,7 +2874,6 @@ DEVICE=eth1000
 HWADDR=07-1c-c6-75-a4-be
 NM_CONTROLLED=no
 ONBOOT=yes
-STARTMODE=auto
 TYPE=Ethernet
 USERCTL=no
 """.lstrip()
@@ -2890,7 +2995,6 @@ IPADDR=10.0.2.15
 NETMASK=255.255.255.0
 NM_CONTROLLED=no
 ONBOOT=yes
-STARTMODE=auto
 TYPE=Ethernet
 USERCTL=no
 """
@@ -2922,7 +3026,6 @@ MTU=1500
 NETMASK=255.255.240.0
 NM_CONTROLLED=no
 ONBOOT=yes
-STARTMODE=auto
 TYPE=Ethernet
 USERCTL=no
 """
@@ -2937,7 +3040,6 @@ HWADDR=fa:16:3e:b1:ca:29
 MTU=9000
 NM_CONTROLLED=no
 ONBOOT=yes
-STARTMODE=auto
 TYPE=Ethernet
 USERCTL=no
 """
@@ -2963,7 +3065,6 @@ BOOTPROTO=dhcp
 DEVICE=eth0
 NM_CONTROLLED=no
 ONBOOT=yes
-STARTMODE=auto
 TYPE=Ethernet
 USERCTL=no
 """
@@ -2972,10 +3073,9 @@ USERCTL=no
         self.assertEqual(resolvconf_content, found['/etc/resolv.conf'])
 
     def test_bond_config(self):
-        expected_name = 'expected_sysconfig_rhel'
         entry = NETWORK_CONFIGS['bond']
         found = self._render_and_read(network_config=yaml.load(entry['yaml']))
-        self._compare_files_to_expected(entry[expected_name], found)
+        self._compare_files_to_expected(entry[self.expected_name], found)
         self._assert_headers(found)
 
     def test_vlan_config(self):
@@ -3163,14 +3263,12 @@ USERCTL=no
                    GATEWAY=192.168.42.1
                    HWADDR=52:54:00:ab:cd:ef
                    IPADDR=192.168.42.100
-                   IPADDR6=2001:db8::100/32
                    IPV6ADDR=2001:db8::100/32
                    IPV6INIT=yes
                    IPV6_DEFAULTGW=2001:db8::1
                    NETMASK=255.255.255.0
                    NM_CONTROLLED=no
                    ONBOOT=yes
-                   STARTMODE=auto
                    TYPE=Ethernet
                    USERCTL=no
                    """),
@@ -3196,7 +3294,6 @@ USERCTL=no
                 DEVICE=eno1
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no
                 """),
@@ -3209,7 +3306,6 @@ USERCTL=no
                 NM_CONTROLLED=no
                 ONBOOT=yes
                 PHYSDEV=eno1
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no
                 VLAN=yes
@@ -3240,7 +3336,6 @@ USERCTL=no
                 NETMASK=255.255.255.192
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Bond
                 USERCTL=no
                 """),
@@ -3252,7 +3347,6 @@ USERCTL=no
                 NM_CONTROLLED=no
                 ONBOOT=yes
                 SLAVE=yes
-                STARTMODE=auto
                 TYPE=Bond
                 USERCTL=no
                 """),
@@ -3264,7 +3358,6 @@ USERCTL=no
                 NM_CONTROLLED=no
                 ONBOOT=yes
                 SLAVE=yes
-                STARTMODE=auto
                 TYPE=Bond
                 USERCTL=no
                 """)
@@ -3288,7 +3381,6 @@ USERCTL=no
                 METRIC=100
                 NM_CONTROLLED=no
                 ONBOOT=yes
-                STARTMODE=auto
                 TYPE=Ethernet
                 USERCTL=no
                 """),
@@ -3311,7 +3403,7 @@ class TestOpenSuseSysConfigRendering(CiT
     header = ('# Created by cloud-init on instance boot automatically, '
               'do not edit.\n#\n')
 
-    expected_name = 'expected_sysconfig'
+    expected_name = 'expected_sysconfig_opensuse'
 
     def _get_renderer(self):
         distro_cls = distros.fetch('opensuse')
@@ -3383,19 +3475,17 @@ class TestOpenSuseSysConfigRendering(CiT
             expected_content = """
 # Created by cloud-init on instance boot automatically, do not edit.
 #
-BOOTPROTO=dhcp
-DEVICE=eth1000
-HWADDR=07-1c-c6-75-a4-be
-NM_CONTROLLED=no
-ONBOOT=yes
+BOOTPROTO=dhcp4
+LLADDR=07-1c-c6-75-a4-be
 STARTMODE=auto
-TYPE=Ethernet
-USERCTL=no
 """.lstrip()
             self.assertEqual(expected_content, content)
 
     def test_multiple_ipv4_default_gateways(self):
         """ValueError is raised when duplicate ipv4 gateways exist."""
+        # TODO(rjschwei): re-enable test once route writing is implemented
+        # for SUSE distros
+        return
         net_json = {
             "services": [{"type": "dns", "address": "172.19.0.12"}],
             "networks": [{
@@ -3434,6 +3524,9 @@ USERCTL=no
 
     def test_multiple_ipv6_default_gateways(self):
         """ValueError is raised when duplicate ipv6 gateways exist."""
+        # TODO(rjschwei): re-enable test once route writing is implemented
+        # for SUSE distros
+        return
         net_json = {
             "services": [{"type": "dns", "address": "172.19.0.12"}],
             "networks": [{
@@ -3501,18 +3594,11 @@ USERCTL=no
         expected = """\
 # Created by cloud-init on instance boot automatically, do not edit.
 #
-BOOTPROTO=none
-DEFROUTE=yes
-DEVICE=interface0
-GATEWAY=10.0.2.2
-HWADDR=52:54:00:12:34:00
+BOOTPROTO=static
 IPADDR=10.0.2.15
+LLADDR=52:54:00:12:34:00
 NETMASK=255.255.255.0
-NM_CONTROLLED=no
-ONBOOT=yes
 STARTMODE=auto
-TYPE=Ethernet
-USERCTL=no
 """
         self.assertEqual(expected, found[nspath + 'ifcfg-interface0'])
         # The configuration has no nameserver information make sure we
@@ -3537,12 +3623,7 @@ USERCTL=no
 # Created by cloud-init on instance boot automatically, do not edit.
 #
 BOOTPROTO=dhcp
-DEVICE=eth0
-NM_CONTROLLED=no
-ONBOOT=yes
 STARTMODE=auto
-TYPE=Ethernet
-USERCTL=no
 """
         self.assertEqual(expected, found[nspath + 'ifcfg-eth0'])
         # a dhcp only config should not modify resolv.conf
openSUSE Build Service is sponsored by