Browse Source

Adding Non-ampp support for VDX

Add support for NON-AMPP(VLAN) based networking on VDX switches.
NON-AMPP based networking can be accessed through a seperate mechanism driver.

Change-Id: I4e67ff816af71ebbed1be29023c8b3c652ab3f73
Ritesh Madapurath 3 years ago
parent
commit
8bfc8971a4
46 changed files with 6730 additions and 9 deletions
  1. 0
    0
      networking_brocade/vdx/ampp/__init__.py
  2. 0
    0
      networking_brocade/vdx/ampp/ml2driver/__init__.py
  3. 464
    0
      networking_brocade/vdx/ampp/ml2driver/mechanism_brocade.py
  4. 0
    0
      networking_brocade/vdx/ampp/ml2driver/nos/__init__.py
  5. 433
    0
      networking_brocade/vdx/ampp/ml2driver/nos/nctemplates.py
  6. 488
    0
      networking_brocade/vdx/ampp/ml2driver/nos/nosdriver.py
  7. 0
    0
      networking_brocade/vdx/ampp/tests/__init__.py
  8. 0
    0
      networking_brocade/vdx/ampp/tests/unit/__init__.py
  9. 0
    0
      networking_brocade/vdx/ampp/tests/unit/ml2/__init__.py
  10. 0
    0
      networking_brocade/vdx/ampp/tests/unit/ml2/drivers/__init__.py
  11. 0
    0
      networking_brocade/vdx/ampp/tests/unit/ml2/drivers/brocade/__init__.py
  12. 57
    0
      networking_brocade/vdx/ampp/tests/unit/ml2/drivers/brocade/test_brocade_l3_plugin.py
  13. 118
    0
      networking_brocade/vdx/ampp/tests/unit/ml2/drivers/brocade/test_brocade_mechanism_driver.py
  14. 0
    0
      networking_brocade/vdx/bare_metal/__init__.py
  15. 200
    0
      networking_brocade/vdx/bare_metal/mechanism_brocade.py
  16. 235
    0
      networking_brocade/vdx/bare_metal/util.py
  17. 0
    0
      networking_brocade/vdx/db/__init__.py
  18. 0
    0
      networking_brocade/vdx/db/migration/__init__.py
  19. 0
    0
      networking_brocade/vdx/db/migration/alembic_migrations/__init__.py
  20. 123
    0
      networking_brocade/vdx/db/migration/alembic_migrations/env.py
  21. 1
    0
      networking_brocade/vdx/db/migration/alembic_migrations/versions/HEAD.bk
  22. 2
    0
      networking_brocade/vdx/db/migration/alembic_migrations/versions/HEADS
  23. 27
    0
      networking_brocade/vdx/db/migration/alembic_migrations/versions/kilo_release.py
  24. 35
    0
      networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/contract/4fadb44a1e2d_ml2_brcd_contract.py
  25. 0
    0
      networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/contract/__init__.py
  26. 0
    0
      networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/expand/__init__.py
  27. 53
    0
      networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/expand/a84d6a05d397_ml2_brcd.py
  28. 34
    0
      networking_brocade/vdx/db/migration/alembic_migrations/versions/start_networking_brocade_migration.py
  29. 220
    0
      networking_brocade/vdx/db/models.py
  30. 3
    2
      networking_brocade/vdx/ml2driver/mechanism_brocade.py
  31. 2
    1
      networking_brocade/vdx/ml2driver/nos/nosdriver.py
  32. 0
    0
      networking_brocade/vdx/non_ampp/__init__.py
  33. 0
    0
      networking_brocade/vdx/non_ampp/ml2driver/__init__.py
  34. 293
    0
      networking_brocade/vdx/non_ampp/ml2driver/brocade_fwaas_driver.py
  35. 230
    0
      networking_brocade/vdx/non_ampp/ml2driver/brocade_fwaas_plugin.py
  36. 408
    0
      networking_brocade/vdx/non_ampp/ml2driver/fwaas_plugin.py
  37. 346
    0
      networking_brocade/vdx/non_ampp/ml2driver/l3_router_plugin.py
  38. 493
    0
      networking_brocade/vdx/non_ampp/ml2driver/mechanism_brocade.py
  39. 0
    0
      networking_brocade/vdx/non_ampp/ml2driver/nos/__init__.py
  40. 825
    0
      networking_brocade/vdx/non_ampp/ml2driver/nos/nctemplates.py
  41. 1013
    0
      networking_brocade/vdx/non_ampp/ml2driver/nos/nosdriver.py
  42. 615
    0
      networking_brocade/vdx/non_ampp/ml2driver/utils.py
  43. 4
    4
      networking_brocade/vdx/services/l3_router/l3_router_plugin.py
  44. 1
    1
      networking_brocade/vdx/tests/unit/ml2/drivers/brocade/test_brocade_l3_plugin.py
  45. 6
    0
      setup.cfg
  46. 1
    1
      tox.ini

+ 0
- 0
networking_brocade/vdx/ampp/__init__.py View File


+ 0
- 0
networking_brocade/vdx/ampp/ml2driver/__init__.py View File


+ 464
- 0
networking_brocade/vdx/ampp/ml2driver/mechanism_brocade.py View File

