diff --git a/environments/network-environment-v6.j2.yaml b/environments/network-environment-v6.j2.yaml index 8937b562f2..e632f4c140 100644 --- a/environments/network-environment-v6.j2.yaml +++ b/environments/network-environment-v6.j2.yaml @@ -52,6 +52,10 @@ parameter_defaults: # Customize the VLAN ID to match the local environment {{network.name}}NetworkVlanID: {{network.vlan}} {%- endif %} +{%- if network.enabled|default(true) and network.routes_ipv6 %} + # Routes to add to host_routes property of the subnets in neutron. + {{network.name}}Routes: {{network.routes_ipv6|default([])}} +{%- endif %} {% endfor %} {#- FIXME: These global parameters should be defined in a YAML file, e.g. network_data.yaml. #} # Define the DNS servers (maximum 2) for the overcloud nodes diff --git a/environments/network-environment.j2.yaml b/environments/network-environment.j2.yaml index 7cceeefa3c..a4da2901ae 100644 --- a/environments/network-environment.j2.yaml +++ b/environments/network-environment.j2.yaml @@ -50,6 +50,10 @@ parameter_defaults: # Customize the VLAN ID to match the local environment {{network.name}}NetworkVlanID: {{network.vlan}} {%- endif %} +{%- if network.enabled|default(true) and network.routes %} + # Routes to add to host_routes property of the subnets in neutron. + {{network.name}}Routes: {{network.routes|default([])}} +{%- endif %} {% endfor %} {#- FIXME: These global parameters should be defined in a YAML file, e.g. network_data.yaml. #} # Define the DNS servers (maximum 2) for the overcloud nodes diff --git a/network/network.j2 b/network/network.j2 index 607c530c71..16c46c5671 100644 --- a/network/network.j2 +++ b/network/network.j2 @@ -71,6 +71,14 @@ parameters: description: Vlan ID for the {{network.name_lower}} network traffic. type: number {%- endif %} + {{network.name}}Routes: + default: {{network.routes|default([])}} + description: > + Routes for the {{network.name_lower}} network traffic. + JSON route e.g. [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}] + Routes are added to the host_routes property on the subnet in neutron + when the network and subnet is created. + type: json resources: {{network.name}}Network: @@ -96,6 +104,7 @@ resources: network: {get_resource: {{network.name}}Network} allocation_pools: {get_param: {{network.name}}AllocationPools} gateway_ip: {get_param: {{network.name}}InterfaceDefaultRoute} + host_routes: {get_param: {{network.name}}Routes} outputs: OS::stack_id: diff --git a/network_data.yaml b/network_data.yaml index e2a5f32349..24cb9ec3c1 100644 --- a/network_data.yaml +++ b/network_data.yaml @@ -16,6 +16,9 @@ # (optional, may use parameter defaults instead) # allocation_pools: IP range list e.g. [{'start':'10.0.0.4', 'end':'10.0.0.250'}] # gateway_ip: gateway for the network (optional, may use parameter defaults) +# routes: Optional, list of networks that should be routed via network gateway. +# Example: [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}] +# A single /16 supernet route could be used for 255 smaller /24 subnets. # ipv6_subnet: Optional, sets default IPv6 subnet if IPv4 is already defined. # ipv6_allocation_pools: Set default IPv6 allocation pools if IPv4 allocation pools # are already defined. diff --git a/network_data_ganesha.yaml b/network_data_ganesha.yaml index df30f52355..a0205db0ea 100644 --- a/network_data_ganesha.yaml +++ b/network_data_ganesha.yaml @@ -13,6 +13,9 @@ # (optional, may use parameter defaults instead) # allocation_pools: IP range list e.g. [{'start':'10.0.0.4', 'end':'10.0.0.250'}] # gateway_ip: gateway for the network (optional, may use parameter defaults) +# routes: Optional, list of networks that should be routed via network gateway. +# Example: [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}] +# A single /16 supernet route could be used for 255 smaller /24 subnets. # ipv6_subnet: Optional, sets default IPv6 subnet if IPv4 is already defined. # ipv6_allocation_pools: Set default IPv6 allocation pools if IPv4 allocation pools # are already defined. diff --git a/network_data_routed.yaml b/network_data_routed.yaml new file mode 100644 index 0000000000..ad63ed91dd --- /dev/null +++ b/network_data_routed.yaml @@ -0,0 +1,184 @@ +# List of networks, used for j2 templating of enabled networks +# +# This file demonstrates routed spine/leaf networks. Supernets +# are used to segregate traffic and provide symmetric routing. +# Each type of network has a supernet, and the supernet route +# on each network points to the local network gateway. This +# ensures that traffic uses the appropriate network and not +# the default gateway for destinations matching the supernet. +# +# Supported values: +# +# name: Name of the network (mandatory) +# name_lower: lowercase version of name used for filenames +# (optional, defaults to name.lower()) +# service_net_map_replace: if name_lower is set to a custom name this should be set +# to original default (optional). This field is only necessary when +# changing the default network names, not when adding a new custom network. +# enabled: Is the network enabled (optional, defaults to true) +# NOTE: False will use noop.yaml for unused legacy networks to support upgrades. +# vlan: vlan for the network (optional) +# vip: Enable creation of a virtual IP on this network +# ip_subnet: IP/CIDR, e.g. '192.168.24.0/24' or '2001:db8:fd00:1000::/64' +# (optional, may use parameter defaults instead) +# allocation_pools: IP range list e.g. [{'start':'10.0.0.4', 'end':'10.0.0.250'}] +# gateway_ip: gateway for the network (optional, may use parameter defaults) +# routes: Optional, list of networks that should be routed via network gateway. +# Example: [{'destination':'10.0.0.0/16', 'nexthop':'10.0.0.1'}] +# A single /16 supernet route could be used for 255 smaller /24 subnets. +# ipv6_subnet: Optional, sets default IPv6 subnet if IPv4 is already defined. +# ipv6_allocation_pools: Set default IPv6 allocation pools if IPv4 allocation pools +# are already defined. +# ipv6_gateway: Set an IPv6 gateway if IPv4 gateway already defined. +# routes_ipv6: Optional, list of networks that should be routed via network gateway. +# Example: [{'destination':'fd00:fd00:fd00:3004::/64', +# 'nexthop':'fd00:fd00:fd00:3000::1'}] +# A single /16 supernet route could be used for 255 smaller /24 subnets. +# ipv6: If ip_subnet not defined, this specifies that the network is IPv6-only. +# NOTE: IP-related values set parameter defaults in templates, may be overridden, +# either by operators, or e.g in environments/network-isolation-v6.yaml where we +# set some default IPv6 addresses. +# compat_name: for existing stack you may need to override the default +# transformation for the resource's name. +# +# Example: # A single 10.0.0.0/16 route works for up to 255 /24 networks +# - name Example1 +# vip: false +# ip_subnet: '10.0.1.0/24' +# allocation_pools: [{'start': '10.0.1.4', 'end': '10.0.1.250'}] +# gateway_ip: '10.0.1.254' +# routes: [{'destination':'10.0.0.0/16', 'nexthop':'10.0.1.254'}] +# - name Example2 +# vip: false +# ip_subnet: '10.0.2.0/24' +# allocation_pools: [{'start': '10.0.2.4', 'end': '10.0.2.250'}] +# gateway_ip: '10.0.2.254' +# routes: [{'destination':'10.0.0.0/16', 'nexthop':'10.0.2.254'}] +# +# To support backward compatility, two versions of the network definitions will +# be created, network/.yaml and network/_v6.yaml. Only +# one of these files may be used in the deployment at a time, since the +# parameters used for configuration are the same in both files. In the +# future, this behavior may be changed to create only one file for custom +# networks. You may specify IPv6 addresses for ip_subnet, allocation_pools, +# and gateway_ip if no IPv4 addresses are used for a custom network, or set +# ipv6: true, and the network/.yaml file will be configured as IPv6. +# +# For configuring both IPv4 and IPv6 on the same interface, use two separate +# networks, and then assign both IPs to the same interface in a custom NIC +# configuration templates. +# +# The ordering of the networks below will determine the order in which NICs +# are assigned in the network/config/multiple-nics templates, beginning with +# NIC2, Control Plane is always NIC1. + +- name: Storage + vip: true + vlan: 30 + name_lower: storage + ip_subnet: '172.16.16.0/24' + gateway_ip: '172.16.16.1' + routes: [{'destination':'172.16.16.0/20', 'nexthop':'172.16.16.1'}] + allocation_pools: [{'start': '172.16.16.4', 'end': '172.16.16.250'}] + ipv6_subnet: 'fd00:fd00:fd00:3000::/64' + ipv6_allocation_pools: [{'start': 'fd00:fd00:fd00:3000::10', 'end': 'fd00:fd00:fd00:3000:ffff:ffff:ffff:fffe'}] + routes_ipv6: [{'destination':'fd00:fd00:fd00:3004::/64', 'nexthop':'fd00:fd00:fd00:3000::1'}] +- name: StorageLeaf2 + vip: false + vlan: 31 + name_lower: storage2 + ip_subnet: '172.16.17.0/24' + gateway_ip: '172.16.17.1' + routes: [{'destination':'172.16.16.0/20', 'nexthop':'172.16.17.1'}] + allocation_pools: [{'start': '172.16.17.4', 'end': '172.16.17.250'}] + ipv6_subnet: 'fd00:fd00:fd00:3004::/64' + ipv6_allocation_pools: [{'start': 'fd00:fd00:fd00:3004::10', 'end': 'fd00:fd00:fd00:3004:ffff:ffff:ffff:fffe'}] + routes_ipv6: [{'destination':'fd00:fd00:fd00:3000::/64', 'nexthop':'fd00:fd00:fd00:3004::1'}] +- name: StorageMgmt + name_lower: storage_mgmt + vip: true + vlan: 40 + ip_subnet: '172.16.48.0/24' + gateway_ip: '172.16.48.1' + routes: [{'destination':'172.16.48.0/20', 'nexthop':'172.16.48.1'}] + allocation_pools: [{'start': '172.16.48.4', 'end': '172.16.48.250'}] + ipv6_subnet: 'fd00:fd00:fd00:4000::/64' + ipv6_allocation_pools: [{'start': 'fd00:fd00:fd00:4000::10', 'end': 'fd00:fd00:fd00:4000:ffff:ffff:ffff:fffe'}] + routes_ipv6: [{'destination':'fd00:fd00:fd00:4004::/64', 'nexthop':'fd00:fd00:fd00:4000::1'}] +- name: StorageMgmtLeaf2 + name_lower: storage_mgmt2 + vip: false + vlan: 41 + ip_subnet: '172.16.49.0/24' + gateway_ip: '172.16.49.1' + routes: [{'destination':'172.16.48.0/20', 'nexthop':'172.16.49.1'}] + allocation_pools: [{'start': '172.16.49.4', 'end': '172.16.49.250'}] + ipv6_subnet: 'fd00:fd00:fd00:4004::/64' + ipv6_allocation_pools: [{'start': 'fd00:fd00:fd00:4004::10', 'end': 'fd00:fd00:fd00:4004:ffff:ffff:ffff:fffe'}] + routes_ipv6: [{'destination':'fd00:fd00:fd00:4000::/64', 'nexthop':'fd00:fd00:fd00:4004::1'}] +- name: InternalApi + name_lower: internal_api + vip: true + vlan: 20 + ip_subnet: '172.16.32.0/24' + gateway_ip: '172.16.32.1' + routes: [{'destination':'172.16.32.0/20', 'nexthop':'172.16.32.1'}] + allocation_pools: [{'start': '172.16.32.4', 'end': '172.16.32.250'}] + ipv6_subnet: 'fd00:fd00:fd00:2000::/64' + ipv6_allocation_pools: [{'start': 'fd00:fd00:fd00:2000::10', 'end': 'fd00:fd00:fd00:2000:ffff:ffff:ffff:fffe'}] + routes_ipv6: [{'destination':'fd00:fd00:fd00:2004::/64', 'nexthop':'fd00:fd00:fd00:2000::1'}] +- name: InternalApiLeaf2 + name_lower: internal_api2 + vip: false + vlan: 21 + ip_subnet: '172.16.33.0/24' + gateway_ip: '172.16.33.1' + routes: [{'destination':'172.16.32.0/20', 'nexthop':'172.16.33.1'}] + allocation_pools: [{'start': '172.16.33.4', 'end': '172.16.33.250'}] + ipv6_subnet: 'fd00:fd00:fd00:2004::/64' + ipv6_allocation_pools: [{'start': 'fd00:fd00:fd00:2004::10', 'end': 'fd00:fd00:fd00:2004:ffff:ffff:ffff:fffe'}] + routes_ipv6: [{'destination':'fd00:fd00:fd00:2000::/64', 'nexthop':'fd00:fd00:fd00:2004::1'}] +- name: Tenant + vip: false # Tenant networks do not use VIPs + name_lower: tenant + vlan: 50 + ip_subnet: '172.16.0.0/24' + gateway_ip: '172.16.0.1' + routes: [{'ip_netmask':'172.16.0.0/20', 'next_hop':'172.16.0.1'}] + allocation_pools: [{'start': '172.16.0.4', 'end': '172.16.0.250'}] + # Note that tenant tunneling is only compatible with IPv4 addressing at this time. + ipv6_subnet: 'fd00:fd00:fd00:5000::/64' + ipv6_allocation_pools: [{'start': 'fd00:fd00:fd00:5000::10', 'end': 'fd00:fd00:fd00:5000:ffff:ffff:ffff:fffe'}] + routes_ipv6: [{'destination':'fd00:fd00:fd00:5004::/64', 'nexthop':'fd00:fd00:fd00:5000::1'}] +- name: TenantLeaf2 + vip: false # Tenant networks do not use VIPs + name_lower: tenant2 + vlan: 51 + ip_subnet: '172.16.1.0/24' + gateway_ip: '172.16.1.1' + routes: [{'destination':'172.16.0.0/20', 'nexthop':'172.16.1.1'}] + allocation_pools: [{'start': '172.16.1.4', 'end': '172.16.1.250'}] + # Note that tenant tunneling is only compatible with IPv4 addressing at this time. + ipv6_subnet: 'fd00:fd00:fd00:5004::/64' + ipv6_allocation_pools: [{'start': 'fd00:fd00:fd00:5004::10', 'end': 'fd00:fd00:fd00:5004:ffff:ffff:ffff:fffe'}] + routes_ipv6: [{'destination':'fd00:fd00:fd00:5000::/64', 'nexthop':'fd00:fd00:fd00:5004::1'}] +- name: External + vip: true + name_lower: external + vlan: 10 + ip_subnet: '10.0.0.0/24' + allocation_pools: [{'start': '10.0.0.4', 'end': '10.0.0.250'}] + gateway_ip: '10.0.0.1' + ipv6_subnet: '2001:db8:fd00:1000::/64' + ipv6_allocation_pools: [{'start': '2001:db8:fd00:1000::10', 'end': '2001:db8:fd00:1000:ffff:ffff:ffff:fffe'}] + gateway_ipv6: '2001:db8:fd00:1000::1' +- name: Management + # Management network is enabled by default for backwards-compatibility, but + # is not included in any roles by default. Add to role definitions to use. + enabled: true + vip: false # Management network does not use VIPs + name_lower: management + vlan: 60 + ip_subnet: '10.0.1.0/24' + allocation_pools: [{'start': '10.0.1.4', 'end': '10.0.1.250'}] + ipv6_subnet: 'fd00:fd00:fd00:6000::/64' diff --git a/releasenotes/notes/add-host-routes-to-composable-network-subnets-7076e3b7a466d5fd.yaml b/releasenotes/notes/add-host-routes-to-composable-network-subnets-7076e3b7a466d5fd.yaml new file mode 100644 index 0000000000..69e13210cd --- /dev/null +++ b/releasenotes/notes/add-host-routes-to-composable-network-subnets-7076e3b7a466d5fd.yaml @@ -0,0 +1,15 @@ +--- +features: + - | + A new routes field is available for the network definition in + ``network_data.yaml``. This field contains a list of network routes. + For example:: + + routes: + - destination: 10.0.1.0/24 + nexthop: 10.0.0.1 + - destination: 10.0.2.0/24 + nexthop: 10.0.0.1 + + The routes are used to set the ``host_routes`` property of the neutron + subnet resource created for the network. diff --git a/tools/yaml-validate.py b/tools/yaml-validate.py index 77014a43ad..88ffb2a414 100755 --- a/tools/yaml-validate.py +++ b/tools/yaml-validate.py @@ -1106,7 +1106,11 @@ def validate(filename, param_map): if filename == './roles/Compute.yaml': retval |= validate_multiarch_compute_roles(filename, tpl) - if filename.startswith('./network_data_'): + # NOTE(hjensas): The routed network data example is very different ... + # We need to develop a more advanced validator, probably using a schema + # definition instead. + if (filename.startswith('./network_data_') and + not filename.endswith('routed.yaml')): result = validate_network_data_file(filename) retval |= result else: