From ff4e918d21970a81604a0aaa2af888141f93cdac Mon Sep 17 00:00:00 2001
From: Feng Pan <fpan@redhat.com>
Date: Sun, 5 Feb 2017 21:34:19 -0500
Subject: [PATCH] Add NSDriver

---
 neutron/agent/l3/namespaces.py   |  6 ++--
 neutron/agent/l3/router_info.py  | 14 ++++----
 neutron/agent/linux/interface.py | 76 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 87 insertions(+), 9 deletions(-)

diff --git a/neutron/agent/l3/namespaces.py b/neutron/agent/l3/namespaces.py
index e70d7bb..3c932a8 100644
--- a/neutron/agent/l3/namespaces.py
+++ b/neutron/agent/l3/namespaces.py
@@ -18,6 +18,7 @@ import functools
 from oslo_log import log as logging
 from oslo_utils import excutils
 
+from neutron.agent.linux.interface import OVSInterfaceDriver
 from neutron._i18n import _LE, _LW
 from neutron.agent.linux import ip_lib
 
@@ -110,8 +111,9 @@ class Namespace(object):
 
 class RouterNamespace(Namespace):
 
-    def __init__(self, router_id, agent_conf, driver, use_ipv6):
+    def __init__(self, router_id, agent_conf, driver, use_ipv6, ovs_driver):
         self.router_id = router_id
+        self.ovs_driver = ovs_driver
         name = self._get_ns_name(router_id)
         super(RouterNamespace, self).__init__(
             name, agent_conf, driver, use_ipv6)
@@ -131,7 +133,7 @@ class RouterNamespace(Namespace):
             elif d.name.startswith(ROUTER_2_FIP_DEV_PREFIX):
                 ns_ip.del_veth(d.name)
             elif d.name.startswith(EXTERNAL_DEV_PREFIX):
-                self.driver.unplug(
+                self.ovs_driver.unplug(
                     d.name,
                     bridge=self.agent_conf.external_network_bridge,
                     namespace=self.name,
diff --git a/neutron/agent/l3/router_info.py b/neutron/agent/l3/router_info.py
index 3fd3934..b33fb7e 100644
--- a/neutron/agent/l3/router_info.py
+++ b/neutron/agent/l3/router_info.py
@@ -27,6 +27,7 @@ from neutron.common import exceptions as n_exc
 from neutron.common import ipv6_utils
 from neutron.common import utils as common_utils
 from neutron.ipam import utils as ipam_utils
+from neutron.agent.linux.interface import OVSInterfaceDriver
 
 LOG = logging.getLogger(__name__)
 INTERNAL_DEV_PREFIX = namespaces.INTERNAL_DEV_PREFIX
@@ -47,6 +48,7 @@ class RouterInfo(object):
                  agent_conf,
                  interface_driver,
                  use_ipv6=False):
+        self.ovs_driver = OVSInterfaceDriver(agent_conf)
         self.router_id = router_id
         self.ex_gw_port = None
         self._snat_enabled = None
@@ -57,7 +59,7 @@ class RouterInfo(object):
         self.router = router
         self.use_ipv6 = use_ipv6
         ns = self.create_router_namespace_object(
-            router_id, agent_conf, interface_driver, use_ipv6)
+            router_id, agent_conf, interface_driver, use_ipv6, self.ovs_driver)
         self.router_namespace = ns
         self.ns_name = ns.name
         self.available_mark_ids = set(range(ADDRESS_SCOPE_MARK_ID_MIN,
@@ -94,9 +96,9 @@ class RouterInfo(object):
         self.router_namespace.create()
 
     def create_router_namespace_object(
-            self, router_id, agent_conf, iface_driver, use_ipv6):
+            self, router_id, agent_conf, iface_driver, use_ipv6, ovs_driver):
         return namespaces.RouterNamespace(
-            router_id, agent_conf, iface_driver, use_ipv6)
+            router_id, agent_conf, iface_driver, use_ipv6, ovs_driver)
 
     @property
     def router(self):
@@ -583,7 +585,7 @@ class RouterInfo(object):
                 for ip in floating_ips]
 
     def _plug_external_gateway(self, ex_gw_port, interface_name, ns_name):