@@ -0,0 +1,464 @@
1
+# Copyright 2016 Brocade Communications System, Inc.
2
+# All rights reserved.
3
+#
4
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
5
+#    not use this file except in compliance with the License. You may obtain
6
+#    a copy of the License at
7
+#
8
+#         http://www.apache.org/licenses/LICENSE-2.0
9
+#
10
+#    Unless required by applicable law or agreed to in writing, software
11
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+#    License for the specific language governing permissions and limitations
14
+#    under the License.
15
+
16
+
17
+"""Implentation of Brocade ML2 Mechanism driver for ML2 Plugin."""
18
+
19
+from networking_brocade._i18n import _
20
+from networking_brocade._i18n import _LE
21
+from networking_brocade._i18n import _LI
22
+from networking_brocade.vdx.db import models as brocade_db
23
+from neutron.plugins.common import constants as p_const
24
+from neutron.plugins.ml2 import driver_api
25
+from oslo_config import cfg
26
+from oslo_log import log as logging
27
+from oslo_utils import importutils
28
+
29
+LOG = logging.getLogger(__name__)
30
+MECHANISM_VERSION = 0.9
31
+NOS_DRIVER = 'networking_brocade.vdx.ampp.ml2driver.nos.nosdriver.NOSdriver'
32
+
33
+ML2_BROCADE = [cfg.StrOpt('address', default='',
34
+                          help=_('The address of the host to SSH to')),
35
+               cfg.StrOpt('username', default='admin',
36
+                          help=_('The SSH username to use')),
37
+               cfg.StrOpt('password', default='password', secret=True,
38
+                          help=_('The SSH password to use')),
39
+               cfg.StrOpt('physical_networks', default='',
40
+                          help=_('Allowed physical networks')),
41
+               cfg.StrOpt('ostype', default='NOS',
42
+                          help=_('OS Type of the switch')),
43
+               cfg.StrOpt('osversion', default='4.0.0',
44
+                          help=_('OS Version number'))
45
+               ]
46
+
47
+cfg.CONF.register_opts(ML2_BROCADE, "ml2_brocade")
48
+
49
+
50
+class BrocadeMechanism(driver_api.MechanismDriver):
51
+
52
+    """ML2 Mechanism driver for Brocade VDX switches.
53
+
54
+    This is the upper layer driver class that interfaces to
55
+    lower layer (NETCONF) below.
56
+    """
57
+
58
+    def __init__(self):
59
+        self._driver = None
60
+        self._physical_networks = None
61
+        self._switch = None
62
+        self.initialize()
63
+
64
+    def initialize(self):
65
+        """Initilize of variables needed by this class."""
66
+
67
+        self._physical_networks = cfg.CONF.ml2_brocade.physical_networks
68
+        self.brocade_init()
69
+        self._driver.close_session()
70
+
71
+    def brocade_init(self):
72
+        """Brocade specific initialization for this class."""
73
+
74
+        osversion = None
75
+        self._switch = {
76
+            'address': cfg.CONF.ml2_brocade.address,
77
+            'username': cfg.CONF.ml2_brocade.username,
78
+            'password': cfg.CONF.ml2_brocade.password,
79
+            'ostype': cfg.CONF.ml2_brocade.ostype,
80
+            'osversion': cfg.CONF.ml2_brocade.osversion}
81
+
82
+        self._driver = importutils.import_object(NOS_DRIVER)
83
+
84
+        # Detect version of NOS on the switch
85
+        osversion = self._switch['osversion']
86
+        if osversion == "autodetect":
87
+            osversion = self._driver.get_nos_version(
88
+                self._switch['address'],
89
+                self._switch['username'],
90
+                self._switch['password'])
91
+
92
+        virtual_fabric_enabled = self._driver.is_virtual_fabric_enabled(
93
+            self._switch['address'],
94
+            self._switch['username'],
95
+            self._switch['password'])
96
+
97
+        if virtual_fabric_enabled:
98
+            LOG.debug("Virtual Fabric: enabled")
99
+        else:
100
+            LOG.debug("Virtual Fabric: not enabled")
101
+
102
+        self.set_features_enabled(osversion, virtual_fabric_enabled)
103
+
104
+    def is_flat_network(self, segment):
105
+        if not segment or segment['network_type'] == p_const.TYPE_FLAT:
106
+            LOG.info(_LI("Flat network nothing to be done"))
107
+            return True
108
+        return False
109
+
110
+    def set_features_enabled(self, nos_version, virtual_fabric_enabled):
111
+        self._virtual_fabric_enabled = virtual_fabric_enabled
112
+        version = nos_version.split(".", 2)
113
+
114
+        # Starting 4.1.0 port profile domains are supported
115
+        if int(version[0]) >= 5 or (int(version[0]) >= 4 and
116
+                                    int(version[1]) >= 1):
117
+            self._pp_domains_supported = True
118
+        else:
119
+            self._pp_domains_supported = False
120
+        self._driver.set_features_enabled(self._pp_domains_supported,
121
+                                          self._virtual_fabric_enabled)
122
+
123
+    def get_features_enabled(self):
124
+        return self._pp_domains_supported, self._virtual_fabric_enabled
125
+
126
+    def create_network_precommit(self, mech_context):
127
+        """Create Network in the mechanism specific database table."""
128
+        if self.is_flat_network(mech_context.network_segments[0]):
129
+            return
130
+
131
+        network = mech_context.current
132
+        context = mech_context._plugin_context
133
+        tenant_id = network['tenant_id']
134
+        network_id = network['id']
135
+
136
+        segments = mech_context.network_segments
137
+        # currently supports only one segment per network
138
+        segment = segments[0]
139
+
140
+        network_type = segment['network_type']
141
+        vlan_id = segment['segmentation_id']
142
+        segment_id = segment['id']
143
+
144
+        if segment['physical_network'] not in self._physical_networks:
145
+            raise Exception(
146
+                _("Brocade Mechanism: failed to create network, "
147
+                  "network cannot be created in the configured "
148
+                  "physical network"))
149
+
150
+        if network_type not in [p_const.TYPE_VLAN]:
151
+            raise Exception(
152
+                _("Brocade Mechanism: failed to create network, "
153
+                  "only network type vlan is supported"))
154
+
155
+        try:
156
+            brocade_db.create_network(context, network_id, vlan_id,
157
+                                      segment_id, network_type, tenant_id)
158
+        except Exception:
159
+            LOG.exception(
160
+                _LE("Brocade Mechanism: failed to create network in db"))
161
+            raise Exception(
162
+                _("Brocade Mechanism: create_network_precommit failed"))
163
+
164
+        LOG.info(_LI("create network (precommit): %(network_id)s "
165
+                     "of network type = %(network_type)s "
166
+                     "with vlan = %(vlan_id)s "
167
+                     "for tenant %(tenant_id)s"),
168
+                 {'network_id': network_id,
169
+                  'network_type': network_type,
170
+                  'vlan_id': vlan_id,
171
+                  'tenant_id': tenant_id})
172
+
173
+    def create_network_postcommit(self, mech_context):
174
+        """Create Network as a portprofile on the switch."""
175
+
176
+        LOG.debug("create_network_postcommit: called")
177
+        if self.is_flat_network(mech_context.network_segments[0]):
178
+            return
179
+
180
+        network = mech_context.current
181
+        # use network_id to get the network attributes
182
+        # ONLY depend on our db for getting back network attributes
183
+        # this is so we can replay postcommit from db
184
+        context = mech_context._plugin_context
185
+
186
+        network_id = network['id']
187
+        network = brocade_db.get_network(context, network_id)
188
+        network_type = network.network_type
189
+        tenant_id = network['tenant_id']
190
+        vlan_id = network['vlan']
191
+
192
+        try:
193
+            self._driver.create_network(self._switch['address'],
194
+                                        self._switch['username'],
195
+                                        self._switch['password'],
196
+                                        vlan_id)
197
+        except Exception:
198
+            LOG.exception(_LE("Brocade NOS driver: failed in create network"))
199
+            brocade_db.delete_network(context, network_id)
200
+            raise Exception(
201
+                _("Brocade Mechanism: create_network_postcommmit failed"))
202
+
203
+        LOG.info(_LI("created network (postcommit): %(network_id)s"
204
+                     " of network type = %(network_type)s"
205
+                     " with vlan = %(vlan_id)s"
206
+                     " for tenant %(tenant_id)s"),
207
+                 {'network_id': network_id,
208
+                  'network_type': network_type,
209
+                  'vlan_id': vlan_id,
210
+                  'tenant_id': tenant_id})
211
+
212
+    def delete_network_precommit(self, mech_context):
213
+        """Delete Network from the plugin specific database table."""
214
+
215
+        LOG.debug("delete_network_precommit: called")
216
+        if self.is_flat_network(mech_context.network_segments[0]):
217
+            return
218
+
219
+        network = mech_context.current
220
+        network_id = network['id']
221
+        vlan_id = network['provider:segmentation_id']
222
+        tenant_id = network['tenant_id']
223
+
224
+        context = mech_context._plugin_context
225
+
226
+        try:
227
+            brocade_db.delete_network(context, network_id)
228
+        except Exception:
229
+            LOG.exception(
230
+                _LE("Brocade Mechanism: failed to delete network in db"))
231
+            raise Exception(
232
+                _("Brocade Mechanism: delete_network_precommit failed"))
233
+
234
+        LOG.info(_LI("delete network (precommit): %(network_id)s"
235
+                     " with vlan = %(vlan_id)s"
236
+                     " for tenant %(tenant_id)s"),
237
+                 {'network_id': network_id,
238
+                  'vlan_id': vlan_id,
239
+                  'tenant_id': tenant_id})
240
+
241
+    def delete_network_postcommit(self, mech_context):
242
+        """Delete network.
243
+
244
+        This translates to removng portprofile
245
+        from the switch.
246
+        """
247
+
248
+        LOG.debug("delete_network_postcommit: called")
249
+        if self.is_flat_network(mech_context.network_segments[0]):
250
+            return
251
+
252
+        network = mech_context.current
253
+        network_id = network['id']
254
+        vlan_id = network['provider:segmentation_id']
255
+        tenant_id = network['tenant_id']
256
+
257
+        try:
258
+            self._driver.delete_network(self._switch['address'],
259
+                                        self._switch['username'],
260
+                                        self._switch['password'],
261
+                                        vlan_id)
262
+        except Exception:
263
+            LOG.exception(_LE("Brocade NOS driver: failed to delete network"))
264
+            raise Exception(
265
+                _("Brocade switch exception, "
266
+                  "delete_network_postcommit failed"))
267
+
268
+        LOG.info(_LI("delete network (postcommit): %(network_id)s"
269
+                     " with vlan = %(vlan_id)s"
270
+                     " for tenant %(tenant_id)s"),
271
+                 {'network_id': network_id,
272
+                  'vlan_id': vlan_id,
273
+                  'tenant_id': tenant_id})
274
+
275
+    def update_network_precommit(self, mech_context):
276
+        """Noop now, it is left here for future."""
277
+        pass
278
+
279
+    def update_network_postcommit(self, mech_context):
280
+        """Noop now, it is left here for future."""
281
+        pass
282
+
283
+    def create_port_precommit(self, mech_context):
284
+        """Create logical port on the switch (db update)."""
285
+
286
+        LOG.debug("create_port_precommit: called")
287
+        if self.is_flat_network(mech_context.network.network_segments[0]):
288
+            return
289
+
290
+        port = mech_context.current
291
+        port_id = port['id']
292
+        network_id = port['network_id']
293
+        tenant_id = port['tenant_id']
294
+        admin_state_up = port['admin_state_up']
295
+
296
+        context = mech_context._plugin_context
297
+
298
+        network = brocade_db.get_network(context, network_id)
299
+        vlan_id = network['vlan']
300
+
301
+        try:
302
+            brocade_db.create_port(context, port_id, network_id,
303
+                                   None,
304
+                                   vlan_id, tenant_id, admin_state_up,
305
+                                   None)
306
+        except Exception:
307
+            LOG.exception(_LE("Brocade Mechanism: failed to create port"
308
+                              " in db"))
309
+            raise Exception(
310
+                _("Brocade Mechanism: create_port_precommit failed"))
311
+
312
+    def create_port_postcommit(self, mech_context):
313
+        """Associate the assigned MAC address to the portprofile."""
314
+
315
+        LOG.debug("create_port_postcommit: called")
316
+        if self.is_flat_network(mech_context.network.network_segments[0]):
317
+            return
318
+
319
+        port = mech_context.current
320
+        port_id = port['id']
321
+        network_id = port['network_id']
322
+        tenant_id = port['tenant_id']
323
+
324
+        context = mech_context._plugin_context
325
+
326
+        network = brocade_db.get_network(context, network_id)
327
+        if not network:
328
+            LOG.info(_LI("network not populated nothing to be done"))
329
+            return
330
+        vlan_id = network['vlan']
331
+
332
+        interface_mac = port['mac_address']
333
+
334
+        # convert mac format: xx:xx:xx:xx:xx:xx -> xxxx.xxxx.xxxx
335
+        mac = self.mac_reformat_62to34(interface_mac)
336
+        try:
337
+            self._driver.associate_mac_to_network(self._switch['address'],
338
+                                                  self._switch['username'],
339
+                                                  self._switch['password'],
340
+                                                  vlan_id,
341
+                                                  mac)
342
+        except Exception:
343
+            LOG.exception(
344
+                _LE("Brocade NOS driver: failed to associate mac %s"),
345
+                interface_mac)
346
+            raise Exception(
347
+                _("Brocade switch exception: create_port_postcommit failed"))
348
+
349
+        LOG.info(
350
+            _LI("created port (postcommit): port_id=%(port_id)s"
351
+                " network_id=%(network_id)s tenant_id=%(tenant_id)s"),
352
+            {'port_id': port_id,
353
+             'network_id': network_id, 'tenant_id': tenant_id})
354
+
355
+    def delete_port_precommit(self, mech_context):
356
+        """Delete logical port on the switch (db update)."""
357
+
358
+        LOG.debug("delete_port_precommit: called")
359
+        if self.is_flat_network(mech_context.network.network_segments[0]):
360
+            return
361
+        port = mech_context.current
362
+        port_id = port['id']
363
+
364
+        context = mech_context._plugin_context
365
+
366
+        try:
367
+            brocade_db.delete_port(context, port_id)
368
+        except Exception:
369
+            LOG.exception(_LE("Brocade Mechanism: failed to delete port"
370
+                              " in db"))
371
+            raise Exception(
372
+                _("Brocade Mechanism: delete_port_precommit failed"))
373
+
374
+    def delete_port_postcommit(self, mech_context):
375
+        """Dissociate MAC address from the portprofile."""
376
+
377
+        LOG.debug("delete_port_postcommit: called")
378
+        if self.is_flat_network(mech_context.network.network_segments[0]):
379
+            return
380
+        port = mech_context.current
381
+        port_id = port['id']
382
+        network_id = port['network_id']
383
+        tenant_id = port['tenant_id']
384
+
385
+        context = mech_context._plugin_context
386
+
387
+        network = brocade_db.get_network(context, network_id)
388
+        if not network:
389
+            LOG.info(_LI("network not populated nothing to be done"))
390
+            return
391
+        vlan_id = network['vlan']
392
+
393
+        interface_mac = port['mac_address']
394
+
395
+        # convert mac format: xx:xx:xx:xx:xx:xx -> xxxx.xxxx.xxxx
396
+        mac = self.mac_reformat_62to34(interface_mac)
397
+        try:
398
+            self._driver.dissociate_mac_from_network(
399
+                self._switch['address'],
400
+                self._switch['username'],
401
+                self._switch['password'],
402
+                vlan_id,
403
+                mac)
404
+        except Exception:
405
+            LOG.exception(
406
+                _LE("Brocade NOS driver: failed to dissociate MAC %s"),
407
+                interface_mac)
408
+            raise Exception(
409
+                _("Brocade switch exception, delete_port_postcommit failed"))
410
+
411
+        LOG.info(
412
+            _LI("delete port (postcommit): port_id=%(port_id)s"
413
+                " network_id=%(network_id)s tenant_id=%(tenant_id)s"),
414
+            {'port_id': port_id,
415
+             'network_id': network_id, 'tenant_id': tenant_id})
416
+
417
+    def update_port_precommit(self, mech_context):
418
+        """Noop now, it is left here for future."""
419
+        LOG.debug("update_port_precommit(self: called")
420
+
421
+    def update_port_postcommit(self, mech_context):
422
+        """Noop now, it is left here for future."""
423
+        LOG.debug("update_port_postcommit: called")
424
+
425
+    def create_subnet_precommit(self, mech_context):
426
+        """Noop now, it is left here for future."""
427
+        LOG.debug("create_subnetwork_precommit: called")
428
+
429
+    def create_subnet_postcommit(self, mech_context):
430
+        """Noop now, it is left here for future."""
431
+        LOG.debug("create_subnetwork_postcommit: called")
432
+
433
+    def delete_subnet_precommit(self, mech_context):
434
+        """Noop now, it is left here for future."""
435
+        LOG.debug("delete_subnetwork_precommit: called")
436
+
437
+    def delete_subnet_postcommit(self, mech_context):
438
+        """Noop now, it is left here for future."""
439
+        LOG.debug("delete_subnetwork_postcommit: called")
440
+
441
+    def update_subnet_precommit(self, mech_context):
442
+        """Noop now, it is left here for future."""
443
+        LOG.debug("update_subnet_precommit(self: called")
444
+
445
+    def update_subnet_postcommit(self, mech_context):
446
+        """Noop now, it is left here for future."""
447
+        LOG.debug("update_subnet_postcommit: called")
448
+
449
+    @staticmethod
450
+    def mac_reformat_62to34(interface_mac):
451
+        """Transform MAC address format.
452
+
453
+        Transforms from 6 groups of 2 hexadecimal numbers delimited by ":"
454
+        to 3 groups of 4 hexadecimals numbers delimited by ".".
455
+
456
+        :param interface_mac: MAC address in the format xx:xx:xx:xx:xx:xx
457
+        :type interface_mac: string
458
+        :returns: MAC address in the format xxxx.xxxx.xxxx
459
+        :rtype: string
460
+        """
461
+
462
+        mac = interface_mac.replace(":", "")
463
+        mac = mac[0:4] + "." + mac[4:8] + "." + mac[8:12]
464
+        return mac

+ 0
- 0
networking_brocade/vdx/ampp/ml2driver/nos/__init__.py View File


+ 433
- 0
networking_brocade/vdx/ampp/ml2driver/nos/nctemplates.py View File

