From cd5605fa717e4da8b2b3ecd392be59e4f9121530 Mon Sep 17 00:00:00 2001 From: Mark Goddard Date: Tue, 24 Oct 2017 19:21:07 +0100 Subject: [PATCH] Add support for configuration of IP route tables and rules --- ansible/filter_plugins/networks.py | 21 ++++++-- ansible/group_vars/all/network | 7 +++ ansible/network.yml | 1 + doc/source/configuration/network.rst | 77 ++++++++++++++++++++++++++-- etc/kayobe/networks.yml | 7 +++ 5 files changed, 107 insertions(+), 6 deletions(-) diff --git a/ansible/filter_plugins/networks.py b/ansible/filter_plugins/networks.py index 27f8787c9..e48ee432e 100644 --- a/ansible/filter_plugins/networks.py +++ b/ansible/filter_plugins/networks.py @@ -125,6 +125,7 @@ def net_vlan(context, name, inventory_hostname=None): net_mtu = _make_attr_filter('mtu') net_routes = _make_attr_filter('routes') +net_rules = _make_attr_filter('rules') net_physical_network = _make_attr_filter('physical_network') @@ -154,14 +155,21 @@ def _route_obj(route): The returned dict is compatible with the route item of the interfaces_ether_interfaces and interfaces_bridge_interfaces variables in - the MichaelRigaert.interfaces role. + the MichaelRigart.interfaces role. """ net = netaddr.IPNetwork(route['cidr']) - return { + route_obj = { 'network': str(net.network), 'netmask': str(net.netmask), - 'gateway': route['gateway'], } + optional = { + 'gateway', + 'table', + } + for option in optional: + if option in route: + route_obj[option] = route[option] + return route_obj @jinja2.contextfilter @@ -187,6 +195,7 @@ def net_interface_obj(context, name, inventory_hostname=None): routes = net_routes(context, name, inventory_hostname) if routes: routes = [_route_obj(route) for route in routes] + rules = net_rules(context, name, inventory_hostname) interface = { 'device': device, 'address': ip, @@ -195,6 +204,7 @@ def net_interface_obj(context, name, inventory_hostname=None): 'vlan': vlan, 'mtu': mtu, 'route': routes, + 'rules': rules, 'bootproto': 'static', 'onboot': 'yes', } @@ -226,6 +236,7 @@ def net_bridge_obj(context, name, inventory_hostname=None): routes = net_routes(context, name, inventory_hostname) if routes: routes = [_route_obj(route) for route in routes] + rules = net_rules(context, name, inventory_hostname) interface = { 'device': device, 'address': ip, @@ -235,6 +246,7 @@ def net_bridge_obj(context, name, inventory_hostname=None): 'mtu': mtu, 'ports': ports, 'route': routes, + 'rules': rules, 'bootproto': 'static', 'onboot': 'yes', } @@ -268,6 +280,7 @@ def net_bond_obj(context, name, inventory_hostname=None): routes = net_routes(context, name, inventory_hostname) if routes: routes = [_route_obj(route) for route in routes] + rules = net_rules(context, name, inventory_hostname) interface = { 'device': device, 'address': ip, @@ -279,6 +292,7 @@ def net_bond_obj(context, name, inventory_hostname=None): 'bond_mode': mode, 'bond_miimon': miimon, 'route': routes, + 'rules': rules, 'bootproto': 'static', 'onboot': 'yes', } @@ -429,6 +443,7 @@ class FilterModule(object): 'net_vlan': net_vlan, 'net_mtu': net_mtu, 'net_routes': net_routes, + 'net_rules': net_rules, 'net_physical_network': net_physical_network, 'net_interface_obj': net_interface_obj, 'net_bridge_obj': net_bridge_obj, diff --git a/ansible/group_vars/all/network b/ansible/group_vars/all/network index c90bf29e4..1d9caa53a 100644 --- a/ansible/group_vars/all/network +++ b/ansible/group_vars/all/network @@ -54,3 +54,10 @@ network_patch_suffix_phy: '-phy' # Suffix for virtual patch link interface names when connected towards the # OVS bridge. network_patch_suffix_ovs: '-ovs' + +############################################################################### +# Network routing table configuration. + +# List of IP routing tables. Each item should be a dict containing 'id' and +# 'name' items. These tables will be added to /etc/iproute2/rt_tables. +network_route_tables: [] diff --git a/ansible/network.yml b/ansible/network.yml index 146045103..e5115f55e 100644 --- a/ansible/network.yml +++ b/ansible/network.yml @@ -52,6 +52,7 @@ become: True - role: MichaelRigart.interfaces + interfaces_route_tables: "{{ network_route_tables }}" interfaces_ether_interfaces: > {{ ether_interfaces | map('net_interface_obj') | diff --git a/doc/source/configuration/network.rst b/doc/source/configuration/network.rst index 604c7bf5e..1f7c490c9 100644 --- a/doc/source/configuration/network.rst +++ b/doc/source/configuration/network.rst @@ -41,8 +41,13 @@ supported: Maximum Transmission Unit (MTU). ``routes`` List of static IP routes. Each item should be a dict containing the - items ``cidr`` and ``gateway``. ``cidr`` is the CIDR representation of the - route's destination. ``gateway`` is the IP address of the next hop. + item ``cidr``, and optionally ``gateway`` and ``table``. ``cidr`` is the CIDR + representation of the route's destination. ``gateway`` is the IP address of + the next hop. ``table`` is the name or ID of a routing table to which the + route will be added. +``rules`` + List of IP routing rules. Each item should be an ``iproute2`` IP routing + rule. ``physical_network`` Name of the physical network on which this network exists. This aligns with the physical network concept in neutron. @@ -86,7 +91,8 @@ Configuring Static IP Routes Static IP routes may be configured by setting the ``routes`` attribute for a network to a list of routes. -To configure a network called ``example`` with a single IP route: +To configure a network called ``example`` with a single IP route to the +``10.1.0.0/24`` subnet via ``10.0.0.1``: .. code-block:: yaml :caption: ``networks.yml`` @@ -155,6 +161,71 @@ addresses for hosts ``host1`` and ``host2``: host1: 10.0.0.1 host2: 10.0.0.2 +Advanced: Policy-Based Routing +------------------------------ + +Policy-based routing can be useful in complex networking environments, +particularly where asymmetric routes exist, and strict reverse path filtering +is enabled. + +Configuring IP Routing Tables +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Custom IP routing tables may be configured by setting the global variable +``network_route_tables`` in ``${KAYOBE_CONFIG_PATH}/networks.yml`` to a list of +route tables. These route tables will be added to ``/etc/iproute2/rt_tables``. + +To configure a routing table called ``exampleroutetable`` with ID ``1``: + +.. code-block:: yaml + :caption: ``networks.yml`` + + network_route_tables: + - name: exampleroutetable + id: 1 + +To configure route tables on specific hosts, use a host or group variables +file. + +Configuring IP Routing Policy Rules +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +IP routing policy rules may be configured by setting the ``rules`` attribute +for a network to a list of rules. The format of a rule is the string which +would be appended to ``ip rule `` to create or delete the rule. + +To configure a network called ``example`` with an IP routing policy rule to +handle traffic from the subnet ``10.1.0.0/24`` using the routing table +``exampleroutetable``: + +.. code-block:: yaml + :caption: ``networks.yml`` + + example_rules: + - from 10.1.0.0/24 table exampleroutetable + +These rules will be configured on all hosts to which the network is mapped. + +Configuring IP Routes on Specific Tables +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A route may be added to a specific routing table by adding the name or ID of +the table to a ``table`` attribute of the route: + +To configure a network called ``example`` with a default route and a +'connected' (local subnet) route to the subnet ``10.1.0.0/24`` on the table +``exampleroutetable``: + +.. code-block:: yaml + :caption: ``networks.yml`` + + example_routes: + - cidr: 0.0.0.0/0 + gateway 10.1.0.1 + table: exampleroutetable + - cidr: 10.1.0.0/24 + table: exampleroutetable + Per-host Network Configuration ============================== diff --git a/etc/kayobe/networks.yml b/etc/kayobe/networks.yml index 0d43d5ec0..cc5ec3bb9 100644 --- a/etc/kayobe/networks.yml +++ b/etc/kayobe/networks.yml @@ -150,6 +150,13 @@ # OVS bridge. #network_patch_suffix_ovs: +############################################################################### +# Network routing table configuration. + +# List of IP routing tables. Each item should be a dict containing 'id' and +# 'name' items. These tables will be added to /etc/iproute2/rt_tables. +#network_route_tables: + ############################################################################### # Dummy variable to allow Ansible to accept this file. workaround_ansible_issue_8743: yes