From 64dcfb7291d0454d52dc8f5a547ae57caa3b628e Mon Sep 17 00:00:00 2001 From: Mark Goddard Date: Wed, 19 Jun 2024 14:05:32 +0100 Subject: [PATCH] Add support for customising Neutron physical network names Previously Kolla Ansible hard-coded Neutron physical networks starting at physnet1 up to physnetN, matching the number of interfaces in neutron_external_interface and bridges in neutron_bridge_name. Sometimes we may want to customise the physical network names used. This may be to allow for not all hosts having access to all physical networks, or to use more descriptive names. For example, in an environment with a separate physical network for Ironic provisioning, controllers might have access to two physical networks, while compute nodes have access to one. This change adds a neutron_physical_networks variable, making it possible to customise the Neutron physical network names used for the OVS, OVN, Linux bridge and OVS DPDK plugins. The default behaviour is unchanged. Change-Id: Ib5b8ea727014964919c6b3bd2352bac4a4ac1787 --- ansible/group_vars/all.yml | 1 + .../templates/linuxbridge_agent.ini.j2 | 3 +- .../roles/neutron/templates/ml2_conf.ini.j2 | 4 +- .../templates/openvswitch_agent.ini.j2 | 3 +- .../roles/ovn-controller/tasks/setup-ovs.yml | 6 ++- ansible/roles/ovs-dpdk/defaults/main.yml | 6 ++- doc/source/reference/networking/neutron.rst | 41 ++++++++++++++++--- ...on-physical-networks-5b908bed9809c3b4.yaml | 6 +++ 8 files changed, 57 insertions(+), 13 deletions(-) create mode 100644 releasenotes/notes/neutron-physical-networks-5b908bed9809c3b4.yaml diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml index e8cdca9f83..5b5e417a64 100644 --- a/ansible/group_vars/all.yml +++ b/ansible/group_vars/all.yml @@ -1080,6 +1080,7 @@ designate_notifications_topic_name: "notifications_designate" ####################### neutron_bgp_router_id: "1.1.1.1" neutron_bridge_name: "{{ 'br-dvs' if neutron_plugin_agent == 'vmware_dvs' else 'br_dpdk' if enable_ovs_dpdk | bool else 'br-ex' }}" +neutron_physical_networks: "{% for bridge in neutron_bridge_name.split(',') %}physnet{{ loop.index }}{% if not loop.last %},{% endif %}{% endfor %}" # Comma-separated type of enabled ml2 type drivers neutron_type_drivers: "flat,vlan,vxlan{% if neutron_plugin_agent == 'ovn' %},geneve{% endif %}" # Comma-separated types of tenant networks (should be listed in 'neutron_type_drivers') diff --git a/ansible/roles/neutron/templates/linuxbridge_agent.ini.j2 b/ansible/roles/neutron/templates/linuxbridge_agent.ini.j2 index 1dbaae0ede..5b0ae990b8 100644 --- a/ansible/roles/neutron/templates/linuxbridge_agent.ini.j2 +++ b/ansible/roles/neutron/templates/linuxbridge_agent.ini.j2 @@ -5,7 +5,8 @@ extensions = {{ neutron_agent_extensions|map(attribute='name')|join(',') }} [linux_bridge] {% if inventory_hostname in groups["network"] or (inventory_hostname in groups["compute"] and computes_need_external_bridge | bool ) %} -physical_interface_mappings = {% for interface in neutron_external_interface.split(',') %}physnet{{ loop.index0 + 1 }}:{{ interface }}{% if not loop.last %},{% endif %}{% endfor %} +{# Format: physnet1:br1,physnet2:br2 #} +physical_interface_mappings = {{ neutron_physical_networks.split(',') | zip(neutron_external_interface.split(',')) | map('join', ':') | join(',') }} {% endif %} [securitygroup] diff --git a/ansible/roles/neutron/templates/ml2_conf.ini.j2 b/ansible/roles/neutron/templates/ml2_conf.ini.j2 index 9c70eb898a..0e34477691 100644 --- a/ansible/roles/neutron/templates/ml2_conf.ini.j2 +++ b/ansible/roles/neutron/templates/ml2_conf.ini.j2 @@ -15,7 +15,7 @@ extension_drivers = {{ neutron_extension_drivers | map(attribute='name') | join( [ml2_type_vlan] {% if enable_ironic | bool %} -network_vlan_ranges = physnet1 +network_vlan_ranges = {{ neutron_physical_networks }} {% else %} network_vlan_ranges = {% endif %} @@ -24,7 +24,7 @@ network_vlan_ranges = {% if enable_ironic | bool %} flat_networks = * {% else %} -flat_networks = {% for interface in neutron_external_interface.split(',') %}physnet{{ loop.index0 + 1 }}{% if not loop.last %},{% endif %}{% endfor %} +flat_networks = {{ neutron_physical_networks }} {% endif %} [ml2_type_vxlan] diff --git a/ansible/roles/neutron/templates/openvswitch_agent.ini.j2 b/ansible/roles/neutron/templates/openvswitch_agent.ini.j2 index 88834e2dea..8ac25af7e1 100644 --- a/ansible/roles/neutron/templates/openvswitch_agent.ini.j2 +++ b/ansible/roles/neutron/templates/openvswitch_agent.ini.j2 @@ -15,7 +15,8 @@ firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewal [ovs] {% if inventory_hostname in groups["network"] or (inventory_hostname in groups["compute"] and computes_need_external_bridge | bool ) %} -bridge_mappings = {% for bridge in neutron_bridge_name.split(',') %}physnet{{ loop.index0 + 1 }}:{{ bridge }}{% if not loop.last %},{% endif %}{% endfor %} +{# Format: physnet1:br1,physnet2:br2 #} +bridge_mappings = {{ neutron_physical_networks.split(',') | zip(neutron_bridge_name.split(',')) | map('join', ':') | join(',') }} {% endif %} datapath_type = {{ ovs_datapath }} ovsdb_connection = tcp:127.0.0.1:{{ ovsdb_port }} diff --git a/ansible/roles/ovn-controller/tasks/setup-ovs.yml b/ansible/roles/ovn-controller/tasks/setup-ovs.yml index 5ac61a16b3..0d9ab0e30c 100644 --- a/ansible/roles/ovn-controller/tasks/setup-ovs.yml +++ b/ansible/roles/ovn-controller/tasks/setup-ovs.yml @@ -12,8 +12,10 @@ - name: Configure OVN in OVSDB vars: - ovn_mappings: "{% for bridge in neutron_bridge_name.split(',') %}physnet{{ loop.index0 + 1 }}:{{ bridge }}{% if not loop.last %},{% endif %}{% endfor %}" - ovn_macs: "{% for bridge in neutron_bridge_name.split(',') %}physnet{{ loop.index0 + 1 }}:{{ ovn_base_mac | random_mac(seed=inventory_hostname + bridge) }}{% if not loop.last %},{% endif %}{% endfor %}" + # Format: physnet1:br1,physnet2:br2 + ovn_mappings: "{{ neutron_physical_networks.split(',') | zip(neutron_bridge_name.split(',')) | map('join', ':') | join(',') }}" + # Format: physnet1:00:11:22:33:44:55,physnet2:00:11:22:33:44:56 + ovn_macs: "{% for physnet, bridge in neutron_physical_networks.split(',') | zip(neutron_bridge_name.split(',')) %}{{ physnet }}:{{ ovn_base_mac | random_mac(seed=inventory_hostname + bridge) }}{% if not loop.last %},{% endif %}{% endfor %}" ovn_cms_opts: "{{ 'enable-chassis-as-gw' if inventory_hostname in groups['ovn-controller-network'] else '' }}{{ ',availability-zones=' + neutron_ovn_availability_zones | join(',') if inventory_hostname in groups['ovn-controller-network'] and neutron_ovn_availability_zones }}" become: true kolla_toolbox: diff --git a/ansible/roles/ovs-dpdk/defaults/main.yml b/ansible/roles/ovs-dpdk/defaults/main.yml index 209eb95fbe..ac9cd0c731 100644 --- a/ansible/roles/ovs-dpdk/defaults/main.yml +++ b/ansible/roles/ovs-dpdk/defaults/main.yml @@ -37,8 +37,10 @@ ovsdpdk_services: #################### # OVS #################### -ovs_bridge_mappings: "{% for bridge in neutron_bridge_name.split(',') %}physnet{{ loop.index0 + 1 }}:{{ bridge }}{% if not loop.last %},{% endif %}{% endfor %}" -ovs_port_mappings: "{% for bridge in neutron_bridge_name.split(',') %} {{ neutron_external_interface.split(',')[loop.index0] }}:{{ bridge }}{% if not loop.last %},{% endif %}{% endfor %}" +# Format: physnet1:br1,physnet2:br2 +ovs_bridge_mappings: "{{ neutron_physical_networks.split(',') | zip(neutron_bridge_name.split(',')) | map('join', ':') | join(',') }}" +# Format: eth1:br1,eth2:br2 +ovs_port_mappings: "{{ neutron_external_interface.split(',') | zip(neutron_bridge_name.split(',')) | map('join', ':') | join(',') }}" tunnel_interface_network: "{{ hostvars[inventory_hostname].ansible_facts[dpdk_tunnel_interface]['ipv4']['network'] }}/{{ hostvars[inventory_hostname].ansible_facts[dpdk_tunnel_interface]['ipv4']['netmask'] }}" tunnel_interface_cidr: "{{ dpdk_tunnel_interface_address }}/{{ tunnel_interface_network | ipaddr('prefix') }}" ovs_cidr_mappings: "{% if neutron_bridge_name.split(',') | length != 1 %} {neutron_bridge_name.split(',')[0]}:{{ tunnel_interface_cidr }} {% else %} {{ neutron_bridge_name }}:{{ tunnel_interface_cidr }} {% endif %}" diff --git a/doc/source/reference/networking/neutron.rst b/doc/source/reference/networking/neutron.rst index c748c6d4e4..8a627572d7 100644 --- a/doc/source/reference/networking/neutron.rst +++ b/doc/source/reference/networking/neutron.rst @@ -20,13 +20,20 @@ Neutron external interface is used for communication with the external world, for example provider networks, routers and floating IPs. For setting up the neutron external interface modify ``/etc/kolla/globals.yml`` setting ``neutron_external_interface`` to the -desired interface name. This interface is used by hosts in the ``network`` -group. It is also used by hosts in the ``compute`` group if +desired interface name or comma-separated list of interface names. Its default +value is ``eth1``. These external interfaces are used by hosts in the +``network`` group. They are also used by hosts in the ``compute`` group if ``enable_neutron_provider_networks`` is set or DVR is enabled. -The interface is plugged into a bridge (Open vSwitch or Linux Bridge, depending -on the driver) defined by ``neutron_bridge_name``, which defaults to ``br-ex``. -The default Neutron physical network is ``physnet1``. +The external interfaces are each plugged into a bridge (Open vSwitch or Linux +Bridge, depending on the driver) defined by ``neutron_bridge_name``, which +defaults to ``br-ex``. When there are multiple external interfaces, +``neutron_bridge_name`` should be a comma-separated list of the same length. + +The default Neutron physical network is ``physnet1``, or ``physnet1`` to +``physnetN`` when there are multiple external network interfaces. This may be +changed by setting ``neutron_physical_networks`` to a comma-separated list of +networks of the same length. Example: single interface ------------------------- @@ -54,6 +61,30 @@ These two lists are "zipped" together, such that ``eth1`` is plugged into the Ansible maps these interfaces to Neutron physical networks ``physnet1`` and ``physnet2`` respectively. +Example: custom physical networks +--------------------------------- + +Sometimes we may want to customise the physical network names used. This may be +to allow for not all hosts having access to all physical networks, or to use +more descriptive names. + +For example, in an environment with a separate physical network for Ironic +provisioning, controllers might have access to two physical networks: + +.. code-block:: yaml + + neutron_external_interface: "eth1,eth2" + neutron_bridge_name: "br-ex1,br-ex2" + neutron_physical_network: "physnet1,physnet2" + +While compute nodes have access only to ``physnet2``. + +.. code-block:: yaml + + neutron_external_interface: "eth1" + neutron_bridge_name: "br-ex1" + neutron_physical_network: "physnet2" + Example: shared interface ------------------------- diff --git a/releasenotes/notes/neutron-physical-networks-5b908bed9809c3b4.yaml b/releasenotes/notes/neutron-physical-networks-5b908bed9809c3b4.yaml new file mode 100644 index 0000000000..a62e400089 --- /dev/null +++ b/releasenotes/notes/neutron-physical-networks-5b908bed9809c3b4.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Adds a ``neutron_physical_networks`` variable for customising Neutron + physical network names. The default behaviour of using ``physnet1`` to + ``physnetN`` is unchanged.