@@ -0,0 +1,433 @@
1
+# Copyright (c) 2014 Brocade Communications Systems, Inc.
2
+# All Rights Reserved.
3
+#
4
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
5
+#    not use this file except in compliance with the License. You may obtain
6
+#    a copy of the License at
7
+#
8
+#         http://www.apache.org/licenses/LICENSE-2.0
9
+#
10
+#    Unless required by applicable law or agreed to in writing, software
11
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+#    License for the specific language governing permissions and limitations
14
+#    under the License.
15
+
16
+
17
+"""NOS NETCONF XML Configuration Command Templates.
18
+
19
+Interface Configuration Commands
20
+"""
21
+
22
+# Get NOS Version
23
+SHOW_FIRMWARE_VERSION = (
24
+    "show-firmware-version xmlns:nc="
25
+    "'urn:brocade.com:mgmt:brocade-firmware-ext'"
26
+)
27
+GET_VCS_DETAILS = (
28
+    'get-vcs-details xmlns:nc="urn:brocade.com:mgmt:brocade-vcs"'
29
+)
30
+SHOW_VIRTUAL_FABRIC = (
31
+    'show-virtual-fabric xmlns:nc="urn:brocade.com:mgmt:brocade-vcs"'
32
+)
33
+GET_VIRTUAL_FABRIC_INFO = (
34
+    'interface xmlns:nc="urn:brocade.com:mgmt:brocade-firmware-ext"'
35
+)
36
+
37
+NOS_VERSION = "./*/{urn:brocade.com:mgmt:brocade-firmware-ext}os-version"
38
+VFAB_ENABLE = "./*/*/*/{urn:brocade.com:mgmt:brocade-vcs}vfab-enable"
39
+
40
+# Create VLAN (vlan_id)
41
+CREATE_VLAN_INTERFACE = """
42
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
43
+        <interface-vlan xmlns="urn:brocade.com:mgmt:brocade-interface">
44
+            <interface>
45
+                <vlan>
46
+                    <name>{vlan_id}</name>
47
+                </vlan>
48
+            </interface>
49
+        </interface-vlan>
50
+    </config>
51
+"""
52
+
53
+# Delete VLAN (vlan_id)
54
+DELETE_VLAN_INTERFACE = """
55
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
56
+        <interface-vlan xmlns="urn:brocade.com:mgmt:brocade-interface">
57
+            <interface>
58
+                <vlan operation="delete">
59
+                    <name>{vlan_id}</name>
60
+                </vlan>
61
+            </interface>
62
+        </interface-vlan>
63
+    </config>
64
+"""
65
+
66
+#
67
+# AMPP Life-cycle Management Configuration Commands
68
+#
69
+
70
+# Create AMPP port-profile (port_profile_name)
71
+CREATE_PORT_PROFILE = """
72
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
73
+        <port-profile xmlns="urn:brocade.com:mgmt:brocade-port-profile">
74
+            <name>{name}</name>
75
+        </port-profile>
76
+    </config>
77
+"""
78
+
79
+# Create VLAN sub-profile for port-profile (port_profile_name)
80
+CREATE_VLAN_PROFILE_FOR_PORT_PROFILE = """
81
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
82
+        <port-profile xmlns="urn:brocade.com:mgmt:brocade-port-profile">
83
+            <name>{name}</name>
84
+            <vlan-profile/>
85
+        </port-profile>
86
+    </config>
87
+"""
88
+
89
+# Configure L2 mode for VLAN sub-profile (port_profile_name)
90
+CONFIGURE_L2_MODE_FOR_VLAN_PROFILE_IN_DOMAIN = """
91
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
92
+        <port-profile xmlns="urn:brocade.com:mgmt:brocade-port-profile">
93
+            <name>{name}</name>
94
+            <vlan-profile>
95
+                <switchport-basic>
96
+                   <basic/>
97
+                </switchport-basic>
98
+            </vlan-profile>
99
+        </port-profile>
100
+    </config>
101
+"""
102
+
103
+# Configure L2 mode for VLAN sub-profile (port_profile_name)
104
+CONFIGURE_L2_MODE_FOR_VLAN_PROFILE = """
105
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
106
+        <port-profile xmlns="urn:brocade.com:mgmt:brocade-port-profile">
107
+            <name>{name}</name>
108
+            <vlan-profile>
109
+                <switchport/>
110
+            </vlan-profile>
111
+        </port-profile>
112
+    </config>
113
+"""
114
+
115
+# Configure trunk mode for VLAN sub-profile (port_profile_name)
116
+CONFIGURE_TRUNK_MODE_FOR_VLAN_PROFILE = """
117
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
118
+        <port-profile xmlns="urn:brocade.com:mgmt:brocade-port-profile">
119
+            <name>{name}</name>
120
+            <vlan-profile>
121
+                <switchport>
122
+                    <mode>
123
+                        <vlan-mode>trunk</vlan-mode>
124
+                    </mode>
125
+                </switchport>
126
+            </vlan-profile>
127
+        </port-profile>
128
+    </config>
129
+"""
130
+
131
+# Configure allowed VLANs for VLAN sub-profile
132
+# (port_profile_name, allowed_vlan, native_vlan)
133
+CONFIGURE_ALLOWED_VLANS_FOR_VLAN_PROFILE = """
134
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
135
+        <port-profile xmlns="urn:brocade.com:mgmt:brocade-port-profile">
136
+            <name>{name}</name>
137
+            <vlan-profile>
138
+                <switchport>
139
+                    <trunk>
140
+                        <allowed>
141
+                            <vlan>
142
+                                <add>{vlan_id}</add>
143
+                            </vlan>
144
+                        </allowed>
145
+                    </trunk>
146
+                </switchport>
147
+            </vlan-profile>
148
+        </port-profile>
149
+    </config>
150
+"""
151
+
152
+# Delete port-profile (port_profile_name)
153
+DELETE_PORT_PROFILE = """
154
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
155
+        <port-profile
156
+xmlns="urn:brocade.com:mgmt:brocade-port-profile" operation="delete">
157
+            <name>{name}</name>
158
+        </port-profile>
159
+    </config>
160
+"""
161
+
162
+# Activate port-profile (port_profile_name)
163
+ACTIVATE_PORT_PROFILE = """
164
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
165
+        <port-profile-global xmlns="urn:brocade.com:mgmt:brocade-port-profile">
166
+            <port-profile>
167
+                <name>{name}</name>
168
+                <activate/>
169
+            </port-profile>
170
+        </port-profile-global>
171
+    </config>
172
+"""
173
+
174
+# Deactivate port-profile (port_profile_name)
175
+DEACTIVATE_PORT_PROFILE = """
176
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
177
+        <port-profile-global xmlns="urn:brocade.com:mgmt:brocade-port-profile">
178
+            <port-profile>
179
+                <name>{name}</name>
180
+                <activate
181
+xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="delete" />
182
+            </port-profile>
183
+        </port-profile-global>
184
+    </config>
185
+"""
186
+
187
+# Associate MAC address to port-profile (port_profile_name, mac_address)
188
+ASSOCIATE_MAC_TO_PORT_PROFILE = """
189
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
190
+        <port-profile-global xmlns="urn:brocade.com:mgmt:brocade-port-profile">
191
+            <port-profile>
192
+                <name>{name}</name>
193
+                <static>
194
+                    <mac-address>{mac_address}</mac-address>
195
+                </static>
196
+            </port-profile>
197
+        </port-profile-global>
198
+    </config>
199
+"""
200
+
201
+# Dissociate MAC address from port-profile (port_profile_name, mac_address)
202
+DISSOCIATE_MAC_FROM_PORT_PROFILE = """
203
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
204
+        <port-profile-global xmlns="urn:brocade.com:mgmt:brocade-port-profile">
205
+            <port-profile>
206
+                <name>{name}</name>
207
+                <static
208
+xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="delete">
209
+                    <mac-address>{mac_address}</mac-address>
210
+                </static>
211
+            </port-profile>
212
+        </port-profile-global>
213
+    </config>
214
+"""
215
+
216
+# port-profile domain management commands
217
+REMOVE_PORTPROFILE_FROM_DOMAIN = """
218
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
219
+        <port-profile-domain xmlns="urn:brocade.com:mgmt:brocade-port-profile">
220
+            <port-profile-domain-name>{domain_name}</port-profile-domain-name>
221
+                <profile  operation="delete">
222
+                    <profile-name>{name}</profile-name>
223
+                </profile>
224
+            </port-profile-domain>
225
+    </config>
226
+"""
227
+# put port profile in default domain
228
+CONFIGURE_PORTPROFILE_IN_DOMAIN = """
229
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
230
+        <port-profile-domain xmlns="urn:brocade.com:mgmt:brocade-port-profile">
231
+            <port-profile-domain-name>{domain_name}</port-profile-domain-name>
232
+                <profile>
233
+                    <profile-name>{name}</profile-name>
234
+                </profile>
235
+            </port-profile-domain>
236
+    </config>
237
+"""
238
+
239
+#
240
+# L3 Life-cycle Management Configuration Commands
241
+#
242
+
243
+# Create SVI and assign ippaddres (rbridge_id,vlan_id,ip_address)
244
+CONFIGURE_SVI_WITH_IP_ADDRESS = """
245
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
246
+         <rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
247
+            <rbridge-id>{rbridge_id}</rbridge-id>
248
+            <interface xmlns="urn:brocade.com:mgmt:brocade-interface">
249
+                <ve>
250
+                    <name>{vlan_id}</name>
251
+                    <ip xmlns="urn:brocade.com:mgmt:brocade-ip-config">
252
+                        <ip-config>
253
+                          <address>
254
+                             <address>{ip_address}</address>
255
+                          </address>
256
+                        </ip-config>
257
+                    </ip>
258
+                </ve>
259
+            </interface>
260
+         </rbridge-id>
261
+    </config>
262
+"""
263
+
264
+# delete SVI (rbridge_id,vlan_id)
265
+DELETE_SVI = """
266
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
267
+         <rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
268
+            <rbridge-id>{rbridge_id}</rbridge-id>
269
+            <interface xmlns="urn:brocade.com:mgmt:brocade-interface">
270
+                <ve operation="delete">
271
+                    <name>{vlan_id}</name>
272
+                </ve>
273
+            </interface>
274
+         </rbridge-id>
275
+    </config>
276
+"""
277
+
278
+# Activate SVI (rbridge_id,vlan_id)
279
+ACTIVATE_SVI = """
280
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
281
+         <rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
282
+            <rbridge-id>{rbridge_id}</rbridge-id>
283
+            <interface xmlns="urn:brocade.com:mgmt:brocade-interface">
284
+                <ve>
285
+                    <name>{vlan_id}</name>
286
+                    <shutdown xmlns="urn:brocade.com:mgmt:brocade-ip-config"
287
+                    xc:operation="delete"></shutdown>
288
+                </ve>
289
+            </interface>
290
+         </rbridge-id>
291
+    </config>
292
+"""
293
+
294
+# Remove ipaddress from SVI (rbridge_id,vlan_id)
295
+DECONFIGURE_IP_FROM_SVI = """
296
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
297
+         <rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
298
+            <rbridge-id>{rbridge_id}</rbridge-id>
299
+            <interface xmlns="urn:brocade.com:mgmt:brocade-interface">
300
+                <ve>
301
+                    <name>{vlan_id}</name>
302
+                    <ip xmlns="urn:brocade.com:mgmt:brocade-ip-config">
303
+                        <ip-config>
304
+                            <address xc:operation="delete">
305
+                                <address>{gw_ip}</address>
306
+                            </address>
307
+                        </ip-config>
308
+                    </ip>
309
+                </ve>
310
+            </interface>
311
+         </rbridge-id>
312
+    </config>
313
+"""
314
+
315
+# create vrf (rbridge_id,vrf_name)
316
+CREATE_VRF = """
317
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
318
+         <rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
319
+            <rbridge-id>{rbridge_id}</rbridge-id>
320
+                <vrf xmlns="urn:brocade.com:mgmt:brocade-vrf">
321
+                    <vrf-name>{vrf_name}</vrf-name>
322
+                </vrf>
323
+         </rbridge-id>
324
+    </config>
325
+"""
326
+
327
+
328
+# delete vrf (rbridge_id,vrf_name)
329
+DELETE_VRF = """
330
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
331
+        <rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
332
+            <rbridge-id>{rbridge_id}</rbridge-id>
333
+                <vrf xmlns="urn:brocade.com:mgmt:brocade-vrf"
334
+                       xc:operation="delete">
335
+                    <vrf-name>{vrf_name}</vrf-name>
336
+                </vrf>
337
+         </rbridge-id>
338
+    </config>
339
+"""
340
+
341
+# configure route distinguisher for vrf (rbridge_id,vrf_name, rd)
342
+CONFIGURE_RD_FOR_VRF = """
343
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
344
+         <rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
345
+            <rbridge-id>{rbridge_id}</rbridge-id>
346
+            <vrf xmlns="urn:brocade.com:mgmt:brocade-vrf">
347
+                <vrf-name>{vrf_name}</vrf-name>
348
+                <route-distiniguisher>{rd}</route-distiniguisher>
349
+            </vrf>
350
+         </rbridge-id>
351
+    </config>
352
+"""
353
+
354
+# configure address-family for vrf (rbridge_id,vrf_name)
355
+ADD_ADDRESS_FAMILY_FOR_VRF_V1 = """
356
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
357
+         <rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
358
+            <rbridge-id>{rbridge_id}</rbridge-id>
359
+            <vrf xmlns="urn:brocade.com:mgmt:brocade-vrf">
360
+                <vrf-name>{vrf_name}</vrf-name>
361
+                <address-family xmlns="urn:brocade.com:mgmt:brocade-vrf">
362
+                    <ipv4>
363
+                        <max-route>1200</max-route>
364
+                    </ipv4>
365
+                </address-family>
366
+            </vrf>
367
+         </rbridge-id>
368
+    </config>
369
+"""
370
+
371
+# configure address-family for vrf (rbridge_id,vrf_name)
372
+ADD_ADDRESS_FAMILY_FOR_VRF = """
373
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
374
+         <rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
375
+            <rbridge-id>{rbridge_id}</rbridge-id>
376
+            <vrf xmlns="urn:brocade.com:mgmt:brocade-vrf">
377
+                <vrf-name>{vrf_name}</vrf-name>
378
+                <address-family xmlns="urn:brocade.com:mgmt:brocade-vrf">
379
+                    <ip>
380
+                        <unicast/>
381
+                    </ip>
382
+                </address-family>
383
+            </vrf>
384
+         </rbridge-id>
385
+    </config>
386
+"""
387
+
388
+# Bind vrf to SVI (rbridge_id,vlan_idi, vrf)
389
+ADD_VRF_TO_SVI = """
390
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
391
+         <rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
392
+            <rbridge-id>{rbridge_id}</rbridge-id>
393
+            <interface xmlns="urn:brocade.com:mgmt:brocade-interface">
394
+                <ve>
395
+                    <name>{vlan_id}</name>
396
+                    <vrf xmlns="urn:brocade.com:mgmt:brocade-ip-config">
397
+                        <forwarding>{vrf_name}</forwarding>
398
+                    </vrf>
399
+                </ve>
400
+            </interface>
401
+         </rbridge-id>
402
+    </config>
403
+"""
404
+
405
+# unbind  vrf from SVI (rbridge_id,vlan_idi, vrf)
406
+DELETE_VRF_FROM_SVI = """
407
+    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
408
+         <rbridge-id xmlns="urn:brocade.com:mgmt:brocade-rbridge">
409
+            <rbridge-id>{rbridge_id}</rbridge-id>
410
+            <interface xmlns="urn:brocade.com:mgmt:brocade-interface">
411
+                <ve>
412
+                    <name>{vlan_id}</name>
413
+                    <vrf xmlns="urn:brocade.com:mgmt:brocade-ip-config"
414
+                            operation="delete">
415
+                        <forwarding>{vrf_name}</forwarding>
416
+                    </vrf>
417
+                </ve>
418
+            </interface>
419
+         </rbridge-id>
420
+    </config>
421
+"""
422
+
423
+#
424
+# Constants
425
+#
426
+
427
+# Port profile naming convention for Neutron networks
428
+OS_PORT_PROFILE_NAME = "openstack-profile-{id}"
429
+OS_VRF_NAME = "osv-{id}"
430
+
431
+# Port profile filter expressions
432
+PORT_PROFILE_XPATH_FILTER = "/port-profile"
433
+PORT_PROFILE_NAME_XPATH_FILTER = "/port-profile[name='{name}']"

