1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
From ea53f407637d7ed8b5447fc261b1577d4795744a 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 | 12 ++++---
neutron/agent/linux/interface.py | 76 +++++++++++++++++++++++++++++++++++++++-
3 files changed, 86 insertions(+), 8 deletions(-)
diff --git a/neutron/agent/l3/namespaces.py b/neutron/agent/l3/namespaces.py
index 71e8cbcf35..7152cd94ff 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.agent.linux import ip_lib
LOG = logging.getLogger(__name__)
@@ -119,8 +120,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)
@@ -140,7 +142,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 f578a9e5e2..cadc0371d7 100644
--- a/neutron/agent/l3/router_info.py
+++ b/neutron/agent/l3/router_info.py
@@ -29,6 +29,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
@@ -51,6 +52,7 @@ class RouterInfo(object):
interface_driver,
use_ipv6=False):
self.agent = agent
+ self.ovs_driver = OVSInterfaceDriver(agent_conf)
self.router_id = router_id
self.ex_gw_port = None
self._snat_enabled = None
@@ -62,7 +64,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,
@@ -100,9 +102,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):
@@ -630,7 +632,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'],
@@ -700,7 +702,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,
diff --git a/neutron/agent/linux/interface.py b/neutron/agent/linux/interface.py
index 88d6e67f31..c0fab604d1 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
@@ -308,6 +308,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("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.opendev.org/327651
+ try:
+ # Note: network_device_mtu will be deprecated in future
+ mtu_override = self.conf.network_device_mtu
+ except cfg.NoSuchOptError:
+ LOG.warning("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."""
--
2.14.3
|