Skip to content

Commit

Permalink
Support disabling inactive links
Browse files Browse the repository at this point in the history
Currently, when a port is unbound by NGS, this is typically implemented
by removing the VLAN association from the corresponding switch
interface. This puts the interface on the default VLAN of the switch,
and leaves it administratively up (active). This may be an issue in some
scenarios, such as:

* If there is more than one interface on the server, subsequent
  instances may choose not to attach a network to one or more
  interfaces. If these interfaces are active on a default VLAN this
  would be a security hole.

* If configuration of an interface fails but is silently ignored by NGS,
  the interface will remain on the default VLAN.

To avoid these issues this change adds support for administratively
disabling ports when they are not in use. This behaviour is optional,
since it might not be appropriate on all devices or in all scenarios.
Configuration of the behaviour is controlled by a per-device config
flag, 'ngs_disable_inactive_ports'.

Change-Id: Ibdbb871d7f3e9ad0d3ade1049cc09a2da5e36fab
Story: 2003391
Task: 24511
  • Loading branch information
markgoddard committed Aug 30, 2018
1 parent cd0fa3c commit e373156
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 9 deletions.
11 changes: 11 additions & 0 deletions networking_generic_switch/devices/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
{'name': 'ngs_ssh_connect_timeout', 'default': 60},
{'name': 'ngs_ssh_connect_interval', 'default': 10},
{'name': 'ngs_max_connections', 'default': 1},
# If True, disable switch ports that are not in use.
{'name': 'ngs_disable_inactive_ports', 'default': False},
]


Expand Down Expand Up @@ -91,6 +93,15 @@ def _get_physical_networks(self):
return []
return physnets.split(',')

@staticmethod
def _str_to_bool(value):
truthy = ('true', 'yes', '1')
return str(value).lower() in truthy

def _disable_inactive_ports(self):
"""Return whether inactive ports should be disabled."""
return self._str_to_bool(self.ngs_config['ngs_disable_inactive_ports'])

@abc.abstractmethod
def add_network(self, segmentation_id, network_id):
pass
Expand Down
25 changes: 17 additions & 8 deletions networking_generic_switch/devices/netmiko_devices/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ class NetmikoSwitch(devices.GenericSwitchDevice):

DELETE_PORT = None

ENABLE_PORT = None

DISABLE_PORT = None

PLUG_TRUNK_PORT_TO_NETWORK = None

UNPLUG_TRUNK_PORT_FROM_NETWORK = None
Expand Down Expand Up @@ -179,16 +183,21 @@ def del_network(self, segmentation_id, network_id):
self.send_commands_to_device(cmds)

def plug_port_to_network(self, port, segmentation_id):
self.send_commands_to_device(
self._format_commands(self.PLUG_PORT_TO_NETWORK,
port=port,
segmentation_id=segmentation_id))
cmds = []
if self._disable_inactive_ports() and self.ENABLE_PORT:
cmds += self._format_commands(self.ENABLE_PORT, port=port)
cmds += self._format_commands(self.PLUG_PORT_TO_NETWORK,
port=port,
segmentation_id=segmentation_id)
self.send_commands_to_device(cmds)

def delete_port(self, port, segmentation_id):
self.send_commands_to_device(
self._format_commands(self.DELETE_PORT,
port=port,
segmentation_id=segmentation_id))
cmds = self._format_commands(self.DELETE_PORT,
port=port,
segmentation_id=segmentation_id)
if self._disable_inactive_ports() and self.DISABLE_PORT:
cmds += self._format_commands(self.DISABLE_PORT, port=port)
self.send_commands_to_device(cmds)

def send_config_set(self, net_connect, cmd_set):
"""Send a set of configuration lines to the device.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,27 @@ def test_plug_port_to_network(self, m_sctd):
self.switch.plug_port_to_network(2222, 22)
m_sctd.assert_called_with([])

@mock.patch('networking_generic_switch.devices.netmiko_devices.'
'NetmikoSwitch.send_commands_to_device')
def test_plug_port_to_network_disable_inactive(self, m_sctd):
switch = self._make_switch_device(
{'ngs_disable_inactive_ports': 'true'})
switch.plug_port_to_network(2222, 22)
m_sctd.assert_called_with([])

@mock.patch('networking_generic_switch.devices.netmiko_devices.'
'NetmikoSwitch.send_commands_to_device')
def test_delete_port(self, m_sctd):
self.switch.delete_port(2222, 22)
m_sctd.assert_called_with(None)
m_sctd.assert_called_with([])

@mock.patch('networking_generic_switch.devices.netmiko_devices.'
'NetmikoSwitch.send_commands_to_device')
def test_delete_port_disable_inactive(self, m_sctd):
switch = self._make_switch_device(
{'ngs_disable_inactive_ports': 'true'})
switch.delete_port(2222, 22)
m_sctd.assert_called_with([])

def test__format_commands(self):
self.switch._format_commands(
Expand Down

0 comments on commit e373156

Please sign in to comment.