+ 488
- 0
networking_brocade/vdx/ampp/ml2driver/nos/nosdriver.py View File

@@ -0,0 +1,488 @@
1
+# Copyright 2016 Brocade Communications System, Inc.
2
+# All rights reserved.
3
+#
4
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
5
+#    not use this file except in compliance with the License. You may obtain
6
+#    a copy of the License at
7
+#
8
+#         http://www.apache.org/licenses/LICENSE-2.0
9
+#
10
+#    Unless required by applicable law or agreed to in writing, software
11
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+#    License for the specific language governing permissions and limitations
14
+#    under the License.
15
+
16
+
17
+"""Brocade NOS Driver implements NETCONF over SSHv2 for
18
+Neutron network life-cycle management.
19
+"""
20
+
21
+from ncclient import manager
22
+from oslo_log import log as logging
23
+from oslo_utils import excutils
24
+
25
+from xml.etree import ElementTree
26
+
27
+from networking_brocade._i18n import _
28
+from networking_brocade._i18n import _LE
29
+from networking_brocade.vdx.ampp.ml2driver.nos import nctemplates as template
30
+
31
+LOG = logging.getLogger(__name__)
32
+SSH_PORT = 22
33
+
34
+
35
+def nos_unknown_host_cb(host, fingerprint):
36
+    """An unknown host callback.
37
+
38
+    Returns `True` if it finds the key acceptable,
39
+    and `False` if not. This default callback for NOS always returns 'True'
40
+    (i.e. trusts all hosts for now).
41
+    """
42
+    return True
43
+
44
+
45
+class NOSdriver(object):
46
+
47
+    """NOS NETCONF interface driver for Neutron network.
48
+
49
+    Handles life-cycle management of Neutron network (leverages AMPP on NOS)
50
+    """
51
+
52
+    def __init__(self):
53
+        self.mgr = None
54
+        self._virtual_fabric_enabled = False
55
+        self._pp_domains_supported = False
56
+
57
+    def set_features_enabled(self, pp_domains_supported,
58
+                             virtual_fabric_enabled):
59
+        """Set features in the driver based on what was detected by the MD."""
60
+        self._pp_domains_supported = pp_domains_supported
61
+        self._virtual_fabric_enabled = virtual_fabric_enabled
62
+
63
+    def get_features_enabled(self):
64
+        """Respond to status of features enabled."""
65
+        return self._pp_domains_supported, self._virtual_fabric_enabled
66
+
67
+    def connect(self, host, username, password):
68
+        """Connect via SSH and initialize the NETCONF session."""
69
+
70
+        # Use the persisted NETCONF connection
71
+        if self.mgr and self.mgr.connected:
72
+            return self.mgr
73
+
74
+        # check if someone forgot to edit the conf file with real values
75
+        if host == '':
76
+            raise Exception(_("Brocade Switch IP address is not set, "
77
+                              "check config ml2_conf_brocade.ini file"))
78
+
79
+        # Open new NETCONF connection
80
+        try:
81
+            self.mgr = manager.connect(host=host, port=SSH_PORT,
82
+                                       username=username, password=password,
83
+                                       unknown_host_cb=nos_unknown_host_cb)
84
+
85
+        except Exception:
86
+            with excutils.save_and_reraise_exception():
87
+                LOG.exception(_LE("Connect failed to switch"))
88
+
89
+        LOG.debug("Connect success to host %(host)s:%(ssh_port)d",
90
+                  dict(host=host, ssh_port=SSH_PORT))
91
+        return self.mgr
92
+
93
+    def close_session(self):
94
+        """Close NETCONF session."""
95
+        if self.mgr:
96
+            self.mgr.close_session()
97
+            self.mgr = None
98
+
99
+    def get_nos_version(self, host, username, password):
100
+        """Show version of NOS."""
101
+        try:
102
+            mgr = self.connect(host, username, password)
103
+            return self.nos_version_request(mgr)
104
+        except Exception:
105
+            with excutils.save_and_reraise_exception():
106
+                LOG.exception(_LE("NETCONF error"))
107
+                self.close_session()
108
+
109
+    def is_virtual_fabric_enabled(self, host, username, password):
110
+        """Show version of NOS."""
111
+        try:
112
+            mgr = self.connect(host, username, password)
113
+            return (self.virtual_fabric_info(mgr) == "enabled")
114
+        except Exception:
115
+            with excutils.save_and_reraise_exception():
116
+                LOG.exception(_LE("NETCONF error"))
117
+                self.close_session()
118
+
119
+    def create_network(self, host, username, password, net_id):
120
+        """Creates a new virtual network."""
121
+
122
+        domain_name = "default"
123
+        name = template.OS_PORT_PROFILE_NAME.format(id=net_id)
124
+        try:
125
+            mgr = self.connect(host, username, password)
126
+            self.create_vlan_interface(mgr, net_id)
127
+            self.create_port_profile(mgr, name)
128
+
129
+            if self._pp_domains_supported and self._virtual_fabric_enabled:
130
+                self.configure_port_profile_in_domain(mgr, domain_name, name)
131
+
132
+            self.create_vlan_profile_for_port_profile(mgr, name)
133
+
134
+            if self._pp_domains_supported:
135
+                self.configure_l2_mode_for_vlan_profile_with_domains(mgr, name)
136
+            else:
137
+                self.configure_l2_mode_for_vlan_profile(mgr, name)
138
+
139
+            self.configure_trunk_mode_for_vlan_profile(mgr, name)
140
+            self.configure_allowed_vlans_for_vlan_profile(mgr, name, net_id)
141
+            self.activate_port_profile(mgr, name)
142
+        except Exception:
143
+            with excutils.save_and_reraise_exception():
144
+                LOG.exception(_LE("NETCONF error"))
145
+                self.close_session()
146
+
147
+    def delete_network(self, host, username, password, net_id):
148
+        """Deletes a virtual network."""
149
+
150
+        domain_name = "default"
151
+        name = template.OS_PORT_PROFILE_NAME.format(id=net_id)
152
+        try:
153
+            mgr = self.connect(host, username, password)
154
+            if self._pp_domains_supported and self._virtual_fabric_enabled:
155
+                self.remove_port_profile_from_domain(mgr, domain_name, name)
156
+            self.deactivate_port_profile(mgr, name)
157
+            self.delete_port_profile(mgr, name)
158
+            self.delete_vlan_interface(mgr, net_id)
159
+        except Exception:
160
+            with excutils.save_and_reraise_exception():
161
+                LOG.exception(_LE("NETCONF error"))
162
+                self.close_session()
163
+
164
+    def associate_mac_to_network(self, host, username, password,
165
+                                 net_id, mac):
166
+        """Associates a MAC address to virtual network."""
167
+
168
+        name = template.OS_PORT_PROFILE_NAME.format(id=net_id)
169
+        try:
170
+            mgr = self.connect(host, username, password)
171
+            self.associate_mac_to_port_profile(mgr, name, mac)
172
+        except Exception:
173
+            with excutils.save_and_reraise_exception():
174
+                LOG.exception(_LE("NETCONF error"))
175
+                self.close_session()
176
+
177
+    def dissociate_mac_from_network(self, host, username, password,
178
+                                    net_id, mac):
179
+        """Dissociates a MAC address from virtual network."""
180
+
181
+        name = template.OS_PORT_PROFILE_NAME.format(id=net_id)
182
+        try:
183
+            mgr = self.connect(host, username, password)
184
+            self.dissociate_mac_from_port_profile(mgr, name, mac)
185
+        except Exception:
186
+            with excutils.save_and_reraise_exception():
187
+                LOG.exception(_LE("NETCONF error"))
188
+                self.close_session()
189
+
190
+    def create_vlan_interface(self, mgr, vlan_id):
191
+        """Configures a VLAN interface."""
192
+
193
+        confstr = template.CREATE_VLAN_INTERFACE.format(vlan_id=vlan_id)
194
+        mgr.edit_config(target='running', config=confstr)
195
+
196
+    def delete_vlan_interface(self, mgr, vlan_id):
197
+        """Deletes a VLAN interface."""
198
+
199
+        confstr = template.DELETE_VLAN_INTERFACE.format(vlan_id=vlan_id)
200
+        mgr.edit_config(target='running', config=confstr)
201
+
202
+    def get_port_profiles(self, mgr):
203
+        """Retrieves all port profiles."""
204
+
205
+        filterstr = template.PORT_PROFILE_XPATH_FILTER
206
+        response = mgr.get_config(source='running',
207
+                                  filter=('xpath', filterstr)).data_xml
208
+        return response
209
+
210
+    def get_port_profile(self, mgr, name):
211
+        """Retrieves a port profile."""
212
+
213
+        filterstr = template.PORT_PROFILE_NAME_XPATH_FILTER.format(name=name)
214
+        response = mgr.get_config(source='running',
215
+                                  filter=('xpath', filterstr)).data_xml
216
+        return response
217
+
218
+    def create_port_profile(self, mgr, name):
219
+        """Creates a port profile."""
220
+
221
+        confstr = template.CREATE_PORT_PROFILE.format(name=name)
222
+        mgr.edit_config(target='running', config=confstr)
223
+
224
+    def delete_port_profile(self, mgr, name):
225
+        """Deletes a port profile."""
226
+
227
+        confstr = template.DELETE_PORT_PROFILE.format(name=name)
228
+        mgr.edit_config(target='running', config=confstr)
229
+
230
+    def activate_port_profile(self, mgr, name):
231
+        """Activates a port profile."""
232
+
233
+        confstr = template.ACTIVATE_PORT_PROFILE.format(name=name)
234
+        mgr.edit_config(target='running', config=confstr)
235
+
236
+    def deactivate_port_profile(self, mgr, name):
237
+        """Deactivates a port profile."""
238
+
239
+        confstr = template.DEACTIVATE_PORT_PROFILE.format(name=name)
240
+        mgr.edit_config(target='running', config=confstr)
241
+
242
+    def associate_mac_to_port_profile(self, mgr, name, mac_address):
243
+        """Associates a MAC address to a port profile."""
244
+
245
+        confstr = template.ASSOCIATE_MAC_TO_PORT_PROFILE.format(
246
+            name=name, mac_address=mac_address)
247
+        mgr.edit_config(target='running', config=confstr)
248
+
249
+    def dissociate_mac_from_port_profile(self, mgr, name, mac_address):
250
+        """Dissociates a MAC address from a port profile."""
251
+
252
+        confstr = template.DISSOCIATE_MAC_FROM_PORT_PROFILE.format(
253
+            name=name, mac_address=mac_address)
254
+        mgr.edit_config(target='running', config=confstr)
255
+
256
+    def create_vlan_profile_for_port_profile(self, mgr, name):
257
+        """Creates VLAN sub-profile for port profile."""
258
+
259
+        confstr = template.CREATE_VLAN_PROFILE_FOR_PORT_PROFILE.format(
260
+            name=name)
261
+        mgr.edit_config(target='running', config=confstr)
262
+
263
+    def configure_l2_mode_for_vlan_profile(self, mgr, name):
264
+        """Configures L2 mode for VLAN sub-profile."""
265
+
266
+        confstr = template.CONFIGURE_L2_MODE_FOR_VLAN_PROFILE.format(
267
+            name=name)
268
+        mgr.edit_config(target='running', config=confstr)
269
+
270
+    def configure_trunk_mode_for_vlan_profile(self, mgr, name):
271
+        """Configures trunk mode for VLAN sub-profile."""
272
+
273
+        confstr = template.CONFIGURE_TRUNK_MODE_FOR_VLAN_PROFILE.format(
274
+            name=name)
275
+        mgr.edit_config(target='running', config=confstr)
276
+
277
+    def configure_allowed_vlans_for_vlan_profile(self, mgr, name, vlan_id):
278
+        """Configures allowed VLANs for VLAN sub-profile."""
279
+
280
+        confstr = template.CONFIGURE_ALLOWED_VLANS_FOR_VLAN_PROFILE.format(
281
+            name=name, vlan_id=vlan_id)
282
+        mgr.edit_config(target='running', config=confstr)
283
+
284
+    def remove_port_profile_from_domain(self, mgr, domain_name, name):
285
+        """Remove port-profile from default domain."""
286
+        confstr = template.REMOVE_PORTPROFILE_FROM_DOMAIN.format(
287
+            domain_name=domain_name, name=name)
288
+        mgr.edit_config(target='running', config=confstr)
289
+
290
+    def configure_port_profile_in_domain(self, mgr, domain_name, name):
291
+        """put port-profile in default domain."""
292
+        confstr = template.CONFIGURE_PORTPROFILE_IN_DOMAIN.format(
293
+            domain_name=domain_name, name=name)
294
+        mgr.edit_config(target='running', config=confstr)
295
+
296
+    def configure_l2_mode_for_vlan_profile_with_domains(self, mgr, name):
297
+        """Configures L2 mode for VLAN sub-profile."""
298
+        confstr = template.CONFIGURE_L2_MODE_FOR_VLAN_PROFILE_IN_DOMAIN.format(
299
+            name=name)
300
+        mgr.edit_config(target='running', config=confstr)
301
+
302
+    def nos_version_request(self, mgr):
303
+        """Get firmware information using NETCONF rpc."""
304
+        reply = mgr.dispatch(template.SHOW_FIRMWARE_VERSION, None, None)
305
+        et = ElementTree.fromstring(str(reply))
306
+        return et.find(template.NOS_VERSION).text
307
+
308
+    def virtual_fabric_info(self, mgr):
309
+        """Get virtual fabric info using NETCONF get-config."""
310
+        response = mgr.get_config('running',
311
+                                  filter=("xpath", "/vcs/virtual-fabric"))
312
+        et = ElementTree.fromstring(str(response))
313
+        vfab_enable = et.find(template.VFAB_ENABLE)
314
+        if vfab_enable is not None:
315
+            return "enabled"
316
+        return "disabled"
317
+
318
+    def create_svi(self, host, username, password,
319
+                   rbridge_id, vlan_id, ip_address, router_id):
320
+        """create svi on configured rbridge-id."""
321
+        try:
322
+            mgr = self.connect(host, username, password)
323
+            self.bind_vrf_to_svi(host, username, password,
324
+                                 rbridge_id, vlan_id, router_id)
325
+            self.configure_svi_with_ip_address(mgr,
326
+                                               rbridge_id, vlan_id, ip_address)
327
+            self.activate_svi(mgr, rbridge_id, vlan_id)
328
+        except Exception as ex:
329
+            with excutils.save_and_reraise_exception():
330
+                LOG.exception(_LE("NETCONF error: %s"), ex)
331
+                self.close_session()
332
+
333
+    def delete_svi(self, host, username, password,
334
+                   rbridge_id, vlan_id, gw_ip, router_id):
335
+        """delete svi from configured rbridge-id."""
336
+        try:
337
+            mgr = self.connect(host, username, password)
338
+            self.remove_svi(mgr, rbridge_id, vlan_id)
339
+        except Exception as ex:
340
+            with excutils.save_and_reraise_exception():
341
+                LOG.exception(_LE("NETCONF error: %s"), ex)
342
+                self.close_session()
343
+
344
+    def create_router(self, host, username, password, rbridge_id, router_id):
345
+        """create vrf and associate vrf."""
346
+        router_id = router_id[0:11]
347
+        vrf_name = template.OS_VRF_NAME.format(id=router_id)
348
+        rd = "".join(i for i in router_id if i in "0123456789")
349
+        rd = rd[:4] + ":" + rd[:4]
350
+        try:
351
+            mgr = self.connect(host, username, password)
352
+            self.create_vrf(mgr, rbridge_id, vrf_name)
353
+        except Exception:
354
+            with excutils.save_and_reraise_exception():
355
+                LOG.exception(_LE("NETCONF error"))
356
+                self.close_session()
357
+        try:
358
+            # For Nos5.0.0
359
+            self.configure_rd_for_vrf(mgr, rbridge_id, vrf_name, rd)
360
+            self.configure_address_family_for_vrf(mgr, rbridge_id, vrf_name)
361
+        except Exception:
362
+            with excutils.save_and_reraise_exception() as ctxt:
363
+                try:
364
+                    # This is done because on 4.0.0 rd doesnt accept alpha
365
+                    # character nor hyphen
366
+                    rd = "".join(i for i in router_id if i in "0123456789")
367
+                    rd = rd[:4] + ":" + rd[:4]
368
+                    self.configure_rd_for_vrf(mgr, rbridge_id, vrf_name, rd)
369
+                    self.configure_address_family_for_vrf_v1(mgr,
370
+                                                             rbridge_id,
371
+                                                             vrf_name)
372
+                except Exception:
373
+                    with excutils.save_and_reraise_exception():
374
+                        LOG.exception(_LE("NETCONF error"))
375
+                        self.close_session()
376
+
377
+                ctxt.reraise = False
378
+
379
+    def delete_router(self, host, username, password, rbridge_id, router_id):
380
+        """delete router and associated vrf."""
381
+        router_id = router_id[0:11]
382
+        vrf_name = template.OS_VRF_NAME.format(id=router_id)
383
+        try:
384
+            mgr = self.connect(host, username, password)
385
+            self.delete_vrf(mgr, rbridge_id, vrf_name)
386
+        except Exception:
387
+            with excutils.save_and_reraise_exception():
388
+                LOG.exception(_LE("NETCONF error"))
389
+                self.close_session()
390
+
391
+    def bind_vrf_to_svi(self, host, username, password, rbridge_id,
392
+                        vlan_id, router_id):
393
+        """binds vrf to a svi."""
394
+        router_id = router_id[0:11]
395
+        vrf_name = template.OS_VRF_NAME.format(id=router_id)
396
+        try:
397
+            mgr = self.connect(host, username, password)
398
+            self.add_vrf_to_svi(mgr, rbridge_id, vlan_id, vrf_name)
399
+        except Exception:
400
+            with excutils.save_and_reraise_exception():
401
+                LOG.exception(_LE("NETCONF error"))
402
+                self.close_session()
403
+
404
+    def unbind_vrf_to_svi(self, host, username, password, rbridge_id,
405
+                          vlan_id, router_id):
406
+        """unbind vrf from the svi."""
407
+        router_id = router_id[0:11]
408
+        vrf_name = template.OS_VRF_NAME.format(id=router_id)
409
+        try:
410
+            mgr = self.connect(host, username, password)
411
+            self.delete_vrf_from_svi(mgr, rbridge_id, vlan_id, vrf_name)
412
+        except Exception:
413
+            with excutils.save_and_reraise_exception():
414
+                LOG.exception(_LE("NETCONF error"))
415
+                self.close_session()
416
+
417
+    def create_vrf(self, mgr, rbridge_id, vrf_name):
418
+        """create vrf on rbridge."""
419
+        confstr = template.CREATE_VRF.format(rbridge_id=rbridge_id,
420
+                                             vrf_name=vrf_name)
421
+        mgr.edit_config(target='running', config=confstr)
422
+
423
+    def delete_vrf(self, mgr, rbridge_id, vrf_name):
424
+        """delete vrf on rbridge."""
425
+
426
+        confstr = template.DELETE_VRF.format(rbridge_id=rbridge_id,
427
+                                             vrf_name=vrf_name)
428
+        mgr.edit_config(target='running', config=confstr)
429
+
430
+    def configure_rd_for_vrf(self, mgr, rbridge_id, vrf_name, rd):
431
+        """configure rd on vrf  on rbridge."""
432
+
433
+        confstr = template.CONFIGURE_RD_FOR_VRF.format(rbridge_id=rbridge_id,
434
+                                                       vrf_name=vrf_name,
435
+                                                       rd=rd)
436
+        mgr.edit_config(target='running', config=confstr)
437
+
438
+    def configure_address_family_for_vrf_v1(self, mgr, rbridge_id, vrf_name):
439
+        """configure ipv4 address family to vrf  on rbridge."""
440
+
441
+        confstr = template.ADD_ADDRESS_FAMILY_FOR_VRF_V1.format(
442
+            rbridge_id=rbridge_id,
443
+            vrf_name=vrf_name)
444
+        mgr.edit_config(target='running', config=confstr)
445
+
446
+    def configure_address_family_for_vrf(self, mgr, rbridge_id, vrf_name):
447
+        """configure ipv4 address family to vrf  on rbridge."""
448
+
449
+        confstr = template.ADD_ADDRESS_FAMILY_FOR_VRF.format(
450
+            rbridge_id=rbridge_id, vrf_name=vrf_name)
451
+        mgr.edit_config(target='running', config=confstr)
452
+
453
+    def configure_svi_with_ip_address(self, mgr, rbridge_id,
454
+                                      vlan_id, ip_address):
455
+        """configure SVI with ip address on rbridge."""
456
+
457
+        confstr = template.CONFIGURE_SVI_WITH_IP_ADDRESS.format(
458
+            rbridge_id=rbridge_id,
459
+            vlan_id=vlan_id,
460
+            ip_address=ip_address)
461
+
462
+        mgr.edit_config(target='running', config=confstr)
463
+
464
+    def activate_svi(self, mgr, rbridge_id, vlan_id):
465
+        """activate the svi on the rbridge."""
466
+        confstr = template.ACTIVATE_SVI.format(rbridge_id=rbridge_id,
467
+                                               vlan_id=vlan_id)
468
+        mgr.edit_config(target='running', config=confstr)
469
+
470
+    def add_vrf_to_svi(self, mgr, rbridge_id, vlan_id, vrf_name):
471
+        """add vrf to svi on rbridge."""
472
+        confstr = template.ADD_VRF_TO_SVI.format(rbridge_id=rbridge_id,
473
+                                                 vlan_id=vlan_id,
474
+                                                 vrf_name=vrf_name)
475
+        mgr.edit_config(target='running', config=confstr)
476
+
477
+    def delete_vrf_from_svi(self, mgr, rbridge_id, vlan_id, vrf_name):
478
+        """delete vrf from svi on rbridge."""
479
+        confstr = template.DELETE_VRF_FROM_SVI.format(rbridge_id=rbridge_id,
480
+                                                      vlan_id=vlan_id,
481
+                                                      vrf_name=vrf_name)
482
+        mgr.edit_config(target='running', config=confstr)
483
+
484
+    def remove_svi(self, mgr, rbridge_id, vlan_id):
485
+        """delete vrf from svi on rbridge."""
486
+        confstr = template.DELETE_SVI.format(rbridge_id=rbridge_id,
487
+                                             vlan_id=vlan_id)
488
+        mgr.edit_config(target='running', config=confstr)

