3131from networking_generic_switch .devices import utils as device_utils
3232from networking_generic_switch import exceptions as exc
3333from 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 )
0 commit comments