-        self.driver.plug(ex_gw_port['network_id'],
+        self.ovs_driver.plug(ex_gw_port['network_id'],
                          ex_gw_port['id'],
                          interface_name,
                          ex_gw_port['mac_address'],
@@ -641,7 +643,7 @@ class RouterInfo(object):
 
         self._add_route_to_gw(ex_gw_port, device_name=interface_name,
                               namespace=ns_name, preserve_ips=preserve_ips)
-        self.driver.init_router_port(
+        self.ovs_driver.init_router_port(
             interface_name,
             ip_cidrs,
             namespace=ns_name,
@@ -735,7 +737,7 @@ class RouterInfo(object):
         for stale_dev in stale_devs:
             LOG.debug('Deleting stale external router device: %s', stale_dev)
             pd.remove_gw_interface(self.router['id'])
-            self.driver.unplug(stale_dev,
+            self.ovs_driver.unplug(stale_dev,
                                bridge=self.agent_conf.external_network_bridge,
                                namespace=self.ns_name,
                                prefix=EXTERNAL_DEV_PREFIX)
diff --git a/neutron/agent/linux/interface.py b/neutron/agent/linux/interface.py
index c2eb06e..80da16f 100644
--- a/neutron/agent/linux/interface.py
+++ b/neutron/agent/linux/interface.py
@@ -15,7 +15,7 @@
 
 import abc
 import time
-
+import eventlet
 import netaddr
 from neutron_lib import constants
 from oslo_config import cfg
@@ -288,6 +288,80 @@ class NullDriver(LinuxInterfaceDriver):
     def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
         pass
 
+class NSDriver(LinuxInterfaceDriver):
+    """Device independent driver enabling creation of a non device specific
+    interface in network spaces.  Attachment to the device is not performed.
+    """
+    MAX_TIME_FOR_DEVICE_EXISTENCE = 30
+
+    @classmethod
+    def _device_is_created_in_time(cls, device_name):
+        """See if device is created, within time limit."""
+        attempt = 0
+        while attempt < NSDriver.MAX_TIME_FOR_DEVICE_EXISTENCE:
+            if ip_lib.device_exists(device_name):
+                return True
+            attempt += 1
+            eventlet.sleep(1)
+        LOG.error(_LE("Device %(dev)s was not created in %(time)d seconds"),
+                  {'dev': device_name,
+                   'time': NSDriver.MAX_TIME_FOR_DEVICE_EXISTENCE})
+        return False
+
+    def _configure_mtu(self, ns_dev, mtu=None):
+        # Need to set MTU, after added to namespace. See review
+        # https://review.openstack.org/327651
+        try:
+            # Note: network_device_mtu will be deprecated in future
+            mtu_override = self.conf.network_device_mtu
+        except cfg.NoSuchOptError:
+            LOG.warning(_LW("Config setting for MTU deprecated - any "
+                            "override will be ignored."))
+            mtu_override = None
+        if mtu_override:
+            mtu = mtu_override
+            LOG.debug("Overriding MTU to %d", mtu)
+        if mtu:
+            ns_dev.link.set_mtu(mtu)
+        else:
+            LOG.debug("No MTU provided - skipping setting value")
+
+    def plug(self, network_id, port_id, device_name, mac_address,
+             bridge=None, namespace=None, prefix=None, mtu=None):
+
+        # Overriding this, we still want to add an existing device into the
+        # namespace.
+        self.plug_new(network_id, port_id, device_name, mac_address,
+                      bridge, namespace, prefix, mtu)
+
+    def plug_new(self, network_id, port_id, device_name, mac_address,
+                 bridge=None, namespace=None, prefix=None, mtu=None):
+
+        ip = ip_lib.IPWrapper()
+        ns_dev = ip.device(device_name)
+
+        LOG.debug("Plugging dev: '%s' into namespace: '%s' ",
+                  device_name, namespace)
+
+        # Wait for device creation
+        if not self._device_is_created_in_time(device_name):
+            return
+
+        ns_dev.link.set_address(mac_address)
+
+        if namespace:
+            namespace_obj = ip.ensure_namespace(namespace)
+            namespace_obj.add_device_to_namespace(ns_dev)
+
+        self._configure_mtu(ns_dev, mtu)
+
+        ns_dev.link.set_up()
+
+    def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
+        # Device removal is done externally. Just remove the namespace
+        LOG.debug("Removing namespace: '%s'", namespace)
+        ip_lib.IPWrapper(namespace).garbage_collect_namespace()
+
 
 class OVSInterfaceDriver(LinuxInterfaceDriver):
     """Driver for creating an internal interface on an OVS bridge."""
diff --git a/neutron/agent/l3/ha_router.py b/usr/lib/python2.7/site-packages/neutron/agent/l3/ha_router.py
index ca0e50d..2c4fdad 100644
--- a/neutron/agent/l3/ha_router.py
+++ b/usr/lib/python2.7/site-packages/neutron/agent/l3/ha_router.py
@@ -52,15 +52,14 @@ class HaRouterNamespace(namespaces.RouterNamespace):
 class HaRouter(router.RouterInfo):
     def __init__(self, state_change_callback, *args, **kwargs):
         super(HaRouter, self).__init__(*args, **kwargs)
-
         self.ha_port = None
         self.keepalived_manager = None
         self.state_change_callback = state_change_callback
 
     def create_router_namespace_object(
-            self, router_id, agent_conf, iface_driver, use_ipv6):
+            self, router_id, agent_conf, iface_driver, use_ipv6, ovs_driver):
         return HaRouterNamespace(
-            router_id, agent_conf, iface_driver, use_ipv6)
+            router_id, agent_conf, iface_driver, use_ipv6, ovs_driver)
 
     @property
     def ha_priority(self):

-- 
2.9.3