+ 0
- 0
networking_brocade/vdx/ampp/tests/__init__.py View File


+ 0
- 0
networking_brocade/vdx/ampp/tests/unit/__init__.py View File


+ 0
- 0
networking_brocade/vdx/ampp/tests/unit/ml2/__init__.py View File


+ 0
- 0
networking_brocade/vdx/ampp/tests/unit/ml2/drivers/__init__.py View File


+ 0
- 0
networking_brocade/vdx/ampp/tests/unit/ml2/drivers/brocade/__init__.py View File


+ 57
- 0
networking_brocade/vdx/ampp/tests/unit/ml2/drivers/brocade/test_brocade_l3_plugin.py View File

@@ -0,0 +1,57 @@
1
+# Copyright (c) 2014 OpenStack Foundation
2
+#
3
+# Licensed under the Apache License, Version 2.0 (the "License");
4
+# you may not use this file except in compliance with the License.
5
+# You may obtain a copy of the License at
6
+#
7
+#    http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS,
11
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12
+# implied.
13
+# See the License for the specific language governing permissions and
14
+# limitations under the License.
15
+#
16
+#
17
+
18
+import mock
19
+from networking_brocade._i18n import _LI
20
+from neutron.db import api as db
21
+from neutron.tests.unit.extensions import test_l3
22
+from oslo_config import cfg
23
+from oslo_context import context as oslo_context
24
+from oslo_log import log as logging
25
+from oslo_utils import importutils
26
+
27
+LOG = logging.getLogger(__name__)
28
+L3_SVC_PLUGIN = ('neutron.services.l3_router.'
29
+                 'brocade.l3_router_plugin.BrocadeSVIPlugin')
30
+
31
+
32
+class BrocadeSVIPlugin_TestCases(test_l3.TestL3NatBasePlugin):
33
+
34
+    def setUp(self):
35
+
36
+        def mocked_brocade_init(self):
37
+            LOG.debug("brocadeSVIPlugin::mocked_brocade_init()")
38
+
39
+            self._switch = {'address': cfg.CONF.ml2_brocade.address,
40
+                            'username': cfg.CONF.ml2_brocade.username,
41
+                            'password': cfg.CONF.ml2_brocade.password,
42
+                            'rbridge_id': cfg.CONF.ml2_brocade.rbridge_id
43
+                            }
44
+            LOG.info(_LI("rbridge id %s"), self._switch['rbridge_id'])
45
+            self._driver = mock.MagicMock()
46
+
47
+        self.l3_plugin = importutils.import_object(L3_SVC_PLUGIN)
48
+        with mock.patch.object(self.l3_plugin,
49
+                               'brocade_init', new=mocked_brocade_init):
50
+            super(BrocadeSVIPlugin_TestCases, self).setUp()
51
+        self.context = oslo_context.get_admin_context()
52
+        self.context.session = db.get_session()
53
+
54
+
55
+class TestBrocadeSVINatBase(test_l3.L3NatExtensionTestCase,
56
+                            BrocadeSVIPlugin_TestCases):
57
+    pass

+ 118
- 0
networking_brocade/vdx/ampp/tests/unit/ml2/drivers/brocade/test_brocade_mechanism_driver.py View File

