diff --git a/README.md b/README.md index 3abebfe..8bb9817 100644 --- a/README.md +++ b/README.md @@ -581,7 +581,10 @@ The IP configuration supports the following options: - `suppress_prefixlength` - Reject routing decisions that have a prefix length of the specified or less. - `table` - - The route table to look up for the `to-table` action. + The route table to look up for the `to-table` action. `table` supports both the + numeric table and named table. In order to specify the named table, the users + have to ensure the named table is properly defined in `/etc/iproute2/rt_tables` + or `/etc/iproute2/rt_tables.d/*.conf`. - `to` - The destination address of the packet to match (e.g. `192.168.100.58/24`). - `tos` - diff --git a/module_utils/network_lsr/argument_validator.py b/module_utils/network_lsr/argument_validator.py index 6f43c93..e297168 100644 --- a/module_utils/network_lsr/argument_validator.py +++ b/module_utils/network_lsr/argument_validator.py @@ -2336,7 +2336,10 @@ class ArgValidator_ListConnections(ArgValidatorList): VALIDATE_ONE_MODE_INITSCRIPTS = "initscripts" def validate_route_tables(self, connection, idx): - for r in connection["ip"]["route"]: + rule_route_combined_list = ( + connection["ip"]["route"] + connection["ip"]["routing_rule"] + ) + for r in rule_route_combined_list: if isinstance(r["table"], Util.STRING_TYPE): mapping = IPRouteUtils.get_route_tables_mapping() if r["table"] in mapping: diff --git a/tests/playbooks/tests_routing_rules.yml b/tests/playbooks/tests_routing_rules.yml index a659a6a..0038cc7 100644 --- a/tests/playbooks/tests_routing_rules.yml +++ b/tests/playbooks/tests_routing_rules.yml @@ -19,6 +19,14 @@ state: present - include_tasks: tasks/assert_device_present.yml + - name: Create a dedicated test file in `/etc/iproute2/rt_tables.d/` and + add a new routing table + lineinfile: + path: /etc/iproute2/rt_tables.d/table.conf + line: "200 custom" + mode: "0644" + create: yes + - name: Configure connection profile and specify the numeric table in static routes import_role: @@ -91,6 +99,9 @@ dport: 128 - 256 invert: True table: 30600 + - priority: 200 + from: 198.51.100.56/26 + table: custom # the routing rule selector sport and ipproto are not supported by iproute # since v4.17.0, and the iproute installed in CentOS-7 and RHEL-7 is # v4.11.0 @@ -115,6 +126,13 @@ changed_when: false when: ansible_distribution_major_version != "7" + - name: Get the routing rule for looking up the table 'custom' + command: ip rule list table custom + register: route_rule_table_custom + ignore_errors: yes + changed_when: false + when: ansible_distribution_major_version != "7" + - name: Get the IPv4 routing rule for the connection "{{ interface }}" command: nmcli -f ipv4.routing-rules c show "{{ interface }}" register: connection_route_rule @@ -171,6 +189,16 @@ specified rule" when: ansible_distribution_major_version != "7" + - name: Assert that the routing rule with 'custom' table lookup matches the + specified rule + assert: + that: + - route_rule_table_custom.stdout is search("200:(\s+)from + 198.51.100.56/26 lookup custom") + msg: "the routing rule with 'custom' table lookup does not match the + specified rule" + when: ansible_distribution_major_version != "7" + - name: Assert that the IPv4 routing rule in the connection "{{ interface }}" matches the specified rule assert: @@ -191,6 +219,8 @@ 0.0.0.0/0 iif iiftest table 30400") - connection_route_rule.stdout is search("priority 30402 from 0.0.0.0/0 oif oiftest table 30400") + - connection_route_rule.stdout is search("priority 200 from + 198.51.100.56/26 table 200") msg: "the IPv4 routing rule in the connection '{{ interface }}' does not match the specified rule" @@ -206,6 +236,12 @@ ::/0 dport 128-256 table 30600") msg: "the IPv6 routing rule in the connection '{{ interface }}' does not match the specified rule" + + - name: Remove the dedicated test file in `/etc/iproute2/rt_tables.d/` + file: + state: absent + path: /etc/iproute2/rt_tables.d/table.conf + - import_playbook: down_profile+delete_interface.yml vars: profile: "{{ interface }}" diff --git a/tests/unit/test_network_connections.py b/tests/unit/test_network_connections.py index 3546de4..196a636 100644 --- a/tests/unit/test_network_connections.py +++ b/tests/unit/test_network_connections.py @@ -4395,6 +4395,7 @@ class TestValidatorRouteTable(Python26CompatTestCase): "table": 30400, }, ], + "routing_rule": [], }, } ] @@ -4650,6 +4651,25 @@ class TestValidatorRoutingRules(Python26CompatTestCase): } ] self.validator = network_lsr.argument_validator.ArgValidator_ListConnections() + self.old_getter = ( + network_lsr.argument_validator.IPRouteUtils.get_route_tables_mapping + ) + network_lsr.argument_validator.IPRouteUtils.get_route_tables_mapping = ( + classmethod( + lambda cls: { + "custom": 200, + "eth": 30400, + } + ) + ) + # the connection index is 0 because there is only one connection profile + # defined here + self.connection_index = 0 + + def tearDown(self): + network_lsr.argument_validator.IPRouteUtils.get_route_tables_mapping = ( + self.old_getter + ) def test_routing_rule_missing_address_family(self): """ @@ -4831,6 +4851,23 @@ class TestValidatorRoutingRules(Python26CompatTestCase): self.test_connections, ) + def test_table_found_when_lookup_named_table(self): + """ + Test that the `validate_route_tables()` will find the table id mapping from + `IPRouteUtils.get_route_tables_mapping()`. + """ + + self.test_connections[0]["ip"]["routing_rule"][0]["table"] = "custom" + + self.validator.validate_route_tables( + self.test_connections[0], + self.connection_index, + ) + self.assertEqual( + self.test_connections[0]["ip"]["routing_rule"][0]["table"], + 200, + ) + class TestValidatorDictBond(Python26CompatTestCase): def setUp(self):