Support Neutron VLAN networks

For VLAN networks we need to use a tagged Linux bridge on the controller with a
veth pair to link it to the corresponding Neutron OVS bridge. This must be done
for the physical network(s) carrying the provisioning, tenant, and external
network traffic. We also need untagged VLAN subinterfaces on the tagged bridge
for the controller to communicate on these networks with.

The network interface role in use requires that we use two passes through
interface configuration to ensure that VLAN subinterfaces can be added to
bridge interfaces.

Finally, we must configure Ironic with the name of the Neutron network used
for provisioning.
This commit is contained in:
Mark Goddard 2017-03-24 15:30:20 +00:00
parent 7b2be06725
commit 26be2c5af3
9 changed files with 146 additions and 56 deletions

View File

@ -157,6 +157,11 @@ def net_is_bridge(context, name, inventory_hostname=None):
return net_bridge_ports(context, name) is not None
@jinja2.contextfilter
def net_is_vlan(context, name, inventory_hostname=None):
return net_vlan(context, name) is not None
@jinja2.contextfilter
def net_select_ethers(context, names):
return [name for name in names if net_is_ether(context, name)]
@ -167,6 +172,16 @@ def net_select_bridges(context, names):
return [name for name in names if net_is_bridge(context, name)]
@jinja2.contextfilter
def net_select_vlans(context, names):
return [name for name in names if net_is_vlan(context, name)]
@jinja2.contextfilter
def net_reject_vlans(context, names):
return [name for name in names if not net_is_vlan(context, name)]
@jinja2.contextfilter
def net_configdrive_network_device(context, name, inventory_hostname=None):
device = net_interface(context, name, inventory_hostname)
@ -212,7 +227,10 @@ class FilterModule(object):
'net_bridge_obj': net_bridge_obj,
'net_is_ether': net_is_ether,
'net_is_bridge': net_is_bridge,
'net_is_vlan': net_is_vlan,
'net_select_ethers': net_select_ethers,
'net_select_bridges': net_select_bridges,
'net_select_vlans': net_select_vlans,
'net_reject_vlans': net_reject_vlans,
'net_configdrive_network_device': net_configdrive_network_device,
}

View File

@ -0,0 +1,16 @@
---
###############################################################################
# Ironic configuration.
# List of enabled Ironic drivers.
kolla_ironic_drivers:
- agent_ssh
- agent_ipmitool
- pxe_ssh
- pxe_ipmitool
# Name of the Neutron network to use for cleaning.
kolla_ironic_cleaning_network: 'provision-net'
# Name of the Neutron network to use for provisioning.
kolla_ironic_provisioning_network: 'provision-net'

View File

@ -20,6 +20,7 @@
}]
}}
with_items: "{{ network_interfaces }}"
when: "{{ item|net_cidr != None }}"
roles:
- role: ip-allocation
ip_allocation_filename: "{{ kayobe_config_path }}/network-allocation.yml"

View File

@ -52,24 +52,35 @@
kolla_cluster_interface: "{{ storage_mgmt_net_name | net_interface(controller_host) | replace('-', '_') }}"
kolla_provision_interface: "{{ provision_wl_net_name | net_interface(controller_host) | replace('-', '_') }}"
kolla_inspector_dnsmasq_interface: "{{ provision_wl_net_name | net_interface(controller_host) | replace('-', '_') }}"
# Initialise the following lists.
kolla_neutron_bridge_names: []
kolla_neutron_external_interfaces: []
kolla_neutron_bridge_interfaces: []
- name: Set facts containing the Neutron bridge and interface names for the provisioning network
# When these networks are VLANs, we need to use the underlying tagged
# bridge interface rather than the untagged interface. We therefore
# strip the .<vlan> suffix of the interface name. We use a union here
# as a single tagged interface may be shared between these networks.
- name: Set a fact containing the bridges to be patched to the Neutron OVS bridges
set_fact:
kolla_neutron_bridge_names:
- "{{ provision_wl_net_name | net_interface(controller_host) ~ network_bridge_suffix_ovs }}"
kolla_neutron_external_interfaces:
- "{{ network_patch_prefix ~ provision_wl_net_name | net_interface(controller_host) ~ network_patch_suffix_ovs }}"
kolla_neutron_bridge_interfaces: >
{{ kolla_neutron_bridge_interfaces |
union([item | net_interface(controller_host) | replace('.' ~ item | net_vlan(controller_host) | default('!nomatch!'), '')]) |
list }}
with_items:
- "{{ provision_wl_net_name }}"
- "{{ external_net_name }}"
when: "{{ item in hostvars[controller_host].network_interfaces }}"
- name: Update facts containing the Neutron bridge and interface names for the external network
- name: Set facts containing the Neutron bridge and interface names
set_fact:
kolla_neutron_bridge_names: >
{{ kolla_neutron_bridge_names +
[external_net_name | net_interface(controller_host) ~ network_bridge_suffix_ovs] }}
[item ~ network_bridge_suffix_ovs] }}
kolla_neutron_external_interfaces: >
{{ kolla_neutron_external_interfaces +
[network_patch_prefix ~ external_net_name | net_interface(controller_host) ~ network_patch_suffix_ovs] }}
when:
- "{{ provision_wl_net_name != external_net_name }}"
{{ kolla_neutron_bridge_names +
[network_patch_prefix ~ item ~ network_patch_suffix_ovs] }}
with_items: "{{ kolla_neutron_bridge_interfaces }}"
- name: Validate controller Kolla Ansible network configuration
fail:

