Skip to content

Commit 5354d91

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Add vlan aware VMs support"
2 parents c074c99 + ff0085a commit 5354d91

16 files changed

Lines changed: 1344 additions & 150 deletions

File tree

devstack/plugin.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ function ngs_configure_tempest {
220220
if [ $GENERIC_SWITCH_USER_MAX_SESSIONS -gt 0 ]; then
221221
iniset $TEMPEST_CONFIG ngs port_dlm_concurrency $(($GENERIC_SWITCH_USER_MAX_SESSIONS * 2))
222222
fi
223+
iniset $TEMPEST_CONFIG baremetal_feature_enabled trunks_supported True
223224
}
224225

225226
# check for service enabled

networking_generic_switch/devices/__init__.py

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,14 @@ def __init__(self, device_cfg, device_name=""):
112112

113113
self._validate_network_name_format()
114114

115+
@property
116+
def support_trunk_on_ports(self):
117+
return False
118+
119+
@property
120+
def support_trunk_on_bond_ports(self):
121+
return False
122+
115123
def _validate_network_name_format(self):
116124
"""Validate the network name format configuration option."""
117125
network_name_format = self.ngs_config['ngs_network_name_format']
@@ -223,17 +231,78 @@ def del_network(self, segmentation_id, network_id):
223231
pass
224232

225233
@abc.abstractmethod
226-
def plug_port_to_network(self, port_id, segmentation_id):
234+
def plug_port_to_network(self, port_id, segmentation_id,
235+
trunk_details=None):
236+
"""Plug port into network.
237+
238+
:param port_id: Then name of the switch interface
239+
:param segmentation_id: VLAN identifier of the network used as access
240+
or native VLAN for port.
241+
242+
:param trunk_details: trunk information if port is a part of trunk
243+
"""
227244
pass
228245

229246
@abc.abstractmethod
230-
def delete_port(self, port_id, segmentation_id):
247+
def delete_port(self, port_id, segmentation_id, trunk_details=None):
248+
"""Delete port from specific network.
249+
250+
:param port_id: Then name of the switch interface
251+
:param segmentation_id: VLAN identifier of the network used as access
252+
or native VLAN for port.
253+
254+
:param trunk_details: trunk information if port is a part of trunk
255+
"""
231256
pass
232257

233-
def plug_bond_to_network(self, bond_id, segmentation_id):
258+
def plug_bond_to_network(self, bond_id, segmentation_id,
259+
trunk_details=None):
260+
"""Plug bond port into network.
261+
262+
:param port_id: Then name of the switch interface
263+
:param segmentation_id: VLAN identifier of the network used as access
264+
or native VLAN for port.
265+
266+
:param trunk_details: trunk information if port is a part of trunk
267+
"""
268+
kwargs = {}
269+
if trunk_details:
270+
kwargs["trunk_details"] = trunk_details
234271
# Fall back to interface method.
235-
return self.plug_port_to_network(bond_id, segmentation_id)
272+
return self.plug_port_to_network(bond_id, segmentation_id, **kwargs)
236273

237-
def unplug_bond_from_network(self, bond_id, segmentation_id):
274+
def unplug_bond_from_network(self, bond_id, segmentation_id,
275+
trunk_details=None):
276+
"""Unplug bond port from network.
277+
278+
:param port_id: Then name of the switch interface
279+
:param segmentation_id: VLAN identifier of the network used as access
280+
or native VLAN for port.
281+
282+
:param trunk_details: trunk information if port is a part of trunk
283+
"""
284+
kwargs = {}
285+
if trunk_details:
286+
kwargs["trunk_details"] = trunk_details
238287
# Fall back to interface method.
239-
return self.delete_port(bond_id, segmentation_id)
288+
return self.delete_port(bond_id, segmentation_id, **kwargs)
289+
290+
def add_subports_on_trunk(self, binding_profile, port_id, subports):
291+
"""Allow subports on trunk
292+
293+
:param binding_profile: Binding profile of parent port
294+
:param port_id: The name of the switch port from
295+
Local Link Information
296+
:param subports: List with subports objects.
297+
"""
298+
pass
299+
300+
def del_subports_on_trunk(self, binding_profile, port_id, subports):
301+
"""Allow subports on trunk
302+
303+
:param binding_profile: Binding profile of parent port
304+
:param port_id: The name of the switch port from
305+
Local Link Information
306+
:param subports: List with subports objects.
307+
"""
308+
pass