@@ -0,0 +1,118 @@
1
+# Copyright (c) 2016 OpenStack Foundation
2
+#
3
+# Licensed under the Apache License, Version 2.0 (the "License");
4
+# you may not use this file except in compliance with the License.
5
+# You may obtain a copy of the License at
6
+#
7
+#    http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS,
11
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12
+# implied.
13
+# See the License for the specific language governing permissions and
14
+# limitations under the License.
15
+
16
+import mock
17
+from networking_brocade.vdx.ml2driver import (
18
+    mechanism_brocade as brocademechanism)
19
+from neutron.plugins.ml2 import config as ml2_config
20
+from neutron.tests.unit.plugins.ml2 import test_plugin
21
+from oslo_log import log as logging
22
+from oslo_utils import importutils
23
+
24
+LOG = logging.getLogger(__name__)
25
+
26
+MECHANISM_NAME = ('networking_brocade.'
27
+                  'vdx.ml2driver.mechanism_brocade.BrocadeMechanism')
28
+
29
+
30
+class TestBrocadeMechDriverV2(test_plugin.Ml2PluginV2TestCase):
31
+
32
+    """Test Brocade VCS/VDX mechanism driver.
33
+
34
+    """
35
+
36
+    _mechanism_name = MECHANISM_NAME
37
+
38
+    def setUp(self):
39
+
40
+        _mechanism_name = MECHANISM_NAME
41
+
42
+        ml2_opts = {
43
+            'mechanism_drivers': ['brocade'],
44
+            'tenant_network_types': ['vlan']}
45
+
46
+        for opt, val in ml2_opts.items():
47
+            ml2_config.cfg.CONF.set_override(opt, val, 'ml2')
48
+
49
+        def mocked_brocade_init(self):
50
+            self._driver = mock.MagicMock()
51
+
52
+        with mock.patch.object(brocademechanism.BrocadeMechanism,
53
+                               'brocade_init', new=mocked_brocade_init):
54
+            super(TestBrocadeMechDriverV2, self).setUp()
55
+            self.mechanism_driver = importutils.import_object(_mechanism_name)
56
+
57
+
58
+class TestBrocadeMechDriverNetworksV2(test_plugin.TestMl2NetworksV2,
59
+                                      TestBrocadeMechDriverV2):
60
+    pass
61
+
62
+
63
+class TestBrocadeMechDriverPortsV2(test_plugin.TestMl2PortsV2,
64
+                                   TestBrocadeMechDriverV2):
65
+    pass
66
+
67
+
68
+class TestBrocadeMechDriverSubnetsV2(test_plugin.TestMl2SubnetsV2,
69
+                                     TestBrocadeMechDriverV2):
70
+    pass
71
+
72
+
73
+class TestBrocadeMechDriverFeaturesEnabledTestCase(TestBrocadeMechDriverV2):
74
+
75
+    def setUp(self):
76
+        super(TestBrocadeMechDriverFeaturesEnabledTestCase, self).setUp()
77
+
78
+    def test_version_features(self):
79
+
80
+        vf = True
81
+        # Test for NOS version 4.0.3
82
+        self.mechanism_driver.set_features_enabled("4.0.3", vf)
83
+        # Verify
84
+        pp_domain_support, virtual_fabric_enabled = (
85
+            self.mechanism_driver.get_features_enabled()
86
+        )
87
+        self.assertFalse(pp_domain_support)
88
+        self.assertTrue(virtual_fabric_enabled)
89
+
90
+        # Test for NOS version 4.1.0
91
+        vf = True
92
+        self.mechanism_driver.set_features_enabled("4.1.0", vf)
93
+        # Verify
94
+        pp_domain_support, virtual_fabric_enabled = (
95
+            self.mechanism_driver.get_features_enabled()
96
+        )
97
+        self.assertTrue(pp_domain_support)
98
+        self.assertTrue(virtual_fabric_enabled)
99
+
100
+        # Test for NOS version 4.1.3
101
+        vf = False
102
+        self.mechanism_driver.set_features_enabled("4.1.3", vf)
103
+        # Verify
104
+        pp_domain_support, virtual_fabric_enabled = (
105
+            self.mechanism_driver.get_features_enabled()
106
+        )
107
+        self.assertTrue(pp_domain_support)
108
+        self.assertFalse(virtual_fabric_enabled)
109
+
110
+        # Test for NOS version 5.0.0
111
+        vf = True
112
+        self.mechanism_driver.set_features_enabled("5.0.0", vf)
113
+        # Verify
114
+        pp_domain_support, virtual_fabric_enabled = (
115
+            self.mechanism_driver.get_features_enabled()
116
+        )
117
+        self.assertTrue(pp_domain_support)
118
+        self.assertTrue(virtual_fabric_enabled)

+ 0
- 0
networking_brocade/vdx/bare_metal/__init__.py View File


+ 200
- 0
networking_brocade/vdx/bare_metal/mechanism_brocade.py View File

@@ -0,0 +1,200 @@
1
+# Copyright 2014 Brocade Communications System, Inc.
2
+# All rights reserved.
3
+#
4
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
5
+#    not use this file except in compliance with the License. You may obtain
6
+#    a copy of the License at
7
+#
8
+#         http://www.apache.org/licenses/LICENSE-2.0
9
+#
10
+#    Unless required by applicable law or agreed to in writing, software
11
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+#    License for the specific language governing permissions and limitations
14
+#    under the License.
15
+
16
+
17
+"""Implentation of Brocade ML2 Mechanism driver for ML2 Plugin."""
18
+
19
+from networking_brocade._i18n import _
20
+from networking_brocade._i18n import _LE
21
+from networking_brocade._i18n import _LI
22
+from networking_brocade.vdx.bare_metal import util as baremetal_util
23
+from networking_brocade.vdx.non_ampp.ml2driver.nos import nosdriver as driver
24
+from neutron.common import constants as n_const
25
+from neutron.extensions import portbindings
26
+from neutron.plugins.ml2 import driver_api as api
27
+from oslo_config import cfg
28
+from oslo_log import helpers as log_helpers
29
+try:
30
+    from oslo_log import log as logging
31
+except ImportError:
32
+    from neutron.openstack.common import log as logging
33
+
34
+LOG = logging.getLogger(__name__)
35
+
36
+NOS_DRIVER = 'networking_brocade.vdx.non_ampp.ml2driver'
37
+'.nos.nosdriver.NOSdriver'
38
+ML2_BROCADE = [cfg.StrOpt('address', default='',
39
+                          help=_('The address of the host to SSH to')),
40
+               cfg.StrOpt('username', default='admin',
41
+                          help=_('The SSH username to use')),
42
+               cfg.StrOpt('password', default='password', secret=True,
43
+                          help=_('The SSH password to use')),
44
+               cfg.StrOpt('physical_networks', default='',
45
+                          help=_('Allowed physical networks')),
46
+               cfg.StrOpt('ostype', default='NOS',
47
+                          help=_('OS Type of the switch')),
48
+               cfg.StrOpt('osversion', default='4.0.0',
49
+                          help=_('OS Version number'))
50
+               ]
51
+
52
+cfg.CONF.register_opts(ML2_BROCADE, "ml2_brocade")
53
+
54
+
55
+class BrocadeMechanism(api.MechanismDriver):
56
+    """ML2 Mechanism driver for Brocade VDX switches.
57
+    This is the upper layer driver class that interfaces to
58
+    lower layer (NETCONF) below.
59
+    """
60
+
61
+    def __init__(self):
62
+        self._driver = None
63
+        self._physical_networks = None
64
+        self._switch = None
65
+        self.initialize()
66
+
67
+    def initialize(self):
68
+        """Initilize of variables needed by this class."""
69
+
70
+        self._physical_networks = cfg.CONF.ml2_brocade.physical_networks
71
+        self.brocade_init()
72
+        self._driver.close_session()
73
+
74
+    def brocade_init(self):
75
+        """Brocade specific initialization for this class."""
76
+
77
+        osversion = None
78
+        self._switch = {
79
+            'address': cfg.CONF.ml2_brocade.address,
80
+            'username': cfg.CONF.ml2_brocade.username,
81
+            'password': cfg.CONF.ml2_brocade.password,
82
+            'ostype': cfg.CONF.ml2_brocade.ostype,
83
+            'osversion': cfg.CONF.ml2_brocade.osversion}
84
+
85
+        self._driver = driver.NOSdriver(self._switch['address'],
86
+                                        self._switch['username'],
87
+                                        self._switch['password'])
88
+
89
+        # Detect version of NOS on the switch
90
+        osversion = self._switch['osversion']
91
+        if osversion == "autodetect":
92
+            osversion = self._driver.get_nos_version(
93
+                self._switch['address'],
94
+                self._switch['username'],
95
+                self._switch['password'])
96
+        self._driver.close_session()
97
+
98
+    def create_network_precommit(self, mech_context):
99
+        """Create Network in the mechanism specific database table."""
100
+
101
+    def create_network_postcommit(self, mech_context):
102
+        """Create Network as a portprofile on the switch."""
103
+
104
+    def delete_network_precommit(self, mech_context):
105
+        """Delete Network from the plugin specific database table."""
106
+
107
+    def delete_network_postcommit(self, mech_context):
108
+        """Delete network.
109
+
110
+        This translates to removng portprofile
111
+        from the switch.
112
+        """
113
+
114
+    def update_network_precommit(self, mech_context):
115
+        """Noop now, it is left here for future."""
116
+
117
+    def update_network_postcommit(self, mech_context):
118
+        """Noop now, it is left here for future."""
119
+
120
+    def create_port_precommit(self, mech_context):
121
+        """Create logical port on the switch (db update)."""
122
+
123
+    def create_port_postcommit(self, mech_context):
124
+        """Associate the assigned MAC address to the portprofile."""
125
+
126
+    def delete_port_precommit(self, mech_context):
127
+        """Delete logical port on the switch (db update)."""
128
+
129
+    def delete_port_postcommit(self, mech_context):
130
+        """Dissociate VLAN from baremetal connected
131
+           port.
132
+        """
133
+        LOG.debug(("brocade_baremetal delete_port_postcommit(self: called"))
134
+        port = mech_context.current
135
+        if baremetal_util.is_baremetal_deploy(port):
136
+            params = baremetal_util.validate_physical_net_params(mech_context)
137
+            try:
138
+                # TODO(rmadapur): Handle local_link_info portgroups
139
+                for i in params["local_link_information"]:
140
+                    speed, name = i['port_id']
141
+                    self._driver.remove_native_vlan_from_interface(speed, name)
142
+            except Exception:
143
+                LOG.exception(_LE("Brocade NOS driver:failed to remove native"
144
+                                  " vlan from bare metal interface"))
145
+                raise Exception(_("NOS driver:failed to remove native vlan"))
146
+
147
+    def update_port_precommit(self, mech_context):
148
+        """Noop now, it is left here for future."""
149
+
150
+    def update_port_postcommit(self, mech_context):
151
+        """Noop now, it is left here for future."""
152
+
153
+    @log_helpers.log_method_call
154
+    def bind_port(self, context):
155
+        port = context.current
156
+        vnic_type = port['binding:vnic_type']
157
+
158
+        LOG.debug("Brcd:Attempting to bind port %(port)s with vnic_type "
159
+                  "%(vnic_type)s on network %(network)s",
160
+                  {'port': port['id'], 'vnic_type': vnic_type,
161
+                   'network': context.network.current['id']})
162
+
163
+        if baremetal_util.is_baremetal_deploy(port):
164
+            segments = context.segments_to_bind
165
+            LOG.info(_LI("Segments:%s"), segments)
166
+            params = baremetal_util.validate_physical_net_params(context)
167
+            try:
168
+                # TODO(rmadapur): Handle local_link_info portgroups
169
+                for i in params["local_link_information"]:
170
+                    speed, name = i['port_id']
171
+                    vlan_id = segments[0][api.SEGMENTATION_ID]
172
+                    self._driver.configure_native_vlan_on_interface(
173
+                        speed,
174
+                        name, vlan_id)
175
+            except Exception:
176
+                LOG.exception(_LE("Brocade NOS driver:failed to trunk"
177
+                                  " bare metal vlan"))
178
+                raise Exception(_("Brocade switch exception:"
179
+                                  " bind_port failed for baremetal"))
180
+            context.set_binding(segments[0][api.ID],
181
+                                portbindings.VIF_TYPE_OTHER, {},
182
+                                status=n_const.PORT_STATUS_ACTIVE)
183
+
184
+    def create_subnet_precommit(self, mech_context):
185
+        """Noop now, it is left here for future."""
186
+
187
+    def create_subnet_postcommit(self, mech_context):
188
+        """Noop now, it is left here for future."""
189
+
190
+    def delete_subnet_precommit(self, mech_context):
191
+        """Noop now, it is left here for future."""
192
+
193
+    def delete_subnet_postcommit(self, mech_context):
194
+        """Noop now, it is left here for future."""
195
+
196
+    def update_subnet_precommit(self, mech_context):
197
+        """Noop now, it is left here for future."""
198
+
199
+    def update_subnet_postcommit(self, mech_context):
200
+        """Noop now, it is left here for future."""

+ 235
- 0
networking_brocade/vdx/bare_metal/util.py View File

