From bb78f3a9ad28f62896a536719783011794deb64c Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Thu, 3 Mar 2022 20:23:09 +0100 Subject: static: T4283: support "reject" routes - emit an ICMP unreachable when matched --- data/templates/frr/static_routes_macro.j2 | 3 ++ .../include/static/static-route-reject.xml.i | 12 +++++ .../include/static/static-route.xml.i | 1 + .../include/static/static-route6.xml.i | 1 + smoketest/scripts/cli/test_protocols_static.py | 57 +++++++++++++++++++--- src/conf_mode/protocols_static.py | 4 ++ 6 files changed, 70 insertions(+), 8 deletions(-) create mode 100644 interface-definitions/include/static/static-route-reject.xml.i diff --git a/data/templates/frr/static_routes_macro.j2 b/data/templates/frr/static_routes_macro.j2 index 86c7470ca..8359357b7 100644 --- a/data/templates/frr/static_routes_macro.j2 +++ b/data/templates/frr/static_routes_macro.j2 @@ -2,6 +2,9 @@ {% if prefix_config.blackhole is defined %} {{ ip_ipv6 }} route {{ prefix }} blackhole {{ prefix_config.blackhole.distance if prefix_config.blackhole.distance is defined }} {{ 'tag ' + prefix_config.blackhole.tag if prefix_config.blackhole.tag is defined }} {{ 'table ' + table if table is defined and table is not none }} {% endif %} +{% if prefix_config.reject is defined %} +{{ ip_ipv6 }} route {{ prefix }} reject {{ prefix_config.reject.distance if prefix_config.reject.distance is defined }} {{ 'tag ' + prefix_config.reject.tag if prefix_config.reject.tag is defined }} {{ 'table ' + table if table is defined and table is not none }} +{% endif %} {% if prefix_config.dhcp_interface is defined and prefix_config.dhcp_interface is not none %} {% set next_hop = prefix_config.dhcp_interface | get_dhcp_router %} {% if next_hop is defined and next_hop is not none %} diff --git a/interface-definitions/include/static/static-route-reject.xml.i b/interface-definitions/include/static/static-route-reject.xml.i new file mode 100644 index 000000000..81d4f9afd --- /dev/null +++ b/interface-definitions/include/static/static-route-reject.xml.i @@ -0,0 +1,12 @@ + + + + Emit an ICMP unreachable when matched + + + #include + #include + + + + diff --git a/interface-definitions/include/static/static-route.xml.i b/interface-definitions/include/static/static-route.xml.i index 8433703a5..2de5dc58f 100644 --- a/interface-definitions/include/static/static-route.xml.i +++ b/interface-definitions/include/static/static-route.xml.i @@ -12,6 +12,7 @@ #include + #include #include diff --git a/interface-definitions/include/static/static-route6.xml.i b/interface-definitions/include/static/static-route6.xml.i index 124b2b062..35feef41c 100644 --- a/interface-definitions/include/static/static-route6.xml.i +++ b/interface-definitions/include/static/static-route6.xml.i @@ -12,6 +12,7 @@ #include + #include IPv6 gateway interface name diff --git a/smoketest/scripts/cli/test_protocols_static.py b/smoketest/scripts/cli/test_protocols_static.py index 4c4eb5a7c..3ef9c76d8 100755 --- a/smoketest/scripts/cli/test_protocols_static.py +++ b/smoketest/scripts/cli/test_protocols_static.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021 VyOS maintainers and contributors +# Copyright (C) 2021-2022 VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -52,9 +52,16 @@ routes = { }, 'blackhole' : { 'distance' : '90' }, }, - '100.64.0.0/10' : { + '100.64.0.0/16' : { 'blackhole' : { }, }, + '100.65.0.0/16' : { + 'reject' : { 'distance' : '10', 'tag' : '200' }, + }, + '100.66.0.0/16' : { + 'blackhole' : { }, + 'reject' : { 'distance' : '10', 'tag' : '200' }, + }, '2001:db8:100::/40' : { 'next_hop' : { '2001:db8::1' : { 'distance' : '10' }, @@ -74,6 +81,9 @@ routes = { }, 'blackhole' : { 'distance' : '250', 'tag' : '500' }, }, + '2001:db8:300::/40' : { + 'reject' : { 'distance' : '250', 'tag' : '500' }, + }, '2001:db8::/32' : { 'blackhole' : { 'distance' : '200', 'tag' : '600' }, }, @@ -82,9 +92,15 @@ routes = { tables = ['80', '81', '82'] class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase): - def setUp(self): - # This is our "target" VRF when leaking routes: - self.cli_set(['vrf', 'name', 'black', 'table', '43210']) + @classmethod + def setUpClass(cls): + super(cls, cls).setUpClass() + cls.cli_set(cls, ['vrf', 'name', 'black', 'table', '43210']) + + @classmethod + def tearDownClass(cls): + cls.cli_delete(cls, ['vrf']) + super(cls, cls).tearDownClass() def tearDown(self): for route, route_config in routes.items(): @@ -135,6 +151,20 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase): if 'tag' in route_config['blackhole']: self.cli_set(base + ['blackhole', 'tag', route_config['blackhole']['tag']]) + if 'reject' in route_config: + self.cli_set(base + ['reject']) + if 'distance' in route_config['reject']: + self.cli_set(base + ['reject', 'distance', route_config['reject']['distance']]) + if 'tag' in route_config['reject']: + self.cli_set(base + ['reject', 'tag', route_config['reject']['tag']]) + + if {'blackhole', 'reject'} <= set(route_config): + # Can not use blackhole and reject at the same time + with self.assertRaises(ConfigSessionError): + self.cli_commit() + self.cli_delete(base + ['blackhole']) + self.cli_delete(base + ['reject']) + # commit changes self.cli_commit() @@ -177,6 +207,11 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase): else: self.assertIn(tmp, frrconfig) + if {'blackhole', 'reject'} <= set(route_config): + # Can not use blackhole and reject at the same time + # Config error validated above - skip this route + continue + if 'blackhole' in route_config: tmp = f'{ip_ipv6} route {route} blackhole' if 'tag' in route_config['blackhole']: @@ -186,6 +221,15 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase): self.assertIn(tmp, frrconfig) + if 'reject' in route_config: + tmp = f'{ip_ipv6} route {route} reject' + if 'tag' in route_config['reject']: + tmp += ' tag ' + route_config['reject']['tag'] + if 'distance' in route_config['reject']: + tmp += ' ' + route_config['reject']['distance'] + + self.assertIn(tmp, frrconfig) + def test_02_static_table(self): for table in tables: for route, route_config in routes.items(): @@ -389,11 +433,8 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase): self.assertIn(tmp, frrconfig) - self.cli_delete(['vrf']) - def test_04_static_zebra_route_map(self): # Implemented because of T3328 - self.debug = True route_map = 'foo-static-in' self.cli_set(['policy', 'route-map', route_map, 'rule', '10', 'action', 'permit']) diff --git a/src/conf_mode/protocols_static.py b/src/conf_mode/protocols_static.py index c1e427b16..f0ec48de4 100755 --- a/src/conf_mode/protocols_static.py +++ b/src/conf_mode/protocols_static.py @@ -82,6 +82,10 @@ def verify(static): for interface, interface_config in prefix_options[type].items(): verify_vrf(interface_config) + if {'blackhole', 'reject'} <= set(prefix_options): + raise ConfigError(f'Can not use both blackhole and reject for '\ + 'prefix "{prefix}"!') + return None def generate(static): -- cgit v1.2.3