Skip to content

Synchronise master with upstream #111

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 16 commits into
base: stackhpc/master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 53 additions & 37 deletions devstack/plugin.sh
Original file line number Diff line number Diff line change
Expand Up @@ -124,45 +124,46 @@ function configure_generic_switch {
# Generate SSH keypair
configure_generic_switch_user

sudo ovs-vsctl --may-exist add-br $GENERIC_SWITCH_TEST_BRIDGE
ip link show gs_port_01 || sudo ip link add gs_port_01 type dummy
sudo ovs-vsctl --may-exist add-port $GENERIC_SWITCH_TEST_BRIDGE $GENERIC_SWITCH_TEST_PORT
if [[ "$GENERIC_SWITCH_USER_MAX_SESSIONS" -gt 0 ]]; then
# NOTE(pas-ha) these are used for concurrent tests in tempest plugin
N_PORTS=$(($GENERIC_SWITCH_USER_MAX_SESSIONS * 2))
for ((n=0;n<$N_PORTS;n++)); do
sudo ovs-vsctl --may-exist add-port $GENERIC_SWITCH_TEST_BRIDGE ${GENERIC_SWITCH_TEST_PORT}_${n}
done
fi
if [[ "${IRONIC_NETWORK_SIMULATOR:-ovs}" == "ovs" ]]; then
sudo ovs-vsctl --may-exist add-br $GENERIC_SWITCH_TEST_BRIDGE
ip link show gs_port_01 || sudo ip link add gs_port_01 type dummy
sudo ovs-vsctl --may-exist add-port $GENERIC_SWITCH_TEST_BRIDGE $GENERIC_SWITCH_TEST_PORT
if [[ "$GENERIC_SWITCH_USER_MAX_SESSIONS" -gt 0 ]]; then
# NOTE(pas-ha) these are used for concurrent tests in tempest plugin
N_PORTS=$(($GENERIC_SWITCH_USER_MAX_SESSIONS * 2))
for ((n=0;n<$N_PORTS;n++)); do
sudo ovs-vsctl --may-exist add-port $GENERIC_SWITCH_TEST_BRIDGE ${GENERIC_SWITCH_TEST_PORT}_${n}
done
fi

if [ -e "$HOME/.ssh/id_rsa" ] && [[ "$HOST_TOPOLOGY" == "multinode" ]]; then
# NOTE(TheJulia): Reset the key pair to utilize a pre-existing key,
# this is instead of generating one, which doesn't work in multinode
# environments. This is because the keys are managed and placed by zuul.
GENERIC_SWITCH_KEY_FILE="${HOME}/.ssh/id_rsa"
fi
if [ -e "$HOME/.ssh/id_rsa" ] && [[ "$HOST_TOPOLOGY" == "multinode" ]]; then
# NOTE(TheJulia): Reset the key pair to utilize a pre-existing key,
# this is instead of generating one, which doesn't work in multinode
# environments. This is because the keys are managed and placed by zuul.
GENERIC_SWITCH_KEY_FILE="${HOME}/.ssh/id_rsa"
fi

# Create generic_switch ml2 config
for switch in $GENERIC_SWITCH_TEST_BRIDGE $IRONIC_VM_NETWORK_BRIDGE; do
local bridge_mac
bridge_mac=$(ip link show dev $switch | egrep -o "ether [A-Za-z0-9:]+"|sed "s/ether\ //")
switch="genericswitch:$switch"
add_generic_switch_to_ml2_config $switch $GENERIC_SWITCH_KEY_FILE $GENERIC_SWITCH_USER ::1 netmiko_ovs_linux "$GENERIC_SWITCH_PORT" "$bridge_mac"
done
echo "HOST_TOPOLOGY: $HOST_TOPOLOGY"
echo "HOST_TOPOLOGY_SUBNODES: $HOST_TOPOLOGY_SUBNODES"
if [ -n "$HOST_TOPOLOGY_SUBNODES" ]; then
# NOTE(vsaienko) with multinode topology we need to add switches from all
# the subnodes to the config on primary node
local cnt=0
local section
for node in $HOST_TOPOLOGY_SUBNODES; do
cnt=$((cnt+1))
section="genericswitch:sub${cnt}${IRONIC_VM_NETWORK_BRIDGE}"
add_generic_switch_to_ml2_config $section $GENERIC_SWITCH_KEY_FILE $GENERIC_SWITCH_USER $node netmiko_ovs_linux "$GENERIC_SWITCH_PORT"
# Create generic_switch ml2 config
for switch in $GENERIC_SWITCH_TEST_BRIDGE $IRONIC_VM_NETWORK_BRIDGE; do
local bridge_mac
bridge_mac=$(ip link show dev $switch | egrep -o "ether [A-Za-z0-9:]+"|sed "s/ether\ //")
switch="genericswitch:$switch"
add_generic_switch_to_ml2_config $switch $GENERIC_SWITCH_KEY_FILE $GENERIC_SWITCH_USER ::1 netmiko_ovs_linux "$GENERIC_SWITCH_PORT" "$bridge_mac"
done
echo "HOST_TOPOLOGY: $HOST_TOPOLOGY"
echo "HOST_TOPOLOGY_SUBNODES: $HOST_TOPOLOGY_SUBNODES"
if [ -n "$HOST_TOPOLOGY_SUBNODES" ]; then
# NOTE(vsaienko) with multinode topology we need to add switches from all
# the subnodes to the config on primary node
local cnt=0
local section
for node in $HOST_TOPOLOGY_SUBNODES; do
cnt=$((cnt+1))
section="genericswitch:sub${cnt}${IRONIC_VM_NETWORK_BRIDGE}"
add_generic_switch_to_ml2_config $section $GENERIC_SWITCH_KEY_FILE $GENERIC_SWITCH_USER $node netmiko_ovs_linux "$GENERIC_SWITCH_PORT"
done
fi
fi

neutron_server_config_add $GENERIC_SWITCH_INI_FILE

}
Expand All @@ -175,11 +176,22 @@ function add_generic_switch_to_ml2_config {
local device_type=$5
local port=$6
local ngs_mac_address=$7

populate_ml2_config $GENERIC_SWITCH_INI_FILE $switch_name key_file=$key_file
local password=$8
local enable_secret=$9
# Use curly braces above 9 to prevent expression expansion
local trunk_interface="${10}"

if [[ -n "$key_file" ]]; then
populate_ml2_config $GENERIC_SWITCH_INI_FILE $switch_name key_file=$key_file
elif [[ -n "$password" ]]; then
populate_ml2_config $GENERIC_SWITCH_INI_FILE $switch_name password=$password
fi
populate_ml2_config $GENERIC_SWITCH_INI_FILE $switch_name username=$username
populate_ml2_config $GENERIC_SWITCH_INI_FILE $switch_name ip=$ip
populate_ml2_config $GENERIC_SWITCH_INI_FILE $switch_name device_type=$device_type
if [[ -n "$enable_secret" ]]; then
populate_ml2_config $GENERIC_SWITCH_INI_FILE $switch_name secret=$enable_secret
fi
if [[ -n "$port" ]]; then
populate_ml2_config $GENERIC_SWITCH_INI_FILE $switch_name port=$port
fi
Expand All @@ -190,6 +202,9 @@ function add_generic_switch_to_ml2_config {
if [[ "$device_type" =~ "netmiko" && "$GENERIC_SWITCH_USER_MAX_SESSIONS" -gt 0 ]]; then
populate_ml2_config $GENERIC_SWITCH_INI_FILE $switch_name ngs_max_connections=$GENERIC_SWITCH_USER_MAX_SESSIONS
fi
if [[ -n "$trunk_interface" ]]; then
populate_ml2_config $GENERIC_SWITCH_INI_FILE $switch_name ngs_trunk_ports=$trunk_interface
fi
}

function cleanup_networking_generic_switch {
Expand Down Expand Up @@ -220,6 +235,7 @@ function ngs_configure_tempest {
if [ $GENERIC_SWITCH_USER_MAX_SESSIONS -gt 0 ]; then
iniset $TEMPEST_CONFIG ngs port_dlm_concurrency $(($GENERIC_SWITCH_USER_MAX_SESSIONS * 2))
fi
iniset $TEMPEST_CONFIG baremetal_feature_enabled trunks_supported True
}

# check for service enabled
Expand Down
85 changes: 82 additions & 3 deletions doc/source/supported-devices.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ The following devices are supported by this plugin:
* Cisco NX-OS switches (Nexus)
* Cumulus Linux (via NCLU)
* Cumulus Linux (via NVUE)
* Dell Force10
* Dell OS10
* Dell Force10 (netmiko_dell_force10)
* Dell OS10 (netmiko_dell_os10)
* Dell PowerConnect
* HPE 5900 Series switches
* Huawei switches
Expand All @@ -32,4 +32,83 @@ of any type.

These device plugins use `Netmiko <https://github.com/ktbyers/netmiko>`_
library, which in turn uses `Paramiko` library to access and configure
the switches via SSH protocol.
the switches via the SSH protocol.

Cisco Nexus (netmiko_cisco_nxos)
--------------------------------

Known working firmware versions: 10.3.7

Notes:

* Default state for switches is well suited for networking-generic-switch
as long as SSH is utilized *and* the underlying role provided to the
account permits configuration of switchports.
* Pre-configuration of upstream network trunk ports to the neutron networking
nodes is advisable, however the ``ngs_trunk_ports`` setting should be
suitable for most users as well.
* Use of an "enable" secret through the ``secret`` configuration option has
not been tested.

Dell Force10 OS9 (netmiko_dell_force10)
---------------------------------------

Known working firmware versions: 9.13.0.0

Notes:

* Dell Force10 Simulator for 9.13.0 lacks the ability to set a switchport
mode to trunk, which prevents automated or even semi-automated testing.
That being said, creating VLANs and tagging/untagging works as expected.
* Uplink switchports to the rest of the network fabric must be configured in
advance if the ``ngs_trunk_ports`` switch device level configuration
option is *not* utilized.
* Use of SSH is expected and must be configured on the remote switch.
* Set each port to "switchport" to enable L2 switchport mode.
* Use of an "enable" secret through the switch level configuration option
``secret`` was the tested path. Depending on precise switch configuration
and access control modeling, it may be possible to use without an enable
secret, but that has not been tested.

Known Issues:

* `bug 2100641 <https://bugs.launchpad.net/ironic/+bug/2100641>`_ is
alieviated by setting a port to "switchport" *before* attempting to utilize
networking-generic-switch.

Dell Force10 OS10 (netmiko_dell_os10)
-------------------------------------

Known working firmware version: 10.6.0.2.74

Notes:

* Uplink switchports may need to be configured as Trunk ports prior to the
use of networking-generic-switch through a "switchport mode trunk" command.
Further specific trunk configuration may be necessary, however NGS can
leverage the ``ngs_trunk_ports`` configuration option and does appropriately
tag switchports as permitted when creating/deleting attachments.
* Password authentication for networking-generic-switch needs to be setup in
advance, specifically "ip ssh server enable" and
"ip ssh server password-authentication" commands.
* This driver was tested *without* the use of an enable secret to
permit a higher level of configuration access within the Switch.

Sonic - Community Distribution (netmiko_sonic)
----------------------------------------------

Known working firmware version: master branch - March 2025

Notes:

* The driver expects to be able to SSH into the switch running
SONiC, execute sudo, and then execute configuration commands.
* Ports *must* be in Layer-2 mode. As such,
``sudo config interface ip remove $INTERFACE $IP_ADDRESS/$CIDR``
and ``sudo config switchport mode access $INTERFACE`` commands
may be required.
* Uplink switch ports should be configured in advance with the
``sudo config switchport mode trunk $INTERFACE`` command.
Testing for the configuraiton utilized this advanced state
configuration of the trunk uplink ports with the ``ngs_trunk_ports``
configuration option for Networking-Generic-Switch.
81 changes: 75 additions & 6 deletions networking_generic_switch/devices/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,14 @@ def __init__(self, device_cfg, device_name=""):

self._validate_network_name_format()

@property
def support_trunk_on_ports(self):
return False

@property
def support_trunk_on_bond_ports(self):
return False

def _validate_network_name_format(self):
"""Validate the network name format configuration option."""
network_name_format = self.ngs_config['ngs_network_name_format']
Expand Down Expand Up @@ -223,17 +231,78 @@ def del_network(self, segmentation_id, network_id):
pass

@abc.abstractmethod
def plug_port_to_network(self, port_id, segmentation_id):
def plug_port_to_network(self, port_id, segmentation_id,
trunk_details=None):
"""Plug port into network.

:param port_id: Then name of the switch interface
:param segmentation_id: VLAN identifier of the network used as access
or native VLAN for port.

:param trunk_details: trunk information if port is a part of trunk
"""
pass

@abc.abstractmethod
def delete_port(self, port_id, segmentation_id):
def delete_port(self, port_id, segmentation_id, trunk_details=None):
"""Delete port from specific network.

:param port_id: Then name of the switch interface
:param segmentation_id: VLAN identifier of the network used as access
or native VLAN for port.

:param trunk_details: trunk information if port is a part of trunk
"""
pass

def plug_bond_to_network(self, bond_id, segmentation_id):
def plug_bond_to_network(self, bond_id, segmentation_id,
trunk_details=None):
"""Plug bond port into network.

:param port_id: Then name of the switch interface
:param segmentation_id: VLAN identifier of the network used as access
or native VLAN for port.

:param trunk_details: trunk information if port is a part of trunk
"""
kwargs = {}
if trunk_details:
kwargs["trunk_details"] = trunk_details
# Fall back to interface method.
return self.plug_port_to_network(bond_id, segmentation_id)
return self.plug_port_to_network(bond_id, segmentation_id, **kwargs)

def unplug_bond_from_network(self, bond_id, segmentation_id):
def unplug_bond_from_network(self, bond_id, segmentation_id,
trunk_details=None):
"""Unplug bond port from network.

:param port_id: Then name of the switch interface
:param segmentation_id: VLAN identifier of the network used as access
or native VLAN for port.

:param trunk_details: trunk information if port is a part of trunk
"""
kwargs = {}
if trunk_details:
kwargs["trunk_details"] = trunk_details
# Fall back to interface method.
return self.delete_port(bond_id, segmentation_id)
return self.delete_port(bond_id, segmentation_id, **kwargs)

def add_subports_on_trunk(self, binding_profile, port_id, subports):
"""Allow subports on trunk

:param binding_profile: Binding profile of parent port
:param port_id: The name of the switch port from
Local Link Information
:param subports: List with subports objects.
"""
pass

def del_subports_on_trunk(self, binding_profile, port_id, subports):
"""Allow subports on trunk

:param binding_profile: Binding profile of parent port
:param port_id: The name of the switch port from
Local Link Information
:param subports: List with subports objects.
"""
pass
Loading