@@ -0,0 +1,235 @@
1
+# Copyright 2014 Brocade Communications System, Inc.
2
+# All rights reserved.
3
+#
4
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
5
+#    not use this file except in compliance with the License. You may obtain
6
+#    a copy of the License at
7
+#
8
+#         http://www.apache.org/licenses/LICENSE-2.0
9
+#
10
+#    Unless required by applicable law or agreed to in writing, software
11
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+#    License for the specific language governing permissions and limitations
14
+#    under the License.
15
+
16
+from neutron.extensions import portbindings
17
+from neutron.plugins.ml2.common import exceptions as ml2_exc
18
+from neutron.plugins.ml2 import driver_api
19
+import oslo_i18n
20
+from oslo_log import helpers as log_helpers
21
+from oslo_log import log as logging
22
+import re
23
+
24
+LOG = logging.getLogger(__name__)
25
+RANGE_DEFINITION = re.compile(r'(\d)-(\d)')
26
+_translators = oslo_i18n.TranslatorFactory(domain="fj")
27
+_LI = _translators.log_info
28
+_LW = _translators.log_warning
29
+_LE = _translators.log_error
30
+_LC = _translators.log_critical
31
+
32
+
33
+def eliminate_val(definition, target):
34
+    """Eliminate specified value from range value.
35
+
36
+    @param definition a string of range definition separated with ","
37
+           ex. "1,2,3" or "1-5"
38
+    @param target an integer of the target to eliminate
39
+    @return eliminated a string of eliminated value
40
+    """
41
+    if definition is None:
42
+        return []
43
+    targets = definition.split(',')
44
+    rejected = targets
45
+    val = str(target)
46
+    LOG.info(_LI("Before rejected:%s"), targets)
47
+    for t in targets:
48
+        m = RANGE_DEFINITION.match(t)
49
+        if m:
50
+            low = m.group(1)
51
+            high = m.group(2)
52
+            if val in t:
53
+                rejected.remove(t)
54
+                # matches the lowest one
55
+                if (val == low):
56
+                    # Case: definition is "1-2" and target is "1"
57
+                    if ((int(val) + 1) == int(high)):
58
+                        rejected.append(high)
59
+                    else:
60
+                        rejected.append(str(int(val) + 1) + "-" + high)
61
+                        LOG.info(_LI("Rejected result:%s"), rejected)
62
+                        return ','.join(rejected)
63
+                # matches the highest one
64
+                else:
65
+                    # Ex. definition is "1-2" and target is "2"
66
+                    if ((int(val) - 1) == int(low)):
67
+                        rejected.append(low)
68
+                    else:
69
+                        rejected.append(low + "-" + str(int(val) - 1))
70
+                    LOG.info(_LI("Rejected result:%s"), rejected)
71
+                    return ','.join(rejected)
72
+            # matches between lower one and higher one
73
+            elif (int(low) < int(val) and int(val) < int(high)):
74
+                rejected.remove(t)
75
+                # Ex. definition is "1-n" and target is "2"
76
+                if ((int(val) - 1) == int(low)):
77
+                    rejected.append(low)
78
+                    # Ex. definition is "1-3" and target is "2"
79
+                    if ((int(val) + 1) == int(high)):
80
+                        rejected.append(high)
81
+                    # Ex. definition is "1-4" and target is "2"
82
+                    else:
83
+                        rejected.append(str(int(val) + 1) + "-" + high)
84
+                # Ex. definition is "n-5" and target is "4"(n is NOT "3")
85
+                elif ((int(val) + 1) == int(high)):
86
+                    rejected.append(high)
87
+                    rejected.append(low + "-" + str(int(val) - 1))
88
+                # Ex. definition is "1-5" and target is "3"
89
+                else:
90
+                    rejected.append(low + "-" + str(int(val) - 1))
91
+                    rejected.append(str(int(val) + 1) + "-" + high)
92
+                LOG.info(_LI("Rejected result:%s"), rejected)
93
+                return ','.join(rejected)
94
+        elif val == t:
95
+            rejected.remove(t)
96
+            LOG.info(_LI('Rejected result:%s'), rejected)
97
+            return ','.join(rejected)
98
+    LOG.info(_LI('target for eliminate doesn\'t exist.'))
99
+    return ','.join(rejected)
100
+
101
+
102
+def get_network_segments(network):
103
+    """Get network_type and segmentation_id from specified network.
104
+
105
+    @param network a network object
106
+    @return network_type a string of network type(ex. "vlan" or "vxlan")
107
+            segmentation_id a integer of segmentation_id
108
+    """
109
+
110
+    _validate_network(network)
111
+    segment = network.network_segments[0]
112
+    network_type = segment[driver_api.NETWORK_TYPE]
113
+    segmentation_id = segment[driver_api.SEGMENTATION_ID]
114
+    LOG.info(_LI("network_type = %s") % network_type)
115
+    LOG.info(_LI("segmentation_id = %s") % segmentation_id)
116
+    return network_type, segmentation_id
117
+
118
+
119
+def _get_long_speed(short_speed):
120
+    if 'Te' in short_speed:
121
+        return "tengigabitethernet"
122
+
123
+    elif 'Gi' in short_speed:
124
+        return "gigabitethernet"
125
+
126
+    elif 'Fo' in short_speed:
127
+        return "fortyGigabitEthernet"
128
+
129
+    elif 'Hu' in short_speed:
130
+        return "hundredGigabitEthernet"
131
+    else:
132
+        return "unknown"
133
+
134
+
135
+def get_physical_connectivity(port):
136
+    """Get local_link_information from specified port.
137
+
138
+    @param port a port object
139
+    @return lli a list of following dict
140
+                {"switch_id": "MAC_of_switch", "port_id": "Te:1/0/1",
141
+                 "switch_info": "switch_name"}
142
+    """
143
+
144
+    link_infos = []
145
+    binding_profile = port['binding:profile']
146
+    lli = binding_profile.get("local_link_information", {})
147
+    is_all_specified = True if lli else False
148
+    for i in lli:
149
+        if not (i.get('switch_id') and i.get('port_id') and
150
+                i.get('switch_info')):
151
+            is_all_specified = False
152
+
153
+        else:
154
+            p = i.get('port_id')
155
+            speed, port = p.split(':')
156
+            speed = _get_long_speed(speed)
157
+            speed_port = (speed, port)
158
+            i['port_id'] = speed_port
159
+            link_infos.append(i)
160
+
161
+    if is_all_specified:
162
+        return link_infos
163
+    LOG.error(_LE("Some physical network param is missing:%s"), lli)
164
+    raise ml2_exc.MechanismDriverError(method="get_physical_connectivity")
165
+
166
+
167
+def is_baremetal_deploy(port):
168
+    """Judge a specified port is for baremetal or not.
169
+
170
+    @param port a port object
171
+    @return True/False a boolean baremetal:True, otherwise:False
172
+    """
173
+
174
+    vnic_type = port.get(portbindings.VNIC_TYPE, portbindings.VNIC_NORMAL)
175
+    if (vnic_type == portbindings.VNIC_BAREMETAL):
176
+        return True
177
+    else:
178
+        return False
179
+
180
+
181
+def is_lag(local_link_information):
182
+    """Judge a specified port param is for LAG(linkaggregation) or not.
183
+
184
+    @param local_link_information a list of dict
185
+    @return True/False a boolean LAG:True, otherwise:False
186
+    """
187
+
188
+    return True if len(local_link_information) > 1 else False
189
+
190
+
191
+def _validate_network(network):
192
+    """Validate network parameter(network_type and segmentation_id).
193
+
194
+    @param a network object
195
+    @return None if both network_type and segmentation_id are included
196
+    """
197
+
198
+    segment = network.network_segments[0]
199
+    vlan_id = segment[driver_api.SEGMENTATION_ID]
200
+    if (segment[driver_api.NETWORK_TYPE] == 'vlan' and vlan_id):
201
+        return
202
+    LOG.error(_LE("Fujitsu Mechanism: only network type vlan is supported"))
203
+    raise ml2_exc.MechanismDriverError(method="_validate_network_type")
204
+
205
+
206
+@log_helpers.log_method_call
207
+def validate_physical_net_params(mech_context):
208
+    """Validate physical network parameters for baremetal deployment.
209
+
210
+    Validates network & port params and returns dictionary.
211
+    'local_link_information' is a dictionary from Ironic-port.  This value
212
+    includes as follows:
213
+        'switch_id': A string of switch's MAC address
214
+                     This value is equal to 'chassis_id' from LLDP TLV.
215
+        'port_id': A string of switch interface name.
216
+                     This value is equal to 'port_id' from LLDP TLV.
217
+        'switch_info': A string of switch name.
218
+                     This value is equal to 'system_name' from LLDP TLV.
219
+
220
+    @param  mech_context  a Context instance
221
+    @return  A dictionary parameters for baremetal deploy
222
+    """
223
+
224
+    port = mech_context.current
225
+    _validate_network(mech_context.network)
226
+
227
+    # currently supports only one segment per network
228
+    segment = mech_context.network.network_segments[0]
229
+    vlan_id = segment[driver_api.SEGMENTATION_ID]
230
+    local_link_information = get_physical_connectivity(port)
231
+    return {
232
+        "local_link_information": local_link_information,
233
+        "vlan_id": vlan_id,
234
+        "lag": is_lag(local_link_information)
235
+    }

+ 0
- 0
networking_brocade/vdx/db/__init__.py View File


+ 0
- 0
networking_brocade/vdx/db/migration/__init__.py View File


+ 0
- 0
networking_brocade/vdx/db/migration/alembic_migrations/__init__.py View File


+ 123
- 0
networking_brocade/vdx/db/migration/alembic_migrations/env.py View File

@@ -0,0 +1,123 @@
1
+# Copyright (c) 2015 Brocade Networks, Inc.
2
+#
3
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+#    not use this file except in compliance with the License. You may obtain
5
+#    a copy of the License at
6
+#
7
+#         http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+#    Unless required by applicable law or agreed to in writing, software
10
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+#    License for the specific language governing permissions and limitations
13
+#    under the License.
14
+
15
+from logging.config import fileConfig
16
+
17
+from alembic import context
18
+from oslo_config import cfg
19
+from oslo_db.sqlalchemy import session
20
+import sqlalchemy as sa
21
+from sqlalchemy import event
22
+
23
+from neutron.db.migration.alembic_migrations import external
24
+from neutron.db.migration.models import head  # noqa
25
+from neutron.db import model_base
26
+
27
+# this is the Alembic Config object, which provides
28
+# access to the values within the .ini file in use.
29
+config = context.config
30
+neutron_config = config.neutron_config
31
+
32
+# Interpret the config file for Python logging.
33
+# This line sets up loggers basically.
34
+fileConfig(config.config_file_name)
35
+
36
+# add your model's MetaData object here
37
+# for 'autogenerate' support
38
+# from myapp import mymodel
39
+# target_metadata = mymodel.Base.metadata
40
+target_metadata = model_base.BASEV2.metadata
41
+
42
+MYSQL_ENGINE = None
43
+BROCADE_VERSION_TABLE = 'brocade_alembic_version'
44
+
45
+
46
+def set_mysql_engine():
47
+    try:
48
+        mysql_engine = neutron_config.command.mysql_engine
49
+    except cfg.NoSuchOptError:
50
+        mysql_engine = None
51
+
52
+    global MYSQL_ENGINE
53
+    MYSQL_ENGINE = (mysql_engine or
54
+                    model_base.BASEV2.__table_args__['mysql_engine'])
55
+
56
+
57
+def include_object(object, name, type_, reflected, compare_to):
58
+    if type_ == 'table' and name in external.TABLES:
59
+        return False
60
+    else:
61
+        return True
62
+
63
+
64
+def run_migrations_offline():
65
+    """Run migrations in 'offline' mode.
66
+
67
+    This configures the context with just a URL or an Engine.
68
+
69
+    Calls to context.execute() here emit the given string to the
70
+    script output.
71
+
72
+    """
73
+    set_mysql_engine()
74
+
75
+    kwargs = dict()
76
+    if neutron_config.database.connection:
77
+        kwargs['url'] = neutron_config.database.connection
78
+    else:
79
+        kwargs['dialect_name'] = neutron_config.database.engine
80
+    kwargs['include_object'] = include_object
81
+    kwargs['version_table'] = BROCADE_VERSION_TABLE
82
+    context.configure(**kwargs)
83
+
84
+    with context.begin_transaction():
85
+        context.run_migrations()
86
+
87
+
88
+@event.listens_for(sa.Table, 'after_parent_attach')
89
+def set_storage_engine(target, parent):
90
+    if MYSQL_ENGINE:
91
+        target.kwargs['mysql_engine'] = MYSQL_ENGINE
92
+
93
+
94
+def run_migrations_online():
95
+    """Run migrations in 'online' mode.
96
+
97
+    In this scenario we need to create an Engine
98
+    and associate a connection with the context.
99
+
100
+    """
101
+    set_mysql_engine()
102
+    engine = session.create_engine(neutron_config.database.connection)
103
+
104
+    connection = engine.connect()
105
+    context.configure(
106
+        connection=connection,
107
+        target_metadata=target_metadata,
108
+        include_object=include_object,
109
+        version_table=BROCADE_VERSION_TABLE,
110
+    )
111
+
112
+    try:
113
+        with context.begin_transaction():
114
+            context.run_migrations()
115
+    finally:
116
+        connection.close()
117
+        engine.dispose()
118
+
119
+
120
+if context.is_offline_mode():
121
+    run_migrations_offline()
122
+else:
123
+    run_migrations_online()

+ 1
- 0
networking_brocade/vdx/db/migration/alembic_migrations/versions/HEAD.bk View File

@@ -0,0 +1 @@
1
+4fadb44a1e2d

+ 2
- 0
networking_brocade/vdx/db/migration/alembic_migrations/versions/HEADS View File

