Browse Source

refactor vhost and pipe management

vhosts and pipes are created in advance according to configuration.
vlan bridge is deleted when no port is attached except pipe
and pipe pair is reused.

Change-Id: I77271fe54a0b7501f78d0e2c2f0c8e0b4e9ac4c8
Itsuro Oda 1 year ago
parent
commit
fce17a53d0

+ 34
- 0
networking_lagopus/agent/lagopus_lib.py View File

@@ -317,6 +317,40 @@ class LagopusBridge(LagopusResource):
317 317
 
318 318
         self.installed_vlan.append(vlan_id)
319 319
 
320
+    def uninstall_vlan(self, vlan_id, port):
321
+        if vlan_id not in self.installed_vlan:
322
+            return
323
+        ofport = port.ofport
324
+        ofp = self.datapath.ofproto
325
+        ofpp = self.datapath.ofproto_parser
326
+        vlan_vid = vlan_id | ofp.OFPVID_PRESENT
327
+
328
+        # pipe port -> phys port: push vlan, output:1
329
+        match = ofpp.OFPMatch(in_port=ofport)
330
+        msg = ofpp.OFPFlowMod(self.datapath,
331
+                              command=ofp.OFPFC_DELETE,
332
+                              table_id=0,
333
+                              priority=2,
334
+                              match=match,
335
+                              out_group=ofp.OFPG_ANY,
336
+                              out_port=ofp.OFPP_ANY)
337
+        # TODO(hichihara): error handling
338
+        ofctl_api.send_msg(self.ryu_app, msg)
339
+
340
+        # phys port -> pipe port: pop vlan, output:<ofport>
341
+        match = ofpp.OFPMatch(in_port=1, vlan_vid=vlan_vid)
342
+        msg = ofpp.OFPFlowMod(self.datapath,
343
+                              command=ofp.OFPFC_DELETE,
344
+                              table_id=0,
345
+                              priority=2,
346
+                              match=match,
347
+                              out_group=ofp.OFPG_ANY,
348
+                              out_port=ofp.OFPP_ANY)
349
+        # TODO(hichihara): error handling
350
+        ofctl_api.send_msg(self.ryu_app, msg)
351
+
352
+        self.installed_vlan.remove(vlan_id)
353
+
320 354
     def dump_flows(self):
321 355
         ofpp = self.datapath.ofproto_parser
322 356
         msg = ofpp.OFPFlowStatsRequest(self.datapath)

+ 7
- 0
networking_lagopus/common/config.py View File

@@ -15,6 +15,8 @@ from oslo_config import cfg
15 15
 from networking_lagopus._i18n import _
16 16
 
17 17
 DEFAULT_BRIDGE_MAPPINGS = []
18
+DEFAULT_MAX_ETH_PORTS = 32
19
+DEFAULT_MAX_VLAN_NETWORKS = 0
18 20
 
