summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRitesh Madapurath <rmadapur@brocade.com>2016-03-29 02:18:27 -0700
committerRitesh Madapurath <rmadapur@brocade.com>2016-04-13 03:42:48 -0700
commit8bfc8971a47ecde1e0bf2d06e75728c446286fd2 (patch)
tree569df8fdc1cb9fb606e76e9eb6cebc7eec75730b
parente2c8ecd218280c1cd7869fa8040ad02bf0f6b02b (diff)
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
Notes
Notes (review): Code-Review+1: Prem <raghuprem1@gmail.com> Code-Review+2: Ritesh Madapurath <rmadapur@brocade.com> Workflow+1: Ritesh Madapurath <rmadapur@brocade.com> Verified+2: Jenkins Submitted-by: Jenkins Submitted-at: Wed, 13 Apr 2016 11:13:03 +0000 Reviewed-on: https://review.openstack.org/298616 Project: openstack/networking-brocade Branch: refs/heads/master
-rw-r--r--networking_brocade/vdx/ampp/__init__.py0
-rw-r--r--networking_brocade/vdx/ampp/ml2driver/__init__.py0
-rw-r--r--networking_brocade/vdx/ampp/ml2driver/mechanism_brocade.py464
-rw-r--r--networking_brocade/vdx/ampp/ml2driver/nos/__init__.py0
-rw-r--r--networking_brocade/vdx/ampp/ml2driver/nos/nctemplates.py433
-rw-r--r--networking_brocade/vdx/ampp/ml2driver/nos/nosdriver.py488
-rw-r--r--networking_brocade/vdx/ampp/tests/__init__.py0
-rw-r--r--networking_brocade/vdx/ampp/tests/unit/__init__.py0
-rw-r--r--networking_brocade/vdx/ampp/tests/unit/ml2/__init__.py0
-rw-r--r--networking_brocade/vdx/ampp/tests/unit/ml2/drivers/__init__.py0
-rw-r--r--networking_brocade/vdx/ampp/tests/unit/ml2/drivers/brocade/__init__.py0
-rw-r--r--networking_brocade/vdx/ampp/tests/unit/ml2/drivers/brocade/test_brocade_l3_plugin.py57
-rw-r--r--networking_brocade/vdx/ampp/tests/unit/ml2/drivers/brocade/test_brocade_mechanism_driver.py118
-rw-r--r--networking_brocade/vdx/bare_metal/__init__.py0
-rw-r--r--networking_brocade/vdx/bare_metal/mechanism_brocade.py200
-rw-r--r--networking_brocade/vdx/bare_metal/util.py235
-rw-r--r--networking_brocade/vdx/db/__init__.py0
-rw-r--r--networking_brocade/vdx/db/migration/__init__.py0
-rw-r--r--networking_brocade/vdx/db/migration/alembic_migrations/__init__.py0
-rw-r--r--networking_brocade/vdx/db/migration/alembic_migrations/env.py123
-rw-r--r--networking_brocade/vdx/db/migration/alembic_migrations/versions/HEAD.bk1
-rw-r--r--networking_brocade/vdx/db/migration/alembic_migrations/versions/HEADS2
-rw-r--r--networking_brocade/vdx/db/migration/alembic_migrations/versions/kilo_release.py27
-rw-r--r--networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/contract/4fadb44a1e2d_ml2_brcd_contract.py35
-rw-r--r--networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/contract/__init__.py0
-rw-r--r--networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/expand/__init__.py0
-rw-r--r--networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/expand/a84d6a05d397_ml2_brcd.py53
-rw-r--r--networking_brocade/vdx/db/migration/alembic_migrations/versions/start_networking_brocade_migration.py34
-rw-r--r--networking_brocade/vdx/db/models.py220
-rw-r--r--networking_brocade/vdx/ml2driver/mechanism_brocade.py5
-rw-r--r--networking_brocade/vdx/ml2driver/nos/nosdriver.py3
-rw-r--r--networking_brocade/vdx/non_ampp/__init__.py0
-rw-r--r--networking_brocade/vdx/non_ampp/ml2driver/__init__.py0
-rw-r--r--networking_brocade/vdx/non_ampp/ml2driver/brocade_fwaas_driver.py293
-rw-r--r--networking_brocade/vdx/non_ampp/ml2driver/brocade_fwaas_plugin.py230
-rw-r--r--networking_brocade/vdx/non_ampp/ml2driver/fwaas_plugin.py408
-rw-r--r--networking_brocade/vdx/non_ampp/ml2driver/l3_router_plugin.py346
-rw-r--r--networking_brocade/vdx/non_ampp/ml2driver/mechanism_brocade.py493
-rw-r--r--networking_brocade/vdx/non_ampp/ml2driver/nos/__init__.py0
-rw-r--r--networking_brocade/vdx/non_ampp/ml2driver/nos/nctemplates.py825
-rw-r--r--networking_brocade/vdx/non_ampp/ml2driver/nos/nosdriver.py1013
-rw-r--r--networking_brocade/vdx/non_ampp/ml2driver/utils.py615
-rw-r--r--networking_brocade/vdx/services/l3_router/l3_router_plugin.py8
-rw-r--r--networking_brocade/vdx/tests/unit/ml2/drivers/brocade/test_brocade_l3_plugin.py2
-rw-r--r--setup.cfg6
-rw-r--r--tox.ini2
46 files changed, 6730 insertions, 9 deletions
diff --git a/networking_brocade/vdx/ampp/__init__.py b/networking_brocade/vdx/ampp/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_brocade/vdx/ampp/__init__.py
diff --git a/networking_brocade/vdx/ampp/ml2driver/__init__.py b/networking_brocade/vdx/ampp/ml2driver/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_brocade/vdx/ampp/ml2driver/__init__.py
diff --git a/networking_brocade/vdx/ampp/ml2driver/mechanism_brocade.py b/networking_brocade/vdx/ampp/ml2driver/mechanism_brocade.py
new file mode 100644
index 0000000..ecdbd3c
--- /dev/null
+++ b/networking_brocade/vdx/ampp/ml2driver/mechanism_brocade.py
@@ -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
19from networking_brocade._i18n import _
20from networking_brocade._i18n import _LE
21from networking_brocade._i18n import _LI
22from networking_brocade.vdx.db import models as brocade_db
23from neutron.plugins.common import constants as p_const
24from neutron.plugins.ml2 import driver_api
25from oslo_config import cfg
26from oslo_log import log as logging
27from oslo_utils import importutils
28
29LOG = logging.getLogger(__name__)
30MECHANISM_VERSION = 0.9
31NOS_DRIVER = 'networking_brocade.vdx.ampp.ml2driver.nos.nosdriver.NOSdriver'
32
33ML2_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
47cfg.CONF.register_opts(ML2_BROCADE, "ml2_brocade")
48
49
50class 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
diff --git a/networking_brocade/vdx/ampp/ml2driver/nos/__init__.py b/networking_brocade/vdx/ampp/ml2driver/nos/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_brocade/vdx/ampp/ml2driver/nos/__init__.py
diff --git a/networking_brocade/vdx/ampp/ml2driver/nos/nctemplates.py b/networking_brocade/vdx/ampp/ml2driver/nos/nctemplates.py
new file mode 100644
index 0000000..f52c8c9
--- /dev/null
+++ b/networking_brocade/vdx/ampp/ml2driver/nos/nctemplates.py
@@ -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
19Interface Configuration Commands
20"""
21
22# Get NOS Version
23SHOW_FIRMWARE_VERSION = (
24 "show-firmware-version xmlns:nc="
25 "'urn:brocade.com:mgmt:brocade-firmware-ext'"
26)
27GET_VCS_DETAILS = (
28 'get-vcs-details xmlns:nc="urn:brocade.com:mgmt:brocade-vcs"'
29)
30SHOW_VIRTUAL_FABRIC = (
31 'show-virtual-fabric xmlns:nc="urn:brocade.com:mgmt:brocade-vcs"'
32)
33GET_VIRTUAL_FABRIC_INFO = (
34 'interface xmlns:nc="urn:brocade.com:mgmt:brocade-firmware-ext"'
35)
36
37NOS_VERSION = "./*/{urn:brocade.com:mgmt:brocade-firmware-ext}os-version"
38VFAB_ENABLE = "./*/*/*/{urn:brocade.com:mgmt:brocade-vcs}vfab-enable"
39
40# Create VLAN (vlan_id)
41CREATE_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)
54DELETE_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)
71CREATE_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)
80CREATE_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)
90CONFIGURE_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)
104CONFIGURE_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)
116CONFIGURE_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)
133CONFIGURE_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)
153DELETE_PORT_PROFILE = """
154 <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
155 <port-profile
156xmlns="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)
163ACTIVATE_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)
175DEACTIVATE_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
181xmlns: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)
188ASSOCIATE_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)
202DISSOCIATE_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
208xmlns: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
217REMOVE_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
228CONFIGURE_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)
244CONFIGURE_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)
265DELETE_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)
279ACTIVATE_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)
295DECONFIGURE_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)
316CREATE_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)
329DELETE_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)
342CONFIGURE_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)
355ADD_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)
372ADD_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)
389ADD_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)
406DELETE_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
428OS_PORT_PROFILE_NAME = "openstack-profile-{id}"
429OS_VRF_NAME = "osv-{id}"
430
431# Port profile filter expressions
432PORT_PROFILE_XPATH_FILTER = "/port-profile"
433PORT_PROFILE_NAME_XPATH_FILTER = "/port-profile[name='{name}']"
diff --git a/networking_brocade/vdx/ampp/ml2driver/nos/nosdriver.py b/networking_brocade/vdx/ampp/ml2driver/nos/nosdriver.py
new file mode 100644
index 0000000..a09553b
--- /dev/null
+++ b/networking_brocade/vdx/ampp/ml2driver/nos/nosdriver.py
@@ -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
18Neutron network life-cycle management.
19"""
20
21from ncclient import manager
22from oslo_log import log as logging
23from oslo_utils import excutils
24
25from xml.etree import ElementTree
26
27from networking_brocade._i18n import _
28from networking_brocade._i18n import _LE
29from networking_brocade.vdx.ampp.ml2driver.nos import nctemplates as template
30
31LOG = logging.getLogger(__name__)
32SSH_PORT = 22
33
34
35def 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
45class 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)
diff --git a/networking_brocade/vdx/ampp/tests/__init__.py b/networking_brocade/vdx/ampp/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_brocade/vdx/ampp/tests/__init__.py
diff --git a/networking_brocade/vdx/ampp/tests/unit/__init__.py b/networking_brocade/vdx/ampp/tests/unit/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_brocade/vdx/ampp/tests/unit/__init__.py
diff --git a/networking_brocade/vdx/ampp/tests/unit/ml2/__init__.py b/networking_brocade/vdx/ampp/tests/unit/ml2/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_brocade/vdx/ampp/tests/unit/ml2/__init__.py
diff --git a/networking_brocade/vdx/ampp/tests/unit/ml2/drivers/__init__.py b/networking_brocade/vdx/ampp/tests/unit/ml2/drivers/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_brocade/vdx/ampp/tests/unit/ml2/drivers/__init__.py
diff --git a/networking_brocade/vdx/ampp/tests/unit/ml2/drivers/brocade/__init__.py b/networking_brocade/vdx/ampp/tests/unit/ml2/drivers/brocade/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_brocade/vdx/ampp/tests/unit/ml2/drivers/brocade/__init__.py
diff --git a/networking_brocade/vdx/ampp/tests/unit/ml2/drivers/brocade/test_brocade_l3_plugin.py b/networking_brocade/vdx/ampp/tests/unit/ml2/drivers/brocade/test_brocade_l3_plugin.py
new file mode 100644
index 0000000..801b30b
--- /dev/null
+++ b/networking_brocade/vdx/ampp/tests/unit/ml2/drivers/brocade/test_brocade_l3_plugin.py
@@ -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
18import mock
19from networking_brocade._i18n import _LI
20from neutron.db import api as db
21from neutron.tests.unit.extensions import test_l3
22from oslo_config import cfg
23from oslo_context import context as oslo_context
24from oslo_log import log as logging
25from oslo_utils import importutils
26
27LOG = logging.getLogger(__name__)
28L3_SVC_PLUGIN = ('neutron.services.l3_router.'
29 'brocade.l3_router_plugin.BrocadeSVIPlugin')
30
31
32class 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
55class TestBrocadeSVINatBase(test_l3.L3NatExtensionTestCase,
56 BrocadeSVIPlugin_TestCases):
57 pass
diff --git a/networking_brocade/vdx/ampp/tests/unit/ml2/drivers/brocade/test_brocade_mechanism_driver.py b/networking_brocade/vdx/ampp/tests/unit/ml2/drivers/brocade/test_brocade_mechanism_driver.py
new file mode 100644
index 0000000..23d038e
--- /dev/null
+++ b/networking_brocade/vdx/ampp/tests/unit/ml2/drivers/brocade/test_brocade_mechanism_driver.py
@@ -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
16import mock
17from networking_brocade.vdx.ml2driver import (
18 mechanism_brocade as brocademechanism)
19from neutron.plugins.ml2 import config as ml2_config
20from neutron.tests.unit.plugins.ml2 import test_plugin
21from oslo_log import log as logging
22from oslo_utils import importutils
23
24LOG = logging.getLogger(__name__)
25
26MECHANISM_NAME = ('networking_brocade.'
27 'vdx.ml2driver.mechanism_brocade.BrocadeMechanism')
28
29
30class 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
58class TestBrocadeMechDriverNetworksV2(test_plugin.TestMl2NetworksV2,
59 TestBrocadeMechDriverV2):
60 pass
61
62
63class TestBrocadeMechDriverPortsV2(test_plugin.TestMl2PortsV2,
64 TestBrocadeMechDriverV2):
65 pass
66
67
68class TestBrocadeMechDriverSubnetsV2(test_plugin.TestMl2SubnetsV2,
69 TestBrocadeMechDriverV2):
70 pass
71
72
73class 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)
diff --git a/networking_brocade/vdx/bare_metal/__init__.py b/networking_brocade/vdx/bare_metal/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_brocade/vdx/bare_metal/__init__.py
diff --git a/networking_brocade/vdx/bare_metal/mechanism_brocade.py b/networking_brocade/vdx/bare_metal/mechanism_brocade.py
new file mode 100644
index 0000000..111e67e
--- /dev/null
+++ b/networking_brocade/vdx/bare_metal/mechanism_brocade.py
@@ -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
19from networking_brocade._i18n import _
20from networking_brocade._i18n import _LE
21from networking_brocade._i18n import _LI
22from networking_brocade.vdx.bare_metal import util as baremetal_util
23from networking_brocade.vdx.non_ampp.ml2driver.nos import nosdriver as driver
24from neutron.common import constants as n_const
25from neutron.extensions import portbindings
26from neutron.plugins.ml2 import driver_api as api
27from oslo_config import cfg
28from oslo_log import helpers as log_helpers
29try:
30 from oslo_log import log as logging
31except ImportError:
32 from neutron.openstack.common import log as logging
33
34LOG = logging.getLogger(__name__)
35
36NOS_DRIVER = 'networking_brocade.vdx.non_ampp.ml2driver'
37'.nos.nosdriver.NOSdriver'
38ML2_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
52cfg.CONF.register_opts(ML2_BROCADE, "ml2_brocade")
53
54
55class 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."""
diff --git a/networking_brocade/vdx/bare_metal/util.py b/networking_brocade/vdx/bare_metal/util.py
new file mode 100644
index 0000000..349ee28
--- /dev/null
+++ b/networking_brocade/vdx/bare_metal/util.py
@@ -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
16from neutron.extensions import portbindings
17from neutron.plugins.ml2.common import exceptions as ml2_exc
18from neutron.plugins.ml2 import driver_api
19import oslo_i18n
20from oslo_log import helpers as log_helpers
21from oslo_log import log as logging
22import re
23
24LOG = logging.getLogger(__name__)
25RANGE_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
33def 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
102def 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
119def _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
135def 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
167def 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
181def 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
191def _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
207def 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 }
diff --git a/networking_brocade/vdx/db/__init__.py b/networking_brocade/vdx/db/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_brocade/vdx/db/__init__.py
diff --git a/networking_brocade/vdx/db/migration/__init__.py b/networking_brocade/vdx/db/migration/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_brocade/vdx/db/migration/__init__.py
diff --git a/networking_brocade/vdx/db/migration/alembic_migrations/__init__.py b/networking_brocade/vdx/db/migration/alembic_migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_brocade/vdx/db/migration/alembic_migrations/__init__.py
diff --git a/networking_brocade/vdx/db/migration/alembic_migrations/env.py b/networking_brocade/vdx/db/migration/alembic_migrations/env.py
new file mode 100644
index 0000000..30120e9
--- /dev/null
+++ b/networking_brocade/vdx/db/migration/alembic_migrations/env.py
@@ -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
15from logging.config import fileConfig
16
17from alembic import context
18from oslo_config import cfg
19from oslo_db.sqlalchemy import session
20import sqlalchemy as sa
21from sqlalchemy import event
22
23from neutron.db.migration.alembic_migrations import external
24from neutron.db.migration.models import head # noqa
25from 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.
29config = context.config
30neutron_config = config.neutron_config
31
32# Interpret the config file for Python logging.
33# This line sets up loggers basically.
34fileConfig(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
40target_metadata = model_base.BASEV2.metadata
41
42MYSQL_ENGINE = None
43BROCADE_VERSION_TABLE = 'brocade_alembic_version'
44
45
46def 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
57def 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
64def 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')
89def set_storage_engine(target, parent):
90 if MYSQL_ENGINE:
91 target.kwargs['mysql_engine'] = MYSQL_ENGINE
92
93
94def 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
120if context.is_offline_mode():
121 run_migrations_offline()
122else:
123 run_migrations_online()
diff --git a/networking_brocade/vdx/db/migration/alembic_migrations/versions/HEAD.bk b/networking_brocade/vdx/db/migration/alembic_migrations/versions/HEAD.bk
new file mode 100644
index 0000000..638ff42
--- /dev/null
+++ b/networking_brocade/vdx/db/migration/alembic_migrations/versions/HEAD.bk
@@ -0,0 +1 @@
4fadb44a1e2d \ No newline at end of file
diff --git a/networking_brocade/vdx/db/migration/alembic_migrations/versions/HEADS b/networking_brocade/vdx/db/migration/alembic_migrations/versions/HEADS
new file mode 100644
index 0000000..65e26ca
--- /dev/null
+++ b/networking_brocade/vdx/db/migration/alembic_migrations/versions/HEADS
@@ -0,0 +1,2 @@
1a84d6a05d397
24fadb44a1e2d
diff --git a/networking_brocade/vdx/db/migration/alembic_migrations/versions/kilo_release.py b/networking_brocade/vdx/db/migration/alembic_migrations/versions/kilo_release.py
new file mode 100644
index 0000000..90ee786
--- /dev/null
+++ b/networking_brocade/vdx/db/migration/alembic_migrations/versions/kilo_release.py
@@ -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
16Revision ID: kilo
17Revises: start_networking_brcd_clos
18Create Date: 2015-04-16 00:00:00.000000
19
20"""
21# revision identifiers, used by Alembic.
22revision = 'kilo'
23down_revision = 'start_ml2_brcd'
24
25
26def upgrade():
27 pass
diff --git a/networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/contract/4fadb44a1e2d_ml2_brcd_contract.py b/networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/contract/4fadb44a1e2d_ml2_brcd_contract.py
new file mode 100644
index 0000000..3aa9568
--- /dev/null
+++ b/networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/contract/4fadb44a1e2d_ml2_brcd_contract.py
@@ -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
18Revision ID: 4fadb44a1e2d
19Revises: 30d703af31fb
20Create Date: 2016-02-09 15:30:27.535472
21
22"""
23
24from neutron.db.migration import cli
25
26# revision identifiers, used by Alembic.
27revision = '4fadb44a1e2d'
28down_revision = 'kilo'
29branch_labels = None
30depends_on = None
31branch_labels = (cli.CONTRACT_BRANCH,)
32
33
34def upgrade():
35 pass
diff --git a/networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/contract/__init__.py b/networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/contract/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/contract/__init__.py
diff --git a/networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/expand/__init__.py b/networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/expand/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/expand/__init__.py
diff --git a/networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/expand/a84d6a05d397_ml2_brcd.py b/networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/expand/a84d6a05d397_ml2_brcd.py
new file mode 100644
index 0000000..a00fb98
--- /dev/null
+++ b/networking_brocade/vdx/db/migration/alembic_migrations/versions/liberty/expand/a84d6a05d397_ml2_brcd.py
@@ -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
18Revision ID: a84d6a05d397
19Revises: kilo
20Create Date: 2016-02-09 14:56:58.752583
21
22"""
23from alembic import op
24from neutron.db.migration import cli
25import sqlalchemy as sa
26
27# revision identifiers, used by Alembic.
28revision = 'a84d6a05d397'
29down_revision = 'kilo'
30branch_labels = None
31depends_on = None
32branch_labels = (cli.EXPAND_BRANCH,)
33
34
35def 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))
diff --git a/networking_brocade/vdx/db/migration/alembic_migrations/versions/start_networking_brocade_migration.py b/networking_brocade/vdx/db/migration/alembic_migrations/versions/start_networking_brocade_migration.py
new file mode 100644
index 0000000..6a4589a
--- /dev/null
+++ b/networking_brocade/vdx/db/migration/alembic_migrations/versions/start_networking_brocade_migration.py
@@ -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
18Revision ID: start_networking_brocade_migration
19Revises: None
20Create Date: 2015-02-04 11:06:18.196062
21
22"""
23
24# revision identifiers, used by Alembic.
25revision = 'start_ml2_brcd'
26down_revision = None
27
28
29def upgrade():
30 pass
31
32
33def downgrade():
34 pass
diff --git a/networking_brocade/vdx/db/models.py b/networking_brocade/vdx/db/models.py
new file mode 100644
index 0000000..f6bc925
--- /dev/null
+++ b/networking_brocade/vdx/db/models.py
@@ -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."""
23import sqlalchemy as sa
24
25from neutron.db import model_base
26from neutron.db import models_v2
27
28
29class 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
39class 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
53class 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
63def 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
78def 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
88def 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
98def 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
104def 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
113def 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
129def 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
139def 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
146def 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
153def 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
173def 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
180def 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
188def 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
196def 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
204def 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
214def update_port_state(context, port_id, admin_state_up):
215 """Update port attributes."""
216
217 session = context.session
218 with session.begin(subtransactions=True):
219 session.query(ML2_BrocadePort).filter_by(
220 id=port_id).update({'admin_state_up': admin_state_up})
diff --git a/networking_brocade/vdx/ml2driver/mechanism_brocade.py b/networking_brocade/vdx/ml2driver/mechanism_brocade.py
index 19daa5f..45e9789 100644
--- a/networking_brocade/vdx/ml2driver/mechanism_brocade.py
+++ b/networking_brocade/vdx/ml2driver/mechanism_brocade.py
@@ -16,8 +16,9 @@
16 16
17"""Implentation of Brocade ML2 Mechanism driver for ML2 Plugin.""" 17"""Implentation of Brocade ML2 Mechanism driver for ML2 Plugin."""
18 18
19from neutron.i18n import _LE 19from networking_brocade._i18n import _
20from neutron.i18n import _LI 20from networking_brocade._i18n import _LE
21from networking_brocade._i18n import _LI
21from neutron.plugins.ml2 import driver_api 22from neutron.plugins.ml2 import driver_api
22from oslo_config import cfg 23from oslo_config import cfg
23from oslo_log import log as logging 24from oslo_log import log as logging
diff --git a/networking_brocade/vdx/ml2driver/nos/nosdriver.py b/networking_brocade/vdx/ml2driver/nos/nosdriver.py
index ea65a7b..a9645da 100644
--- a/networking_brocade/vdx/ml2driver/nos/nosdriver.py
+++ b/networking_brocade/vdx/ml2driver/nos/nosdriver.py
@@ -24,8 +24,9 @@ from oslo_utils import excutils
24 24
25from xml.etree import ElementTree 25from xml.etree import ElementTree
26 26
27from networking_brocade._i18n import _
28from networking_brocade._i18n import _LE
27from networking_brocade.vdx.ml2driver.nos import nctemplates as template 29from networking_brocade.vdx.ml2driver.nos import nctemplates as template
28from neutron.i18n import _LE
29 30
30LOG = logging.getLogger(__name__) 31LOG = logging.getLogger(__name__)
31SSH_PORT = 22 32SSH_PORT = 22
diff --git a/networking_brocade/vdx/non_ampp/__init__.py b/networking_brocade/vdx/non_ampp/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_brocade/vdx/non_ampp/__init__.py
diff --git a/networking_brocade/vdx/non_ampp/ml2driver/__init__.py b/networking_brocade/vdx/non_ampp/ml2driver/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/networking_brocade/vdx/non_ampp/ml2driver/__init__.py
diff --git a/networking_brocade/vdx/non_ampp/ml2driver/brocade_fwaas_driver.py b/networking_brocade/vdx/non_ampp/ml2driver/brocade_fwaas_driver.py
new file mode 100644
index 0000000..727e881
--- /dev/null
+++ b/networking_brocade/vdx/non_ampp/ml2driver/brocade_fwaas_driver.py
@@ -0,0 +1,293 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2#
3# Copyright 2016 Brocade Networks Inc.
4# All Rights Reserved.
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17from networking_brocade._i18n import _LE
18from networking_brocade._i18n import _LW
19from networking_brocade.vdx.non_ampp.ml2driver.nos import (
20 nctemplates as template)
21from networking_brocade.vdx.non_ampp.ml2driver.nos import (
22 nosdriver as driver)
23from networking_brocade.vdx.non_ampp.ml2driver import utils
24from neutron_fwaas.services.firewall.drivers import fwaas_base
25import os.path
26from oslo_log import log as logging
27from oslo_serialization import jsonutils
28
29ACL_BATCH_SIZE = 510
30LOG = logging.getLogger(__name__)
31
32
33class BrocadeFwaasDriver(fwaas_base.FwaasDriverBase):
34
35 def __init__(self):
36 LOG.debug("Initializing fwaas Brocade driver")
37 self._driver = None
38 self._seq_id_low = None
39 self._seq_id_high = None
40 self.brocade_init()
41
42 def brocade_init(self):
43 """Brocade specific initialization."""
44 LOG.debug("brocade init BrocadeFwaas Drivers")
45 self._switch = utils.get_brocade_credentials()
46 self._svi = utils.get_brocade_l3_config()
47 self._switch['rbridge_ids'] = self._svi['rbridge_ids']
48 self._fwaas = utils.get_brocade_fwaas_config()
49 LOG.debug("FWAAS PARAMETERS seq_ids %s direction %s count %s"
50 " log %s", self._fwaas['seq_ids'],
51 self._fwaas['direction'],
52 self._fwaas['count'],
53 self._fwaas['log'])
54
55 if not ((self._fwaas['direction'] == 'both') or
56 (self._fwaas['direction'] == 'in') or
57 (self._fwaas['direction'] == 'out')):
58 LOG.warning(_LW("invalid direction %s intializing"
59 " todirection both"),
60 self._fwaas['direction'])
61 self._fwaas['direction'] = 'both'
62 self._seq_id_low, self._seq_id_high = utils.get_seq_ids(
63 self._fwaas['seq_ids'])
64 self.seq_id_bm = utils.SeqIdBitmap(int(self._seq_id_low),
65 int(self._seq_id_high))
66 self._driver = driver.NOSdriver(self._switch['address'],
67 self._switch['username'],
68 self._switch['password'])
69 self._pre_acls, self._post_acls = self.open_file_if_exists(
70 self._fwaas['acl_file'])
71 self.req = []
72 self._driver.close_session()
73
74 def open_file_if_exists(self, fname):
75 pre_acls = []
76 post_acls = []
77 if os.path.isfile(fname):
78 with open(fname, "r") as acl_file:
79 try:
80 data = jsonutils.load(acl_file)
81 if 'pre_acls' in data:
82 pre_acls = data['pre_acls']
83 if 'post_acls' in data:
84 post_acls = data['post_acls']
85 LOG.debug("pre acls : %s", pre_acls)
86 LOG.debug("post acls : %s", post_acls)
87 except Exception:
88 LOG.warning(_LW("Error Loadng %s file(may be empty file)"),
89 fname)
90 return pre_acls, post_acls
91 else:
92 LOG.warning(_LW("%s file doesn't exists"), fname)
93
94 return pre_acls, post_acls
95
96 def create_firewall(self, apply_list, firewall):
97 LOG.debug('create_firewall (%s)', firewall['id'])
98 # update firewall would take lock so no lock here
99 return self.update_firewall(apply_list, firewall)
100
101 def update_firewall(self, apply_list, firewall):
102 LOG.debug("update_firewall (%s)", firewall['id'])
103
104 if firewall['admin_state_up']:
105 return self._update_firewall(apply_list, firewall)
106 else:
107 return self.apply_default_policy(apply_list, firewall)
108
109 def delete_firewall(self, apply_list, firewall):
110 LOG.debug("delete_firewall (%s)", firewall['id'])
111
112 return self.apply_default_policy(apply_list, firewall)
113
114 def apply_default_policy(self, apply_list, firewall):
115 LOG.debug("apply_default_policy (%s)", firewall['id'])
116
117 self._clear_policy(apply_list, firewall)
118 return True
119
120 def _update_firewall(self, apply_list, firewall):
121 LOG.debug("Updating firewall (%s)", firewall['id'])
122 self._clear_policy(apply_list, firewall)
123 try:
124 self._setup_policy(apply_list, firewall)
125 except Exception as e:
126 LOG.error(_LE("_update_firewall::Error creating ACL policy :"
127 "Error: %s"), e)
128 raise e
129 return True
130
131 def _apply_policy_on_interface(self, policy_name, svi):
132 LOG.debug("brocade_fwaas:_setup_policy svi %s", svi)
133 if(self._fwaas['direction'] == 'both' or
134 self._fwaas['direction'] == 'in'):
135 for rbridge_id in self._switch['rbridge_ids']:
136 self._driver.configure_policy_on_interface(rbridge_id,
137 svi,
138 policy_name,
139 "in")
140 if(self._fwaas['direction'] == 'both' or
141 self._fwaas['direction'] == 'out'):
142 for rbridge_id in self._switch['rbridge_ids']:
143 self._driver.configure_policy_on_interface(rbridge_id,
144 svi,
145 policy_name,
146 "out")
147
148 def _is_policy_exists(self, policy_name):
149 return self._driver.is_ip_acl_exists(policy_name)
150
151 def merge_and_replay_acls(self, name):
152 if self.req:
153 all_rules = "".join(self.req)
154 acl_header = template.IP_ACL_RULE_BULKING_START.format(name=name)
155 acl_footer = template.IP_ACL_RULE_BULKING_END.format()
156 acl_netconf = acl_header + all_rules + acl_footer
157 LOG.debug("merge_and_replay_acls netconf %s", acl_netconf)
158 self._driver.create_acl_rule(acl_netconf)
159 del self.req[:]
160
161 def _config_replay_acls(self, policy_name, rule, seq_id):
162 try:
163 req = self._make_policy(policy_name, rule, seq_id)
164 self.req.append(req)
165 if len(self.req) >= ACL_BATCH_SIZE:
166 self.merge_and_replay_acls(policy_name)
167 except Exception as e:
168 LOG.error(_LE("error creating rule %s"), e)
169 raise e
170 return
171
172 def _config_replay_acls_file(self, policy_name, acl_file, seq_ids, index):
173 for rule in acl_file:
174 rule = rule['acl']
175 try:
176 self._config_replay_acls(
177 policy_name, rule, str(seq_ids[index]))
178 except Exception as e:
179 LOG.error(_LE("error _config_replay_acls_file %s"), e)
180 raise e
181 index = index + 1
182 return index
183
184 def _setup_policy(self, apply_list, fw):
185 # create zones no matter if they exist. Interfaces are added by router
186 policy_name = utils.get_firewall_object_prefix(fw)
187 num_seq_id = len(fw['firewall_rule_list']) + len(self._pre_acls) +\
188 len(self._post_acls)
189 seq_ids = self.seq_id_bm.get_seq_ids(policy_name, num_seq_id)
190 index = 0
191 try:
192 if not self._driver.is_ip_acl_exists(policy_name):
193 index = self._config_replay_acls_file(policy_name,
194 self._pre_acls,
195 seq_ids, index)
196 for rule in fw['firewall_rule_list']:
197 if not rule['enabled']:
198 continue
199 if rule['ip_version'] == 4:
200 self._config_replay_acls(policy_name, rule,
201 str(seq_ids[index]))
202 index = index + 1
203 else:
204 LOG.warning(_LW("Unsupported IP version rule."))
205 index = self._config_replay_acls_file(policy_name,
206 self._post_acls,
207 seq_ids, index)
208 self.merge_and_replay_acls(policy_name)
209
210 for ri in apply_list:
211 for svi in ri.router['svis']:
212 self._apply_policy_on_interface(policy_name, svi)
213 except Exception as e:
214 LOG.error(_LE("Error creating ACL policy :Error: %s"), e)
215 self._clear_policy(apply_list, fw)
216 raise e
217
218 def _clear_policy(self, apply_list, fw):
219 policy = utils.get_firewall_object_prefix(fw)
220 for ri in apply_list:
221 for svi in ri.router['svis']:
222 LOG.debug("brocade_fwaas:_clear_policy svi %s", svi)
223 if(self._fwaas['direction'] == 'both' or
224 self._fwaas['direction'] == 'in'):
225 for rbridge_id in self._switch['rbridge_ids']:
226 self._driver.remove_policy_on_interface(rbridge_id,
227 svi,
228 policy,
229 "in")
230 if(self._fwaas['direction'] == 'both' or
231 self._fwaas['direction'] == 'out'):
232 for rbridge_id in self._switch['rbridge_ids']:
233 self._driver.remove_policy_on_interface(rbridge_id,
234 svi,
235 policy,
236 "out")
237
238 for rbridge_id in self._switch['rbridge_ids']:
239 self._driver.delete_policy(rbridge_id, policy)
240
241 def _make_policy(self, name, rule, seq_id):
242 src_ip = 'any'
243 dst_ip = 'any'
244 src_mask = ''
245 dst_mask = ''
246 sport_operator = None
247 sport_low = None
248 sport_high = None
249 dport_operator = None
250 dport_low = None
251 dport_high = None
252 dscp = None
253 if rule.get('action') == 'allow':
254 action = 'permit'
255 else:
256 action = 'deny'
257
258 protocol = rule.get('protocol')
259 if((protocol == 'any') or (protocol is None)):
260 protocol = 'ip'
261 if ((protocol == 'tcp') or (protocol == 'udp')):
262 if 'source_port' in rule:
263 sport = rule['source_port']
264 sport_low, sport_high = utils.get_ports(sport)
265 sport_operator = utils.get_port_operator(sport_low, sport_high)
266 if 'destination_port' in rule:
267 dport = rule['destination_port']
268 dport_low, dport_high = utils.get_ports(dport)
269 dport_operator = utils.get_port_operator(dport_low,
270 dport_high)
271
272 src_address = rule.get('source_ip_address') or 'any'
273 if src_address != 'any':
274 src_ip, src_mask = utils.cidr_2_nwm(src_address)
275 dst_address = rule.get('destination_ip_address') or 'any'
276 if dst_address != 'any':
277 dst_ip, dst_mask = utils.cidr_2_nwm(dst_address)
278
279 if 'dscp' in rule:
280 dscp = str(rule.get('dscp'))
281 try:
282 xml_request = utils.make_rule(
283 name, seq_id, action, protocol, src_ip,
284 src_mask, dst_ip, dst_mask, sport_operator, sport_low,
285 sport_high, dport_operator, dport_low, dport_high,
286 self._fwaas['count'], self._fwaas['log'], dscp)
287 except Exception as e:
288 LOG.error(_LE("error _make_policy %s"), e)
289 raise e
290
291 LOG.debug("xml request %s", xml_request)
292
293 return xml_request
diff --git a/networking_brocade/vdx/non_ampp/ml2driver/brocade_fwaas_plugin.py b/networking_brocade/vdx/non_ampp/ml2driver/brocade_fwaas_plugin.py
new file mode 100644
index 0000000..093f236
--- /dev/null
+++ b/networking_brocade/vdx/non_ampp/ml2driver/brocade_fwaas_plugin.py
@@ -0,0 +1,230 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2#
3# Copyright 2016 Brocade Networks Inc.
4# All Rights Reserved.
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17from networking_brocade._i18n import _LE
18from networking_brocade._i18n import _LI
19from networking_brocade.vdx.non_ampp.ml2driver import\
20 brocade_fwaas_driver as fwaas_driver
21from networking_brocade.vdx.non_ampp.ml2driver import fwaas_plugin as plugin
22from networking_brocade.vdx.non_ampp.ml2driver import utils
23from neutron import manager
24from neutron.plugins.common import constants as const
25from neutron.plugins.common import constants as plugin_constants
26from neutron.plugins.ml2.drivers.brocade.db import models as brocade_db
27import neutron_fwaas
28from neutron_fwaas.extensions import firewall as fw_ext
29from oslo_config import cfg
30from oslo_log import log as logging
31import threading
32LOG = logging.getLogger(__name__)
33
34
35class RouterInfo(object):
36
37 def __init__(self, router):
38 self._router = router
39
40 @property
41 def router(self):
42 return self._router
43
44
45class BrocadeFirewallPlugin(plugin.FirewallPlugin):
46
47 """Implementation of the Neutron Brocade Firewall Service Plugin.
48 This class manages fwass request and response with the help
49 fwaas_driver.BrocadeFwaasDriver
50 """
51 supported_extension_aliases = ["fwaas"]
52 path_prefix = fw_ext.FIREWALL_PREFIX
53
54 def __init__(self):
55 super(BrocadeFirewallPlugin, self).__init__()
56 ext_path = neutron_fwaas.extensions.__path__[0]
57 if ext_path not in cfg.CONF.api_extensions_path.split(':'):
58 cfg.CONF.set_override('api_extensions_path',
59 cfg.CONF.api_extensions_path + ':' +
60 ext_path)
61 self._fwaas_driver = fwaas_driver.BrocadeFwaasDriver()
62 self._lock = threading.Lock()
63
64 def get_plugin_type(self):
65 return plugin_constants.FIREWALL
66
67 def _is_l3_agent_running(self, context):
68 l3plugin = manager.NeutronManager.get_service_plugins()[
69 plugin_constants.L3_ROUTER_NAT]
70 if not l3plugin:
71 LOG.error(_LE('No plugin for L3 routing registered! Will reply '
72 'no l3 agents!! '))
73 return False
74 l3_agents = l3plugin.get_l3_agents(context, True)
75 LOG.info(_LI("List of L3 agents _is_l3_agent_running %s"), l3_agents)
76 return ((l3_agents) and (len(l3_agents) > 0))
77
78 def _get_routers(self, context):
79 """get all active routers for tenant"""
80 l3plugin = manager.NeutronManager.get_service_plugins()[
81 plugin_constants.L3_ROUTER_NAT]
82 if not l3plugin:
83 routers = {}
84 LOG.error(_LE('No plugin for L3 routing registered! Will reply '
85 'to l3 agent with empty router dictionary.'))
86 return routers
87 routers = l3plugin._get_sync_routers(context)
88 for r in routers:
89 router_id = r['id']
90 tenant_id = r['tenant_id']
91 svis = brocade_db.get_list_svi_ids(context, router_id, tenant_id)
92 r['svis'] = svis
93 return routers
94
95 def handle_router_interface_add(self, context, svi, tenant_id):
96 fw_list = self.get_firewalls(context)
97 for fw in fw_list:
98 fw = self._make_firewall_dict(fw)
99 policy_name = utils.get_firewall_object_prefix(fw)
100 if fw['tenant_id'] == tenant_id and\
101 fw['status'] == const.ACTIVE:
102 try:
103 if not self._fwaas_driver._is_policy_exists(policy_name):
104 fw_with_rules = (
105 self._make_firewall_dict_with_rules(context,
106 fw['id']))
107 self._invoke_driver_for_plugin_api(context,
108 fw_with_rules,
109 'update_firewall')
110 else:
111 self._fwaas_driver._apply_policy_on_interface(
112 policy_name, svi)
113 except Exception as e:
114 LOG.error(_LE("Error adding Firewall rule to"
115 "interface %s "), e)
116 elif fw['tenant_id'] == tenant_id and\
117 fw['status'] == const.PENDING_CREATE:
118 fw_with_rules = (
119 self._make_firewall_dict_with_rules(context, fw['id']))
120 self._invoke_driver_for_plugin_api(context, fw_with_rules,
121 'update_firewall')
122 self.endpoints[0].set_firewall_status(context, fw['id'],
123 const.ACTIVE)
124
125 def create_firewall(self, context, firewall):
126 with self._lock:
127 fw = super(BrocadeFirewallPlugin, self).create_firewall(
128 context, firewall)
129 fw_with_rules = (
130 self._make_firewall_dict_with_rules(context, fw['id']))
131 self._invoke_driver_for_plugin_api(context, fw_with_rules,
132 'create_firewall')
133 return fw
134
135 def update_firewall(self, context, id, firewall):
136 with self._lock:
137 fw = super(BrocadeFirewallPlugin, self).update_firewall(context,
138 id,
139 firewall)
140 fw_with_rules = (
141 self._make_firewall_dict_with_rules(context, fw['id']))
142 self._invoke_driver_for_plugin_api(context, fw_with_rules,
143 'update_firewall')
144 return fw
145
146 def delete_firewall(self, context, id):
147 with self._lock:
148 fw_with_rules = (
149 self._make_firewall_dict_with_rules(context, id))
150 super(BrocadeFirewallPlugin, self).delete_firewall(context, id)
151 self._invoke_driver_for_plugin_api(context, fw_with_rules,
152 'delete_firewall')
153 self.endpoints[0].firewall_deleted(context, id)
154
155 def _rpc_update_firewall(self, context, firewall_id):
156 with self._lock:
157 super(BrocadeFirewallPlugin, self).\
158 _rpc_update_firewall(context,
159 firewall_id)
160 fw_with_rules = (
161 self._make_firewall_dict_with_rules(context,
162 firewall_id))
163 self._invoke_driver_for_plugin_api(context,
164 fw_with_rules,
165 'update_firewall')
166
167 def _get_router_info_list_for_tenant(self, routers, tenant_id):
168 """Returns the list of router info objects on which to apply the fw."""
169 router_info_list = []
170 for router in routers:
171 # for routers without an interface - _get_routers returns
172 # the router - but this is not yet populated in router_info
173 if router['tenant_id'] != tenant_id:
174 continue
175 LOG.info(_LI("_get_router_info_list_for_tenant router %s"), router)
176 # This is done to Keep fwaas driver code unchanged
177 ri = RouterInfo(router)
178 router_info_list.append(ri)
179 return router_info_list
180
181 def _is_interface_present_added_to_routers(self, appply_list):
182 for ri in appply_list:
183 router = ri.router
184 if router['svis']:
185 return True
186 return False
187
188 def _invoke_driver_for_plugin_api(self, context, fw, func_name):
189 """Invoke driver method for plugin API and provide status back."""
190 LOG.debug("%(func_name)s from agent for fw: %(fwid)s",
191 {'func_name': func_name, 'fwid': fw['id']})
192 try:
193 routers = self._get_routers(context)
194 router_info_list = self._get_router_info_list_for_tenant(
195 routers,
196 fw['tenant_id'])
197 if not router_info_list and func_name != 'delete_firewall':
198 LOG.debug('No Routers on tenant: %s', fw['tenant_id'])
199 # fw was created before any routers were added, and if a
200 # delete is sent then we need to ack so that plugin can
201 # cleanup.
202 return
203 elif not self._is_interface_present_added_to_routers(
204 router_info_list) and func_name != 'delete_firewall':
205 LOG.debug('No Router interface')
206 return
207 LOG.debug("Apply fw on Router List: '%s'",
208 [ri.router['id'] for ri in router_info_list])
209 # call into the driver
210 try:
211 self._fwaas_driver.__getattribute__(func_name)(
212 router_info_list,
213 fw)
214 if func_name != "delete_firewall":
215 self.endpoints[0].set_firewall_status(context, fw['id'],
216 const.ACTIVE)
217 except Exception as e:
218 LOG.error(_LE("Exception %s"), e)
219 LOG.error(_LE("Firewall Driver Error for %(func_name)s "
220 "for fw: %(fwid)s"),
221 {'func_name': func_name, 'fwid': fw['id']})
222 raise e
223
224 except Exception as e:
225 LOG.exception(
226 _LE("FWaaS RPC failure in %(func_name)s for fw: %(fwid)s"),
227 {'func_name': func_name, 'fwid': fw['id']})
228 raise e
229
230 return
diff --git a/networking_brocade/vdx/non_ampp/ml2driver/fwaas_plugin.py b/networking_brocade/vdx/non_ampp/ml2driver/fwaas_plugin.py
new file mode 100644
index 0000000..8ff2c42
--- /dev/null
+++ b/networking_brocade/vdx/non_ampp/ml2driver/fwaas_plugin.py
@@ -0,0 +1,408 @@
1# Copyright 2016 Big Switch Networks, 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
16from networking_brocade._i18n import _
17from networking_brocade._i18n import _LW
18from neutron.api.v2 import attributes as attr
19from neutron.common import exceptions as n_exception
20from neutron.common import rpc as n_rpc
21from neutron.common import topics
22from neutron import context as neutron_context
23from neutron import manager
24from neutron.plugins.common import constants as const
25from oslo_config import cfg
26from oslo_log import log as logging
27import oslo_messaging
28
29from neutron_fwaas.db.firewall import firewall_db
30from neutron_fwaas.db.firewall import firewall_router_insertion_db
31from neutron_fwaas.extensions import firewall as fw_ext
32
33
34LOG = logging.getLogger(__name__)
35
36
37class FirewallCallbacks(object):
38 target = oslo_messaging.Target(version='1.0')
39
40 def __init__(self, plugin):
41 super(FirewallCallbacks, self).__init__()
42 self.plugin = plugin
43
44 def set_firewall_status(self, context, firewall_id, status, **kwargs):
45 """Agent uses this to set a firewall's status."""
46 LOG.debug("Setting firewall %s to status: %s" % (firewall_id, status))
47 # Sanitize status first
48 if status in (const.ACTIVE, const.DOWN, const.INACTIVE):
49 to_update = status
50 else:
51 to_update = const.ERROR
52 # ignore changing status if firewall expects to be deleted
53 # That case means that while some pending operation has been
54 # performed on the backend, neutron server received delete request
55 # and changed firewall status to PENDING_DELETE
56 updated = self.plugin.update_firewall_status(
57 context, firewall_id, to_update, not_in=(const.PENDING_DELETE,))
58 if updated:
59 LOG.debug("firewall %s status set: %s" % (firewall_id, to_update))
60 return updated and to_update != const.ERROR
61
62 def firewall_deleted(self, context, firewall_id, **kwargs):
63 """Agent uses this to indicate firewall is deleted."""
64 LOG.debug("firewall_deleted() called")
65 with context.session.begin(subtransactions=True):
66 fw_db = self.plugin._get_firewall(context, firewall_id)
67 # allow to delete firewalls in ERROR state
68 if fw_db.status in (const.PENDING_DELETE, const.ERROR):
69 self.plugin.delete_db_firewall_object(context, firewall_id)
70 return True
71 else:
72 LOG.warning(_LW('Firewall %(fw)s unexpectedly'
73 ' deleted by agent, '
74 'status was %(status)s'),
75 {'fw': firewall_id, 'status': fw_db.status})
76 fw_db.update({"status": const.ERROR})
77 return False
78
79 def get_firewalls_for_tenant(self, context, **kwargs):
80 """Agent uses this to get all firewalls and rules for a tenant."""
81 LOG.debug("get_firewalls_for_tenant() called")
82 fw_list = []
83 for fw in self.plugin.get_firewalls(context):
84 fw_with_rules = self.plugin._make_firewall_dict_with_rules(
85 context, fw['id'])
86 if fw['status'] == const.PENDING_DELETE:
87 fw_with_rules['add-router-ids'] = []
88