View File

@ -1,6 +1,11 @@
---
- name: Ensure networking is configured
hosts: seed:controllers
tags:
- config
vars:
ether_interfaces: "{{ network_interfaces | net_select_ethers | list }}"
bridge_interfaces: "{{ network_interfaces | net_select_bridges | list }}"
pre_tasks:
- block:
- name: Validate network interface configuration
@ -8,7 +13,7 @@
msg: >
Network interface validation failed - no interface configured for
{{ item }}. This should be configured via '{{ item }}_interface'.
with_items: "{{ network_interfaces | net_select_ethers | list }}"
with_items: "{{ ether_interfaces }}"
when: "{{ not item | net_interface }}"
- name: Validate bridge interface configuration
@ -16,10 +21,9 @@
msg: >
Bridge interface validation failed - no interface configured for
{{ item }}. This should be configured via '{{ item }}_interface'.
with_items: "{{ network_interfaces | net_select_bridges | list }}"
with_items: "{{ bridge_interfaces }}"
when: "{{ not item | net_interface }}"
tags:
- config
- config-validation
- name: Ensure NetworkManager is disabled
@ -37,53 +41,67 @@
roles:
- role: ahuffman.resolv
become: True
tags:
- config
# On the first pass we configure all ethernet interfaces that are not on
# VLANs and all bridges. On the second pass we configure all ethernet
# interfaces that are on VLANs. This allows us to specify VLAN interfaces
# on bridges.
- role: MichaelRigart.interfaces
interfaces_ether_interfaces: >
{{ network_interfaces |
net_select_ethers |
{{ ether_interfaces |
net_reject_vlans |
map('net_interface_obj') |
list }}
interfaces_bridge_interfaces: >
{{ network_interfaces |
net_select_bridges |
{{ bridge_interfaces |
map('net_bridge_obj') |
list }}
become: True
tags:
- config
- role: MichaelRigart.interfaces
interfaces_ether_interfaces: >
{{ ether_interfaces |
net_select_vlans |
map('net_interface_obj') |
list }}
become: True
# Configure a virtual ethernet patch links to connect the workload provision
# and external network bridges to the Neutron OVS bridge.
- name: Ensure controller workload OVS patch links exist
hosts: controllers
roles:
# Configure a virtual ethernet patch link to connect the workload provision
# network bridge to the Neutron OVS bridge.
- role: veth
veth_interfaces:
- device: "{{ network_patch_prefix ~ provision_wl_net_name | net_interface ~ network_patch_suffix_phy }}"
bootproto: "static"
bridge: "{{ provision_wl_net_name | net_interface }}"
peer_device: "{{ network_patch_prefix ~ provision_wl_net_name | net_interface ~ network_patch_suffix_ovs }}"
peer_bootproto: "static"
onboot: yes
when: "{{ provision_wl_net_name in network_interfaces }}"
tags:
- config
vars:
veth_bridges: []
veth_interfaces: []
pre_tasks:
# When these networks are VLANs, we need to use the underlying tagged
# bridge interface rather than the untagged interface. We therefore strip
# the .<vlan> suffix of the interface name. We use a union here as a single
# tagged interface may be shared between these networks.
- name: Update a fact containing bridges to be patched to the Neutron OVS bridge
set_fact:
veth_bridges: >
{{ veth_bridges |
union([item | net_interface | replace('.' ~ item | net_vlan | default('!nomatch!'), '')]) |
list }}
with_items:
- "{{ provision_wl_net_name }}"
- "{{ external_net_name }}"
when: "{{ item in network_interfaces }}"
# Configure a virtual ethernet patch link to connect the external network
# bridge to the Neutron OVS bridge.
- name: Update a fact containing veth interfaces
set_fact:
veth_interfaces: >
{{ veth_interfaces +
[{'device': network_patch_prefix ~ item ~ network_patch_suffix_phy,
'bootproto': 'static',
'bridge': item,
'peer_device': network_patch_prefix ~ item ~ network_patch_suffix_ovs,
'peer_bootproto': 'static',
'onboot': 'yes'}] }}
with_items: "{{ veth_bridges }}"
roles:
- role: veth
veth_interfaces:
- device: "{{ network_patch_prefix ~ external_net_name | net_interface ~ network_patch_suffix_phy }}"
bootproto: "static"
bridge: "{{ external_net_name | net_interface }}"
peer_device: "{{ network_patch_prefix ~ external_net_name | net_interface ~ network_patch_suffix_ovs }}"
peer_bootproto: "static"
onboot: yes
when:
- "{{ external_net_name in network_interfaces }}"
- "{{ external_net_name != provision_wl_net_name }}"
tags:
- config

View File

@ -10,13 +10,13 @@
neutron_net_openstack_auth_type: "{{ openstack_auth_type }}"
neutron_net_openstack_auth: "{{ openstack_auth }}"
# Network configuration.
neutron_net_name: "provision-net"
neutron_net_type: "flat"
neutron_net_name: "{{ kolla_ironic_provisioning_network }}"
neutron_net_type: "{% if provision_wl_net_name | net_vlan %}vlan{% else %}flat{% endif %}"
neutron_net_physical_network: "physnet1"
neutron_net_segmentation_id:
neutron_net_segmentation_id: "{{ provision_wl_net_name | net_vlan }}"
neutron_net_shared: True
# Subnet configuration.
neutron_net_subnet_name: "provision-subnet"
neutron_net_subnet_name: "{{ kolla_ironic_provisioning_network }}"
neutron_net_cidr: "{{ provision_wl_net_name | net_cidr }}"
neutron_net_gateway_ip: "{{ provision_wl_net_name | net_gateway }}"
neutron_net_allocation_pool_start: "{{ provision_wl_net_name | net_allocation_pool_start }}"

View File

@ -6,12 +6,18 @@ kolla_node_custom_config_path:
# Ironic configuration.
# List of enabled Ironic drivers.
ironic_drivers:
kolla_ironic_drivers:
- agent_ssh
- agent_ipmitool
- pxe_ssh
- pxe_ipmitool
# Name or UUID of the Neutron network to use for cleaning.
kolla_ironic_cleaning_network:
# Name or UUID of the Neutron network to use for provisioning.
kolla_ironic_provisioning_network:
# Free form extra configuration to append to ironic.conf.
kolla_extra_ironic:

View File

@ -1,7 +1,7 @@
# {{ ansible_managed }}
[DEFAULT]
enabled_drivers = {{ ironic_drivers | join(',') }}
enabled_drivers = {{ kolla_ironic_drivers | join(',') }}
[conductor]
{% raw %}
@ -11,6 +11,10 @@ api_url = {{ internal_protocol }}://{{ hostvars[inventory_hostname]['ansible_' +
[agent]
deploy_logs_local_path = /var/log/kolla/ironic/deploy
[neutron]
cleaning_network = {{ kolla_ironic_cleaning_network }}
provisioning_network = {{ kolla_ironic_provisioning_network }}
[pxe]
{% raw %}
tftp_server = {{ hostvars[inventory_hostname]['ansible_' + provision_interface | replace('-', '_')]['ipv4']['address'] }}

16
etc/kayobe/ironic.yml Normal file
View File

@ -0,0 +1,16 @@
---
###############################################################################
# Ironic configuration.
# List of enabled Ironic drivers.
#kolla_ironic_drivers:
# Name of the Neutron network to use for cleaning.
#kolla_ironic_cleaning_network:
# Name of the Neutron network to use for provisioning.
#kolla_ironic_provisioning_network:
###############################################################################
# Dummy variable to allow Ansible to accept this file.
workaround_ansible_issue_8743: yes