19 21
 lagopus_opts = [
20 22
     cfg.BoolOpt('vhost_mode', default=True,
@@ -35,6 +37,11 @@ lagopus_opts = [
35 37
     cfg.PortOpt('of_listen_port', default=6633,
36 38
                 help=_("Port to listen on for OpenFlow connections. "
37 39
                        "Used only for 'native' driver.")),
40
+    cfg.IntOpt('max_eth_ports', default=DEFAULT_MAX_ETH_PORTS,
41
+               help=_("Max number of ether ports on a host.")),
42
+    cfg.IntOpt('max_vlan_networks', default=DEFAULT_MAX_VLAN_NETWORKS,
43
+               help=_("Max number of vlan networks available at the same "
44
+                      "time on a host.")),
38 45
 ]
39 46
 
40 47
 

+ 79
- 59
networking_lagopus/ml2/agent/lagopus_agent.py View File

@@ -146,24 +146,34 @@ class LagopusManager(object):
146 146
                 sys.exit(1)
147 147
             self.phys_to_bridge[phys_net] = self.bridges[name]
148 148
 
149
-        # vost_id and pipe_id management
150
-        self.free_vhost_interfaces = []
151
-        self.num_vhost = 0
152
-        max_pipe_num = 0
153
-        for interface in self.interfaces.values():
154
-            if interface.type == lg_lib.INTERFACE_TYPE_VHOST:
155
-                self.num_vhost += 1
156
-                if not interface.is_used:
157
-                    self.free_vhost_interfaces.append(interface)
158
-            elif interface.type == lg_lib.INTERFACE_TYPE_PIPE:
159
-                # only interested in even number
160
-                if interface.id % 2 == 0:
161
-                    max_pipe_num = max(max_pipe_num, interface.id)
162
-        self.next_pipe_id = max_pipe_num + 2
163
-
164 149
         # make initial dsl
165 150
         self._rebuild_dsl()
166 151
 
152
+        # vhost and pipe management
153
+        self.max_pipe_pairs = cfg.CONF.lagopus.max_vlan_networks
154
+        self.max_vhosts = (cfg.CONF.lagopus.max_eth_ports
155
+                           - self.max_pipe_pairs * 2
156
+                           - len(bridge_mappings))
157
+
158
+        self.free_vhost_interfaces = []
159
+        for vhost_id in range(self.max_vhosts):
160
+            interface = self._create_vhost_interface(vhost_id)
161
+            if not interface.is_used:
162
+                self.free_vhost_interfaces.append(interface)
163
+
164
+        used_pipe_id = []
165
+        for bridge in self.bridges.values():
166
+            if bridge.pipe_id is not None:
167
+                used_pipe_id.append(bridge.pipe_id)
168
+        self.pipe_pairs = {}
169
+        self.free_pipe_pairs = []
170
+        for i in range(self.max_pipe_pairs):
171
+            pipe_id = i * 2
172
+            pipe_pair = self._create_pipe_pair(pipe_id)
173
+            self.pipe_pairs[pipe_id] = pipe_pair
174
+            if pipe_id not in used_pipe_id:
175
+                self.free_pipe_pairs.append(pipe_pair)
176
+
167 177
     def _wait_lagopus_initialized(self):
168 178
         for retry in range(MAX_WAIT_LAGOPUS_RETRY):
169 179
             try:
@@ -200,7 +210,13 @@ class LagopusManager(object):
200 210
     def _sock_path(self, vhost_id):
201 211
         return "/tmp/sock%d" % vhost_id
202 212
 
203
-    def create_pipe_interfaces(self, pipe_id):
213
+    def _create_vhost_interface(self, vhost_id):
214
+        i_name = self.interfaces.mk_name(lg_lib.INTERFACE_TYPE_VHOST, vhost_id)
215
+        sock_path = self._sock_path(vhost_id)
216
+        device = "eth_vhost%d,iface=%s,client=1" % (vhost_id, sock_path)
217
+        return self.interfaces.create(i_name, lg_lib.DEVICE_TYPE_PHYS, device)
218
+
219
+    def _create_pipe_pair(self, pipe_id):
204 220
         i_name1 = self.interfaces.mk_name(lg_lib.INTERFACE_TYPE_PIPE, pipe_id)
205 221
         i_name2 = self.interfaces.mk_name(lg_lib.INTERFACE_TYPE_PIPE,
206 222
                                           pipe_id + 1)
@@ -212,27 +228,19 @@ class LagopusManager(object):
212 228
         inter2 = self.interfaces.create(i_name2, lg_lib.DEVICE_TYPE_PHYS,
213 229
                                         device2)
214 230
 
215
-        return inter1, inter2
216
-
217
-    def _get_pipe_id(self):
218
-        pipe_id = self.next_pipe_id
219
-        self.next_pipe_id += 2
220
-        return pipe_id
221
-
222
-    def create_pipe_ports(self, bridge):
223
-        if bridge.pipe_id is not None:
224
-            pipe_id = bridge.pipe_id
225
-        else:
226
-            pipe_id = self._get_pipe_id()
227
-
228
-        inter1, inter2 = self.create_pipe_interfaces(pipe_id)
229
-
230
-        p_name1 = self.ports.mk_name(lg_lib.INTERFACE_TYPE_PIPE, inter1.name)
231
-        p_name2 = self.ports.mk_name(lg_lib.INTERFACE_TYPE_PIPE, inter2.name)
231
+        p_name1 = self.ports.mk_name(lg_lib.INTERFACE_TYPE_PIPE, i_name1)
232
+        p_name2 = self.ports.mk_name(lg_lib.INTERFACE_TYPE_PIPE, i_name2)
232 233
         port1 = self.ports.create(p_name1, inter1)
233 234
         port2 = self.ports.create(p_name2, inter2)
234 235
 
235
-        return port1, port2
236
+        return (port1, port2)
237
+
238
+    def get_pipe_ports(self, bridge):
239
+        if bridge.pipe_id is not None:
240
+            return self.pipe_pairs[bridge.pipe_id]
241
+        if self.free_pipe_pairs:
242
+            return self.free_pipe_pairs.pop()
243
+        raise RuntimeError("too many networks.")
236 244
 
237 245
     def create_bridge(self, b_name, dpid):
238 246
         channel = self.channels.mk_name(b_name)
@@ -274,7 +282,7 @@ class LagopusManager(object):
274 282
             bridge.enable()
275 283
 
276 284
         # make sure there is pipe connection between phys_bridge
277
-        port1, port2 = self.create_pipe_ports(bridge)
285
+        port1, port2 = self.get_pipe_ports(bridge)
278 286
         self.bridge_add_port(bridge, port1)
279 287
         self.bridge_add_port(phys_bridge, port2)
280 288
 
@@ -282,30 +290,39 @@ class LagopusManager(object):
282 290
 
283 291
         return bridge
284 292
 
285
-    def create_vhost_interface(self, vhost_id):
286
-        i_name = self.interfaces.mk_name(lg_lib.INTERFACE_TYPE_VHOST, vhost_id)
287
-        sock_path = self._sock_path(vhost_id)
288
-        device = "eth_vhost%d,iface=%s,client=1" % (vhost_id, sock_path)
289
-        interface = self.interfaces.create(i_name, lg_lib.DEVICE_TYPE_PHYS,
290
-                                           device)
291
-        LOG.debug("vhost %d added.", vhost_id)
292
-        return interface
293
+    def put_bridge(self, bridge):
294
+        if bridge is None or bridge.type != lg_lib.BRIDGE_TYPE_VLAN:
295
+            return
296
+        if len(bridge.used_ofport) > 1:
297
+            return
293 298
 
294
-    def get_vhost_interface(self):
295
-        if self.free_vhost_interfaces:
296
-            return self.free_vhost_interfaces.pop()
299
+        port1, port2 = self.pipe_pairs[bridge.pipe_id]
300
+        phys_bridge = port2.bridge
301
+
302
+        if phys_bridge:
303
+            vlan_id = bridge.dpid >> 48
304
+            phys_bridge.uninstall_vlan(vlan_id, port2)
305
+        self.bridge_del_port(port1)
306
+        self.bridge_del_port(port2)
297 307
 
298
-        # create new vhost interface
299
-        vhost_id = self.num_vhost
300
-        interface = self.create_vhost_interface(vhost_id)
301
-        self.num_vhost += 1
302
-        return interface
308
+        self.bridges.destroy(bridge.name)
309
+        self.free_pipe_pairs.append((port1, port2))
303 310
 
304 311
     def create_vhost_port(self, p_name):
305
-        if p_name not in self.ports:
306
-            interface = self.get_vhost_interface()
307
-            self.ports.create(p_name, interface)
308
-        return self.ports[p_name]
312
+        if p_name in self.ports:
313
+            return self.ports[p_name]
314
+
315
+        if self.free_vhost_interfaces:
316
+            interface = self.free_vhost_interfaces.pop()
317
+        else:
318
+            raise RuntimeError("too many vhosts.")
319
+
320
+        return self.ports.create(p_name, interface)
321
+
322
+    def destroy_vhost_port(self, port):
323
+        interface = port.interface
324
+        self.ports.destroy(port.name)
325
+        self.free_vhost_interfaces.append(interface)
309 326
 
310 327
     @log_helpers.log_method_call
311 328
     def plug_vhost(self, context, **kwargs):
@@ -328,10 +345,10 @@ class LagopusManager(object):
328 345
         with self.serializer:
329 346
             port = self.ports.get(p_name)
330 347
             if port:
348
+                bridge = port.bridge
331 349
                 self.bridge_del_port(port)
332
-                interface = port.interface
333
-                self.ports.destroy(p_name)
334
-                self.free_vhost_interfaces.append(interface)
350
+                self.destroy_vhost_port(port)
351
+                self.put_bridge(bridge)
335 352
 
336 353
     @log_helpers.log_method_call
337 354
     def plug_rawsock(self, context, **kwargs):
@@ -357,9 +374,12 @@ class LagopusManager(object):
357 374
         p_name = self.ports.mk_name(lg_lib.INTERFACE_TYPE_RAWSOCK, device)
358 375
 
359 376
         with self.serializer:
360
-            self.bridge_del_port(self.ports.get(p_name))
377
+            port = self.ports.get(p_name)
378
+            bridge = port.bridge if port else None
379
+            self.bridge_del_port(port)
361 380
             self.ports.destroy(p_name)
362 381
             self.interfaces.destroy(i_name)
382
+            self.put_bridge(bridge)
363 383
 
364 384
 
365 385
 class LagopusAgent(service.Service):

Loading…
Cancel
Save