#
# Cisco Nexus Switch Format.
# [ml2_mech_cisco_nexus:<IP address of switch>]
-# <hostname>=<port> (1)
+# <hostname>=<intf_type:port> (1)
# ssh_port=<ssh port> (2)
# username=<credential username> (3)
# password=<credential password> (4)
#
# (1) For each host connected to a port on the switch, specify the hostname
# and the Nexus physical port (interface) it is connected to.
+# Valid intf_type's are 'ethernet' and 'port-channel'.
+# The default setting for <intf_type:> is 'ethernet' and need not be
+# added to this setting.
# (2) The TCP port for connecting via SSH to manage the switch. This is
# port number 22 unless the switch has been configured otherwise.
# (3) The username for logging into the switch to manage it.
# Example:
# [ml2_mech_cisco_nexus:1.1.1.1]
# compute1=1/1
-# compute2=1/2
+# compute2=ethernet:1/2
+# compute3=port-channel:1
# ssh_port=22
# username=admin
# password=mySecretPassword
return port['status'] == n_const.PORT_STATUS_ACTIVE
def _get_switch_info(self, host_id):
+ host_connections = []
for switch_ip, attr in self._nexus_switches:
if str(attr) == str(host_id):
port_id = self._nexus_switches[switch_ip, attr]
- return port_id, switch_ip
+ if ':' in port_id:
+ intf_type, port = port_id.split(':')
+ else:
+ intf_type, port = 'ethernet', port_id
+ host_connections.append((switch_ip, intf_type, port))
+
+ if host_connections:
+ return host_connections
else:
raise excep.NexusComputeHostNotConfigured(host=host_id)
Called during update precommit port event.
"""
- port_id, switch_ip = self._get_switch_info(host_id)
- nxos_db.add_nexusport_binding(port_id, str(vlan_id), switch_ip,
- device_id)
+ host_connections = self._get_switch_info(host_id)
+ for switch_ip, intf_type, nexus_port in host_connections:
+ port_id = '%s:%s' % (intf_type, nexus_port)
+ nxos_db.add_nexusport_binding(port_id, str(vlan_id), switch_ip,
+ device_id)
def _configure_switch_entry(self, vlan_id, device_id, host_id):
"""Create a nexus switch entry.
Called during update postcommit port event.
"""
- port_id, switch_ip = self._get_switch_info(host_id)
vlan_name = cfg.CONF.ml2_cisco.vlan_name_prefix + str(vlan_id)
-
- # Check to see if this is the first binding to use this vlan on the
- # switch/port. Configure switch accordingly.
- bindings = nxos_db.get_nexusvlan_binding(vlan_id, switch_ip)
- if len(bindings) == 1:
- LOG.debug(_("Nexus: create & trunk vlan %s"), vlan_name)
- self.driver.create_and_trunk_vlan(switch_ip, vlan_id, vlan_name,
- port_id)
- else:
- LOG.debug(_("Nexus: trunk vlan %s"), vlan_name)
- self.driver.enable_vlan_on_trunk_int(switch_ip, vlan_id, port_id)
+ host_connections = self._get_switch_info(host_id)
+
+ for switch_ip, intf_type, nexus_port in host_connections:
+ # Check to see if this is the first binding to use this vlan on the
+ # switch/port. Configure switch accordingly.
+ bindings = nxos_db.get_nexusvlan_binding(vlan_id, switch_ip)
+ if len(bindings) == 1:
+ LOG.debug(_("Nexus: create & trunk vlan %s"), vlan_name)
+ self.driver.create_and_trunk_vlan(
+ switch_ip, vlan_id, vlan_name, intf_type, nexus_port)
+ else:
+ LOG.debug(_("Nexus: trunk vlan %s"), vlan_name)
+ self.driver.enable_vlan_on_trunk_int(switch_ip, vlan_id,
+ intf_type, nexus_port)
def _delete_nxos_db(self, vlan_id, device_id, host_id):
"""Delete the nexus database entry.
Called during delete precommit port event.
"""
try:
- row = nxos_db.get_nexusvm_binding(vlan_id, device_id)
- nxos_db.remove_nexusport_binding(row.port_id, row.vlan_id,
- row.switch_ip, row.instance_id)
+ rows = nxos_db.get_nexusvm_bindings(vlan_id, device_id)
+ for row in rows:
+ nxos_db.remove_nexusport_binding(
+ row.port_id, row.vlan_id, row.switch_ip, row.instance_id)
except excep.NexusPortBindingNotFound:
return
Called during update postcommit port event.
"""
- port_id, switch_ip = self._get_switch_info(host_id)
-
- # if there are no remaining db entries using this vlan on this nexus
- # switch port then remove vlan from the switchport trunk.
- try:
- nxos_db.get_port_vlan_switch_binding(port_id, vlan_id, switch_ip)
- except excep.NexusPortBindingNotFound:
- self.driver.disable_vlan_on_trunk_int(switch_ip, vlan_id, port_id)
-
+ host_connections = self._get_switch_info(host_id)
+ for switch_ip, intf_type, nexus_port in host_connections:
# if there are no remaining db entries using this vlan on this
- # nexus switch then remove the vlan.
+ # nexus switch port then remove vlan from the switchport trunk.
+ port_id = '%s:%s' % (intf_type, nexus_port)
try:
- nxos_db.get_nexusvlan_binding(vlan_id, switch_ip)
+ nxos_db.get_port_vlan_switch_binding(port_id, vlan_id,
+ switch_ip)
except excep.NexusPortBindingNotFound:
- self.driver.delete_vlan(switch_ip, vlan_id)
+ self.driver.disable_vlan_on_trunk_int(switch_ip, vlan_id,
+ intf_type, nexus_port)
+
+ # if there are no remaining db entries using this vlan on this
+ # nexus switch then remove the vlan.
+ try:
+ nxos_db.get_nexusvlan_binding(vlan_id, switch_ip)
+ except excep.NexusPortBindingNotFound:
+ self.driver.delete_vlan(switch_ip, vlan_id)
def _is_vm_migration(self, context):
if not context.bound_segment and context.original_bound_segment:
return binding
-def get_nexusvm_binding(vlan_id, instance_id):
+def get_nexusvm_bindings(vlan_id, instance_id):
"""Lists nexusvm bindings."""
- LOG.debug(_("get_nexusvm_binding() called"))
- return _lookup_first_nexus_binding(instance_id=instance_id,
- vlan_id=vlan_id)
+ LOG.debug(_("get_nexusvm_bindings() called"))
+ return _lookup_all_nexus_bindings(instance_id=instance_id,
+ vlan_id=vlan_id)
def get_port_vlan_switch_binding(port_id, vlan_id, switch_ip):
confstr = self.create_xml_snippet(confstr)
self._edit_config(nexus_host, target='running', config=confstr)
- def enable_port_trunk(self, nexus_host, interface):
- """Enable trunk mode an interface on Nexus Switch."""
- confstr = snipp.CMD_PORT_TRUNK % (interface)
- confstr = self.create_xml_snippet(confstr)
- LOG.debug(_("NexusDriver: %s"), confstr)
- self._edit_config(nexus_host, target='running', config=confstr)
-
- def disable_switch_port(self, nexus_host, interface):
- """Disable trunk mode an interface on Nexus Switch."""
- confstr = snipp.CMD_NO_SWITCHPORT % (interface)
- confstr = self.create_xml_snippet(confstr)
- LOG.debug(_("NexusDriver: %s"), confstr)
- self._edit_config(nexus_host, target='running', config=confstr)
-
- def enable_vlan_on_trunk_int(self, nexus_host, vlanid, interface):
+ def enable_vlan_on_trunk_int(self, nexus_host, vlanid, intf_type,
+ interface):
"""Enable a VLAN on a trunk interface."""
# If more than one VLAN is configured on this interface then
# include the 'add' keyword.
- if len(nexus_db_v2.get_port_switch_bindings(interface,
- nexus_host)) == 1:
+ if len(nexus_db_v2.get_port_switch_bindings(
+ '%s:%s' % (intf_type, interface), nexus_host)) == 1:
snippet = snipp.CMD_INT_VLAN_SNIPPET
else:
snippet = snipp.CMD_INT_VLAN_ADD_SNIPPET
- confstr = snippet % (interface, vlanid)
+ confstr = snippet % (intf_type, interface, vlanid, intf_type)
confstr = self.create_xml_snippet(confstr)
LOG.debug(_("NexusDriver: %s"), confstr)
self._edit_config(nexus_host, target='running', config=confstr)
- def disable_vlan_on_trunk_int(self, nexus_host, vlanid, interface):
+ def disable_vlan_on_trunk_int(self, nexus_host, vlanid, intf_type,
+ interface):
"""Disable a VLAN on a trunk interface."""
- confstr = snipp.CMD_NO_VLAN_INT_SNIPPET % (interface, vlanid)
+ confstr = (snipp.CMD_NO_VLAN_INT_SNIPPET %
+ (intf_type, interface, vlanid, intf_type))
confstr = self.create_xml_snippet(confstr)
LOG.debug(_("NexusDriver: %s"), confstr)
self._edit_config(nexus_host, target='running', config=confstr)
def create_and_trunk_vlan(self, nexus_host, vlan_id, vlan_name,
- nexus_port):
+ intf_type, nexus_port):
"""Create VLAN and trunk it on the specified ports."""
self.create_vlan(nexus_host, vlan_id, vlan_name)
LOG.debug(_("NexusDriver created VLAN: %s"), vlan_id)
if nexus_port:
- self.enable_vlan_on_trunk_int(nexus_host, vlan_id, nexus_port)
+ self.enable_vlan_on_trunk_int(nexus_host, vlan_id, intf_type,
+ nexus_port)
- def delete_and_untrunk_vlan(self, nexus_host, vlan_id, nexus_port):
+ def delete_and_untrunk_vlan(self, nexus_host, vlan_id, intf_type,
+ nexus_port):
"""Delete VLAN and untrunk it from the specified ports."""
self.delete_vlan(nexus_host, vlan_id)
if nexus_port:
- self.disable_vlan_on_trunk_int(nexus_host, vlan_id, nexus_port)
+ self.disable_vlan_on_trunk_int(nexus_host, vlan_id, intf_type,
+ nexus_port)
def create_vlan_svi(self, nexus_host, vlan_id, gateway_ip):
confstr = snipp.CMD_VLAN_SVI_SNIPPET % (vlan_id, gateway_ip)
CMD_INT_VLAN_HEADER = """
<interface>
- <ethernet>
+ <%s>
<interface>%s</interface>
<__XML__MODE_if-ethernet-switch>
<switchport>
</trunk>
</switchport>
</__XML__MODE_if-ethernet-switch>
- </ethernet>
+ </%s>
</interface>
"""
CMD_PORT_TRUNK = """
<interface>
- <ethernet>
+ <%s>
<interface>%s</interface>
<__XML__MODE_if-ethernet-switch>
<switchport></switchport>
</mode>
</switchport>
</__XML__MODE_if-ethernet-switch>
- </ethernet>
+ </%s>
</interface>
"""
CMD_NO_SWITCHPORT = """
<interface>
- <ethernet>
+ <%s>
<interface>%s</interface>
<__XML__MODE_if-ethernet-switch>
<no>
</switchport>
</no>
</__XML__MODE_if-ethernet-switch>
- </ethernet>
+ </%s>
</interface>
"""
CMD_NO_VLAN_INT_SNIPPET = """
<interface>
- <ethernet>
+ <%s>
<interface>%s</interface>
<__XML__MODE_if-ethernet-switch>
<switchport></switchport>
</trunk>
</switchport>
</__XML__MODE_if-ethernet-switch>
- </ethernet>
+ </%s>
</interface>
"""
with self._create_resources() as result:
# Verify initial database entry.
# Use port_id to verify that 1st host name was used.
- binding = nexus_db_v2.get_nexusvm_binding(VLAN_START, DEVICE_ID_1)
- self.assertEqual(binding.port_id, NEXUS_INTERFACE)
+ binding = nexus_db_v2.get_nexusvm_bindings(VLAN_START,
+ DEVICE_ID_1)[0]
+ intf_type, nexus_port = binding.port_id.split(':')
+ self.assertEqual(nexus_port, NEXUS_INTERFACE)
port = self.deserialize(self.fmt, result)
port_id = port['port']['id']
# Verify that port entry has been deleted.
self.assertRaises(c_exc.NexusPortBindingNotFound,
- nexus_db_v2.get_nexusvm_binding,
+ nexus_db_v2.get_nexusvm_bindings,
VLAN_START, DEVICE_ID_1)
# Trigger update event to bind segment with new host.
# Verify that port entry has been added using new host name.
# Use port_id to verify that 2nd host name was used.
- binding = nexus_db_v2.get_nexusvm_binding(VLAN_START, DEVICE_ID_1)
- self.assertEqual(binding.port_id, NEXUS_INTERFACE_2)
+ binding = nexus_db_v2.get_nexusvm_bindings(VLAN_START,
+ DEVICE_ID_1)[0]
+ intf_type, nexus_port = binding.port_id.split(':')
+ self.assertEqual(nexus_port, NEXUS_INTERFACE_2)
def test_nexus_config_fail(self):
"""Test a Nexus switch configuration failure.
INSTANCE_1 = 'testvm1'
INSTANCE_2 = 'testvm2'
INSTANCE_PC = 'testpcvm'
-NEXUS_PORT_1 = '1/10'
-NEXUS_PORT_2 = '1/20'
+NEXUS_PORT_1 = 'ethernet:1/10'
+NEXUS_PORT_2 = 'ethernet:1/20'
NEXUS_PORTCHANNELS = 'portchannel:2'
VLAN_ID_1 = 267
VLAN_ID_2 = 265
return nexus_db_v2.get_nexusvlan_binding(npb.vlan, npb.switch)
def _get_nexusvm_binding(self, npb):
- """Gets port bindings based on vlan and instance."""
- return nexus_db_v2.get_nexusvm_binding(npb.vlan, npb.instance)
+ """Gets port binding based on vlan and instance."""
+ return nexus_db_v2.get_nexusvm_bindings(npb.vlan, npb.instance)[0]
def _get_port_vlan_switch_binding(self, npb):
"""Gets port bindings based on port, vlan, and switch."""
self._assert_bindings_match(npb, npb22)
with testtools.ExpectedException(exceptions.NexusPortBindingNotFound):
- nexus_db_v2.get_nexusvm_binding(npb21.vlan, "dummyInstance")
+ nexus_db_v2.get_nexusvm_bindings(npb21.vlan, "dummyInstance")[0]
def test_nexusportvlanswitchbinding_get(self):
"""Tests get of port bindings based on port, vlan, and switch."""