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 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 @jinja2.contextfilter
def net_select_ethers(context, names): def net_select_ethers(context, names):
return [name for name in names if net_is_ether(context, name)] 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)] 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 @jinja2.contextfilter
def net_configdrive_network_device(context, name, inventory_hostname=None): def net_configdrive_network_device(context, name, inventory_hostname=None):
device = net_interface(context, name, inventory_hostname) device = net_interface(context, name, inventory_hostname)
@ -212,7 +227,10 @@ class FilterModule(object):
'net_bridge_obj': net_bridge_obj, 'net_bridge_obj': net_bridge_obj,
'net_is_ether': net_is_ether, 'net_is_ether': net_is_ether,
'net_is_bridge': net_is_bridge, 'net_is_bridge': net_is_bridge,
'net_is_vlan': net_is_vlan,
'net_select_ethers': net_select_ethers, 'net_select_ethers': net_select_ethers,
'net_select_bridges': net_select_bridges, '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, '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 }}" with_items: "{{ network_interfaces }}"
when: "{{ item|net_cidr != None }}"
roles: roles:
- role: ip-allocation - role: ip-allocation
ip_allocation_filename: "{{ kayobe_config_path }}/network-allocation.yml" 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_cluster_interface: "{{ storage_mgmt_net_name | net_interface(controller_host) | replace('-', '_') }}"
kolla_provision_interface: "{{ provision_wl_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('-', '_') }}" 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: set_fact:
kolla_neutron_bridge_names: kolla_neutron_bridge_interfaces: >
- "{{ provision_wl_net_name | net_interface(controller_host) ~ network_bridge_suffix_ovs }}" {{ kolla_neutron_bridge_interfaces |
kolla_neutron_external_interfaces: union([item | net_interface(controller_host) | replace('.' ~ item | net_vlan(controller_host) | default('!nomatch!'), '')]) |
- "{{ network_patch_prefix ~ provision_wl_net_name | net_interface(controller_host) ~ network_patch_suffix_ovs }}" 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: set_fact:
kolla_neutron_bridge_names: > kolla_neutron_bridge_names: >
{{ 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: >
{{ kolla_neutron_external_interfaces + {{ kolla_neutron_bridge_names +
[network_patch_prefix ~ external_net_name | net_interface(controller_host) ~ network_patch_suffix_ovs] }} [network_patch_prefix ~ item ~ network_patch_suffix_ovs] }}
when: with_items: "{{ kolla_neutron_bridge_interfaces }}"
- "{{ provision_wl_net_name != external_net_name }}"
- name: Validate controller Kolla Ansible network configuration - name: Validate controller Kolla Ansible network configuration
fail: fail:

View File

@ -1,6 +1,11 @@
--- ---
- name: Ensure networking is configured - name: Ensure networking is configured
hosts: seed:controllers hosts: seed:controllers
tags:
- config
vars:
ether_interfaces: "{{ network_interfaces | net_select_ethers | list }}"
bridge_interfaces: "{{ network_interfaces | net_select_bridges | list }}"
pre_tasks: pre_tasks:
- block: - block:
- name: Validate network interface configuration - name: Validate network interface configuration
@ -8,7 +13,7 @@
msg: > msg: >
Network interface validation failed - no interface configured for Network interface validation failed - no interface configured for
{{ item }}. This should be configured via '{{ item }}_interface'. {{ 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 }}" when: "{{ not item | net_interface }}"
- name: Validate bridge interface configuration - name: Validate bridge interface configuration
@ -16,10 +21,9 @@
msg: > msg: >
Bridge interface validation failed - no interface configured for Bridge interface validation failed - no interface configured for
{{ item }}. This should be configured via '{{ item }}_interface'. {{ 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 }}" when: "{{ not item | net_interface }}"
tags: tags:
- config
- config-validation - config-validation
- name: Ensure NetworkManager is disabled - name: Ensure NetworkManager is disabled
@ -37,53 +41,67 @@
roles: roles:
- role: ahuffman.resolv - role: ahuffman.resolv
become: True 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 - role: MichaelRigart.interfaces
interfaces_ether_interfaces: > interfaces_ether_interfaces: >
{{ network_interfaces | {{ ether_interfaces |
net_select_ethers | net_reject_vlans |
map('net_interface_obj') | map('net_interface_obj') |
list }} list }}
interfaces_bridge_interfaces: > interfaces_bridge_interfaces: >
{{ network_interfaces | {{ bridge_interfaces |
net_select_bridges |
map('net_bridge_obj') | map('net_bridge_obj') |
list }} list }}
become: True 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 - name: Ensure controller workload OVS patch links exist
hosts: controllers hosts: controllers
roles: tags:
# Configure a virtual ethernet patch link to connect the workload provision - config
# network bridge to the Neutron OVS bridge. vars:
- role: veth veth_bridges: []
veth_interfaces: veth_interfaces: []
- device: "{{ network_patch_prefix ~ provision_wl_net_name | net_interface ~ network_patch_suffix_phy }}" pre_tasks:
bootproto: "static" # When these networks are VLANs, we need to use the underlying tagged
bridge: "{{ provision_wl_net_name | net_interface }}" # bridge interface rather than the untagged interface. We therefore strip
peer_device: "{{ network_patch_prefix ~ provision_wl_net_name | net_interface ~ network_patch_suffix_ovs }}" # the .<vlan> suffix of the interface name. We use a union here as a single
peer_bootproto: "static" # tagged interface may be shared between these networks.
onboot: yes - name: Update a fact containing bridges to be patched to the Neutron OVS bridge
when: "{{ provision_wl_net_name in network_interfaces }}" set_fact:
tags: veth_bridges: >
- config {{ 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 - name: Update a fact containing veth interfaces
# bridge to the Neutron OVS bridge. 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 - 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_type: "{{ openstack_auth_type }}"
neutron_net_openstack_auth: "{{ openstack_auth }}" neutron_net_openstack_auth: "{{ openstack_auth }}"
# Network configuration. # Network configuration.
neutron_net_name: "provision-net" neutron_net_name: "{{ kolla_ironic_provisioning_network }}"
neutron_net_type: "flat" neutron_net_type: "{% if provision_wl_net_name | net_vlan %}vlan{% else %}flat{% endif %}"
neutron_net_physical_network: "physnet1" neutron_net_physical_network: "physnet1"
neutron_net_segmentation_id: neutron_net_segmentation_id: "{{ provision_wl_net_name | net_vlan }}"
neutron_net_shared: True neutron_net_shared: True
# Subnet configuration. # 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_cidr: "{{ provision_wl_net_name | net_cidr }}"
neutron_net_gateway_ip: "{{ provision_wl_net_name | net_gateway }}" neutron_net_gateway_ip: "{{ provision_wl_net_name | net_gateway }}"
neutron_net_allocation_pool_start: "{{ provision_wl_net_name | net_allocation_pool_start }}" 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. # Ironic configuration.
# List of enabled Ironic drivers. # List of enabled Ironic drivers.
ironic_drivers: kolla_ironic_drivers:
- agent_ssh - agent_ssh
- agent_ipmitool - agent_ipmitool
- pxe_ssh - pxe_ssh
- pxe_ipmitool - 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. # Free form extra configuration to append to ironic.conf.
kolla_extra_ironic: kolla_extra_ironic:

View File

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