@@ -0,0 +1,2 @@
1
+a84d6a05d397
2
+4fadb44a1e2d

+ 27
- 0
networking_brocade/vdx/db/migration/alembic_migrations/versions/kilo_release.py View File

@@ -0,0 +1,27 @@
1
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+#    not use this file except in compliance with the License. You may obtain
3
+#    a copy of the License at
4
+#
5
+#         http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+#    Unless required by applicable law or agreed to in writing, software
8
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+#    License for the specific language governing permissions and limitations
11
+#    under the License.
12
+#
13
+
14
+"""kilo
15
+
16
+Revision ID: kilo
17
+Revises: start_networking_brcd_clos
18
+Create Date: 2015-04-16 00:00:00.000000
19
+
20
+"""
21
+# revision identifiers, used by Alembic.
22
+revision = 'kilo'
23
+down_revision = 'start_ml2_brcd'
24
+
25
+
26
+def upgrade():
27
+    pass

+ 35
- 0
networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/contract/4fadb44a1e2d_ml2_brcd_contract.py View File

@@ -0,0 +1,35 @@
1
+# Copyright 2016 Brocade Networks, Inc.
2
+#
3
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+#    not use this file except in compliance with the License. You may obtain
5
+#    a copy of the License at
6
+#
7
+#         http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+#    Unless required by applicable law or agreed to in writing, software
10
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+#    License for the specific language governing permissions and limitations
13
+#    under the License.
14
+#
15
+
16
+"""ml2_brcd_contract
17
+
18
+Revision ID: 4fadb44a1e2d
19
+Revises: 30d703af31fb
20
+Create Date: 2016-02-09 15:30:27.535472
21
+
22
+"""
23
+
24
+from neutron.db.migration import cli
25
+
26
+# revision identifiers, used by Alembic.
27
+revision = '4fadb44a1e2d'
28
+down_revision = 'kilo'
29
+branch_labels = None
30
+depends_on = None
31
+branch_labels = (cli.CONTRACT_BRANCH,)
32
+
33
+
34
+def upgrade():
35
+    pass

+ 0
- 0
networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/contract/__init__.py View File


+ 0
- 0
networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/expand/__init__.py View File


+ 53
- 0
networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/expand/a84d6a05d397_ml2_brcd.py View File

@@ -0,0 +1,53 @@
1
+# Copyright 2016 Brocade Networks, Inc.
2
+#
3
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+#    not use this file except in compliance with the License. You may obtain
5
+#    a copy of the License at
6
+#
7
+#         http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+#    Unless required by applicable law or agreed to in writing, software
10
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+#    License for the specific language governing permissions and limitations
13
+#    under the License.
14
+#
15
+
16
+"""ml2_brcd
17
+
18
+Revision ID: a84d6a05d397
19
+Revises: kilo
20
+Create Date: 2016-02-09 14:56:58.752583
21
+
22
+"""
23
+from alembic import op
24
+from neutron.db.migration import cli
25
+import sqlalchemy as sa
26
+
27
+# revision identifiers, used by Alembic.
28
+revision = 'a84d6a05d397'
29
+down_revision = 'kilo'
30
+branch_labels = None
31
+depends_on = None
32
+branch_labels = (cli.EXPAND_BRANCH,)
33
+
34
+
35
+def upgrade():
36
+
37
+    op.create_table('ml2_brocadesvis',
38
+                    sa.Column('tenant_id', sa.String(
39
+                        length=255), nullable=True),
40
+                    sa.Column('id', sa.String(length=36), nullable=False),
41
+                    sa.Column('svi_id', sa.String(length=36), nullable=False),
42
+                    sa.Column('admin_state_up', sa.Boolean(), nullable=False),
43
+                    sa.Column('ip_address', sa.String(
44
+                        length=36), nullable=True),
45
+                    sa.Column('subnet_mask', sa.String(
46
+                        length=36), nullable=True),
47
+                    sa.PrimaryKeyConstraint('id', 'svi_id'),
48
+                    mysql_engine='InnoDB'
49
+                    )
50
+    op.create_index(op.f('ix_ml2_brocadesvis_tenant_id'),
51
+                    'ml2_brocadesvis', ['tenant_id'], unique=False)
52
+    op.add_column('ml2_brocadeports', sa.Column(
53
+        'host', sa.String(length=255), nullable=True))

+ 34
- 0
networking_brocade/vdx/db/migration/alembic_migrations/versions/start_networking_brocade_migration.py View File

@@ -0,0 +1,34 @@
1
+# opyright 2015 OpenStack Foundation
2
+#
3
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+#    not use this file except in compliance with the License. You may obtain
5
+#    a copy of the License at
6
+#
7
+#         http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+#    Unless required by applicable law or agreed to in writing, software
10
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+#    License for the specific language governing permissions and limitations
13
+#    under the License.
14
+#
15
+
16
+"""start networking-brocade chain
17
+
18
+Revision ID: start_networking_brocade_migration
19
+Revises: None
20
+Create Date: 2015-02-04 11:06:18.196062
21
+
22
+"""
23
+
24
+# revision identifiers, used by Alembic.
25
+revision = 'start_ml2_brcd'
26
+down_revision = None
27
+
28
+
29
+def upgrade():
30
+    pass
31
+
32
+
33
+def downgrade():
34
+    pass

+ 220
- 0
networking_brocade/vdx/db/models.py View File

@@ -0,0 +1,220 @@
1
+# Copyright 2016 Brocade Communications System, Inc.
2
+# All rights reserved.
3
+#
4
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
5
+#    not use this file except in compliance with the License. You may obtain
6
+#    a copy of the License at
7
+#
8
+#         http://www.apache.org/licenses/LICENSE-2.0
9
+#
10
+#    Unless required by applicable law or agreed to in writing, software
11
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+#    License for the specific language governing permissions and limitations
14
+#    under the License.
15
+#
16
+# Authors:
17
+# Shiv Haris (sharis@brocade.com)
18
+# Varma Bhupatiraju (vbhupati@#brocade.com)
19
+# Ritesh Madapurath (rmadapur@brocade.com)
20
+# Raghuprem Muthigi (rmuthigi@brocade.com)
21
+
22
+"""Brocade specific database schema/model."""
23
+import sqlalchemy as sa
24
+
25
+from neutron.db import model_base
26
+from neutron.db import models_v2
27
+
28
+
29
+class ML2_BrocadeNetwork(model_base.BASEV2, models_v2.HasId,
30
+                         models_v2.HasTenant):
31
+
32
+    """Schema for brocade network."""
33
+
34
+    vlan = sa.Column(sa.String(10))
35
+    segment_id = sa.Column(sa.String(36))
36
+    network_type = sa.Column(sa.String(10))
37
+
38
+
39
+class ML2_BrocadePort(model_base.BASEV2, models_v2.HasId,
40
+                      models_v2.HasTenant):
41
+
42
+    """Schema for brocade port."""
43
+
44
+    network_id = sa.Column(sa.String(36),
45
+                           sa.ForeignKey("ml2_brocadenetworks.id"),
46
+                           nullable=False)
47
+    admin_state_up = sa.Column(sa.Boolean, nullable=False)
48
+    physical_interface = sa.Column(sa.String(36))
49
+    vlan_id = sa.Column(sa.String(36))
50
+    host = sa.Column(sa.String(255))
51
+
52
+
53
+class ML2_BrocadeSvi(model_base.BASEV2, models_v2.HasId,
54
+                     models_v2.HasTenant):
55
+
56
+    """schema for brocade svi """
57
+    svi_id = sa.Column(sa.String(36), primary_key=True)
58
+    admin_state_up = sa.Column(sa.Boolean, nullable=False)
59
+    ip_address = sa.Column(sa.String(36))
60
+    subnet_mask = sa.Column(sa.String(36))
61
+
62
+
63
+def create_svi(context, router_id, tenant_id, svi,
64
+               admin_state_up, ip_address, net_mask):
65
+    """create svi port """
66
+    session = context.session
67
+    with session.begin(subtransactions=True):
68
+        ve = get_svi(context, router_id, tenant_id, svi, ip_address, net_mask)
69
+        if not ve:
70
+            svi = ML2_BrocadeSvi(id=router_id, tenant_id=tenant_id,
71
+                                 svi_id=svi, admin_state_up=admin_state_up,
72
+                                 ip_address=ip_address,
73
+                                 subnet_mask=net_mask)
74
+            session.add(svi)
75
+    return svi
76
+
77
+
78
+def delete_svi(context, router_id, tenant_id, svi, ip_address, net_mask):
79
+    """Delete a brocade specific network/port-profiles."""
80
+
81
+    session = context.session
82
+    with session.begin(subtransactions=True):
83
+        svi = get_svi(context, router_id, tenant_id, svi, ip_address, net_mask)
84
+        if svi:
85
+            session.delete(svi)
86
+
87
+
88
+def get_svi(context, router_id, tenant_id, svi, ip_address, net_mask):
89
+    session = context.session
90
+    return session.query(ML2_BrocadeSvi).filter_by(id=router_id,
91
+                                                   tenant_id=tenant_id,
92
+                                                   svi_id=svi,
93
+                                                   ip_address=ip_address,
94
+                                                   subnet_mask=net_mask).\
95
+        first()
96
+
97
+
98
+def get_svis(context, router_id, tenant_id):
99
+    session = context.session
100
+    return session.query(ML2_BrocadeSvi).filter_by(id=router_id,
101
+                                                   tenant_id=tenant_id).all()
102
+
103
+
104
+def get_list_svi_ids(context, router_id, tenant_id):
105
+    ves = []
106
+    svis = get_svis(context, router_id, tenant_id)
107
+    for svi in svis:
108
+        if svi['svi_id']:
109
+            ves.append(svi['svi_id'])
110
+    return ves
111
+
112
+
113
+def create_network(context, net_id, vlan, segment_id, network_type, tenant_id):
114
+    """Create a brocade specific network/port-profiles."""
115
+
116
+    # only network_type of vlan is supported
117
+    session = context.session
118
+    with session.begin(subtransactions=True):
119
+        net = get_network(context, net_id, None)
120
+        if not net:
121
+            net = ML2_BrocadeNetwork(id=net_id, vlan=vlan,
122
+                                     segment_id=segment_id,
123
+                                     network_type=network_type,
124
+                                     tenant_id=tenant_id)
125
+            session.add(net)
126
+    return net
127
+
128
+
129
+def delete_network(context, net_id):
130
+    """Delete a brocade specific network"""
131
+
132
+    session = context.session
133
+    with session.begin(subtransactions=True):
134
+        net = get_network(context, net_id, None)
135
+        if net:
136
+            session.delete(net)
137
+
138
+
139
+def get_network(context, net_id, fields=None):
140
+    """Get brocade specific network, with vlan extension."""
141
+
142
+    session = context.session
143
+    return session.query(ML2_BrocadeNetwork).filter_by(id=net_id).first()
144
+
145
+
146
+def get_networks(context, filters=None, fields=None):
147
+    """Get all brocade specific networks."""
148
+
149
+    session = context.session
150
+    return session.query(ML2_BrocadeNetwork).all()
151
+
152
+
153
+def create_port(context, port_id, network_id, physical_interface,
154
+                vlan_id, tenant_id, admin_state_up, host):
155
+    """Create a brocade specific port, has policy like vlan."""
156
+
157
+    session = context.session
158
+    with session.begin(subtransactions=True):
159
+        port = get_port(context, port_id)
160
+        if not port:
161
+            port = ML2_BrocadePort(id=port_id,
162
+                                   network_id=network_id,
163
+                                   physical_interface=physical_interface,
164
+                                   vlan_id=vlan_id,
165
+                                   admin_state_up=admin_state_up,
166
+                                   tenant_id=tenant_id,
167
+                                   host=host)
168
+            session.add(port)
169
+
170
+    return port
171
+
172
+
173
+def get_port(context, port_id):
174
+    """get a brocade specific port."""
175
+
176
+    session = context.session
177
+    return session.query(ML2_BrocadePort).filter_by(id=port_id).first()
178
+
179
+
180
+def is_vm_exists_on_host(context, host, physnet, vlan_id):
181
+    """check if port is tagged on host"""
182
+    session = context.session
183
+    qc = session.query(ML2_BrocadePort).filter_by(
184
+        physical_interface=physnet, host=host, vlan_id=vlan_id).count()
185
+    return qc > 1
186
+
187
+
188
+def is_last_vm_on_host(context, host, physnet, vlan_id):
189
+    """check if port is tagged on host"""
190
+    session = context.session
191
+    qc = session.query(ML2_BrocadePort).filter_by(
192
+        physical_interface=physnet, host=host, vlan_id=vlan_id).count()
193
+    return qc <= 0
194
+
195
+
196
+def get_ports(context, network_id=None):
197
+    """get a brocade specific port."""
198
+
199
+    session = context.session
200
+    return session.query(ML2_BrocadePort).filter_by(
201
+        network_id=network_id).all()
202
+
203
+
204
+def delete_port(context, port_id):
205
+    """delete brocade specific port."""
206
+
207
+    session = context.session
208
+    with session.begin(subtransactions=True):
209
+        port = get_port(context, port_id)
210
+        if port:
211
+            session.delete(port)
212
+
213
+
214
+def update_port_state(context, port_id, admin_state_up):
215
+    """Update port attributes."""
216
+
217
+    session = context.session