Support linux bridge in addition to OVS

While OVS was used initially due to availability of a
networking-generic-switch driver for it, Linux bridge can be useful for
environments where OVS is not available.

This is configured via bridge_type variable. It defaults to
'openvswitch', but may be set to 'linuxbridge'.

Change-Id: I750a73cebc743edcbcd8c23c67e4920d0058bead
This commit is contained in:
Mark Goddard 2020-03-06 17:44:41 +00:00
parent f2560ae00f
commit ced8a4a528
15 changed files with 183 additions and 60 deletions

View File

@ -35,11 +35,11 @@ class FilterModule(object):
return {
# Network name filters.
'bridge_name': bridge_name,
'ovs_link_name': ovs_link_name,
'peer_link_name': peer_link_name,
'physnet_index_to_name': physnet_index_to_name,
'physnet_name_to_index': physnet_name_to_index,
'source_link_name': source_link_name,
'source_to_ovs_link_name': source_to_ovs_link_name,
'source_to_peer_link_name': source_to_peer_link_name,
'source_link_to_physnet_name': source_link_to_physnet_name,
# Libvirt filters.
@ -104,7 +104,7 @@ def set_libvirt_start_params(node):
@contextfilter
def bridge_name(context, physnet, inventory_hostname=None):
"""Get the Tenks OVS bridge name from a physical network name.
"""Get the Tenks bridge name from a physical network name.
"""
return (_get_hostvar(context, 'bridge_prefix',
inventory_hostname=inventory_hostname) +
@ -123,22 +123,22 @@ def source_link_name(context, node, physnet, inventory_hostname=None):
@contextfilter
def ovs_link_name(context, node, physnet, inventory_hostname=None):
"""Get the OVS veth link name for a node/physnet combination.
def peer_link_name(context, node, physnet, inventory_hostname=None):
"""Get the peer veth link name for a node/physnet combination.
"""
return (_link_name(context, node, physnet,
inventory_hostname=inventory_hostname) +
_get_hostvar(context, 'veth_node_ovs_suffix',
_get_hostvar(context, 'veth_node_peer_suffix',
inventory_hostname=inventory_hostname))
@contextfilter
def source_to_ovs_link_name(context, source, inventory_hostname=None):
"""Get the corresponding OVS link name for a source link name.
def source_to_peer_link_name(context, source, inventory_hostname=None):
"""Get the corresponding peer link name for a source link name.
"""
base = source[:-len(_get_hostvar(context, 'veth_node_source_suffix',
inventory_hostname=inventory_hostname))]
return base + _get_hostvar(context, 'veth_node_ovs_suffix',
return base + _get_hostvar(context, 'veth_node_peer_suffix',
inventory_hostname=inventory_hostname)

View File

@ -6,6 +6,11 @@ physnet_mappings: {}
system_requirements:
- "python{% if ansible_python.version.major == 3 %}3{% endif %}-virtualenv"
# Tenks bridge type. Options are "openvswitch", "linuxbridge". Default is
# "openvswitch". Note that this relates to bridges created by Tenks, not the
# source devices in physnet_mappings.
bridge_type: "openvswitch"
# Naming scheme for bridges created by tenks for physical networks is
# {{ bridge_prefix + i }}, where `i` is the index of the physical network in
# physnet_mappings (sorted alphabetically by key).
@ -14,13 +19,13 @@ bridge_prefix: brtenks
# Prefix for all veth links.
veth_prefix: 'p-'
# Suffix for veth links attached to a Tenks OVS bridge.
veth_bridge_ovs_suffix: '-ovs'
# Suffix for veth links attached to a Tenks bridge.
veth_bridge_peer_suffix: '-{% if bridge_type == "openvswitch" %}ovs{% else %}br{% endif %}'
# Suffix for veth links attached to a source Linux bridge.
veth_bridge_source_suffix: '-phy'
# Suffix for veth links attached to a Tenks OVS bridge.
veth_node_ovs_suffix: '-ovs'
# Suffix for veth links attached to a Tenks bridge.
veth_node_peer_suffix: '-{% if bridge_type == "openvswitch" %}ovs{% else %}br{% endif %}'
# Suffix for veth links attached to a node. Nodes aren't physical so '-phy'
# doesn't seem right.
veth_node_source_suffix: '-tap'

View File

@ -28,19 +28,21 @@
# Don't remove log directory during teardown to preserve historical logs.
when: cmd != 'teardown'
- name: Check if ovs-vsctl command is present
command: ovs-vsctl --version
register: ovs_vsctl_check
failed_when: false
changed_when: false
- block:
- name: Check if ovs-vsctl command is present
command: ovs-vsctl --version
register: ovs_vsctl_check
failed_when: false
changed_when: false
- name: Fail when Open vSwitch is not installed
fail:
msg: >-
Tenks requires openvswitch to be installed and running. Please install
openvswitch. If it is installed, please report this as a bug.
# Assume a non-zero return code means that openvswitch is not installed.
when: ovs_vsctl_check.rc != 0
- name: Fail when Open vSwitch is not installed
fail:
msg: >-
Tenks requires openvswitch to be installed and running. Please install
openvswitch. If it is installed, please report this as a bug.
# Assume a non-zero return code means that openvswitch is not installed.
when: ovs_vsctl_check.rc != 0
when: bridge_type == "openvswitch"
- name: Configure physical networks
include_tasks: physical_network.yml

View File

@ -20,8 +20,9 @@
include_role:
name: veth-pair
vars:
veth_pair_ovs_bridge: "{{ physnet.1 | bridge_name }}"
veth_pair_ovs_link_name: "{{ physnet.0 | ovs_link_name(physnet.1) }}"
veth_pair_peer_bridge_type: "{{ bridge_type }}"
veth_pair_peer_bridge: "{{ physnet.1 | bridge_name }}"
veth_pair_peer_link_name: "{{ physnet.0 | peer_link_name(physnet.1) }}"
veth_pair_source_link_name: "{{ physnet.0 | source_link_name(physnet.1) }}"
veth_pair_state: "{{ physnet.0.get('state', 'present') }}"
# Loop over each physical network for each node allocated to this host.

View File

@ -32,7 +32,7 @@
- name: Register source interface as a Linux bridge
set_fact:
source_type: linux_bridge
source_type: linuxbridge
when: if_details.stdout_lines[-1].split()[0] == 'bridge'
- block:
@ -44,7 +44,7 @@
- name: Register source interface as an Open vSwitch bridge
set_fact:
source_type: ovs_bridge
source_type: openvswitch
when: source_interface in ovs_bridges.stdout_lines
when: if_details.stdout_lines[-1].split()[0] == 'openvswitch'
@ -56,15 +56,44 @@
bridge: "{{ tenks_bridge }}"
state: "{{ state }}"
become: true
when: bridge_type == "openvswitch"
- block:
- name: Check if Tenks bridge exists
stat:
path: /sys/class/net/{{ tenks_bridge }}
register: stat_result
- name: Ensure Tenks bridge exists
vars:
link_operation: "{{ 'add' if state == 'present' else 'del' }}"
command: >-
{{ tenks_ip_path }} link {{ link_operation }} {{ tenks_bridge }} type bridge
changed_when: true
become: true
when: >-
state == 'present' and not stat_result.stat.exists or
state == 'absent' and stat_result.stat.exists
- name: Ensure Tenks bridge is up
command: >-
{{ tenks_ip_path }} link set {{ tenks_bridge }} up
changed_when: true
become: true
when:
- state == 'present'
- not stat_result.stat.exists
when: bridge_type == "linuxbridge"
- name: Configure existing Linux bridge
when: source_type == 'linux_bridge'
when: source_type == 'linuxbridge'
include_role:
name: veth-pair
vars:
veth_pair_ovs_bridge: "{{ tenks_bridge }}"
veth_pair_ovs_link_name: >-
{{ veth_prefix + tenks_bridge + veth_bridge_ovs_suffix }}
veth_pair_peer_bridge_type: "{{ bridge_type }}"
veth_pair_peer_bridge: "{{ tenks_bridge }}"
veth_pair_peer_link_name: >-
{{ veth_prefix + tenks_bridge + veth_bridge_peer_suffix }}
veth_pair_source_bridge: "{{ source_interface }}"
veth_pair_source_link_name: >-
{{ veth_prefix + tenks_bridge + veth_bridge_source_suffix }}
@ -72,16 +101,16 @@
veth_pair_state: "{{ state }}"
- name: Configure existing Open vSwitch bridge
when: source_type == 'ovs_bridge'
when: source_type == 'openvswitch'
block:
- name: Configure patch port on Tenks bridge
openvswitch_port:
bridge: "{{ tenks_bridge }}"
port: "{{ veth_prefix + tenks_bridge + veth_bridge_ovs_suffix }}"
port: "{{ veth_prefix + tenks_bridge + veth_bridge_peer_suffix }}"
# Despite the module documentation, `set` will happily take multiple
# properties.
set: >-
Interface {{ veth_prefix + tenks_bridge + veth_bridge_ovs_suffix }}
Interface {{ veth_prefix + tenks_bridge + veth_bridge_peer_suffix }}
type=patch
options:peer={{ veth_prefix + tenks_bridge +
veth_bridge_source_suffix }}
@ -98,7 +127,7 @@
Interface {{ veth_prefix + tenks_bridge + veth_bridge_source_suffix }}
type=patch
options:peer={{ veth_prefix + tenks_bridge +
veth_bridge_ovs_suffix }}
veth_bridge_peer_suffix }}
state: "{{ state }}"
become: true
@ -108,6 +137,28 @@
port: "{{ source_interface }}"
state: "{{ state }}"
when:
- bridge_type == 'openvswitch'
- source_type == 'direct'
# If 'absent', we've already deleted the bridge earlier, so no need to
# unplug the interface.
- state != 'absent'
become: true
- block:
- name: Speculatively check interface's master
command: >-
realpath /sys/class/net/{{ source_interface }}/master
register: master_result
failed_when: false
changed_when: false
- name: Plug source interface into Tenks bridge
command: >-
{{ tenks_ip_path }} link set dev {{ source_interface }} master {{ tenks_bridge }}
changed_when: true
when: master_result.rc != 0
when:
- bridge_type == 'linuxbridge'
- source_type == 'direct'
# If 'absent', we've already deleted the bridge earlier, so no need to
# unplug the interface.

View File

@ -36,7 +36,7 @@
switch_info: "{{ bridge }}"
port_id: >-
{{ source_interface
| source_to_ovs_link_name(inventory_hostname=ironic_hypervisor) }}
| source_to_peer_link_name(inventory_hostname=ironic_hypervisor) }}
command: >-
'{{ ironic_virtualenv_path }}/bin/openstack' baremetal port set
{{ uuid.stdout }}

View File

@ -4,7 +4,7 @@ Veth Pair
This role manages a veth pair. Actions:
* If `veth_pair_state` is `present`, it will create the veth pair and
plug one end into the specified OVS bridge. If `veth_pair_plug_into_source`
plug one end into the specified peer bridge. If `veth_pair_plug_into_source`
is enabled, it will also plug the other end into/from a source Linux
bridge.
@ -15,14 +15,18 @@ This role manages a veth pair. Actions:
Requirements
------------
The host should have the `ip` and `ovs-vsctl` commands accessible.
The host should have the `ip` command available. If
`veth_pair_peer_bridge_type` is `openvswitch`, or `veth_pair_source_link_name`
is an OVS bridge, the `ovs-vsctl` command should also be accessible.
Role Variables
--------------
- `veth_pair_ovs_link_name`: The name to give the veth link that plugs into the
OVS bridge.
- `veth_pair_ovs_bridge`: The name of the OVS bridge to plug into.
- `veth_pair_peer_bridge_type`: The type of the peer bridge. One of
`openvswitch`, or `linuxbridge`.
- `veth_pair_peer_link_name`: The name to give the veth link that plugs into
the peer bridge.
- `veth_pair_peer_bridge`: The name of the peer bridge to plug into.
- `veth_pair_source_link_name`: The name to give the veth link that plugs into
the source device.
- `veth_pair_source_bridge`: The name of the source Linux bridge to plug into. Must be

View File

@ -15,7 +15,7 @@
- name: Delete veth pair
command: >-
ip link del dev {{ veth_pair_ovs_link_name }}
ip link del dev {{ veth_pair_peer_link_name }}
type veth
peer name {{ veth_pair_source_link_name }}
register: res

View File

@ -1,7 +1,7 @@
---
- name: Create veth pair
command: >-
ip link add dev {{ veth_pair_ovs_link_name }}
ip link add dev {{ veth_pair_peer_link_name }}
type veth
peer name {{ veth_pair_source_link_name }}
register: res
@ -13,7 +13,7 @@
- name: Bring each end of veth up
command: ip link set {{ item }} up
loop:
- "{{ veth_pair_ovs_link_name }}"
- "{{ veth_pair_peer_link_name }}"
- "{{ veth_pair_source_link_name }}"
become: true
# if the interface is already up, this ultimately ends up being a noop, see:
@ -22,10 +22,26 @@
- name: Plug veth into OVS bridge
openvswitch_port:
bridge: "{{ veth_pair_ovs_bridge }}"
port: "{{ veth_pair_ovs_link_name }}"
bridge: "{{ veth_pair_peer_bridge }}"
port: "{{ veth_pair_peer_link_name }}"
when: veth_pair_peer_bridge_type == "openvswitch"
become: true
- block:
- include_tasks: is-attached.yml
vars:
bridge: "{{ veth_pair_peer_bridge }}"
interface: "{{ veth_pair_peer_link_name }}"
- name: Plug veth into source bridge
command: >-
ip link set {{ veth_pair_peer_link_name }} master
{{ veth_pair_peer_bridge }}
when:
- not veth_pair_is_attached
become: true
when: veth_pair_peer_bridge_type == "linuxbridge"
- block:
- include_tasks: is-attached.yml
vars:

View File

@ -49,6 +49,11 @@ are required for different hosts, you will need to individually specify them in
an inventory host_vars file: for a host with hostname *myhost*, set
``physnet_mappings`` within the file ``ansible/inventory/host_vars/myhost``.
Another variable that may be useful is ``bridge_type``. This may be either
``openvswitch`` (default) or ``linuxbridge``, and defines the type of bridges
created by Tenks. This may be different from the type of interfaces or bridges
in ``physnet_mappings``.
Standalone Ironic
-----------------

View File

@ -16,6 +16,7 @@
chdir: "{{ tenks_src_dir }}"
environment:
ANSIBLE_ROLES_PATH: "{{ tenks_src_dir }}/ansible/roles"
when: bridge_type == 'openvswitch'
- name: Deploy tenks cluster
shell:

View File

@ -26,4 +26,6 @@ nova_flavors: []
physnet_mappings:
physnet1: breth1
bridge_type: {{ bridge_type }}
python_upper_constraints_url: file://{{ upper_constraints_path }}

View File

@ -21,3 +21,15 @@
- ^releasenotes/.*
- ^setup.cfg$
- ^tox.ini$
- job:
name: tenks-deploy-teardown-ovs-base
parent: tenks-deploy-teardown-base
vars:
bridge_type: openvswitch
- job:
name: tenks-deploy-teardown-linuxbridge-base
parent: tenks-deploy-teardown-base
vars:
bridge_type: linuxbridge

View File

@ -8,20 +8,38 @@
tox_envlist: alint
- job:
name: tenks-deploy-teardown-centos7
parent: tenks-deploy-teardown-base
name: tenks-deploy-teardown-ovs-centos7
parent: tenks-deploy-teardown-ovs-base
nodeset: centos-7
required-projects:
- name: openstack/requirements
override-checkout: stable/train
- job:
name: tenks-deploy-teardown-centos8
parent: tenks-deploy-teardown-base
name: tenks-deploy-teardown-ovs-centos8
parent: tenks-deploy-teardown-ovs-base
nodeset: centos-8
- job:
name: tenks-deploy-teardown-ubuntu
parent: tenks-deploy-teardown-base
name: tenks-deploy-teardown-ovs-ubuntu
parent: tenks-deploy-teardown-ovs-base
nodeset: ubuntu-bionic
- job:
name: tenks-deploy-teardown-linuxbridge-centos7
parent: tenks-deploy-teardown-linuxbridge-base
nodeset: centos-7
required-projects:
- name: openstack/requirements
override-checkout: stable/train
- job:
name: tenks-deploy-teardown-linuxbridge-centos8
parent: tenks-deploy-teardown-linuxbridge-base
nodeset: centos-8
- job:
name: tenks-deploy-teardown-linuxbridge-ubuntu
parent: tenks-deploy-teardown-linuxbridge-base
nodeset: ubuntu-bionic

View File

@ -9,9 +9,12 @@
check:
jobs:
- tenks-tox-ansible-lint
- tenks-deploy-teardown-centos7
- tenks-deploy-teardown-centos8
- tenks-deploy-teardown-ubuntu
- tenks-deploy-teardown-ovs-centos7
- tenks-deploy-teardown-ovs-centos8
- tenks-deploy-teardown-ovs-ubuntu
- tenks-deploy-teardown-linuxbridge-centos7
- tenks-deploy-teardown-linuxbridge-centos8
- tenks-deploy-teardown-linuxbridge-ubuntu
# Until we have ironic jobs using tenks, gate on the kayobe overcloud
# deploy job, which uses tenks to test bare metal compute provisioning.
- kayobe-overcloud-centos8
@ -19,9 +22,12 @@
queue: tenks
jobs:
- tenks-tox-ansible-lint
- tenks-deploy-teardown-centos7
- tenks-deploy-teardown-centos8
- tenks-deploy-teardown-ubuntu
- tenks-deploy-teardown-ovs-centos7
- tenks-deploy-teardown-ovs-centos8
- tenks-deploy-teardown-ovs-ubuntu
- tenks-deploy-teardown-linuxbridge-centos7
- tenks-deploy-teardown-linuxbridge-centos8
- tenks-deploy-teardown-linuxbridge-ubuntu
# Until we have ironic jobs using tenks, gate on the kayobe overcloud
# deploy job, which uses tenks to test bare metal compute provisioning.
- kayobe-overcloud-centos8