networking_generic_switch/devices/netmiko_devices/__init__.py

Lines changed: 129 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from networking_generic_switch.devices import utils as device_utils
3232
from networking_generic_switch import exceptions as exc
3333
from networking_generic_switch import locking as ngs_lock
34+
from networking_generic_switch import utils as ngs_utils
3435

3536
# NOTE(TheJulia) monkey patch paramiko's get_finerprint function
3637
# to use sha256 instead of md5, since Paramiko's maintainer doesn't
@@ -97,6 +98,22 @@ class NetmikoSwitch(devices.GenericSwitchDevice):
9798

9899
SAVE_CONFIGURATION = None
99100

101+
SET_NATIVE_VLAN = None
102+
103+
DELETE_NATIVE_VLAN = None
104+
105+
SET_NATIVE_VLAN_BOND = None
106+
107+
DELETE_NATIVE_VLAN_BOND = None
108+
109+
ADD_NETWORK_TO_TRUNK = None
110+
111+
REMOVE_NETWORK_FROM_TRUNK = None
112+
113+
ADD_NETWORK_TO_BOND_TRUNK = None
114+
115+
DELETE_NETWORK_ON_BOND_TRUNK = None
116+
100117
ERROR_MSG_PATTERNS = ()
101118
"""Sequence of error message patterns.
102119
@@ -152,6 +169,14 @@ def __init__(self, device_cfg, *args, **kwargs):
152169
self.locker.start()
153170
atexit.register(self.locker.stop)
154171

172+
@property
173+
def support_trunk_on_ports(self):
174+
return bool(self.ADD_NETWORK_TO_TRUNK)
175+
176+
@property
177+
def support_trunk_on_bond_ports(self):
178+
return bool(self.ADD_NETWORK_TO_BOND_TRUNK)
179+
155180
def _format_commands(self, commands, **kwargs):
156181
if not commands:
157182
return []
@@ -284,7 +309,7 @@ def del_network(self, segmentation_id, network_id):
284309
return self.send_commands_to_device(cmds)
285310

286311
@check_output('plug port')
287-
def plug_port_to_network(self, port, segmentation_id):
312+
def plug_port_to_network(self, port, segmentation_id, trunk_details=None):
288313
cmds = []
289314
if self._disable_inactive_ports() and self.ENABLE_PORT:
290315
cmds += self._format_commands(self.ENABLE_PORT, port=port)
@@ -294,18 +319,38 @@ def plug_port_to_network(self, port, segmentation_id):
294319
self.DELETE_PORT,
295320
port=port,
296321
segmentation_id=ngs_port_default_vlan)
297-
cmds += self._format_commands(
298-
self.PLUG_PORT_TO_NETWORK,
299-
port=port,
300-
segmentation_id=segmentation_id)
322+
323+
if trunk_details:
324+
cmds += self._format_commands(self.SET_NATIVE_VLAN,
325+
port=port,
326+
segmentation_id=segmentation_id)
327+
for sub_port in trunk_details.get('sub_ports', []):
328+
cmds += self._format_commands(
329+
self.ADD_NETWORK_TO_TRUNK, port=port,
330+
segmentation_id=sub_port['segmentation_id'])
331+
else:
332+
cmds += self._format_commands(
333+
self.PLUG_PORT_TO_NETWORK,
334+
port=port,
335+
segmentation_id=segmentation_id)
336+
301337
return self.send_commands_to_device(cmds)
302338

303339
@check_output('unplug port')
304-
def delete_port(self, port, segmentation_id):
340+
def delete_port(self, port, segmentation_id, trunk_details=None):
305341
cmds = self._format_commands(self.DELETE_PORT,
306342
port=port,
307343
segmentation_id=segmentation_id)
308344
ngs_port_default_vlan = self._get_port_default_vlan()
345+
if trunk_details:
346+
cmds += self._format_commands(self.DELETE_NATIVE_VLAN,
347+
port=port,
348+
segmentation_id=segmentation_id)
349+
for sub_port in trunk_details.get('sub_ports', []):
350+
cmds += self._format_commands(
351+
self.REMOVE_NETWORK_FROM_TRUNK, port=port,
352+
segmentation_id=sub_port['segmentation_id'])
353+
309354
if ngs_port_default_vlan:
310355
# NOTE(mgoddard): Pass network_id and segmentation_id for drivers
311356
# not yet using network_name.
@@ -322,14 +367,16 @@ def delete_port(self, port, segmentation_id):
322367
segmentation_id=ngs_port_default_vlan)
323368
if self._disable_inactive_ports() and self.DISABLE_PORT:
324369
cmds += self._format_commands(self.DISABLE_PORT, port=port)
370+
325371
return self.send_commands_to_device(cmds)
326372

327373
@check_output('plug bond')
328-
def plug_bond_to_network(self, bond, segmentation_id):
374+
def plug_bond_to_network(self, bond, segmentation_id, trunk_details=None):
329375
# Fallback to regular plug port if no specialist PLUG_BOND_TO_NETWORK
330376
# commands set
331377
if not self.PLUG_BOND_TO_NETWORK:
332-
return self.plug_port_to_network(bond, segmentation_id)
378+
return self.plug_port_to_network(bond, segmentation_id,
379+
trunk_details=trunk_details)
333380
cmds = []
334381
if self._disable_inactive_ports() and self.ENABLE_BOND:
335382
cmds += self._format_commands(self.ENABLE_BOND, bond=bond)
@@ -339,22 +386,44 @@ def plug_bond_to_network(self, bond, segmentation_id):
339386
self.UNPLUG_BOND_FROM_NETWORK,
340387
bond=bond,
341388
segmentation_id=ngs_port_default_vlan)
342-
cmds += self._format_commands(
343-
self.PLUG_BOND_TO_NETWORK,
344-
bond=bond,
345-
segmentation_id=segmentation_id)
389+
390+
if trunk_details:
391+
cmds += self._format_commands(self.SET_NATIVE_VLAN_BOND,
392+
bond=bond,
393+
segmentation_id=segmentation_id)
394+
for sub_port in trunk_details.get('sub_ports', []):
395+
cmds += self._format_commands(
396+
self.ADD_NETWORK_TO_BOND_TRUNK, bond=bond,
397+
segmentation_id=sub_port['segmentation_id'])
398+
else:
399+
cmds += self._format_commands(
400+
self.PLUG_BOND_TO_NETWORK,
401+
bond=bond,
402+
segmentation_id=segmentation_id)
403+
346404
return self.send_commands_to_device(cmds)
347405

348406
@check_output('unplug bond')
349-
def unplug_bond_from_network(self, bond, segmentation_id):
407+
def unplug_bond_from_network(self, bond, segmentation_id,
408+
trunk_details=None):
350409
# Fallback to regular port delete if no specialist
351410
# UNPLUG_BOND_FROM_NETWORK commands set
352411
if not self.UNPLUG_BOND_FROM_NETWORK:
353-
return self.delete_port(bond, segmentation_id)
412+
return self.delete_port(bond, segmentation_id,
413+
trunk_details=trunk_details)
354414
cmds = self._format_commands(self.UNPLUG_BOND_FROM_NETWORK,
355415
bond=bond,
356416
segmentation_id=segmentation_id)
357417
ngs_port_default_vlan = self._get_port_default_vlan()
418+
if trunk_details:
419+
cmds += self._format_commands(self.DELETE_NATIVE_VLAN_BOND,
420+
bond=bond,
421+
segmentation_id=segmentation_id)
422+
for sub_port in trunk_details.get('sub_ports', []):
423+
cmds += self._format_commands(
424+
self.ADD_NETWORK_TO_BOND_TRUNK, bond=bond,
425+
segmentation_id=sub_port['segmentation_id'])
426+
358427
if ngs_port_default_vlan:
359428
# NOTE(mgoddard): Pass network_id and segmentation_id for drivers
360429
# not yet using network_name.
@@ -371,6 +440,7 @@ def unplug_bond_from_network(self, bond, segmentation_id):
371440
segmentation_id=ngs_port_default_vlan)
372441
if self._disable_inactive_ports() and self.DISABLE_BOND:
373442
cmds += self._format_commands(self.DISABLE_BOND, bond=bond)
443+
374444
return self.send_commands_to_device(cmds)
375445

376446
def send_config_set(self, net_connect, cmd_set):
@@ -424,3 +494,48 @@ def check_output(self, output, operation):
424494
raise exc.GenericSwitchNetmikoConfigError(
425495
config=device_utils.sanitise_config(self.config),
426496
error=msg)
497+
498+
def add_subports_on_trunk(self, binding_profile, port_id, subports):
499+
"""Allow subports on trunk
500+
501+
:param binding_profile: Binding profile of parent port
502+
:param port_id: The name of the switch port from
503+
Local Link Information
504+
:param subports: List with subports objects.
505+
"""
506+
cmds = []
507+
is_802_3ad = ngs_utils.is_802_3ad(binding_profile)
508+
509+
for sub_port in subports:
510+
if is_802_3ad:
511+
cmds += self._format_commands(
512+
self.ADD_NETWORK_TO_BOND_TRUNK, bond=port_id,
513+
segmentation_id=sub_port['segmentation_id'])
514+
else:
515+
cmds += self._format_commands(
516+
self.ADD_NETWORK_TO_TRUNK, port=port_id,
517+
segmentation_id=sub_port['segmentation_id'])
518+
return self.send_commands_to_device(cmds)
519+
520+
def del_subports_on_trunk(self, binding_profile, port_id, subports):
521+
"""Allow subports on trunk
522+
523+
:param binding_profile: Binding profile of parent port
524+
:param port_id: The name of the switch port from
525+
Local Link Information
526+
:param subports: List with subports objects.
527+
"""
528+
529+
cmds = []
530+
is_802_3ad = ngs_utils.is_802_3ad(binding_profile)
531+
532+
for sub_port in subports:
533+
if is_802_3ad:
534+
cmds += self._format_commands(
535+
self.DELETE_NETWORK_ON_BOND_TRUNK, bond=port_id,
536+
segmentation_id=sub_port['segmentation_id'])
537+
else:
538+
cmds += self._format_commands(
539+
self.REMOVE_NETWORK_FROM_TRUNK, port=port_id,
540+
segmentation_id=sub_port['segmentation_id'])
541+
return self.send_commands_to_device(cmds)

networking_generic_switch/devices/netmiko_devices/arista.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,26 @@ class AristaEos(netmiko_devices.NetmikoSwitch):
3737
'no switchport mode trunk',
3838
'switchport trunk allowed vlan none'
3939
)
40+
41+
SET_NATIVE_VLAN = (
42+
'interface {port}',
43+
'switchport mode trunk',
44+
'switchport trunk native vlan {segmentation_id}',
45+
'switchport trunk allowed vlan add {segmentation_id}'
46+
)
47+
48+
DELETE_NATIVE_VLAN = (
49+
'interface {port}',
50+
'no switchport trunk native vlan {segmentation_id}',
51+
'switchport trunk allowed vlan remove {segmentation_id}',
52+
)
53+
54+
ADD_NETWORK_TO_TRUNK = (
55+
'interface {port}',
56+
'switchport trunk allowed vlan add {segmentation_id}'
57+
)
58+
59+
REMOVE_NETWORK_FROM_TRUNK = (
60+
'interface {port}',
61+
'switchport trunk allowed vlan remove {segmentation_id}'
62+
)

networking_generic_switch/devices/netmiko_devices/cisco.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,31 @@ class CiscoIos(netmiko_devices.NetmikoSwitch):
3939
'switchport trunk allowed vlan none'
4040
)
4141

42+
SET_NATIVE_VLAN = (
43+
'interface {port}',
44+
'switchport mode trunk',
45+
'switchport trunk native vlan {segmentation_id}',
46+
'switchport trunk allowed vlan add {segmentation_id}',
47+
)
48+
49+
DELETE_NATIVE_VLAN = (
50+
'interface {port}',
51+
'no switchport mode trunk',
52+
'no switchport trunk native vlan {segmentation_id}',
53+
'switchport trunk allowed vlan remove {segmentation_id}',
54+
)
55+
56+
ADD_NETWORK_TO_TRUNK = (
57+
'interface {port}',
58+
'switchport mode trunk',
59+
'switchport trunk allowed vlan add {segmentation_id}',
60+
)
61+
62+
REMOVE_NETWORK_FROM_TRUNK = (
63+
'interface {port}',
64+
'switchport trunk allowed vlan remove {segmentation_id}',
65+
)
66+
4267

4368
class CiscoNxOS(netmiko_devices.NetmikoSwitch):
4469
"""Netmiko device driver for Cisco Nexus switches running NX-OS."""

0 commit comments

Comments
 (0)