From c79a61a67468ba84ad19e6b09097fdbaec1aa649 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 10 Feb 2021 21:04:17 +0100 Subject: frr: T2638: remove dedicated per protocol debugging With commit 015651a8 ("T2638: Enable more debugging in the FRR library") a global debug mechanism was added by creating a file named /tmp/vyos.frr.debug. With this change we can drop the duplicated debug code from every protocol. --- src/conf_mode/protocols_bgp.py | 29 ----------------------------- src/conf_mode/protocols_ospf.py | 28 ---------------------------- src/conf_mode/protocols_ospfv3.py | 28 ---------------------------- src/conf_mode/protocols_rip.py | 27 --------------------------- src/conf_mode/protocols_rpki.py | 28 ---------------------------- src/conf_mode/protocols_static.py | 28 ---------------------------- src/conf_mode/protocols_vrf.py | 28 ---------------------------- 7 files changed, 196 deletions(-) diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index 41d89e03b..a2c129149 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -20,7 +20,6 @@ from sys import exit from vyos.config import Config from vyos.configdict import dict_merge -from vyos.template import render from vyos.template import render_to_string from vyos.util import call from vyos.util import dict_search @@ -29,17 +28,8 @@ from vyos import frr from vyos import airbag airbag.enable() -config_file = r'/tmp/bgp.frr' frr_daemon = 'bgpd' -DEBUG = os.path.exists('/tmp/bgp.debug') -if DEBUG: - import logging - lg = logging.getLogger("vyos.frr") - lg.setLevel(logging.DEBUG) - ch = logging.StreamHandler() - lg.addHandler(ch) - def get_config(config=None): if config: conf = config @@ -156,10 +146,7 @@ def generate(bgp): asn = list(bgp.keys())[0] bgp[asn]['asn'] = asn - # render(config) not needed, its only for debug - render(config_file, 'frr/bgp.frr.tmpl', bgp[asn]) bgp['new_frr_config'] = render_to_string('frr/bgp.frr.tmpl', bgp[asn]) - return None def apply(bgp): @@ -168,21 +155,6 @@ def apply(bgp): frr_cfg.load_configuration(frr_daemon) frr_cfg.modify_section(f'router bgp \S+', '') frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', bgp['new_frr_config']) - - # Debugging - if DEBUG: - from pprint import pprint - print('') - print('--------- DEBUGGING ----------') - pprint(dir(frr_cfg)) - print('Existing config:\n') - for line in frr_cfg.original_config: - print(line) - print(f'Replacement config:\n') - print(f'{bgp["new_frr_config"]}') - print(f'Modified config:\n') - print(f'{frr_cfg}') - frr_cfg.commit_configuration(frr_daemon) # If FRR config is blank, rerun the blank commit x times due to frr-reload @@ -191,7 +163,6 @@ def apply(bgp): for a in range(5): frr_cfg.commit_configuration(frr_daemon) - return None if __name__ == '__main__': diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py index 3310fac5a..5e0794fa0 100755 --- a/src/conf_mode/protocols_ospf.py +++ b/src/conf_mode/protocols_ospf.py @@ -22,7 +22,6 @@ from vyos.config import Config from vyos.configdict import dict_merge from vyos.configverify import verify_route_maps from vyos.configverify import verify_interface_exists -from vyos.template import render from vyos.template import render_to_string from vyos.util import call from vyos.util import dict_search @@ -32,17 +31,8 @@ from vyos import frr from vyos import airbag airbag.enable() -config_file = r'/tmp/ospf.frr' frr_daemon = 'ospfd' -DEBUG = os.path.exists('/tmp/ospf.debug') -if DEBUG: - import logging - lg = logging.getLogger("vyos.frr") - lg.setLevel(logging.DEBUG) - ch = logging.StreamHandler() - lg.addHandler(ch) - def get_config(config=None): if config: conf = config @@ -140,10 +130,7 @@ def generate(ospf): ospf['new_frr_config'] = '' return None - # render(config) not needed, its only for debug - render(config_file, 'frr/ospf.frr.tmpl', ospf) ospf['new_frr_config'] = render_to_string('frr/ospf.frr.tmpl', ospf) - return None def apply(ospf): @@ -153,21 +140,6 @@ def apply(ospf): frr_cfg.modify_section(r'interface \S+', '') frr_cfg.modify_section('router ospf', '') frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', ospf['new_frr_config']) - - # Debugging - if DEBUG: - from pprint import pprint - print('') - print('--------- DEBUGGING ----------') - pprint(dir(frr_cfg)) - print('Existing config:\n') - for line in frr_cfg.original_config: - print(line) - print(f'Replacement config:\n') - print(f'{ospf["new_frr_config"]}') - print(f'Modified config:\n') - print(f'{frr_cfg}') - frr_cfg.commit_configuration(frr_daemon) # If FRR config is blank, rerun the blank commit x times due to frr-reload diff --git a/src/conf_mode/protocols_ospfv3.py b/src/conf_mode/protocols_ospfv3.py index e008a350b..6c3aaf426 100755 --- a/src/conf_mode/protocols_ospfv3.py +++ b/src/conf_mode/protocols_ospfv3.py @@ -21,7 +21,6 @@ from sys import exit from vyos.config import Config from vyos.configdict import dict_merge from vyos.configverify import verify_route_maps -from vyos.template import render from vyos.template import render_to_string from vyos.util import call from vyos.xml import defaults @@ -30,17 +29,8 @@ from vyos import frr from vyos import airbag airbag.enable() -config_file = r'/tmp/ospfv3.frr' frr_daemon = 'ospf6d' -DEBUG = os.path.exists('/tmp/ospfv3.debug') -if DEBUG: - import logging - lg = logging.getLogger("vyos.frr") - lg.setLevel(logging.DEBUG) - ch = logging.StreamHandler() - lg.addHandler(ch) - def get_config(config=None): if config: conf = config @@ -74,10 +64,7 @@ def generate(ospfv3): ospfv3['new_frr_config'] = '' return None - # render(config) not needed, its only for debug - render(config_file, 'frr/ospfv3.frr.tmpl', ospfv3) ospfv3['new_frr_config'] = render_to_string('frr/ospfv3.frr.tmpl', ospfv3) - return None def apply(ospfv3): @@ -86,21 +73,6 @@ def apply(ospfv3): frr_cfg.load_configuration(frr_daemon) frr_cfg.modify_section('router ospf6', '') frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', ospfv3['new_frr_config']) - - # Debugging - if DEBUG: - from pprint import pprint - print('') - print('--------- DEBUGGING ----------') - pprint(dir(frr_cfg)) - print('Existing config:\n') - for line in frr_cfg.original_config: - print(line) - print(f'Replacement config:\n') - print(f'{ospfv3["new_frr_config"]}') - print(f'Modified config:\n') - print(f'{frr_cfg}') - frr_cfg.commit_configuration(frr_daemon) # If FRR config is blank, re-run the blank commit x times due to frr-reload diff --git a/src/conf_mode/protocols_rip.py b/src/conf_mode/protocols_rip.py index 06d7c6d49..6db5143c5 100755 --- a/src/conf_mode/protocols_rip.py +++ b/src/conf_mode/protocols_rip.py @@ -24,24 +24,14 @@ from vyos.configverify import verify_route_maps from vyos.util import call from vyos.util import dict_search from vyos.xml import defaults -from vyos.template import render from vyos.template import render_to_string from vyos import ConfigError from vyos import frr from vyos import airbag airbag.enable() -config_file = r'/tmp/rip.frr' frr_daemon = 'ripd' -DEBUG = os.path.exists('/tmp/rip.debug') -if DEBUG: - import logging - lg = logging.getLogger("vyos.frr") - lg.setLevel(logging.DEBUG) - ch = logging.StreamHandler() - lg.addHandler(ch) - def get_config(config=None): if config: conf = config @@ -106,8 +96,6 @@ def generate(rip): rip['new_frr_config'] = '' return None - # render(config) not needed, its only for debug - render(config_file, 'frr/rip.frr.tmpl', rip) rip['new_frr_config'] = render_to_string('frr/rip.frr.tmpl', rip) return None @@ -120,21 +108,6 @@ def apply(rip): frr_cfg.modify_section(r'interface \S+', '') frr_cfg.modify_section('router rip', '') frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', rip['new_frr_config']) - - # Debugging - if DEBUG: - from pprint import pprint - print('') - print('--------- DEBUGGING ----------') - pprint(dir(frr_cfg)) - print('Existing config:\n') - for line in frr_cfg.original_config: - print(line) - print(f'Replacement config:\n') - print(f'{rip["new_frr_config"]}') - print(f'Modified config:\n') - print(f'{frr_cfg}') - frr_cfg.commit_configuration(frr_daemon) # If FRR config is blank, rerun the blank commit x times due to frr-reload diff --git a/src/conf_mode/protocols_rpki.py b/src/conf_mode/protocols_rpki.py index 0b9525caf..75b870b05 100755 --- a/src/conf_mode/protocols_rpki.py +++ b/src/conf_mode/protocols_rpki.py @@ -20,7 +20,6 @@ from sys import exit from vyos.config import Config from vyos.configdict import dict_merge -from vyos.template import render from vyos.template import render_to_string from vyos.util import call from vyos.util import dict_search @@ -30,17 +29,8 @@ from vyos import frr from vyos import airbag airbag.enable() -config_file = r'/tmp/rpki.frr' frr_daemon = 'bgpd' -DEBUG = os.path.exists('/tmp/rpki.debug') -if DEBUG: - import logging - lg = logging.getLogger("vyos.frr") - lg.setLevel(logging.DEBUG) - ch = logging.StreamHandler() - lg.addHandler(ch) - def get_config(config=None): if config: conf = config @@ -90,10 +80,7 @@ def verify(rpki): return None def generate(rpki): - # render(config) not needed, its only for debug - render(config_file, 'frr/rpki.frr.tmpl', rpki) rpki['new_frr_config'] = render_to_string('frr/rpki.frr.tmpl', rpki) - return None def apply(rpki): @@ -102,21 +89,6 @@ def apply(rpki): frr_cfg.load_configuration(frr_daemon) frr_cfg.modify_section('rpki', '') frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', rpki['new_frr_config']) - - # Debugging - if DEBUG: - from pprint import pprint - print('') - print('--------- DEBUGGING ----------') - pprint(dir(frr_cfg)) - print('Existing config:\n') - for line in frr_cfg.original_config: - print(line) - print(f'Replacement config:\n') - print(f'{rpki["new_frr_config"]}') - print(f'Modified config:\n') - print(f'{frr_cfg}') - frr_cfg.commit_configuration(frr_daemon) # If FRR config is blank, re-run the blank commit x times due to frr-reload diff --git a/src/conf_mode/protocols_static.py b/src/conf_mode/protocols_static.py index 62a3fecd7..5d101b33e 100755 --- a/src/conf_mode/protocols_static.py +++ b/src/conf_mode/protocols_static.py @@ -19,7 +19,6 @@ import os from sys import exit from vyos.config import Config -from vyos.template import render from vyos.template import render_to_string from vyos.util import call from vyos.configverify import verify_route_maps @@ -28,17 +27,8 @@ from vyos import frr from vyos import airbag airbag.enable() -config_file = r'/tmp/static.frr' frr_daemon = 'staticd' -DEBUG = os.path.exists('/tmp/static.debug') -if DEBUG: - import logging - lg = logging.getLogger("vyos.frr") - lg.setLevel(logging.DEBUG) - ch = logging.StreamHandler() - lg.addHandler(ch) - def get_config(config=None): if config: conf = config @@ -53,10 +43,7 @@ def verify(static): return None def generate(static): - # render(config) not needed, its only for debug - render(config_file, 'frr/static.frr.tmpl', static) static['new_frr_config'] = render_to_string('frr/static.frr.tmpl', static) - return None def apply(static): @@ -66,21 +53,6 @@ def apply(static): frr_cfg.modify_section(r'^ip route .*', '') frr_cfg.modify_section(r'^ipv6 route .*', '') frr_cfg.add_before(r'(interface .*|line vty)', static['new_frr_config']) - - # Debugging - if DEBUG: - from pprint import pprint - print('') - print('--------- DEBUGGING ----------') - pprint(dir(frr_cfg)) - print('Existing config:\n') - for line in frr_cfg.original_config: - print(line) - print(f'Replacement config:\n') - print(f'{static["new_frr_config"]}') - print(f'Modified config:\n') - print(f'{frr_cfg}') - frr_cfg.commit_configuration(frr_daemon) # If FRR config is blank, rerun the blank commit x times due to frr-reload diff --git a/src/conf_mode/protocols_vrf.py b/src/conf_mode/protocols_vrf.py index 7c32c7013..227e7d5e1 100755 --- a/src/conf_mode/protocols_vrf.py +++ b/src/conf_mode/protocols_vrf.py @@ -19,7 +19,6 @@ import os from sys import exit from vyos.config import Config -from vyos.template import render from vyos.template import render_to_string from vyos.util import call from vyos import ConfigError @@ -27,17 +26,8 @@ from vyos import frr from vyos import airbag airbag.enable() -config_file = r'/tmp/vrf.frr' frr_daemon = 'staticd' -DEBUG = os.path.exists('/tmp/vrf.debug') -if DEBUG: - import logging - lg = logging.getLogger("vyos.frr") - lg.setLevel(logging.DEBUG) - ch = logging.StreamHandler() - lg.addHandler(ch) - def get_config(config=None): if config: conf = config @@ -52,10 +42,7 @@ def verify(vrf): return None def generate(vrf): - # render(config) not needed, its only for debug - render(config_file, 'frr/vrf.frr.tmpl', vrf) vrf['new_frr_config'] = render_to_string('frr/vrf.frr.tmpl', vrf) - return None def apply(vrf): @@ -64,21 +51,6 @@ def apply(vrf): frr_cfg.load_configuration(frr_daemon) frr_cfg.modify_section(r'vrf \S+', '') frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', vrf['new_frr_config']) - - # Debugging - if DEBUG: - from pprint import pprint - print('') - print('--------- DEBUGGING ----------') - pprint(dir(frr_cfg)) - print('Existing config:\n') - for line in frr_cfg.original_config: - print(line) - print(f'Replacement config:\n') - print(f'{vrf["new_frr_config"]}') - print(f'Modified config:\n') - print(f'{frr_cfg}') - frr_cfg.commit_configuration(frr_daemon) # If FRR config is blank, rerun the blank commit x times due to frr-reload -- cgit v1.2.3 From 4f884631d937b16258f352e085db79e4398c0971 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 10 Feb 2021 21:05:28 +0100 Subject: ripng: T3281: migrate to get_config_dict() and FRR reload --- Makefile | 1 - data/configd-include.json | 1 + data/templates/frr/ripng.frr.tmpl | 82 ++++++++++++++++ interface-definitions/protocols-ripng.xml.in | 4 +- smoketest/scripts/cli/test_protocols_ripng.py | 8 +- src/conf_mode/protocols_ripng.py | 133 ++++++++++++++++++++++++++ 6 files changed, 222 insertions(+), 7 deletions(-) create mode 100644 data/templates/frr/ripng.frr.tmpl create mode 100755 src/conf_mode/protocols_ripng.py diff --git a/Makefile b/Makefile index ad71219eb..882d5311b 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,6 @@ interface_definitions: $(config_xml_obj) rm -f $(TMPL_DIR)/vpn/node.def rm -f $(TMPL_DIR)/vpn/ipsec/node.def rm -rf $(TMPL_DIR)/vpn/nipsec - rm -rf $(TMPL_DIR)/protocols/nripng # XXX: required until OSPF and RIP is migrated from vyatta-cfg-quagga to vyos-1x mkdir $(TMPL_DIR)/interfaces/loopback/node.tag/ipv6 diff --git a/data/configd-include.json b/data/configd-include.json index 495000961..e50dbf1b2 100644 --- a/data/configd-include.json +++ b/data/configd-include.json @@ -40,6 +40,7 @@ "protocols_ospfv3.py", "protocols_pim.py", "protocols_rip.py", +"protocols_ripng.py", "protocols_static.py", "protocols_static_multicast.py", "protocols_vrf.py", diff --git a/data/templates/frr/ripng.frr.tmpl b/data/templates/frr/ripng.frr.tmpl new file mode 100644 index 000000000..ac14dfd3f --- /dev/null +++ b/data/templates/frr/ripng.frr.tmpl @@ -0,0 +1,82 @@ +! +router ripng +{% if default_information is defined and default_information.originate is defined %} + default-information originate +{% endif %} +{% if default_metric is defined and default_metric is not none %} + default-metric {{ default_metric }} +{% endif %} +{% if aggregate_address is defined and aggregate_address is not none %} +{% for prefix in aggregate_address %} + aggregate-address {{ prefix }} +{% endfor %} +{% endif %} +{% if passive_interface is defined and passive_interface is not none %} +{% for ifname in passive_interface %} + passive-interface {{ ifname }} +{% endfor %} +{% endif %} +{% if interface is defined and interface is not none %} +{% for ifname in interface %} + network {{ ifname }} +{% endfor %} +{% endif %} +{% if network is defined and network is not none %} +{% for net in network %} + network {{ net }} +{% endfor %} +{% endif %} +{% if route is defined and route is not none %} +{% for prefix in route %} + route {{ prefix }} +{% endfor %} +{% endif %} +{% if redistribute is defined and redistribute is not none %} +{% for protocol, protocol_config in redistribute.items() %} +{% if protocol == 'ospfv3' %} +{% set protocol = 'ospf6' %} +{% endif %} + redistribute {{ protocol }} {{ 'metric ' + protocol_config.metric if protocol_config.metric is defined }} {{ 'route-map ' + protocol_config.route_map if protocol_config.route_map is defined }} +{% endfor %} +{% endif %} +{# timers have default values #} + timers basic {{ timers['update'] }} {{ timers.timeout }} {{ timers.garbage_collection }} +{% if distribute_list is defined and distribute_list is not none %} +{% if distribute_list.access_list is defined and distribute_list.access_list is not none %} +{% if distribute_list.access_list.in is defined and distribute_list.access_list.in is not none %} + ipv6 distribute-list {{ distribute_list.access_list.in }} in +{% endif %} +{% if distribute_list.access_list.out is defined and distribute_list.access_list.out is not none %} + ipv6 distribute-list {{ distribute_list.access_list.out }} out +{% endif %} +{% endif %} +{% if distribute_list.interface is defined and distribute_list.interface is not none %} +{% for interface, interface_config in distribute_list.interface.items() %} +{% if interface_config.access_list is defined and interface_config.access_list is not none %} +{% if interface_config.access_list.in is defined and interface_config.access_list.in is not none %} + ipv6 distribute-list {{ interface_config.access_list.in }} in {{ interface }} +{% endif %} +{% if interface_config.access_list.out is defined and interface_config.access_list.out is not none %} + ipv6 distribute-list {{ interface_config.access_list.out }} out {{ interface }} +{% endif %} +{% endif %} +{% if interface_config.prefix_list is defined and interface_config.prefix_list is not none %} +{% if interface_config.prefix_list.in is defined and interface_config.prefix_list.in is not none %} + ipv6 distribute-list prefix {{ interface_config.prefix_list.in }} in {{ interface }} +{% endif %} +{% if interface_config.prefix_list.out is defined and interface_config.prefix_list.out is not none %} + ipv6 distribute-list prefix {{ interface_config.prefix_list.out }} out {{ interface }} +{% endif %} +{% endif %} +{% endfor %} +{% endif %} +{% if distribute_list.prefix_list is defined and distribute_list.prefix_list is not none %} +{% if distribute_list.prefix_list.in is defined and distribute_list.prefix_list.in is not none %} + ipv6 distribute-list prefix {{ distribute_list.prefix_list.in }} in +{% endif %} +{% if distribute_list.prefix_list.out is defined and distribute_list.prefix_list.out is not none %} + ipv6 distribute-list prefix {{ distribute_list.prefix_list.out }} out +{% endif %} +{% endif %} +{% endif %} +! diff --git a/interface-definitions/protocols-ripng.xml.in b/interface-definitions/protocols-ripng.xml.in index 74f720e89..e456c3f3b 100644 --- a/interface-definitions/protocols-ripng.xml.in +++ b/interface-definitions/protocols-ripng.xml.in @@ -1,8 +1,8 @@ - + - + Routing Information Protocol (RIPng) parameters diff --git a/smoketest/scripts/cli/test_protocols_ripng.py b/smoketest/scripts/cli/test_protocols_ripng.py index 90cbaccd8..6850b60d3 100755 --- a/smoketest/scripts/cli/test_protocols_ripng.py +++ b/smoketest/scripts/cli/test_protocols_ripng.py @@ -107,10 +107,10 @@ class TestProtocolsRIPng(unittest.TestCase): self.assertIn(f'router ripng', frrconfig) self.assertIn(f' default-information originate', frrconfig) self.assertIn(f' default-metric {metric}', frrconfig) - self.assertIn(f' distribute-list {acl_in} in', frrconfig) - self.assertIn(f' distribute-list {acl_out} out', frrconfig) - self.assertIn(f' distribute-list prefix {prefix_list_in} in', frrconfig) - self.assertIn(f' distribute-list prefix {prefix_list_out} out', frrconfig) + self.assertIn(f' ipv6 distribute-list {acl_in} in', frrconfig) + self.assertIn(f' ipv6 distribute-list {acl_out} out', frrconfig) + self.assertIn(f' ipv6 distribute-list prefix {prefix_list_in} in', frrconfig) + self.assertIn(f' ipv6 distribute-list prefix {prefix_list_out} out', frrconfig) self.assertIn(f' passive-interface default', frrconfig) self.assertIn(f' timers basic {timer_update} {timer_timeout} {timer_garbage}', frrconfig) for aggregate in aggregates: diff --git a/src/conf_mode/protocols_ripng.py b/src/conf_mode/protocols_ripng.py new file mode 100755 index 000000000..8cc5de64a --- /dev/null +++ b/src/conf_mode/protocols_ripng.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 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 +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import os + +from sys import exit + +from vyos.config import Config +from vyos.configdict import dict_merge +from vyos.configverify import verify_route_maps +from vyos.util import call +from vyos.util import dict_search +from vyos.xml import defaults +from vyos.template import render_to_string +from vyos import ConfigError +from vyos import frr +from vyos import airbag +airbag.enable() + +frr_daemon = 'ripngd' + +def get_config(config=None): + if config: + conf = config + else: + conf = Config() + base = ['protocols', 'ripng'] + ripng = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) + + # Bail out early if configuration tree does not exist + if not conf.exists(base): + return ripng + + # We have gathered the dict representation of the CLI, but there are default + # options which we need to update into the dictionary retrived. + default_values = defaults(base) + # merge in remaining default values + ripng = dict_merge(default_values, ripng) + + # We also need some additional information from the config, prefix-lists + # and route-maps for instance. They will be used in verify() + base = ['policy'] + tmp = conf.get_config_dict(base, key_mangling=('-', '_')) + # Merge policy dict into OSPF dict + ripng = dict_merge(tmp, ripng) + + import pprint + pprint.pprint(ripng) + return ripng + +def verify(ripng): + if not ripng: + return None + + acl_in = dict_search('distribute_list.access_list.in', ripng) + if acl_in and acl_in not in (dict_search('policy.access_list6', ripng) or []): + raise ConfigError(f'Inbound access-list6 "{acl_in}" does not exist!') + + acl_out = dict_search('distribute_list.access_list.out', ripng) + if acl_out and acl_out not in (dict_search('policy.access_list6', ripng) or []): + raise ConfigError(f'Outbound access-list6 "{acl_out}" does not exist!') + + prefix_list_in = dict_search('distribute_list.prefix_list.in', ripng) + if prefix_list_in and prefix_list_in.replace('-','_') not in (dict_search('policy.prefix_list6', ripng) or []): + raise ConfigError(f'Inbound prefix-list6 "{prefix_list_in}" does not exist!') + + prefix_list_out = dict_search('distribute_list.prefix_list.out', ripng) + if prefix_list_out and prefix_list_out.replace('-','_') not in (dict_search('policy.prefix_list6', ripng) or []): + raise ConfigError(f'Outbound prefix-list6 "{prefix_list_out}" does not exist!') + + if 'interface' in ripng: + for interface, interface_options in ripng['interface'].items(): + if 'authentication' in interface_options: + if {'md5', 'plaintext_password'} <= set(interface_options['authentication']): + raise ConfigError('Can not use both md5 and plaintext-password at the same time!') + if 'split_horizon' in interface_options: + if {'disable', 'poison_reverse'} <= set(interface_options['split_horizon']): + raise ConfigError(f'You can not have "split-horizon poison-reverse" enabled ' \ + f'with "split-horizon disable" for "{interface}"!') + + verify_route_maps(ripng) + +def generate(ripng): + if not ripng: + ripng['new_frr_config'] = '' + return None + + ripng['new_frr_config'] = render_to_string('frr/ripng.frr.tmpl', ripng) + import pprint + pprint.pprint(ripng['new_frr_config']) + + return None + +def apply(ripng): + # Save original configuration prior to starting any commit actions + frr_cfg = frr.FRRConfig() + frr_cfg.load_configuration(frr_daemon) + frr_cfg.modify_section(r'key chain \S+', '') + frr_cfg.modify_section(r'interface \S+', '') + frr_cfg.modify_section('router ripng', '') + frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', ripng['new_frr_config']) + frr_cfg.commit_configuration(frr_daemon) + + # If FRR config is blank, rerun the blank commit x times due to frr-reload + # behavior/bug not properly clearing out on one commit. + if ripng['new_frr_config'] == '': + for a in range(5): + frr_cfg.commit_configuration(frr_daemon) + + return None + +if __name__ == '__main__': + try: + c = get_config() + verify(c) + generate(c) + apply(c) + except ConfigError as e: + print(e) + exit(1) -- cgit v1.2.3 From e94376ea29218de0368343262fcc110b35a2143e Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 10 Feb 2021 21:05:48 +0100 Subject: Makefile: remove "interfaces ip" node as all components have been migrated ... from vyatta-cfg-quagga to vyos-1x --- Makefile | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 882d5311b..abe4524d1 100644 --- a/Makefile +++ b/Makefile @@ -49,13 +49,10 @@ interface_definitions: $(config_xml_obj) # XXX: required until OSPF and RIP is migrated from vyatta-cfg-quagga to vyos-1x mkdir $(TMPL_DIR)/interfaces/loopback/node.tag/ipv6 mkdir $(TMPL_DIR)/interfaces/dummy/node.tag/ipv6 - mkdir $(TMPL_DIR)/interfaces/openvpn/node.tag/ip - mkdir -p $(TMPL_DIR)/interfaces/vti/node.tag/ip mkdir -p $(TMPL_DIR)/interfaces/vti/node.tag/ipv6 cp $(TMPL_DIR)/interfaces/ethernet/node.tag/ipv6/node.def $(TMPL_DIR)/interfaces/loopback/node.tag/ipv6 cp $(TMPL_DIR)/interfaces/ethernet/node.tag/ipv6/node.def $(TMPL_DIR)/interfaces/dummy/node.tag/ipv6 - cp $(TMPL_DIR)/interfaces/ethernet/node.tag/ip/node.def $(TMPL_DIR)/interfaces/openvpn/node.tag/ip - cp $(TMPL_DIR)/interfaces/ethernet/node.tag/ip/node.def $(TMPL_DIR)/interfaces/vti/node.tag/ip + cp $(TMPL_DIR)/interfaces/ethernet/node.tag/ipv6/node.def $(TMPL_DIR)/interfaces/vti/node.tag/ipv6 .PHONY: op_mode_definitions -- cgit v1.2.3 From a72ea95cb276e13713e4a6433707e368ce8ee8fa Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 10 Feb 2021 21:05:52 +0100 Subject: rip: T2547: fix indention of distribute-list in FRR template --- data/templates/frr/rip.frr.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/templates/frr/rip.frr.tmpl b/data/templates/frr/rip.frr.tmpl index c0d062fc6..50db2e9de 100644 --- a/data/templates/frr/rip.frr.tmpl +++ b/data/templates/frr/rip.frr.tmpl @@ -114,10 +114,10 @@ router rip {% endif %} {% if distribute_list.prefix_list is defined and distribute_list.prefix_list is not none %} {% if distribute_list.prefix_list.in is defined and distribute_list.prefix_list.in is not none %} -distribute-list prefix {{ distribute_list.prefix_list.in }} in + distribute-list prefix {{ distribute_list.prefix_list.in }} in {% endif %} {% if distribute_list.prefix_list.out is defined and distribute_list.prefix_list.out is not none %} -distribute-list prefix {{ distribute_list.prefix_list.out }} out + distribute-list prefix {{ distribute_list.prefix_list.out }} out {% endif %} {% endif %} {% endif %} -- cgit v1.2.3 From 5a98ca315ef96d4553c1530a1bb66d5458f38fe8 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Wed, 10 Feb 2021 21:05:54 +0100 Subject: smoketest: static-routes: enable VRF table leaking test As we have upgrade to FRR 7.5 in current the issue within FRR vtysh [1] is fixed. [1]: https://github.com/FRRouting/frr/issues/8016 --- smoketest/scripts/cli/test_protocols_static.py | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/smoketest/scripts/cli/test_protocols_static.py b/smoketest/scripts/cli/test_protocols_static.py index a4c320a62..cf591f060 100755 --- a/smoketest/scripts/cli/test_protocols_static.py +++ b/smoketest/scripts/cli/test_protocols_static.py @@ -212,11 +212,8 @@ class StaticRouteTest(unittest.TestCase): self.session.set(base + ['next-hop', next_hop, 'distance', next_hop_config['distance']]) if 'interface' in next_hop_config: self.session.set(base + ['next-hop', next_hop, 'interface', next_hop_config['interface']]) - - # This is currently not supported because of an FRR issue: - # https://github.com/FRRouting/frr/issues/8016 - # if 'vrf' in next_hop_config: - # self.session.set(base + ['next-hop', next_hop, 'vrf', next_hop_config['vrf']]) + if 'vrf' in next_hop_config: + self.session.set(base + ['next-hop', next_hop, 'vrf', next_hop_config['vrf']]) if 'interface' in route_config: @@ -226,11 +223,8 @@ class StaticRouteTest(unittest.TestCase): self.session.set(base + ['interface', interface, 'disable']) if 'distance' in interface_config: self.session.set(base + ['interface', interface, 'distance', interface_config['distance']]) - - # This is currently not supported because of an FRR issue: - # https://github.com/FRRouting/frr/issues/8016 - # if 'vrf' in interface_config: - # self.session.set(base + ['interface', interface, 'vrf', interface_config['vrf']]) + if 'vrf' in interface_config: + self.session.set(base + ['interface', interface, 'vrf', interface_config['vrf']]) if 'blackhole' in route_config: self.session.set(base + ['blackhole']) @@ -259,10 +253,8 @@ class StaticRouteTest(unittest.TestCase): tmp += ' ' + next_hop_config['interface'] if 'distance' in next_hop_config: tmp += ' ' + next_hop_config['distance'] - # This is currently not supported because of an FRR issue: - # https://github.com/FRRouting/frr/issues/8016 - # if 'vrf' in next_hop_config: - # tmp += ' nexthop-vrf ' + next_hop_config['vrf'] + if 'vrf' in next_hop_config: + tmp += ' nexthop-vrf ' + next_hop_config['vrf'] tmp += ' table ' + table if 'disable' in next_hop_config: @@ -277,10 +269,8 @@ class StaticRouteTest(unittest.TestCase): tmp += ' ' + interface_config['interface'] if 'distance' in interface_config: tmp += ' ' + interface_config['distance'] - # This is currently not supported because of an FRR issue: - # https://github.com/FRRouting/frr/issues/8016 - # if 'vrf' in interface_config: - # tmp += ' nexthop-vrf ' + interface_config['vrf'] + if 'vrf' in interface_config: + tmp += ' nexthop-vrf ' + interface_config['vrf'] tmp += ' table ' + table if 'disable' in interface_config: -- cgit v1.2.3 From 91130ca7c386ecba291694ff08e521438d352e78 Mon Sep 17 00:00:00 2001 From: Brandon Stepler Date: Wed, 10 Feb 2021 21:30:00 -0500 Subject: conntrack: T3290: remove references to removed GRE plugins --- src/migration-scripts/conntrack/1-to-2 | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100755 src/migration-scripts/conntrack/1-to-2 diff --git a/src/migration-scripts/conntrack/1-to-2 b/src/migration-scripts/conntrack/1-to-2 new file mode 100755 index 000000000..4fc88a1ed --- /dev/null +++ b/src/migration-scripts/conntrack/1-to-2 @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 + +# Delete "set system conntrack modules gre" option + +import sys + +from vyos.configtree import ConfigTree + +if (len(sys.argv) < 1): + print("Must specify file name!") + sys.exit(1) + +file_name = sys.argv[1] + +with open(file_name, 'r') as f: + config_file = f.read() + +config = ConfigTree(config_file) + +if not config.exists(['system', 'conntrack', 'modules', 'gre']): + # Nothing to do + sys.exit(0) +else: + # Delete abandoned node + config.delete(['system', 'conntrack', 'modules', 'gre']) + + try: + with open(file_name, 'w') as f: + f.write(config.to_string()) + except OSError as e: + print("Failed to save the modified config: {}".format(e)) + sys.exit(1) -- cgit v1.2.3 From 224fd3638d62acd72a67d324350dedf32ad06b42 Mon Sep 17 00:00:00 2001 From: JACK Date: Thu, 11 Feb 2021 15:48:15 +0800 Subject: mirror: T3297: redirect stderr to /dev/null --- python/vyos/ifconfig/interface.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py index 8528c4a81..d9507d816 100644 --- a/python/vyos/ifconfig/interface.py +++ b/python/vyos/ifconfig/interface.py @@ -1015,9 +1015,11 @@ class Interface(Control): source_if = next(iter(self._config['is_mirror_intf'])) config = self._config['is_mirror_intf'][source_if].get('mirror', None) + # Please do not clear the 'set $? = 0 '. It's meant to force a return of 0 # Remove existing mirroring rules - delete_tc_cmd = f'tc qdisc del dev {source_if} handle ffff: ingress; ' - delete_tc_cmd += f'tc qdisc del dev {source_if} handle 1: root prio' + delete_tc_cmd = f'tc qdisc del dev {source_if} handle ffff: ingress 2> /dev/null;' + delete_tc_cmd += f'tc qdisc del dev {source_if} handle 1: root prio 2> /dev/null;' + delete_tc_cmd += 'set $?=0' self._popen(delete_tc_cmd) # Bail out early if nothing needs to be configured -- cgit v1.2.3 From 66282cc8a5c8ced4dee8414e5fcb5cbaa457781f Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Thu, 11 Feb 2021 20:00:14 +0100 Subject: ripng: T3281: move common parts into Jinja2 include --- data/templates/frr/rip.frr.tmpl | 34 +------------------------ data/templates/frr/rip_ripng.frr.j2 | 36 ++++++++++++++++++++++++++ data/templates/frr/ripng.frr.tmpl | 50 +++++++++++-------------------------- 3 files changed, 51 insertions(+), 69 deletions(-) create mode 100644 data/templates/frr/rip_ripng.frr.j2 diff --git a/data/templates/frr/rip.frr.tmpl b/data/templates/frr/rip.frr.tmpl index 50db2e9de..bc92bddf9 100644 --- a/data/templates/frr/rip.frr.tmpl +++ b/data/templates/frr/rip.frr.tmpl @@ -35,12 +35,6 @@ interface {{ iface }} {% endif %} ! router rip -{% if default_information is defined and default_information.originate is defined %} - default-information originate -{% endif %} -{% if default_metric is defined and default_metric is not none %} - default-metric {{ default_metric }} -{% endif %} {% if default_distance is defined and default_distance is not none %} distance {{ default_distance }} {% endif %} @@ -56,33 +50,6 @@ router rip neighbor {{ address }} {% endfor %} {% endif %} -{% if network is defined and network is not none %} -{% for prefix in network %} - network {{ prefix }} -{% endfor %} -{% endif %} -{% if interface is defined and interface is not none %} -{% for ifname in interface %} - network {{ ifname }} -{% endfor %} -{% endif %} -{% if passive_interface is defined and passive_interface is not none %} -{% for ifname in passive_interface %} - passive-interface {{ ifname }} -{% endfor %} -{% endif %} -{% if redistribute is defined and redistribute is not none %} -{% for protocol, protocol_config in redistribute.items() %} - redistribute {{ protocol }} {{ 'metric ' + protocol_config.metric if protocol_config.metric is defined }} {{ 'route-map ' + protocol_config.route_map if protocol_config.route_map is defined }} -{% endfor %} -{% endif %} -{% if route is defined and route is not none %} -{% for prefix in route %} - route {{ prefix }} -{% endfor %} -{% endif %} -{# timers have default values #} - timers basic {{ timers['update'] }} {{ timers.timeout }} {{ timers.garbage_collection }} {% if distribute_list is defined and distribute_list is not none %} {% if distribute_list.access_list is defined and distribute_list.access_list is not none %} {% if distribute_list.access_list.in is defined and distribute_list.access_list.in is not none %} @@ -121,4 +88,5 @@ router rip {% endif %} {% endif %} {% endif %} +{% include 'frr/rip_ripng.frr.j2' %} ! diff --git a/data/templates/frr/rip_ripng.frr.j2 b/data/templates/frr/rip_ripng.frr.j2 new file mode 100644 index 000000000..de180ee6b --- /dev/null +++ b/data/templates/frr/rip_ripng.frr.j2 @@ -0,0 +1,36 @@ +{% if default_information is defined and default_information.originate is defined %} + default-information originate +{% endif %} +{% if default_metric is defined and default_metric is not none %} + default-metric {{ default_metric }} +{% endif %} +{% if passive_interface is defined and passive_interface is not none %} +{% for interface in passive_interface %} + passive-interface {{ interface }} +{% endfor %} +{% endif %} +{% if network is defined and network is not none %} +{% for prefix in network %} + network {{ prefix }} +{% endfor %} +{% endif %} +{% if interface is defined and interface is not none %} +{% for ifname in interface %} + network {{ ifname }} +{% endfor %} +{% endif %} +{% if route is defined and route is not none %} +{% for prefix in route %} + route {{ prefix }} +{% endfor %} +{% endif %} +{# timers have default values #} + timers basic {{ timers['update'] }} {{ timers.timeout }} {{ timers.garbage_collection }} +{% if redistribute is defined and redistribute is not none %} +{% for protocol, protocol_config in redistribute.items() %} +{% if protocol == 'ospfv3' %} +{% set protocol = 'ospf6' %} +{% endif %} + redistribute {{ protocol }} {{ 'metric ' + protocol_config.metric if protocol_config.metric is defined }} {{ 'route-map ' + protocol_config.route_map if protocol_config.route_map is defined }} +{% endfor %} +{% endif %} diff --git a/data/templates/frr/ripng.frr.tmpl b/data/templates/frr/ripng.frr.tmpl index ac14dfd3f..25df15121 100644 --- a/data/templates/frr/ripng.frr.tmpl +++ b/data/templates/frr/ripng.frr.tmpl @@ -1,46 +1,23 @@ ! -router ripng -{% if default_information is defined and default_information.originate is defined %} - default-information originate -{% endif %} -{% if default_metric is defined and default_metric is not none %} - default-metric {{ default_metric }} +{# Interface specific configuration #} +{% if interface is defined and interface is not none %} +{% for iface, iface_config in interface.items() %} +interface {{ iface }} +{% if iface_config.split_horizon is defined and iface_config.split_horizon.disable is defined %} + no ipv6 rip split-horizon +{% endif %} +{% if iface_config.split_horizon is defined and iface_config.split_horizon.poison_reverse is defined %} + ipv6 rip split-horizon poisoned-reverse +{% endif %} +{% endfor %} {% endif %} +! +router ripng {% if aggregate_address is defined and aggregate_address is not none %} {% for prefix in aggregate_address %} aggregate-address {{ prefix }} {% endfor %} {% endif %} -{% if passive_interface is defined and passive_interface is not none %} -{% for ifname in passive_interface %} - passive-interface {{ ifname }} -{% endfor %} -{% endif %} -{% if interface is defined and interface is not none %} -{% for ifname in interface %} - network {{ ifname }} -{% endfor %} -{% endif %} -{% if network is defined and network is not none %} -{% for net in network %} - network {{ net }} -{% endfor %} -{% endif %} -{% if route is defined and route is not none %} -{% for prefix in route %} - route {{ prefix }} -{% endfor %} -{% endif %} -{% if redistribute is defined and redistribute is not none %} -{% for protocol, protocol_config in redistribute.items() %} -{% if protocol == 'ospfv3' %} -{% set protocol = 'ospf6' %} -{% endif %} - redistribute {{ protocol }} {{ 'metric ' + protocol_config.metric if protocol_config.metric is defined }} {{ 'route-map ' + protocol_config.route_map if protocol_config.route_map is defined }} -{% endfor %} -{% endif %} -{# timers have default values #} - timers basic {{ timers['update'] }} {{ timers.timeout }} {{ timers.garbage_collection }} {% if distribute_list is defined and distribute_list is not none %} {% if distribute_list.access_list is defined and distribute_list.access_list is not none %} {% if distribute_list.access_list.in is defined and distribute_list.access_list.in is not none %} @@ -79,4 +56,5 @@ router ripng {% endif %} {% endif %} {% endif %} +{% include 'frr/rip_ripng.frr.j2' %} ! -- cgit v1.2.3 From 8919e40a3c0b84053e422a8445a5fca829e5990f Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Thu, 11 Feb 2021 20:35:31 +0100 Subject: ripng: T3281: move interface specific options to "protocols ripng" --- interface-definitions/include/rip-interface.xml.i | 47 -------- interface-definitions/protocols-rip.xml.in | 51 +++++++++ smoketest/configs/rip-router | 129 ++++++++++++++++++++++ src/migration-scripts/interfaces/18-to-19 | 53 +++++++-- 4 files changed, 221 insertions(+), 59 deletions(-) diff --git a/interface-definitions/include/rip-interface.xml.i b/interface-definitions/include/rip-interface.xml.i index 1d5e6f949..6279c16c8 100644 --- a/interface-definitions/include/rip-interface.xml.i +++ b/interface-definitions/include/rip-interface.xml.i @@ -14,53 +14,6 @@ - - - Authentication - - - - - MD5 key id - - u32:1-255 - OSPF key id - - - - - - - - - Authentication password - - txt - MD5 Key (16 characters or less) - - - ^[^[:space:]]{1,16}$ - - Password must be 16 characters or less - - - - - - - Plain text password - - txt - Plain text password (16 characters or less) - - - ^[^[:space:]]{1,16}$ - - Password must be 16 characters or less - - - - Split horizon parameters diff --git a/interface-definitions/protocols-rip.xml.in b/interface-definitions/protocols-rip.xml.in index 4ced26d8a..263350dc8 100644 --- a/interface-definitions/protocols-rip.xml.in +++ b/interface-definitions/protocols-rip.xml.in @@ -50,6 +50,57 @@ #include + + + + + Authentication + + + + + MD5 key id + + u32:1-255 + OSPF key id + + + + + + + + + Authentication password + + txt + MD5 Key (16 characters or less) + + + ^[^[:space:]]{1,16}$ + + Password must be 16 characters or less + + + + + + + Plain text password + + txt + Plain text password (16 characters or less) + + + ^[^[:space:]]{1,16}$ + + Password must be 16 characters or less + + + + + + Neighbor router diff --git a/smoketest/configs/rip-router b/smoketest/configs/rip-router index 0a3a41103..09cb11a45 100644 --- a/smoketest/configs/rip-router +++ b/smoketest/configs/rip-router @@ -16,6 +16,13 @@ interfaces { } } } + ipv6 { + ripng { + split-horizon { + poison-reverse + } + } + } smp-affinity auto speed auto address 172.18.202.10/24 @@ -35,6 +42,13 @@ interfaces { } } } + ipv6 { + ripng { + split-horizon { + disable + } + } + } } vif-s 200 { ip { @@ -49,6 +63,13 @@ interfaces { } } } + ipv6 { + ripng { + split-horizon { + poison-reverse + } + } + } vif-c 2000 { ip { rip { @@ -68,10 +89,52 @@ interfaces { } } } + ipv6 { + ripng { + split-horizon { + poison-reverse + } + } + } } } } } +policy { + access-list6 198 { + rule 10 { + action permit + source { + any + } + } + } + access-list6 199 { + rule 20 { + action deny + source { + any + } + } + } + prefix-list6 bar-prefix { + rule 200 { + action deny + prefix 2001:db8::/32 + } + } + prefix-list6 foo-prefix { + rule 100 { + action permit + prefix 2001:db8::/32 + } + } + route-map FooBar123 { + rule 10 { + action permit + } + } +} protocols { rip { default-distance 20 @@ -89,6 +152,72 @@ protocols { } } } + ripng { + aggregate-address 2001:db8:1000::/48 + default-information { + originate + } + default-metric 8 + distribute-list { + access-list { + in 198 + out 199 + } + interface eth0 { + access-list { + in 198 + out 199 + } + prefix-list { + in foo-prefix + out bar-prefix + } + } + interface eth1 { + access-list { + in 198 + out 199 + } + prefix-list { + in foo-prefix + out bar-prefix + } + } + interface eth2 { + access-list { + in 198 + out 199 + } + prefix-list { + in foo-prefix + out bar-prefix + } + } + prefix-list { + in foo-prefix + out bar-prefix + } + } + interface eth0 + interface eth1 + interface eth2 + network 2001:db8:1000::/64 + network 2001:db8:1001::/64 + network 2001:db8:2000::/64 + network 2001:db8:2001::/64 + passive-interface default + redistribute { + connected { + metric 8 + route-map FooBar123 + } + static { + metric 8 + route-map FooBar123 + } + } + route 2001:db8:1000::/64 + } } service { ssh { diff --git a/src/migration-scripts/interfaces/18-to-19 b/src/migration-scripts/interfaces/18-to-19 index 31e253098..460032602 100755 --- a/src/migration-scripts/interfaces/18-to-19 +++ b/src/migration-scripts/interfaces/18-to-19 @@ -46,6 +46,20 @@ def migrate_rip(config, path, interface): if len(config.list_nodes(path[:-1])) == 0: config.delete(path[:-1]) +def migrate_ripng(config, path, interface): + path = path + ['ripng'] + if config.exists(path): + new_base = ['protocols', 'ripng', 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(path, new_base + [interface]) + config.delete(path) + + # if "ipv6 ripng" was the only setting, we can clean out the empty + # ip node afterwards + if len(config.list_nodes(path[:-1])) == 0: + config.delete(path[:-1]) + if __name__ == '__main__': if (len(argv) < 1): print("Must specify file name!") @@ -62,33 +76,48 @@ if __name__ == '__main__': # for type in config.list_nodes(['interfaces']): for interface in config.list_nodes(['interfaces', type]): - if_base = ['interfaces', type, interface, 'ip'] - migrate_rip(config, if_base, interface) - migrate_ospf(config, if_base, interface) + ip_base = ['interfaces', type, interface, 'ip'] + ipv6_base = ['interfaces', type, interface, 'ipv6'] + migrate_rip(config, ip_base, interface) + migrate_ripng(config, ipv6_base, interface) + migrate_ospf(config, ip_base, interface) vif_path = ['interfaces', type, interface, 'vif'] if config.exists(vif_path): for vif in config.list_nodes(vif_path): - vif_if_base = vif_path + [vif, 'ip'] - migrate_rip(config, vif_if_base, f'{interface}.{vif}') - migrate_ospf(config, vif_if_base, f'{interface}.{vif}') + vif_ip_base = vif_path + [vif, 'ip'] + vif_ipv6_base = vif_path + [vif, 'ipv6'] + ifname = f'{interface}.{vif}' + + migrate_rip(config, vif_ip_base, ifname) + migrate_ripng(config, vif_ipv6_base, ifname) + migrate_ospf(config, vif_ip_base, ifname) + vif_s_path = ['interfaces', type, interface, 'vif-s'] if config.exists(vif_s_path): for vif_s in config.list_nodes(vif_s_path): - vif_s_if_base = vif_s_path + [vif_s, 'ip'] + vif_s_ip_base = vif_s_path + [vif_s, 'ip'] + vif_s_ipv6_base = vif_s_path + [vif_s, 'ipv6'] # vif-c interfaces MUST be migrated before their parent vif-s # interface as the migrate_*() functions delete the path! vif_c_path = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c'] if config.exists(vif_c_path): for vif_c in config.list_nodes(vif_c_path): - vif_c_if_base = vif_c_path + [vif_c, 'ip'] - migrate_rip(config, vif_c_if_base, f'{interface}.{vif_s}.{vif_c}') - migrate_ospf(config, vif_c_if_base, f'{interface}.{vif_s}.{vif_c}') + vif_c_ip_base = vif_c_path + [vif_c, 'ip'] + vif_c_ipv6_base = vif_c_path + [vif_c, 'ipv6'] + ifname = f'{interface}.{vif_s}.{vif_c}' + + migrate_rip(config, vif_c_ip_base, ifname) + migrate_ripng(config, vif_c_ipv6_base, ifname) + migrate_ospf(config, vif_c_ip_base, ifname) + - migrate_rip(config, vif_s_if_base, f'{interface}.{vif_s}') - migrate_ospf(config, vif_s_if_base, f'{interface}.{vif_s}') + ifname = f'{interface}.{vif_s}' + migrate_rip(config, vif_s_ip_base, ifname) + migrate_ripng(config, vif_s_ipv6_base, ifname) + migrate_ospf(config, vif_s_ip_base, ifname) try: with open(file_name, 'w') as f: -- cgit v1.2.3 From 8a39f15242ef0596a7d93001f7d413702f1ad7f5 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Thu, 11 Feb 2021 20:36:08 +0100 Subject: ospfv3: T3267: move interface specific options to "protocols ospfv3" --- Makefile | 9 ---- .../include/ospf-interface-common.xml.i | 39 ++++++++++++++ interface-definitions/protocols-ospf.xml.in | 38 +------------- interface-definitions/protocols-ospfv3.xml.in | 60 ++++++++++++++++++++-- smoketest/configs/ospf-small | 22 ++++++++ src/migration-scripts/interfaces/18-to-19 | 18 +++++++ 6 files changed, 137 insertions(+), 49 deletions(-) create mode 100644 interface-definitions/include/ospf-interface-common.xml.i diff --git a/Makefile b/Makefile index abe4524d1..2adf385f9 100644 --- a/Makefile +++ b/Makefile @@ -46,15 +46,6 @@ interface_definitions: $(config_xml_obj) rm -f $(TMPL_DIR)/vpn/ipsec/node.def rm -rf $(TMPL_DIR)/vpn/nipsec - # XXX: required until OSPF and RIP is migrated from vyatta-cfg-quagga to vyos-1x - mkdir $(TMPL_DIR)/interfaces/loopback/node.tag/ipv6 - mkdir $(TMPL_DIR)/interfaces/dummy/node.tag/ipv6 - mkdir -p $(TMPL_DIR)/interfaces/vti/node.tag/ipv6 - cp $(TMPL_DIR)/interfaces/ethernet/node.tag/ipv6/node.def $(TMPL_DIR)/interfaces/loopback/node.tag/ipv6 - cp $(TMPL_DIR)/interfaces/ethernet/node.tag/ipv6/node.def $(TMPL_DIR)/interfaces/dummy/node.tag/ipv6 - - cp $(TMPL_DIR)/interfaces/ethernet/node.tag/ipv6/node.def $(TMPL_DIR)/interfaces/vti/node.tag/ipv6 - .PHONY: op_mode_definitions .ONESHELL: op_mode_definitions: $(op_xml_obj) diff --git a/interface-definitions/include/ospf-interface-common.xml.i b/interface-definitions/include/ospf-interface-common.xml.i new file mode 100644 index 000000000..c3493faa3 --- /dev/null +++ b/interface-definitions/include/ospf-interface-common.xml.i @@ -0,0 +1,39 @@ + + + + Enable Bidirectional Forwarding Detection (BFD) support + + + + + + Interface cost + + u32:1-65535 + OSPF interface cost + + + + + + + + + Disable Maximum Transmission Unit (MTU) mismatch detection + + + + + + Router priority (default: 1) + + u32:0-255 + OSPF router priority cost + + + + + + 1 + + diff --git a/interface-definitions/protocols-ospf.xml.in b/interface-definitions/protocols-ospf.xml.in index a616c0e60..d0cfa14b1 100644 --- a/interface-definitions/protocols-ospf.xml.in +++ b/interface-definitions/protocols-ospf.xml.in @@ -415,6 +415,7 @@ #include #include + #include Bandwidth of interface (Megabit/sec) @@ -427,24 +428,6 @@ - - - Enable Bidirectional Forwarding Detection (BFD) support - - - - - - Interface cost - - u32:1-65535 - OSPF interface cost - - - - - - Hello multiplier factor @@ -457,12 +440,6 @@ - - - Disable Maximum Transmission Unit (MTU) mismatch detection - - - Network type @@ -491,19 +468,6 @@ Must be broadcast, non-broadcast, point-to-multipoint or point-to-point - - - Router priority (default: 1) - - u32:0-255 - OSPF router priority cost - - - - - - 1 - diff --git a/interface-definitions/protocols-ospfv3.xml.in b/interface-definitions/protocols-ospfv3.xml.in index bd6a55b45..e28faa3cf 100644 --- a/interface-definitions/protocols-ospfv3.xml.in +++ b/interface-definitions/protocols-ospfv3.xml.in @@ -41,7 +41,7 @@ - + Enable routing on an IPv6 interface @@ -54,9 +54,63 @@ - - + + #include + #include + + + Interface MTU + + u32:1-65535 + Interface MTU + + + + + + + + + Instance Id (default: 0) + + u32:0-255 + Instance Id + + + + + + 0 + + + + Network type + + broadcast point-to-point + + + broadcast + Broadcast network type + + + point-to-point + Point-to-point network type + + + ^(broadcast|point-to-point)$ + + Must be broadcast or point-to-point + + + + + Disable forming of adjacency + + + + + Specify IPv6 prefix (border routers only) diff --git a/smoketest/configs/ospf-small b/smoketest/configs/ospf-small index fe313e4b0..d95ba4ea4 100644 --- a/smoketest/configs/ospf-small +++ b/smoketest/configs/ospf-small @@ -24,12 +24,27 @@ interfaces { transmit-delay 1 } } + ipv6 { + ospfv3 { + bfd + cost 40 + } + } } } ethernet eth1 { duplex auto smp-affinity auto speed auto + ipv6 { + ospfv3 { + bfd + cost 60 + mtu-ignore + network broadcast + priority 20 + } + } } } protocols { @@ -47,6 +62,13 @@ protocols { passive-interface default passive-interface-exclude eth0.201 } + ospfv3 { + area 0.0.0.0 { + interface eth0 + interface eth1 + interface eth2 + } + } static { route 0.0.0.0/0 { next-hop 172.18.201.254 { diff --git a/src/migration-scripts/interfaces/18-to-19 b/src/migration-scripts/interfaces/18-to-19 index 460032602..06e07572f 100755 --- a/src/migration-scripts/interfaces/18-to-19 +++ b/src/migration-scripts/interfaces/18-to-19 @@ -32,6 +32,20 @@ def migrate_ospf(config, path, interface): if len(config.list_nodes(path[:-1])) == 0: config.delete(path[:-1]) +def migrate_ospfv3(config, path, interface): + path = path + ['ospfv3'] + if config.exists(path): + new_base = ['protocols', 'ospfv3', 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(path, new_base + [interface]) + config.delete(path) + + # if "ipv6 ospfv3" was the only setting, we can clean out the empty + # ip node afterwards + if len(config.list_nodes(path[:-1])) == 0: + config.delete(path[:-1]) + def migrate_rip(config, path, interface): path = path + ['rip'] if config.exists(path): @@ -81,6 +95,7 @@ if __name__ == '__main__': migrate_rip(config, ip_base, interface) migrate_ripng(config, ipv6_base, interface) migrate_ospf(config, ip_base, interface) + migrate_ospfv3(config, ipv6_base, interface) vif_path = ['interfaces', type, interface, 'vif'] if config.exists(vif_path): @@ -92,6 +107,7 @@ if __name__ == '__main__': migrate_rip(config, vif_ip_base, ifname) migrate_ripng(config, vif_ipv6_base, ifname) migrate_ospf(config, vif_ip_base, ifname) + migrate_ospfv3(config, vif_ipv6_base, ifname) vif_s_path = ['interfaces', type, interface, 'vif-s'] @@ -112,12 +128,14 @@ if __name__ == '__main__': migrate_rip(config, vif_c_ip_base, ifname) migrate_ripng(config, vif_c_ipv6_base, ifname) migrate_ospf(config, vif_c_ip_base, ifname) + migrate_ospfv3(config, vif_c_ipv6_base, ifname) ifname = f'{interface}.{vif_s}' migrate_rip(config, vif_s_ip_base, ifname) migrate_ripng(config, vif_s_ipv6_base, ifname) migrate_ospf(config, vif_s_ip_base, ifname) + migrate_ospfv3(config, vif_s_ipv6_base, ifname) try: with open(file_name, 'w') as f: -- cgit v1.2.3 From 4a0504a96cf0f3078e964ed201f196fb55172e00 Mon Sep 17 00:00:00 2001 From: Esa Varemo Date: Fri, 12 Feb 2021 23:42:47 +0200 Subject: nat: T3307: fix destination nat generation Fix destination NAT template trying to map source->translation instead of destination->translation. Fixes https://phabricator.vyos.net/T3307 --- data/templates/firewall/nftables-nat.tmpl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/data/templates/firewall/nftables-nat.tmpl b/data/templates/firewall/nftables-nat.tmpl index 499733225..b80fc1968 100644 --- a/data/templates/firewall/nftables-nat.tmpl +++ b/data/templates/firewall/nftables-nat.tmpl @@ -24,9 +24,9 @@ {% if config.translation is defined and config.translation.address is defined and config.translation.address is not none %} {# support 1:1 network translation #} {% if config.translation.address | is_ip_network %} -{% set trns_addr = 'dnat ip prefix to ip daddr map { ' + config.source.address + ' : ' + config.translation.address + ' }' %} -{# we can now clear out the src_addr part as it's already covered in aboves map #} -{% set src_addr = '' %} +{% set trns_addr = 'dnat ip prefix to ip daddr map { ' + config.destination.address + ' : ' + config.translation.address + ' }' %} +{# we can now clear out the dst_addr part as it's already covered in aboves map #} +{% set dst_addr = '' %} {% else %} {% set trns_addr = 'dnat to ' + config.translation.address %} {% endif %} -- cgit v1.2.3 From 55b763e1a8ae48f1bc7f46c341479f6140cad3b6 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Fri, 12 Feb 2021 18:31:50 +0100 Subject: smoketest: rpki: remove failfast setting --- smoketest/scripts/cli/test_protocols_rpki.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smoketest/scripts/cli/test_protocols_rpki.py b/smoketest/scripts/cli/test_protocols_rpki.py index 1e742b411..17b9ba346 100755 --- a/smoketest/scripts/cli/test_protocols_rpki.py +++ b/smoketest/scripts/cli/test_protocols_rpki.py @@ -148,4 +148,4 @@ if __name__ == '__main__': if not os.path.isfile(rpki_known_hosts): cmd(f'touch {rpki_known_hosts}') - unittest.main(verbosity=2, failfast=True) + unittest.main(verbosity=2) -- cgit v1.2.3 From ce70f775a2ca071c6b02ad21da0b81850cca3a7b Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Fri, 12 Feb 2021 18:32:18 +0100 Subject: smoketest: bcast-relay: no need to commit() in setUp() --- smoketest/scripts/cli/test_service_bcast-relay.py | 1 - 1 file changed, 1 deletion(-) diff --git a/smoketest/scripts/cli/test_service_bcast-relay.py b/smoketest/scripts/cli/test_service_bcast-relay.py index c28509714..00d7750aa 100755 --- a/smoketest/scripts/cli/test_service_bcast-relay.py +++ b/smoketest/scripts/cli/test_service_bcast-relay.py @@ -30,7 +30,6 @@ class TestServiceBroadcastRelay(unittest.TestCase): self.session = ConfigSession(os.getpid()) self.session.set(['interfaces', 'dummy', 'dum1001', 'address', self._address1]) self.session.set(['interfaces', 'dummy', 'dum1002', 'address', self._address2]) - self.session.commit() def tearDown(self): self.session.delete(['interfaces', 'dummy', 'dum1001']) -- cgit v1.2.3 From cec4b325ea014c09d3c60fac07651ec2a0b2d522 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 13 Feb 2021 19:42:20 +0100 Subject: smoketest: rpki: extend tests with IPv6 caching servers --- smoketest/scripts/cli/test_protocols_rpki.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/smoketest/scripts/cli/test_protocols_rpki.py b/smoketest/scripts/cli/test_protocols_rpki.py index 17b9ba346..bec4ef76f 100755 --- a/smoketest/scripts/cli/test_protocols_rpki.py +++ b/smoketest/scripts/cli/test_protocols_rpki.py @@ -61,6 +61,14 @@ class TestProtocolsRPKI(unittest.TestCase): 'port' : '9090', 'preference' : '2' }, + '2001:db8::1' : { + 'port' : '1234', + 'preference' : '3' + }, + '2001:db8::2' : { + 'port' : '5678', + 'preference' : '4' + }, } self.session.set(base_path + ['polling-period', polling]) -- cgit v1.2.3 From f4e8062651a8feece2d8538755db139d5e0790f7 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 13 Feb 2021 20:42:13 +0100 Subject: bgp: T1513: extend supported evpn support/cli options Add CLI options for: - advertise-pip - rt-auto-derive - flooding - rd - route-target --- data/templates/frr/bgp.frr.tmpl | 144 +++++++++++++++++------------ interface-definitions/protocols-bgp.xml.in | 92 ++++++++++++++++++ 2 files changed, 177 insertions(+), 59 deletions(-) diff --git a/data/templates/frr/bgp.frr.tmpl b/data/templates/frr/bgp.frr.tmpl index 74874ee43..9dafc7f91 100644 --- a/data/templates/frr/bgp.frr.tmpl +++ b/data/templates/frr/bgp.frr.tmpl @@ -78,74 +78,74 @@ {% elif af == 'l2vpn_evpn' %} address-family l2vpn evpn {% endif %} -{% if config.address_family[af].allowas_in is defined and config.address_family[af].allowas_in is not none %} - neighbor {{ neighbor }} allowas-in {{ config.address_family[af].allowas_in.number if config.address_family[af].allowas_in.number is defined }} +{% if config.afi_config.allowas_in is defined and config.afi_config.allowas_in is not none %} + neighbor {{ neighbor }} allowas-in {{ config.afi_config.allowas_in.number if config.afi_config.allowas_in.number is defined }} {% endif %} -{% if config.address_family[af].remove_private_as is defined %} +{% if config.afi_config.remove_private_as is defined %} neighbor {{ neighbor }} remove-private-AS {% endif %} -{% if config.address_family[af].route_reflector_client is defined %} +{% if config.afi_config.route_reflector_client is defined %} neighbor {{ neighbor }} route-reflector-client {% endif %} -{% if config.address_family[af].weight is defined and config.address_family[af].weight is not none %} - neighbor {{ neighbor }} weight {{ config.address_family[af].weight }} +{% if config.afi_config.weight is defined and config.afi_config.weight is not none %} + neighbor {{ neighbor }} weight {{ config.afi_config.weight }} {% endif %} -{% if config.address_family[af].attribute_unchanged is defined and config.address_family[af].attribute_unchanged is not none %} - neighbor {{ neighbor }} attribute-unchanged {{ 'as-path ' if config.address_family[af].attribute_unchanged.as_path is defined }}{{ 'med ' if config.address_family[af].attribute_unchanged.med is defined }}{{ 'next-hop ' if config.address_family[af].attribute_unchanged.next_hop is defined }} +{% if config.afi_config.attribute_unchanged is defined and config.afi_config.attribute_unchanged is not none %} + neighbor {{ neighbor }} attribute-unchanged {{ 'as-path ' if config.afi_config.attribute_unchanged.as_path is defined }}{{ 'med ' if config.afi_config.attribute_unchanged.med is defined }}{{ 'next-hop ' if config.afi_config.attribute_unchanged.next_hop is defined }} {% endif %} -{% if config.address_family[af].capability is defined and config.address_family[af].capability.orf is defined and config.address_family[af].capability.orf.prefix_list is defined and config.address_family[af].capability.orf.prefix_list is not none %} - neighbor {{ neighbor }} capability orf prefix-list {{ config.address_family[af].capability.orf.prefix_list }} +{% if config.afi_config.capability is defined and config.afi_config.capability.orf is defined and config.afi_config.capability.orf.prefix_list is defined and config.afi_config.capability.orf.prefix_list is not none %} + neighbor {{ neighbor }} capability orf prefix-list {{ config.afi_config.capability.orf.prefix_list }} {% endif %} -{% if config.address_family[af].default_originate is defined %} - neighbor {{ neighbor }} default-originate {{ 'route-map ' + config.address_family[af].default_originate.route_map if config.address_family[af].default_originate.route_map is defined }} +{% if config.afi_config.default_originate is defined %} + neighbor {{ neighbor }} default-originate {{ 'route-map ' + config.afi_config.default_originate.route_map if config.afi_config.default_originate.route_map is defined }} {% endif %} -{% if config.address_family[af].distribute_list is defined and config.address_family[af].distribute_list is not none %} -{% if config.address_family[af].distribute_list.export is defined and config.address_family[af].distribute_list.export is not none %} - neighbor {{ neighbor }} distribute-list {{ config.address_family[af].distribute_list.export }} out +{% if config.afi_config.distribute_list is defined and config.afi_config.distribute_list is not none %} +{% if config.afi_config.distribute_list.export is defined and config.afi_config.distribute_list.export is not none %} + neighbor {{ neighbor }} distribute-list {{ config.afi_config.distribute_list.export }} out {% endif %} -{% if config.address_family[af].distribute_list.import is defined and config.address_family[af].distribute_list.import is not none %} - neighbor {{ neighbor }} distribute-list {{ config.address_family[af].distribute_list.import }} in +{% if config.afi_config.distribute_list.import is defined and config.afi_config.distribute_list.import is not none %} + neighbor {{ neighbor }} distribute-list {{ config.afi_config.distribute_list.import }} in {% endif %} {% endif %} -{% if config.address_family[af].filter_list is defined and config.address_family[af].filter_list is not none %} -{% if config.address_family[af].filter_list.export is defined and config.address_family[af].filter_list.export is not none %} - neighbor {{ neighbor }} filter-list {{ config.address_family[af].filter_list.export }} out +{% if config.afi_config.filter_list is defined and config.afi_config.filter_list is not none %} +{% if config.afi_config.filter_list.export is defined and config.afi_config.filter_list.export is not none %} + neighbor {{ neighbor }} filter-list {{ config.afi_config.filter_list.export }} out {% endif %} -{% if config.address_family[af].filter_list.import is defined and config.address_family[af].filter_list.import is not none %} - neighbor {{ neighbor }} filter-list {{ config.address_family[af].filter_list.import }} in +{% if config.afi_config.filter_list.import is defined and config.afi_config.filter_list.import is not none %} + neighbor {{ neighbor }} filter-list {{ config.afi_config.filter_list.import }} in {% endif %} {% endif %} -{% if config.address_family[af].maximum_prefix is defined and config.address_family[af].maximum_prefix is not none %} - neighbor {{ neighbor }} maximum-prefix {{ config.address_family[af].maximum_prefix }} +{% if config.afi_config.maximum_prefix is defined and config.afi_config.maximum_prefix is not none %} + neighbor {{ neighbor }} maximum-prefix {{ config.afi_config.maximum_prefix }} {% endif %} -{% if config.address_family[af].nexthop_self is defined %} +{% if config.afi_config.nexthop_self is defined %} {# https://phabricator.vyos.net/T1817 #} - neighbor {{ neighbor }} next-hop-self {{ 'force' if config.address_family[af].nexthop_self.force is defined }} + neighbor {{ neighbor }} next-hop-self {{ 'force' if config.afi_config.nexthop_self.force is defined }} {% endif %} -{% if config.address_family[af].route_server_client is defined %} +{% if config.afi_config.route_server_client is defined %} neighbor {{ neighbor }} route-server-client {% endif %} -{% if config.address_family[af].route_map is defined and config.address_family[af].route_map is not none %} -{% if config.address_family[af].route_map.export is defined and config.address_family[af].route_map.export is not none %} - neighbor {{ neighbor }} route-map {{ config.address_family[af].route_map.export }} out +{% if config.afi_config.route_map is defined and config.afi_config.route_map is not none %} +{% if config.afi_config.route_map.export is defined and config.afi_config.route_map.export is not none %} + neighbor {{ neighbor }} route-map {{ config.afi_config.route_map.export }} out {% endif %} -{% if config.address_family[af].route_map.import is defined and config.address_family[af].route_map.import is not none %} - neighbor {{ neighbor }} route-map {{ config.address_family[af].route_map.import }} in +{% if config.afi_config.route_map.import is defined and config.afi_config.route_map.import is not none %} + neighbor {{ neighbor }} route-map {{ config.afi_config.route_map.import }} in {% endif %} {% endif %} -{% if config.address_family[af].prefix_list is defined and config.address_family[af].prefix_list is not none %} -{% if config.address_family[af].prefix_list.export is defined and config.address_family[af].prefix_list.export is not none %} - neighbor {{ neighbor }} prefix-list {{ config.address_family[af].prefix_list.export }} out +{% if config.afi_config.prefix_list is defined and config.afi_config.prefix_list is not none %} +{% if config.afi_config.prefix_list.export is defined and config.afi_config.prefix_list.export is not none %} + neighbor {{ neighbor }} prefix-list {{ config.afi_config.prefix_list.export }} out {% endif %} -{% if config.address_family[af].prefix_list.import is defined and config.address_family[af].prefix_list.import is not none %} - neighbor {{ neighbor }} prefix-list {{ config.address_family[af].prefix_list.import }} in +{% if config.afi_config.prefix_list.import is defined and config.afi_config.prefix_list.import is not none %} + neighbor {{ neighbor }} prefix-list {{ config.afi_config.prefix_list.import }} in {% endif %} {% endif %} -{% if config.address_family[af].soft_reconfiguration is defined and config.address_family[af].soft_reconfiguration.inbound is defined %} +{% if config.afi_config.soft_reconfiguration is defined and config.afi_config.soft_reconfiguration.inbound is defined %} neighbor {{ neighbor }} soft-reconfiguration inbound {% endif %} -{% if config.address_family[af].unsuppress_map is defined and config.address_family[af].unsuppress_map is not none %} - neighbor {{ neighbor }} unsuppress-map {{ config.address_family[af].unsuppress_map }} +{% if config.afi_config.unsuppress_map is defined and config.afi_config.unsuppress_map is not none %} + neighbor {{ neighbor }} unsuppress-map {{ config.afi_config.unsuppress_map }} {% endif %} neighbor {{ neighbor }} activate exit-address-family @@ -159,53 +159,79 @@ router bgp {{ asn }} {# https://phabricator.vyos.net/T3183 & https://phabricator.vyos.net/T2100 #} no bgp ebgp-requires-policy {% if address_family is defined and address_family is not none %} -{% for af in address_family %} +{% for afi, afi_config in address_family.items() %} ! -{% if af == 'ipv4_unicast' %} +{% if afi == 'ipv4_unicast' %} address-family ipv4 unicast -{% elif af == 'ipv6_unicast' %} +{% elif afi == 'ipv6_unicast' %} address-family ipv6 unicast -{% elif af == 'l2vpn_evpn' %} +{% elif afi == 'l2vpn_evpn' %} address-family l2vpn evpn {% endif %} -{% if address_family[af].aggregate_address is defined and address_family[af].aggregate_address is not none %} -{% for ip in address_family[af].aggregate_address %} - aggregate-address {{ ip }}{{ ' as-set' if address_family[af].aggregate_address[ip].as_set is defined }}{{ ' summary-only' if address_family[af].aggregate_address[ip].summary_only is defined }} +{% if afi_config.aggregate_address is defined and afi_config.aggregate_address is not none %} +{% for ip in afi_config.aggregate_address %} + aggregate-address {{ ip }}{{ ' as-set' if afi_config.aggregate_address[ip].as_set is defined }}{{ ' summary-only' if afi_config.aggregate_address[ip].summary_only is defined }} {% endfor %} {% endif %} -{% if address_family[af].redistribute is defined and address_family[af].redistribute is not none %} -{% for protocol in address_family[af].redistribute %} +{% if afi_config.redistribute is defined and afi_config.redistribute is not none %} +{% for protocol in afi_config.redistribute %} {% if protocol == 'table' %} - redistribute table {{ address_family[af].redistribute[protocol].table }} + redistribute table {{ afi_config.redistribute[protocol].table }} {% else %} {% set redistribution_protocol = protocol %} {% if protocol == 'ospfv3' %} {% set redistribution_protocol = 'ospf6' %} {% endif %} - redistribute {{ redistribution_protocol }}{% if address_family[af].redistribute[protocol].metric is defined %} metric {{ address_family[af].redistribute[protocol].metric }}{% endif %}{% if address_family[af].redistribute[protocol].route_map is defined %} route-map {{ address_family[af].redistribute[protocol].route_map }}{% endif %} + redistribute {{ redistribution_protocol }}{% if afi_config.redistribute[protocol].metric is defined %} metric {{ afi_config.redistribute[protocol].metric }}{% endif %}{% if afi_config.redistribute[protocol].route_map is defined %} route-map {{ afi_config.redistribute[protocol].route_map }}{% endif %} {####### we need this blank line!! #######} {% endif %} {% endfor %} {% endif %} -{% if address_family[af].network is defined and address_family[af].network is not none %} -{% for network in address_family[af].network %} - network {{ network }}{% if address_family[af].network[network].route_map is defined %} route-map {{ address_family[af].network[network].route_map }}{% endif %}{% if address_family[af].network[network].backdoor is defined %} backdoor{% endif %} +{% if afi_config.network is defined and afi_config.network is not none %} +{% for network in afi_config.network %} + network {{ network }}{% if afi_config.network[network].route_map is defined %} route-map {{ afi_config.network[network].route_map }}{% endif %}{% if afi_config.network[network].backdoor is defined %} backdoor{% endif %} {####### we need this blank line!! #######} {% endfor %} {% endif %} -{% if address_family[af].advertise_all_vni is defined %} +{% if afi_config.advertise_all_vni is defined %} advertise-all-vni {% endif %} -{% if address_family[af].advertise_default_gw is defined %} +{% if afi_config.advertise_default_gw is defined %} advertise-default-gw {% endif %} -{% if address_family[af].advertise_svi_ip is defined %} +{% if afi_config.advertise_pip is defined and afi_config.advertise_pip is not none %} + advertise-pip ip {{ afi_config.advertise_pip }} +{% endif %} +{% if afi_config.advertise_svi_ip is defined %} advertise-svi-ip {% endif %} -{% if address_family[af].vni is defined and address_family[af].vni is not none %} - vni {{ address_family[af].vni }} +{% if afi_config.rt_auto_derive is defined %} + autort rfc8365-compatible +{% endif %} +{% if afi_config.flooding is defined and afi_config.flooding.disable is defined %} + flooding disable +{% endif %} +{% if afi_config.flooding is defined and afi_config.flooding.head_end_replication is defined %} + flooding head-end-replication +{% endif %} +{% if afi_config.rd is defined and afi_config.rd is not none %} + rd {{ afi_config.rd }} +{% endif %} +{% if afi_config.route_target is defined and afi_config.route_target is not none %} +{% if afi_config.route_target.both is defined and afi_config.route_target.both is not none %} + route-target both {{ afi_config.route_target.both }} +{% endif %} +{% if afi_config.route_target.export is defined and afi_config.route_target.export is not none %} + route-target export {{ afi_config.route_target.export }} +{% endif %} +{% if afi_config.route_target.import is defined and afi_config.route_target.import is not none %} + route-target import {{ afi_config.route_target.import }} +{% endif %} +{% endif %} +{% if afi_config.vni is defined and afi_config.vni is not none %} + vni {{ afi_config.vni }} exit-vni {% endif %} exit-address-family diff --git a/interface-definitions/protocols-bgp.xml.in b/interface-definitions/protocols-bgp.xml.in index 3b7910766..ecb5b94d6 100644 --- a/interface-definitions/protocols-bgp.xml.in +++ b/interface-definitions/protocols-bgp.xml.in @@ -234,12 +234,104 @@ + + + EVPN system primary IP + + ipv4 + IP address + + + + + + Advertise svi mac-ip routes in EVPN + + + Auto derivation of Route Target (RFC8365) + + + + + + Specify handling for BUM packets + + + + + Do not flood any BUM packets + + + + + + Flood BUM packets using head-end replication + + + + + + + + Route Distinguisher + + txt + Route Distinguisher, asn:xxx + + + ^[0-9]{1,10}:[0-9]{1,5}$ + + + + + + Route Target + + + + + Route Target both import and export + + txt + Route target (x.x.x.x:yyy|xxxx:yyyy) + + + ^((25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)(\.(25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)){3}|[0-9]{1,10}):[0-9]{1,5}$ + + + + + + Route Target export + + txt + Route target (x.x.x.x:yyy|xxxx:yyyy) + + + ^((25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)(\.(25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)){3}|[0-9]{1,10}):[0-9]{1,5}$ + + + + + + Route Target import + + txt + Route target (x.x.x.x:yyy|xxxx:yyyy) + + + ^((25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)(\.(25[0-5]|2[0-4][0-9]|[1][0-9][0-9]|[1-9][0-9]|[0-9]?)){3}|[0-9]{1,10}):[0-9]{1,5}$ + + + + + VXLAN Network Identifier -- cgit v1.2.3 From 3da513e58da35b00722ac40530616ad6c01f731e Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 13 Feb 2021 21:18:10 +0100 Subject: bgp: T2387: bgp_neighbor macro should access address family dict with items() --- data/templates/frr/bgp.frr.tmpl | 89 ++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 45 deletions(-) diff --git a/data/templates/frr/bgp.frr.tmpl b/data/templates/frr/bgp.frr.tmpl index 9dafc7f91..bfaac7144 100644 --- a/data/templates/frr/bgp.frr.tmpl +++ b/data/templates/frr/bgp.frr.tmpl @@ -70,82 +70,81 @@ {% endif %} ! {% if config.address_family is defined and config.address_family is not none %} -{% for af in config.address_family %} -{% if af == 'ipv4_unicast' %} +{% for afi, afi_config in config.address_family.items() %} +{% if afi == 'ipv4_unicast' %} address-family ipv4 unicast -{% elif af == 'ipv6_unicast' %} +{% elif afi == 'ipv6_unicast' %} address-family ipv6 unicast -{% elif af == 'l2vpn_evpn' %} +{% elif afi == 'l2vpn_evpn' %} address-family l2vpn evpn {% endif %} -{% if config.afi_config.allowas_in is defined and config.afi_config.allowas_in is not none %} - neighbor {{ neighbor }} allowas-in {{ config.afi_config.allowas_in.number if config.afi_config.allowas_in.number is defined }} +{% if afi_config.allowas_in is defined and afi_config.allowas_in is not none %} + neighbor {{ neighbor }} allowas-in {{ afi_config.allowas_in.number if afi_config.allowas_in.number is defined }} {% endif %} -{% if config.afi_config.remove_private_as is defined %} +{% if afi_config.remove_private_as is defined %} neighbor {{ neighbor }} remove-private-AS {% endif %} -{% if config.afi_config.route_reflector_client is defined %} +{% if afi_config.route_reflector_client is defined %} neighbor {{ neighbor }} route-reflector-client {% endif %} -{% if config.afi_config.weight is defined and config.afi_config.weight is not none %} - neighbor {{ neighbor }} weight {{ config.afi_config.weight }} +{% if afi_config.weight is defined and afi_config.weight is not none %} + neighbor {{ neighbor }} weight {{ afi_config.weight }} {% endif %} -{% if config.afi_config.attribute_unchanged is defined and config.afi_config.attribute_unchanged is not none %} - neighbor {{ neighbor }} attribute-unchanged {{ 'as-path ' if config.afi_config.attribute_unchanged.as_path is defined }}{{ 'med ' if config.afi_config.attribute_unchanged.med is defined }}{{ 'next-hop ' if config.afi_config.attribute_unchanged.next_hop is defined }} +{% if afi_config.attribute_unchanged is defined and afi_config.attribute_unchanged is not none %} + neighbor {{ neighbor }} attribute-unchanged {{ 'as-path ' if afi_config.attribute_unchanged.as_path is defined }}{{ 'med ' if afi_config.attribute_unchanged.med is defined }}{{ 'next-hop ' if afi_config.attribute_unchanged.next_hop is defined }} {% endif %} -{% if config.afi_config.capability is defined and config.afi_config.capability.orf is defined and config.afi_config.capability.orf.prefix_list is defined and config.afi_config.capability.orf.prefix_list is not none %} - neighbor {{ neighbor }} capability orf prefix-list {{ config.afi_config.capability.orf.prefix_list }} +{% if afi_config.capability is defined and afi_config.capability.orf is defined and afi_config.capability.orf.prefix_list is defined and afi_config.capability.orf.prefix_list is not none %} + neighbor {{ neighbor }} capability orf prefix-list {{ afi_config.capability.orf.prefix_list }} {% endif %} -{% if config.afi_config.default_originate is defined %} - neighbor {{ neighbor }} default-originate {{ 'route-map ' + config.afi_config.default_originate.route_map if config.afi_config.default_originate.route_map is defined }} +{% if afi_config.default_originate is defined %} + neighbor {{ neighbor }} default-originate {{ 'route-map ' + afi_config.default_originate.route_map if afi_config.default_originate.route_map is defined }} {% endif %} -{% if config.afi_config.distribute_list is defined and config.afi_config.distribute_list is not none %} -{% if config.afi_config.distribute_list.export is defined and config.afi_config.distribute_list.export is not none %} - neighbor {{ neighbor }} distribute-list {{ config.afi_config.distribute_list.export }} out +{% if afi_config.distribute_list is defined and afi_config.distribute_list is not none %} +{% if afi_config.distribute_list.export is defined and afi_config.distribute_list.export is not none %} + neighbor {{ neighbor }} distribute-list {{ afi_config.distribute_list.export }} out {% endif %} -{% if config.afi_config.distribute_list.import is defined and config.afi_config.distribute_list.import is not none %} - neighbor {{ neighbor }} distribute-list {{ config.afi_config.distribute_list.import }} in +{% if afi_config.distribute_list.import is defined and afi_config.distribute_list.import is not none %} + neighbor {{ neighbor }} distribute-list {{ afi_config.distribute_list.import }} in {% endif %} {% endif %} -{% if config.afi_config.filter_list is defined and config.afi_config.filter_list is not none %} -{% if config.afi_config.filter_list.export is defined and config.afi_config.filter_list.export is not none %} - neighbor {{ neighbor }} filter-list {{ config.afi_config.filter_list.export }} out +{% if afi_config.filter_list is defined and afi_config.filter_list is not none %} +{% if afi_config.filter_list.export is defined and afi_config.filter_list.export is not none %} + neighbor {{ neighbor }} filter-list {{ afi_config.filter_list.export }} out {% endif %} -{% if config.afi_config.filter_list.import is defined and config.afi_config.filter_list.import is not none %} - neighbor {{ neighbor }} filter-list {{ config.afi_config.filter_list.import }} in +{% if afi_config.filter_list.import is defined and afi_config.filter_list.import is not none %} + neighbor {{ neighbor }} filter-list {{ afi_config.filter_list.import }} in {% endif %} {% endif %} -{% if config.afi_config.maximum_prefix is defined and config.afi_config.maximum_prefix is not none %} - neighbor {{ neighbor }} maximum-prefix {{ config.afi_config.maximum_prefix }} +{% if afi_config.maximum_prefix is defined and afi_config.maximum_prefix is not none %} + neighbor {{ neighbor }} maximum-prefix {{ afi_config.maximum_prefix }} {% endif %} -{% if config.afi_config.nexthop_self is defined %} -{# https://phabricator.vyos.net/T1817 #} - neighbor {{ neighbor }} next-hop-self {{ 'force' if config.afi_config.nexthop_self.force is defined }} +{% if afi_config.nexthop_self is defined %} + neighbor {{ neighbor }} next-hop-self {{ 'force' if afi_config.nexthop_self.force is defined }} {% endif %} -{% if config.afi_config.route_server_client is defined %} +{% if afi_config.route_server_client is defined %} neighbor {{ neighbor }} route-server-client {% endif %} -{% if config.afi_config.route_map is defined and config.afi_config.route_map is not none %} -{% if config.afi_config.route_map.export is defined and config.afi_config.route_map.export is not none %} - neighbor {{ neighbor }} route-map {{ config.afi_config.route_map.export }} out +{% if afi_config.route_map is defined and afi_config.route_map is not none %} +{% if afi_config.route_map.export is defined and afi_config.route_map.export is not none %} + neighbor {{ neighbor }} route-map {{ afi_config.route_map.export }} out {% endif %} -{% if config.afi_config.route_map.import is defined and config.afi_config.route_map.import is not none %} - neighbor {{ neighbor }} route-map {{ config.afi_config.route_map.import }} in +{% if afi_config.route_map.import is defined and afi_config.route_map.import is not none %} + neighbor {{ neighbor }} route-map {{ afi_config.route_map.import }} in {% endif %} {% endif %} -{% if config.afi_config.prefix_list is defined and config.afi_config.prefix_list is not none %} -{% if config.afi_config.prefix_list.export is defined and config.afi_config.prefix_list.export is not none %} - neighbor {{ neighbor }} prefix-list {{ config.afi_config.prefix_list.export }} out +{% if afi_config.prefix_list is defined and afi_config.prefix_list is not none %} +{% if afi_config.prefix_list.export is defined and afi_config.prefix_list.export is not none %} + neighbor {{ neighbor }} prefix-list {{ afi_config.prefix_list.export }} out {% endif %} -{% if config.afi_config.prefix_list.import is defined and config.afi_config.prefix_list.import is not none %} - neighbor {{ neighbor }} prefix-list {{ config.afi_config.prefix_list.import }} in +{% if afi_config.prefix_list.import is defined and afi_config.prefix_list.import is not none %} + neighbor {{ neighbor }} prefix-list {{ afi_config.prefix_list.import }} in {% endif %} {% endif %} -{% if config.afi_config.soft_reconfiguration is defined and config.afi_config.soft_reconfiguration.inbound is defined %} +{% if afi_config.soft_reconfiguration is defined and afi_config.soft_reconfiguration.inbound is defined %} neighbor {{ neighbor }} soft-reconfiguration inbound {% endif %} -{% if config.afi_config.unsuppress_map is defined and config.afi_config.unsuppress_map is not none %} - neighbor {{ neighbor }} unsuppress-map {{ config.afi_config.unsuppress_map }} +{% if afi_config.unsuppress_map is defined and afi_config.unsuppress_map is not none %} + neighbor {{ neighbor }} unsuppress-map {{ afi_config.unsuppress_map }} {% endif %} neighbor {{ neighbor }} activate exit-address-family -- cgit v1.2.3 From aec887fd6376054dc14f13d7f3a1234027dbb21b Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 14 Feb 2021 09:05:55 +0100 Subject: bgp: xml: add valueHelp for peer-group definition --- interface-definitions/include/bgp-peer-group.xml.i | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface-definitions/include/bgp-peer-group.xml.i b/interface-definitions/include/bgp-peer-group.xml.i index 24585c1ce..73c80e0e4 100644 --- a/interface-definitions/include/bgp-peer-group.xml.i +++ b/interface-definitions/include/bgp-peer-group.xml.i @@ -2,6 +2,10 @@ Peer group for this peer + + txt + Peer-group name + -- cgit v1.2.3 From 0c814f19cdc81360005055dbf24b627ba6449877 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 14 Feb 2021 10:05:37 +0100 Subject: bgp: T1513: make vni a multi node --- data/templates/frr/bgp.frr.tmpl | 4 +++- interface-definitions/protocols-bgp.xml.in | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/data/templates/frr/bgp.frr.tmpl b/data/templates/frr/bgp.frr.tmpl index bfaac7144..792146be0 100644 --- a/data/templates/frr/bgp.frr.tmpl +++ b/data/templates/frr/bgp.frr.tmpl @@ -230,8 +230,10 @@ router bgp {{ asn }} {% endif %} {% endif %} {% if afi_config.vni is defined and afi_config.vni is not none %} - vni {{ afi_config.vni }} +{% for vni in afi_config.vni %} + vni {{ vni }} exit-vni +{% endfor %} {% endif %} exit-address-family {% endfor %} diff --git a/interface-definitions/protocols-bgp.xml.in b/interface-definitions/protocols-bgp.xml.in index ecb5b94d6..13caa7b63 100644 --- a/interface-definitions/protocols-bgp.xml.in +++ b/interface-definitions/protocols-bgp.xml.in @@ -342,6 +342,7 @@ + -- cgit v1.2.3 From d468102e66ff7ed784d794e6884983669bba108e Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 14 Feb 2021 10:09:50 +0100 Subject: bgp: T3308: add graceful-shutdown option --- data/templates/frr/bgp.frr.tmpl | 3 +++ interface-definitions/protocols-bgp.xml.in | 6 ++++++ smoketest/scripts/cli/test_protocols_bgp.py | 5 +++++ 3 files changed, 14 insertions(+) diff --git a/data/templates/frr/bgp.frr.tmpl b/data/templates/frr/bgp.frr.tmpl index 792146be0..8db6015d0 100644 --- a/data/templates/frr/bgp.frr.tmpl +++ b/data/templates/frr/bgp.frr.tmpl @@ -340,6 +340,9 @@ router bgp {{ asn }} {% if parameters.graceful_restart is defined %} bgp graceful-restart {{ 'stalepath-time ' + parameters.graceful_restart.stalepath_time if parameters.graceful_restart.stalepath_time is defined }} {% endif %} +{% if parameters.graceful_shutdown is defined %} + bgp graceful-shutdown +{% endif %} {% if parameters.log_neighbor_changes is defined %} bgp log-neighbor-changes {% endif %} diff --git a/interface-definitions/protocols-bgp.xml.in b/interface-definitions/protocols-bgp.xml.in index 13caa7b63..d7bc86aff 100644 --- a/interface-definitions/protocols-bgp.xml.in +++ b/interface-definitions/protocols-bgp.xml.in @@ -852,6 +852,12 @@ + + + Graceful shutdown + + + Log neighbor up/down changes and reset reason diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index 30d98976d..8bbf0a5d1 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -166,6 +166,7 @@ class TestProtocolsBGP(unittest.TestCase): def test_bgp_01_simple(self): router_id = '127.0.0.1' local_pref = '500' + stalepath_time = '60' self.session.set(base_path + ['parameters', 'router-id', router_id]) self.session.set(base_path + ['parameters', 'log-neighbor-changes']) @@ -173,6 +174,8 @@ class TestProtocolsBGP(unittest.TestCase): self.session.set(base_path + ['parameters', 'default', 'local-pref', local_pref]) # Deactivate IPv4 unicast for a peer by default self.session.set(base_path + ['parameters', 'default', 'no-ipv4-unicast']) + self.session.set(base_path + ['parameters', 'graceful-restart', 'stalepath-time', stalepath_time]) + self.session.set(base_path + ['parameters', 'graceful-shutdown']) # commit changes self.session.commit() @@ -184,6 +187,8 @@ class TestProtocolsBGP(unittest.TestCase): self.assertIn(f' bgp log-neighbor-changes', frrconfig) self.assertIn(f' bgp default local-preference {local_pref}', frrconfig) self.assertIn(f' no bgp default ipv4-unicast', frrconfig) + self.assertIn(f' bgp graceful-restart stalepath-time {stalepath_time}', frrconfig) + self.assertIn(f' bgp graceful-shutdown', frrconfig) def test_bgp_02_neighbors(self): -- cgit v1.2.3 From 081b747e2940ac042e39bac1f209d7df94a413bf Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 14 Feb 2021 11:26:48 +0100 Subject: bgp: T2387: bugfix missing options not added to FRR The following options were not represented in the Jinja2 template: - port - advertisement-interval - strict-capability-match In addition the smoketests have been extended to support IPv6 neighbors, too. --- data/templates/frr/bgp.frr.tmpl | 9 ++ smoketest/scripts/cli/test_protocols_bgp.py | 156 +++++++++++++++++++--------- 2 files changed, 118 insertions(+), 47 deletions(-) diff --git a/data/templates/frr/bgp.frr.tmpl b/data/templates/frr/bgp.frr.tmpl index 8db6015d0..62c675291 100644 --- a/data/templates/frr/bgp.frr.tmpl +++ b/data/templates/frr/bgp.frr.tmpl @@ -9,6 +9,9 @@ {% if config.remote_as is defined and config.remote_as is not none %} neighbor {{ neighbor }} remote-as {{ config.remote_as }} {% endif %} +{% if config.advertisement_interval is defined and config.advertisement_interval is not none %} + neighbor {{ neighbor }} advertisement-interval {{ config.advertisement_interval }} +{% endif %} {% if config.bfd is defined %} neighbor {{ neighbor }} bfd {% endif %} @@ -43,9 +46,15 @@ {% if config.password is defined and config.password is not none %} neighbor {{ neighbor }} password {{ config.password }} {% endif %} +{% if config.port is defined and config.port is not none %} + neighbor {{ neighbor }} port {{ config.port }} +{% endif %} {% if config.shutdown is defined %} neighbor {{ neighbor }} shutdown {% endif %} +{% if config.strict_capability_match is defined %} + neighbor {{ neighbor }} strict-capability-match +{% endif %} {% if config.ttl_security is defined and config.ttl_security.hops is defined and config.ttl_security.hops is not none %} neighbor {{ neighbor }} ttl-security hops {{ config.ttl_security.hops }} {% endif %} diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index 8bbf0a5d1..4c4abc600 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -19,6 +19,7 @@ import unittest from vyos.configsession import ConfigSession from vyos.configsession import ConfigSessionError +from vyos.template import is_ipv6 from vyos.util import cmd from vyos.util import process_named_running @@ -30,6 +31,8 @@ route_map_in = 'foo-map-in' route_map_out = 'foo-map-out' prefix_list_in = 'pfx-foo-in' prefix_list_out = 'pfx-foo-out' +prefix_list_in6 = 'pfx-foo-in6' +prefix_list_out6 = 'pfx-foo-out6' neighbor_config = { '192.0.2.1' : { @@ -62,6 +65,29 @@ neighbor_config = { 'multi_hop' : '5', 'update_src' : 'lo', }, + '2001:db8::1' : { + 'cap_dynamic' : '', + 'cap_ext_next' : '', + 'remote_as' : '123', + 'adv_interv' : '400', + 'passive' : '', + 'password' : 'VyOS-Secure123', + 'shutdown' : '', + 'cap_over' : '', + 'ttl_security' : '5', + 'local_as' : '300', + 'route_map_in' : route_map_in, + 'route_map_out': route_map_out, + }, + '2001:db8::2' : { + 'remote_as' : '456', + 'shutdown' : '', + 'no_cap_nego' : '', + 'port' : '667', + 'cap_strict' : '', + 'pfx_list_in' : prefix_list_in6, + 'pfx_list_out' : prefix_list_out6, + }, } peer_group_config = { @@ -112,11 +138,18 @@ class TestProtocolsBGP(unittest.TestCase): self.session.set(['policy', 'prefix-list', prefix_list_out, 'rule', '10', 'action', 'permit']) self.session.set(['policy', 'prefix-list', prefix_list_out, 'rule', '10', 'prefix', '192.0.2.128/25']) + self.session.set(['policy', 'prefix-list6', prefix_list_in6, 'rule', '10', 'action', 'permit']) + self.session.set(['policy', 'prefix-list6', prefix_list_in6, 'rule', '10', 'prefix', '2001:db8:1000::/64']) + self.session.set(['policy', 'prefix-list6', prefix_list_out6, 'rule', '10', 'action', 'deny']) + self.session.set(['policy', 'prefix-list6', prefix_list_out6, 'rule', '10', 'prefix', '2001:db8:2000::/64']) + def tearDown(self): self.session.delete(['policy', 'route-map', route_map_in]) self.session.delete(['policy', 'route-map', route_map_out]) self.session.delete(['policy', 'prefix-list', prefix_list_in]) self.session.delete(['policy', 'prefix-list', prefix_list_out]) + self.session.delete(['policy', 'prefix-list6', prefix_list_in6]) + self.session.delete(['policy', 'prefix-list6', prefix_list_out6]) self.session.delete(base_path) self.session.commit() @@ -194,47 +227,51 @@ class TestProtocolsBGP(unittest.TestCase): def test_bgp_02_neighbors(self): # Test out individual neighbor configuration items, not all of them are # also available to a peer-group! - for neighbor, config in neighbor_config.items(): - if 'adv_interv' in config: - self.session.set(base_path + ['neighbor', neighbor, 'advertisement-interval', config["adv_interv"]]) - if 'cap_dynamic' in config: - self.session.set(base_path + ['neighbor', neighbor, 'capability', 'dynamic']) - if 'cap_ext_next' in config: - self.session.set(base_path + ['neighbor', neighbor, 'capability', 'extended-nexthop']) - if 'description' in config: - self.session.set(base_path + ['neighbor', neighbor, 'description', config["description"]]) - if 'no_cap_nego' in config: - self.session.set(base_path + ['neighbor', neighbor, 'disable-capability-negotiation']) - if 'multi_hop' in config: - self.session.set(base_path + ['neighbor', neighbor, 'ebgp-multihop', config["multi_hop"]]) - if 'local_as' in config: - self.session.set(base_path + ['neighbor', neighbor, 'local-as', config["local_as"]]) - if 'cap_over' in config: - self.session.set(base_path + ['neighbor', neighbor, 'override-capability']) - if 'passive' in config: - self.session.set(base_path + ['neighbor', neighbor, 'passive']) - if 'password' in config: - self.session.set(base_path + ['neighbor', neighbor, 'password', config["password"]]) - if 'port' in config: - self.session.set(base_path + ['neighbor', neighbor, 'port', config["port"]]) - if 'remote_as' in config: - self.session.set(base_path + ['neighbor', neighbor, 'remote-as', config["remote_as"]]) - if 'cap_strict' in config: - self.session.set(base_path + ['neighbor', neighbor, 'strict-capability-match']) - if 'shutdown' in config: - self.session.set(base_path + ['neighbor', neighbor, 'shutdown']) - if 'ttl_security' in config: - self.session.set(base_path + ['neighbor', neighbor, 'ttl-security', 'hops', config["ttl_security"]]) - if 'update_src' in config: - self.session.set(base_path + ['neighbor', neighbor, 'update-source', config["update_src"]]) - if 'route_map_in' in config: - self.session.set(base_path + ['neighbor', neighbor, 'address-family', 'ipv4-unicast', 'route-map', 'import', config["route_map_in"]]) - if 'route_map_out' in config: - self.session.set(base_path + ['neighbor', neighbor, 'address-family', 'ipv4-unicast', 'route-map', 'export', config["route_map_out"]]) - if 'pfx_list_in' in config: - self.session.set(base_path + ['neighbor', neighbor, 'address-family', 'ipv4-unicast', 'prefix-list', 'import', config["pfx_list_in"]]) - if 'pfx_list_out' in config: - self.session.set(base_path + ['neighbor', neighbor, 'address-family', 'ipv4-unicast', 'prefix-list', 'export', config["pfx_list_out"]]) + for peer, peer_config in neighbor_config.items(): + afi = 'ipv4-unicast' + if is_ipv6(peer): + afi = 'ipv6-unicast' + + if 'adv_interv' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'advertisement-interval', peer_config["adv_interv"]]) + if 'cap_dynamic' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'capability', 'dynamic']) + if 'cap_ext_next' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'capability', 'extended-nexthop']) + if 'description' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'description', peer_config["description"]]) + if 'no_cap_nego' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'disable-capability-negotiation']) + if 'multi_hop' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'ebgp-multihop', peer_config["multi_hop"]]) + if 'local_as' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'local-as', peer_config["local_as"]]) + if 'cap_over' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'override-capability']) + if 'passive' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'passive']) + if 'password' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'password', peer_config["password"]]) + if 'port' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'port', peer_config["port"]]) + if 'remote_as' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'remote-as', peer_config["remote_as"]]) + if 'cap_strict' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'strict-capability-match']) + if 'shutdown' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'shutdown']) + if 'ttl_security' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'ttl-security', 'hops', peer_config["ttl_security"]]) + if 'update_src' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'update-source', peer_config["update_src"]]) + if 'route_map_in' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'address-family', afi, 'route-map', 'import', peer_config["route_map_in"]]) + if 'route_map_out' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'address-family', afi, 'route-map', 'export', peer_config["route_map_out"]]) + if 'pfx_list_in' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'address-family', afi, 'prefix-list', 'import', peer_config["pfx_list_in"]]) + if 'pfx_list_out' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'address-family', afi, 'prefix-list', 'export', peer_config["pfx_list_out"]]) # commit changes self.session.commit() @@ -244,11 +281,11 @@ class TestProtocolsBGP(unittest.TestCase): self.assertIn(f'router bgp {ASN}', frrconfig) for peer, peer_config in neighbor_config.items(): - if 'adv_interv' in config: + if 'adv_interv' in peer_config: self.assertIn(f' neighbor {peer} advertisement-interval {peer_config["adv_interv"]}', frrconfig) - if 'port' in config: + if 'port' in peer_config: self.assertIn(f' neighbor {peer} port {peer_config["port"]}', frrconfig) - if 'cap_strict' in config: + if 'cap_strict' in peer_config: self.assertIn(f' neighbor {peer} strict-capability-match', frrconfig) self.verify_frr_config(peer, peer_config, frrconfig) @@ -354,12 +391,12 @@ class TestProtocolsBGP(unittest.TestCase): def test_bgp_05_afi_ipv6(self): networks = { '2001:db8:100::/48' : { - }, + }, '2001:db8:200::/48' : { - }, + }, '2001:db8:300::/48' : { 'summary_only' : '', - }, + }, } # We want to redistribute ... @@ -425,5 +462,30 @@ class TestProtocolsBGP(unittest.TestCase): for prefix in listen_ranges: self.assertIn(f' bgp listen range {prefix} peer-group {peer_group}', frrconfig) + + def test_bgp_07_l2vpn_evpn(self): + vnis = ['10010', '10020', '10030'] + neighbors = ['192.0.2.10', '192.0.2.20', '192.0.2.30'] + self.session.set(base_path + ['address-family', 'l2vpn-evpn', 'advertise-all-vni']) + self.session.set(base_path + ['address-family', 'l2vpn-evpn', 'advertise-default-gw']) + self.session.set(base_path + ['address-family', 'l2vpn-evpn', 'advertise-svi-ip']) + self.session.set(base_path + ['address-family', 'l2vpn-evpn', 'flooding', 'disable']) + for vni in vnis: + self.session.set(base_path + ['address-family', 'l2vpn-evpn', 'vni', vni]) + + # commit changes + self.session.commit() + + # Verify FRR bgpd configuration + frrconfig = getFRRBGPconfig() + self.assertIn(f'router bgp {ASN}', frrconfig) + self.assertIn(f' address-family l2vpn evpn', frrconfig) + self.assertIn(f' advertise-all-vni', frrconfig) + self.assertIn(f' advertise-default-gw', frrconfig) + self.assertIn(f' advertise-svi-ip', frrconfig) + self.assertIn(f' flooding disable', frrconfig) + for vni in vnis: + self.assertIn(f' vni {vni}', frrconfig) + if __name__ == '__main__': unittest.main(verbosity=2) -- cgit v1.2.3 From a2062824f21432031e65db0f16954f18aba19bec Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 14 Feb 2021 11:54:53 +0100 Subject: bgp: T2387: route-reflector-client is only supported for iBGP peers --- src/conf_mode/protocols_bgp.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index a2c129149..9021d58c8 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -92,7 +92,7 @@ def verify(bgp): if 'peer_group' not in peer_config or 'remote_as' not in asn_config['peer_group'][ peer_config['peer_group'] ]: raise ConfigError('Remote AS must be set for neighbor or peer-group!') - for afi in ['ipv4_unicast', 'ipv6_unicast']: + for afi in ['ipv4_unicast', 'ipv6_unicast', 'l2vpn_evpn']: # Bail out early if address family is not configured if 'address_family' not in peer_config or afi not in peer_config['address_family']: continue @@ -123,6 +123,15 @@ def verify(bgp): if dict_search(f'policy.route_map.{route_map}', asn_config) == None: raise ConfigError(f'route-map "{route_map}" used for "{tmp}" does not exist!') + if 'route_reflector_client' in afi_config: + if 'remote_as' in peer_config and asn != peer_config['remote_as']: + raise ConfigError('route-reflector-client only supported for iBGP peers') + else: + peer_group_as = dict_search(f'peer_group.{peer_group}.remote_as', asn_config) + if 'peer_group' in peer_config and peer_group_as != None and peer_group_as != asn: + raise ConfigError('route-reflector-client only supported for iBGP peers') + + # Throw an error if a peer group is not configured for allow range for prefix in dict_search('listen.range', asn_config) or []: # we can not use dict_search() here as prefix contains dots ... -- cgit v1.2.3 From 5868cbeba1bd9a4c3daaad7aa81af5c45e00cd16 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 14 Feb 2021 12:46:49 +0100 Subject: bgp: T2844: add IPv4 disable-send-community support --- data/templates/frr/bgp.frr.tmpl | 6 ++++++ interface-definitions/protocols-bgp.xml.in | 19 ------------------- smoketest/configs/bgp-small-as | 4 ++++ smoketest/scripts/cli/test_protocols_bgp.py | 18 +++++++++++++++++- src/migration-scripts/quagga/6-to-7 | 8 ++++++++ 5 files changed, 35 insertions(+), 20 deletions(-) diff --git a/data/templates/frr/bgp.frr.tmpl b/data/templates/frr/bgp.frr.tmpl index 62c675291..ab0f94c33 100644 --- a/data/templates/frr/bgp.frr.tmpl +++ b/data/templates/frr/bgp.frr.tmpl @@ -154,6 +154,12 @@ {% endif %} {% if afi_config.unsuppress_map is defined and afi_config.unsuppress_map is not none %} neighbor {{ neighbor }} unsuppress-map {{ afi_config.unsuppress_map }} +{% endif %} +{% if afi_config.disable_send_community is defined and afi_config.disable_send_community.extended is defined %} + no neighbor {{ neighbor }} send-community extended +{% endif %} +{% if afi_config.disable_send_community is defined and afi_config.disable_send_community.standard is defined %} + no neighbor {{ neighbor }} send-community standard {% endif %} neighbor {{ neighbor }} activate exit-address-family diff --git a/interface-definitions/protocols-bgp.xml.in b/interface-definitions/protocols-bgp.xml.in index d7bc86aff..01463ed57 100644 --- a/interface-definitions/protocols-bgp.xml.in +++ b/interface-definitions/protocols-bgp.xml.in @@ -468,25 +468,6 @@ #include #include #include - - - Disable sending community attributes to this neighbor (IPv4) - - - - - Disable sending extended community attributes to this neighbor (IPv4) - - - - - - Disable sending standard community attributes to this neighbor (IPv4) - - - - - #include diff --git a/smoketest/configs/bgp-small-as b/smoketest/configs/bgp-small-as index 61286c324..6b953a3f6 100644 --- a/smoketest/configs/bgp-small-as +++ b/smoketest/configs/bgp-small-as @@ -345,6 +345,10 @@ protocols { } } neighbor 10.0.151.222 { + disable-send-community { + extended + standard + } address-family { ipv4-unicast { default-originate { diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index 4c4abc600..833ca8311 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -48,6 +48,7 @@ neighbor_config = { 'local_as' : '300', 'route_map_in' : route_map_in, 'route_map_out': route_map_out, + 'no_send_comm_ext' : '', }, '192.0.2.2' : { 'remote_as' : '200', @@ -57,6 +58,7 @@ neighbor_config = { 'cap_strict' : '', 'pfx_list_in' : prefix_list_in, 'pfx_list_out' : prefix_list_out, + 'no_send_comm_std' : '', }, '192.0.2.3' : { 'description' : 'foo bar baz', @@ -78,6 +80,7 @@ neighbor_config = { 'local_as' : '300', 'route_map_in' : route_map_in, 'route_map_out': route_map_out, + 'no_send_comm_std' : '', }, '2001:db8::2' : { 'remote_as' : '456', @@ -87,6 +90,7 @@ neighbor_config = { 'cap_strict' : '', 'pfx_list_in' : prefix_list_in6, 'pfx_list_out' : prefix_list_out6, + 'no_send_comm_ext' : '', }, } @@ -108,6 +112,7 @@ peer_group_config = { 'local_as' : '300', 'pfx_list_in' : prefix_list_in, 'pfx_list_out' : prefix_list_out, + 'no_send_comm_ext' : '', }, 'baz' : { 'cap_dynamic' : '', @@ -194,7 +199,10 @@ class TestProtocolsBGP(unittest.TestCase): self.assertIn(f' neighbor {peer} prefix-list {peer_config["pfx_list_in"]} in', frrconfig) if 'pfx_list_out' in peer_config: self.assertIn(f' neighbor {peer} prefix-list {peer_config["pfx_list_out"]} out', frrconfig) - + if 'no_send_comm_std' in peer_config: + self.assertIn(f' no neighbor {peer} send-community', frrconfig) + if 'no_send_comm_ext' in peer_config: + self.assertIn(f' no neighbor {peer} send-community extended', frrconfig) def test_bgp_01_simple(self): router_id = '127.0.0.1' @@ -272,6 +280,10 @@ class TestProtocolsBGP(unittest.TestCase): self.session.set(base_path + ['neighbor', peer, 'address-family', afi, 'prefix-list', 'import', peer_config["pfx_list_in"]]) if 'pfx_list_out' in peer_config: self.session.set(base_path + ['neighbor', peer, 'address-family', afi, 'prefix-list', 'export', peer_config["pfx_list_out"]]) + if 'no_send_comm_std' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'address-family', afi, 'disable-send-community', 'standard']) + if 'no_send_comm_ext' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'address-family', afi, 'disable-send-community', 'extended']) # commit changes self.session.commit() @@ -327,6 +339,10 @@ class TestProtocolsBGP(unittest.TestCase): self.session.set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'prefix-list', 'import', config["pfx_list_in"]]) if 'pfx_list_out' in config: self.session.set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'prefix-list', 'export', config["pfx_list_out"]]) + if 'no_send_comm_std' in config: + self.session.set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'disable-send-community', 'standard']) + if 'no_send_comm_ext' in config: + self.session.set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'disable-send-community', 'extended']) # commit changes self.session.commit() diff --git a/src/migration-scripts/quagga/6-to-7 b/src/migration-scripts/quagga/6-to-7 index 3a229b5df..f7aca0d2b 100755 --- a/src/migration-scripts/quagga/6-to-7 +++ b/src/migration-scripts/quagga/6-to-7 @@ -46,6 +46,14 @@ if asn_list: if not config.exists(bgp_base + [neighbor_type]): continue for neighbor in config.list_nodes(bgp_base + [neighbor_type]): + # T2844 - add IPv4 AFI disable-send-community support + send_comm_path = bgp_base + [neighbor_type, neighbor, 'disable-send-community'] + if config.exists(send_comm_path): + new_base = bgp_base + [neighbor_type, neighbor, 'address-family', 'ipv4-unicast'] + config.set(new_base) + config.copy(send_comm_path, new_base + ['disable-send-community']) + config.delete(send_comm_path) + cap_dynamic = False for afi in ['ipv4-unicast', 'ipv6-unicast']: afi_path = bgp_base + [neighbor_type, neighbor, 'address-family', afi, 'capability', 'dynamic'] -- cgit v1.2.3 From b01c23d48a3ff3b95175568198fb307ffbc04b86 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 14 Feb 2021 13:47:16 +0100 Subject: smoketest: bfd: add initial test --- smoketest/scripts/cli/test_protocols_bfd.py | 124 ++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100755 smoketest/scripts/cli/test_protocols_bfd.py diff --git a/smoketest/scripts/cli/test_protocols_bfd.py b/smoketest/scripts/cli/test_protocols_bfd.py new file mode 100755 index 000000000..044b4b92e --- /dev/null +++ b/smoketest/scripts/cli/test_protocols_bfd.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 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 +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import os +import unittest + +from vyos.configsession import ConfigSession +from vyos.configsession import ConfigSessionError +from vyos.util import cmd +from vyos.util import process_named_running + +PROCESS_NAME = 'bfdd' +base_path = ['protocols', 'bfd'] + +neighbor_config = { + '192.0.2.1' : { + 'intv_rx' : '500', + 'intv_tx' : '600', + 'multihop' : '', + 'source_addr': '192.0.2.254', + }, + '192.0.2.2' : { + 'echo_mode' : '', + 'intv_echo' : '100', + 'intv_mult' : '111', + 'intv_rx' : '222', + 'intv_tx' : '333', + 'shutdown' : '', + 'source_intf': 'lo', + }, + '2001:db8::1' : { + 'source_addr': 'fe80::1', + 'source_intf': 'eth0', + }, + '2001:db8::2' : { + 'source_addr': 'fe80::1', + 'multihop' : '', + }, +} + +def getFRRconfig(): + return cmd('vtysh -c "show run" | sed -n "/^bfd/,/^!/p"') + +def getBFDPeerconfig(peer): + return cmd(f'vtysh -c "show run" | sed -n "/^ {peer}/,/^!/p"') + +class TestProtocolsBFD(unittest.TestCase): + def setUp(self): + self.session = ConfigSession(os.getpid()) + + def tearDown(self): + self.session.delete(base_path) + self.session.commit() + del self.session + + # Check for running process + self.assertTrue(process_named_running(PROCESS_NAME)) + + def test_bfd_simple(self): + for peer, peer_config in neighbor_config.items(): + if 'echo_mode' in peer_config: + self.session.set(base_path + ['peer', peer, 'echo-mode']) + if 'intv_echo' in peer_config: + self.session.set(base_path + ['peer', peer, 'interval', 'echo-interval', peer_config["intv_echo"]]) + if 'intv_mult' in peer_config: + self.session.set(base_path + ['peer', peer, 'interval', 'multiplier', peer_config["intv_mult"]]) + if 'intv_rx' in peer_config: + self.session.set(base_path + ['peer', peer, 'interval', 'receive', peer_config["intv_rx"]]) + if 'intv_tx' in peer_config: + self.session.set(base_path + ['peer', peer, 'interval', 'transmit', peer_config["intv_tx"]]) + if 'multihop' in peer_config: + self.session.set(base_path + ['peer', peer, 'multihop']) + if 'shutdown' in peer_config: + self.session.set(base_path + ['peer', peer, 'shutdown']) + if 'source_addr' in peer_config: + self.session.set(base_path + ['peer', peer, 'source', 'address', peer_config["source_addr"]]) + if 'source_intf' in peer_config: + self.session.set(base_path + ['peer', peer, 'source', 'interface', peer_config["source_intf"]]) + + # commit changes + self.session.commit() + + # Verify FRR bgpd configuration + frrconfig = getFRRconfig() + for peer, peer_config in neighbor_config.items(): + tmp = f'peer {peer}' + if 'multihop' in peer_config: + tmp += f' multihop' + if 'source_addr' in peer_config: + tmp += f' local-address {peer_config["source_addr"]}' + if 'source_intf' in peer_config: + tmp += f' interface {peer_config["source_intf"]}' + + self.assertIn(tmp, frrconfig) + peerconfig = getBFDPeerconfig(tmp) + + if 'echo_mode' in peer_config: + self.assertIn(f' echo-mode', peerconfig) + if 'intv_echo' in peer_config: + self.assertIn(f' echo-interval {peer_config["intv_echo"]}', peerconfig) + if 'intv_mult' in peer_config: + self.assertIn(f' detect-multiplier {peer_config["intv_mult"]}', peerconfig) + if 'intv_rx' in peer_config: + self.assertIn(f' receive-interval {peer_config["intv_rx"]}', peerconfig) + if 'intv_tx' in peer_config: + self.assertIn(f' transmit-interval {peer_config["intv_tx"]}', peerconfig) + if 'shutdown' not in peer_config: + self.assertIn(f' no shutdown', peerconfig) + +if __name__ == '__main__': + unittest.main(verbosity=2) -- cgit v1.2.3 From 580baddebb933ef388c7adabf4f4971c03decf5f Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 14 Feb 2021 17:25:06 +0100 Subject: bgp: T1513: add per VNI advertise-default-gw, advertise-svi-ip options --- data/templates/frr/bgp.frr.tmpl | 8 +++++++- .../include/bgp-afi-l2vpn-common.xml.i | 14 ++++++++++++++ interface-definitions/protocols-bgp.xml.in | 21 ++++++--------------- smoketest/scripts/cli/test_protocols_bgp.py | 15 +++++++++++---- 4 files changed, 38 insertions(+), 20 deletions(-) create mode 100644 interface-definitions/include/bgp-afi-l2vpn-common.xml.i diff --git a/data/templates/frr/bgp.frr.tmpl b/data/templates/frr/bgp.frr.tmpl index ab0f94c33..56a54ef38 100644 --- a/data/templates/frr/bgp.frr.tmpl +++ b/data/templates/frr/bgp.frr.tmpl @@ -245,8 +245,14 @@ router bgp {{ asn }} {% endif %} {% endif %} {% if afi_config.vni is defined and afi_config.vni is not none %} -{% for vni in afi_config.vni %} +{% for vni, vni_config in afi_config.vni.items() %} vni {{ vni }} +{% if vni_config.advertise_default_gw is defined %} + advertise-default-gw +{% endif %} +{% if vni_config.advertise_svi_ip is defined %} + advertise-svi-ip +{% endif %} exit-vni {% endfor %} {% endif %} diff --git a/interface-definitions/include/bgp-afi-l2vpn-common.xml.i b/interface-definitions/include/bgp-afi-l2vpn-common.xml.i new file mode 100644 index 000000000..11b1cf6bf --- /dev/null +++ b/interface-definitions/include/bgp-afi-l2vpn-common.xml.i @@ -0,0 +1,14 @@ + + + + Advertise All default g/w mac-ip routes in EVPN + + + + + + Advertise svi mac-ip routes in EVPN + + + + diff --git a/interface-definitions/protocols-bgp.xml.in b/interface-definitions/protocols-bgp.xml.in index 01463ed57..4af53acdc 100644 --- a/interface-definitions/protocols-bgp.xml.in +++ b/interface-definitions/protocols-bgp.xml.in @@ -228,12 +228,7 @@ - - - Advertise All default g/w mac-ip routes in EVPN - - - + #include EVPN system primary IP @@ -246,12 +241,6 @@ - - - Advertise svi mac-ip routes in EVPN - - - Auto derivation of Route Target (RFC8365) @@ -332,7 +321,7 @@ - + VXLAN Network Identifier @@ -342,9 +331,11 @@ - - + + #include + + diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index 833ca8311..ce643a247 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -127,10 +127,13 @@ peer_group_config = { } def getFRRBGPconfig(): - return cmd(f'vtysh -c "show run" | sed -n "/router bgp {ASN}/,/^!/p"') + return cmd(f'vtysh -c "show run" | sed -n "/^router bgp {ASN}/,/^!/p"') + +def getFRRBGPVNIconfig(vni): + return cmd(f'vtysh -c "show run" | sed -n "/^ vni {vni}/,/^!/p"') def getFRRRPKIconfig(): - return cmd(f'vtysh -c "show run" | sed -n "/rpki/,/^!/p"') + return cmd(f'vtysh -c "show run" | sed -n "/^rpki/,/^!/p"') class TestProtocolsBGP(unittest.TestCase): def setUp(self): @@ -487,7 +490,8 @@ class TestProtocolsBGP(unittest.TestCase): self.session.set(base_path + ['address-family', 'l2vpn-evpn', 'advertise-svi-ip']) self.session.set(base_path + ['address-family', 'l2vpn-evpn', 'flooding', 'disable']) for vni in vnis: - self.session.set(base_path + ['address-family', 'l2vpn-evpn', 'vni', vni]) + self.session.set(base_path + ['address-family', 'l2vpn-evpn', 'vni', vni, 'advertise-default-gw']) + self.session.set(base_path + ['address-family', 'l2vpn-evpn', 'vni', vni, 'advertise-svi-ip']) # commit changes self.session.commit() @@ -501,7 +505,10 @@ class TestProtocolsBGP(unittest.TestCase): self.assertIn(f' advertise-svi-ip', frrconfig) self.assertIn(f' flooding disable', frrconfig) for vni in vnis: - self.assertIn(f' vni {vni}', frrconfig) + vniconfig = getFRRBGPVNIconfig(vni) + self.assertIn(f'vni {vni}', vniconfig) + self.assertIn(f' advertise-default-gw', vniconfig) + self.assertIn(f' advertise-svi-ip', vniconfig) if __name__ == '__main__': unittest.main(verbosity=2) -- cgit v1.2.3 From 97a901dce9be808e918a719b4298e201a9a98ceb Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 14 Feb 2021 17:26:14 +0100 Subject: frr: harden "router" regex --- src/conf_mode/protocols_bgp.py | 2 +- src/conf_mode/protocols_ospf.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index 9021d58c8..54352460c 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -162,7 +162,7 @@ def apply(bgp): # Save original configuration prior to starting any commit actions frr_cfg = frr.FRRConfig() frr_cfg.load_configuration(frr_daemon) - frr_cfg.modify_section(f'router bgp \S+', '') + frr_cfg.modify_section(f'^router bgp \d+$', '') frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', bgp['new_frr_config']) frr_cfg.commit_configuration(frr_daemon) diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py index 5e0794fa0..2ce0ab530 100755 --- a/src/conf_mode/protocols_ospf.py +++ b/src/conf_mode/protocols_ospf.py @@ -138,7 +138,7 @@ def apply(ospf): frr_cfg = frr.FRRConfig() frr_cfg.load_configuration(frr_daemon) frr_cfg.modify_section(r'interface \S+', '') - frr_cfg.modify_section('router ospf', '') + frr_cfg.modify_section('^router ospf$', '') frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', ospf['new_frr_config']) frr_cfg.commit_configuration(frr_daemon) -- cgit v1.2.3 From bbeafa5ed417f25ecbbc3627a346cb9294d66c68 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 14 Feb 2021 17:44:03 +0100 Subject: bgp: T2315: add CLI options for addpath-tx-(all-paths|bestpath-per-AS) * protocols bgp 65000 neighbor 192.0.2.1 address-family ipv4-unicast addpath-tx-all * protocols bgp 65000 neighbor 192.0.2.1 address-family ipv4-unicast addpath-tx-per-as * protocols bgp 65000 neighbor 2001:db8::1 address-family ipv6-unicast addpath-tx-all * protocols bgp 65000 neighbor 2001:db8::1 address-family ipv6-unicast addpath-tx-per-as --- data/templates/frr/bgp.frr.tmpl | 6 ++++++ interface-definitions/include/bgp-afi-common.xml.i | 12 ++++++++++++ smoketest/scripts/cli/test_protocols_bgp.py | 15 +++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/data/templates/frr/bgp.frr.tmpl b/data/templates/frr/bgp.frr.tmpl index 56a54ef38..bb8131730 100644 --- a/data/templates/frr/bgp.frr.tmpl +++ b/data/templates/frr/bgp.frr.tmpl @@ -87,6 +87,12 @@ {% elif afi == 'l2vpn_evpn' %} address-family l2vpn evpn {% endif %} +{% if afi_config.addpath_tx_all is defined %} + neighbor {{ neighbor }} addpath-tx-all-paths +{% endif %} +{% if afi_config.addpath_tx_per_as is defined %} + neighbor {{ neighbor }} addpath-tx-bestpath-per-AS +{% endif %} {% if afi_config.allowas_in is defined and afi_config.allowas_in is not none %} neighbor {{ neighbor }} allowas-in {{ afi_config.allowas_in.number if afi_config.allowas_in.number is defined }} {% endif %} diff --git a/interface-definitions/include/bgp-afi-common.xml.i b/interface-definitions/include/bgp-afi-common.xml.i index 8c483f131..1a824abfe 100644 --- a/interface-definitions/include/bgp-afi-common.xml.i +++ b/interface-definitions/include/bgp-afi-common.xml.i @@ -1,4 +1,16 @@ + + + Use addpath to advertise all paths to a neighbor + + + + + + Use addpath to advertise the bestpath per each neighboring AS + + + #include diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index ce643a247..1de51a1fc 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -49,6 +49,7 @@ neighbor_config = { 'route_map_in' : route_map_in, 'route_map_out': route_map_out, 'no_send_comm_ext' : '', + 'addpath_all' : '', }, '192.0.2.2' : { 'remote_as' : '200', @@ -81,6 +82,7 @@ neighbor_config = { 'route_map_in' : route_map_in, 'route_map_out': route_map_out, 'no_send_comm_std' : '', + 'addpath_per_as' : '', }, '2001:db8::2' : { 'remote_as' : '456', @@ -206,6 +208,11 @@ class TestProtocolsBGP(unittest.TestCase): self.assertIn(f' no neighbor {peer} send-community', frrconfig) if 'no_send_comm_ext' in peer_config: self.assertIn(f' no neighbor {peer} send-community extended', frrconfig) + if 'addpath_all' in peer_config: + self.assertIn(f' neighbor {peer} addpath-tx-all-paths', frrconfig) + if 'addpath_per_as' in peer_config: + self.assertIn(f' neighbor {peer} addpath-tx-bestpath-per-AS', frrconfig) + def test_bgp_01_simple(self): router_id = '127.0.0.1' @@ -287,6 +294,10 @@ class TestProtocolsBGP(unittest.TestCase): self.session.set(base_path + ['neighbor', peer, 'address-family', afi, 'disable-send-community', 'standard']) if 'no_send_comm_ext' in peer_config: self.session.set(base_path + ['neighbor', peer, 'address-family', afi, 'disable-send-community', 'extended']) + if 'addpath_all' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'address-family', afi, 'addpath-tx-all']) + if 'addpath_per_as' in peer_config: + self.session.set(base_path + ['neighbor', peer, 'address-family', afi, 'addpath-tx-per-as']) # commit changes self.session.commit() @@ -346,6 +357,10 @@ class TestProtocolsBGP(unittest.TestCase): self.session.set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'disable-send-community', 'standard']) if 'no_send_comm_ext' in config: self.session.set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'disable-send-community', 'extended']) + if 'addpath_all' in config: + self.session.set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'addpath-tx-all']) + if 'addpath_per_as' in config: + self.session.set(base_path + ['peer-group', peer_group, 'address-family', 'ipv4-unicast', 'addpath-tx-per-as']) # commit changes self.session.commit() -- cgit v1.2.3 From df7e790df0c71c41455c9e05c0544889110dac0f Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 14 Feb 2021 17:46:18 +0100 Subject: templates: convert DOS -> UNIX line endings --- .../accel-ppp/config_chap_secrets_radius.j2 | 66 ++++---- .../accel-ppp/config_modules_auth_mode.j2 | 10 +- .../accel-ppp/config_modules_auth_protocols.j2 | 20 +-- data/templates/accel-ppp/config_modules_ipv6.j2 | 10 +- data/templates/accel-ppp/config_shaper_radius.j2 | 20 +-- data/templates/frr/static_routes_macro.j2 | 30 ++-- data/templates/squid/sg_acl.conf.tmpl | 36 ++-- data/templates/squid/squidGuard.conf.tmpl | 182 ++++++++++----------- data/templates/system/ssh_config.tmpl | 6 +- 9 files changed, 190 insertions(+), 190 deletions(-) diff --git a/data/templates/accel-ppp/config_chap_secrets_radius.j2 b/data/templates/accel-ppp/config_chap_secrets_radius.j2 index 4e2254b21..49af3a228 100644 --- a/data/templates/accel-ppp/config_chap_secrets_radius.j2 +++ b/data/templates/accel-ppp/config_chap_secrets_radius.j2 @@ -1,33 +1,33 @@ -{% if authentication.mode is defined and authentication.mode == 'local' %} -[chap-secrets] -chap-secrets={{ chap_secrets_file }} -{% elif authentication.mode is defined and authentication.mode == 'radius' %} -[radius] -verbose=1 -{% for server, options in authentication.radius.server.items() if not options.disable is defined %} -server={{ server }},{{ options.key }},auth-port={{ options.port }},acct-port={{ options.acct_port }},req-limit=0,fail-time={{ options.fail_time }} -{% endfor %} -{% if authentication.radius.acct_interim_jitter is defined and authentication.radius.acct_interim_jitter is not none %} -acct-interim-jitter={{ authentication.radius.acct_interim_jitter }} -{% endif %} -acct-timeout={{ authentication.radius.acct_timeout }} -timeout={{ authentication.radius.timeout }} -max-try={{ authentication.radius.max_try }} -{% if authentication.radius.nas_identifier is defined and authentication.radius.nas_identifier is not none %} -nas-identifier={{ authentication.radius.nas_identifier }} -{% endif %} -{% if authentication.radius.nas_ip_address is defined and authentication.radius.nas_ip_address is not none %} -nas-ip-address={{ authentication.radius.nas_ip_address }} -{% endif %} -{% if authentication.radius.source_address is defined and authentication.radius.source_address is not none %} -bind={{ authentication.radius.source_address }} -{% endif %} -{% if authentication.radius.dynamic_author.server is defined and authentication.radius.dynamic_author.server is not none %} -dae-server={{ authentication.radius.dynamic_author.server }}:{{ authentication.radius.dynamic_author.port }},{{ authentication.radius.dynamic_author.key }} -{% endif %} -{% endif %} -{# Both chap-secrets and radius block required the gw-ip-address #} -{% if gateway_address is defined and gateway_address is not none %} -gw-ip-address={{ gateway_address }} -{% endif %} - +{% if authentication.mode is defined and authentication.mode == 'local' %} +[chap-secrets] +chap-secrets={{ chap_secrets_file }} +{% elif authentication.mode is defined and authentication.mode == 'radius' %} +[radius] +verbose=1 +{% for server, options in authentication.radius.server.items() if not options.disable is defined %} +server={{ server }},{{ options.key }},auth-port={{ options.port }},acct-port={{ options.acct_port }},req-limit=0,fail-time={{ options.fail_time }} +{% endfor %} +{% if authentication.radius.acct_interim_jitter is defined and authentication.radius.acct_interim_jitter is not none %} +acct-interim-jitter={{ authentication.radius.acct_interim_jitter }} +{% endif %} +acct-timeout={{ authentication.radius.acct_timeout }} +timeout={{ authentication.radius.timeout }} +max-try={{ authentication.radius.max_try }} +{% if authentication.radius.nas_identifier is defined and authentication.radius.nas_identifier is not none %} +nas-identifier={{ authentication.radius.nas_identifier }} +{% endif %} +{% if authentication.radius.nas_ip_address is defined and authentication.radius.nas_ip_address is not none %} +nas-ip-address={{ authentication.radius.nas_ip_address }} +{% endif %} +{% if authentication.radius.source_address is defined and authentication.radius.source_address is not none %} +bind={{ authentication.radius.source_address }} +{% endif %} +{% if authentication.radius.dynamic_author.server is defined and authentication.radius.dynamic_author.server is not none %} +dae-server={{ authentication.radius.dynamic_author.server }}:{{ authentication.radius.dynamic_author.port }},{{ authentication.radius.dynamic_author.key }} +{% endif %} +{% endif %} +{# Both chap-secrets and radius block required the gw-ip-address #} +{% if gateway_address is defined and gateway_address is not none %} +gw-ip-address={{ gateway_address }} +{% endif %} + diff --git a/data/templates/accel-ppp/config_modules_auth_mode.j2 b/data/templates/accel-ppp/config_modules_auth_mode.j2 index 5eca76f91..e3d578b38 100644 --- a/data/templates/accel-ppp/config_modules_auth_mode.j2 +++ b/data/templates/accel-ppp/config_modules_auth_mode.j2 @@ -1,5 +1,5 @@ -{% if authentication is defined and authentication.mode is defined and authentication.mode == 'local' %} -chap-secrets -{% elif authentication is defined and authentication.mode is defined and authentication.mode == 'radius' %} -radius -{% endif %} +{% if authentication is defined and authentication.mode is defined and authentication.mode == 'local' %} +chap-secrets +{% elif authentication is defined and authentication.mode is defined and authentication.mode == 'radius' %} +radius +{% endif %} diff --git a/data/templates/accel-ppp/config_modules_auth_protocols.j2 b/data/templates/accel-ppp/config_modules_auth_protocols.j2 index e122d6c48..454d37792 100644 --- a/data/templates/accel-ppp/config_modules_auth_protocols.j2 +++ b/data/templates/accel-ppp/config_modules_auth_protocols.j2 @@ -1,10 +1,10 @@ -{% for protocol in authentication.protocols %} -{# this should be fixed in the CLI by a migrator #} -{% if protocol == 'chap' %} -auth_chap_md5 -{% elif protocol == 'mschap' %} -auth_mschap_v1 -{% else %} -auth_{{ protocol.replace('-', '_') }} -{% endif %} -{% endfor %} +{% for protocol in authentication.protocols %} +{# this should be fixed in the CLI by a migrator #} +{% if protocol == 'chap' %} +auth_chap_md5 +{% elif protocol == 'mschap' %} +auth_mschap_v1 +{% else %} +auth_{{ protocol.replace('-', '_') }} +{% endif %} +{% endfor %} diff --git a/data/templates/accel-ppp/config_modules_ipv6.j2 b/data/templates/accel-ppp/config_modules_ipv6.j2 index e9ea4924b..02740ce7c 100644 --- a/data/templates/accel-ppp/config_modules_ipv6.j2 +++ b/data/templates/accel-ppp/config_modules_ipv6.j2 @@ -1,5 +1,5 @@ -{% if ppp_options.ipv6 is defined and ppp_options.ipv6 != 'deny' %} -ipv6pool -ipv6_nd -ipv6_dhcp -{% endif %} +{% if ppp_options.ipv6 is defined and ppp_options.ipv6 != 'deny' %} +ipv6pool +ipv6_nd +ipv6_dhcp +{% endif %} diff --git a/data/templates/accel-ppp/config_shaper_radius.j2 b/data/templates/accel-ppp/config_shaper_radius.j2 index 2a6641245..8de5f5df3 100644 --- a/data/templates/accel-ppp/config_shaper_radius.j2 +++ b/data/templates/accel-ppp/config_shaper_radius.j2 @@ -1,10 +1,10 @@ -{% if authentication is defined and authentication.mode is defined and authentication.mode == 'radius' %} -{% if authentication is defined and authentication.radius is defined and authentication.radius.rate_limit is defined and authentication.radius.rate_limit.enable is defined %} -[shaper] -verbose=1 -attr={{ authentication.radius.rate_limit.attribute }} -{% if authentication.radius.rate_limit.vendor is defined and authentication.radius.rate_limit.vendor is not none %} -vendor={{ authentication.radius.rate_limit.vendor }} -{% endif %} -{% endif %} -{% endif %} +{% if authentication is defined and authentication.mode is defined and authentication.mode == 'radius' %} +{% if authentication is defined and authentication.radius is defined and authentication.radius.rate_limit is defined and authentication.radius.rate_limit.enable is defined %} +[shaper] +verbose=1 +attr={{ authentication.radius.rate_limit.attribute }} +{% if authentication.radius.rate_limit.vendor is defined and authentication.radius.rate_limit.vendor is not none %} +vendor={{ authentication.radius.rate_limit.vendor }} +{% endif %} +{% endif %} +{% endif %} diff --git a/data/templates/frr/static_routes_macro.j2 b/data/templates/frr/static_routes_macro.j2 index aadb2805e..b24232ef3 100644 --- a/data/templates/frr/static_routes_macro.j2 +++ b/data/templates/frr/static_routes_macro.j2 @@ -1,15 +1,15 @@ -{% macro static_routes(ip_ipv6, prefix, prefix_config, table=None) %} -{% 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.interface is defined and prefix_config.interface is not none %} -{% for interface, interface_config in prefix_config.interface.items() if interface_config.disable is not defined %} -{{ ip_ipv6 }} route {{ prefix }} {{ interface }} {{ interface_config.distance if interface_config.distance is defined }} {{ 'nexthop-vrf ' + interface_config.vrf if interface_config.vrf is defined }} {{ 'table ' + table if table is defined and table is not none }} -{% endfor %} -{% endif %} -{% if prefix_config.next_hop is defined and prefix_config.next_hop is not none %} -{% for next_hop, next_hop_config in prefix_config.next_hop.items() if next_hop_config.disable is not defined %} -{{ ip_ipv6 }} route {{ prefix }} {{ next_hop }} {{ next_hop_config.interface if next_hop_config.interface is defined }} {{ next_hop_config.distance if next_hop_config.distance is defined }} {{ 'nexthop-vrf ' + next_hop_config.vrf if next_hop_config.vrf is defined }} {{ 'table ' + table if table is defined and table is not none }} -{% endfor %} -{% endif %} -{% endmacro %} +{% macro static_routes(ip_ipv6, prefix, prefix_config, table=None) %} +{% 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.interface is defined and prefix_config.interface is not none %} +{% for interface, interface_config in prefix_config.interface.items() if interface_config.disable is not defined %} +{{ ip_ipv6 }} route {{ prefix }} {{ interface }} {{ interface_config.distance if interface_config.distance is defined }} {{ 'nexthop-vrf ' + interface_config.vrf if interface_config.vrf is defined }} {{ 'table ' + table if table is defined and table is not none }} +{% endfor %} +{% endif %} +{% if prefix_config.next_hop is defined and prefix_config.next_hop is not none %} +{% for next_hop, next_hop_config in prefix_config.next_hop.items() if next_hop_config.disable is not defined %} +{{ ip_ipv6 }} route {{ prefix }} {{ next_hop }} {{ next_hop_config.interface if next_hop_config.interface is defined }} {{ next_hop_config.distance if next_hop_config.distance is defined }} {{ 'nexthop-vrf ' + next_hop_config.vrf if next_hop_config.vrf is defined }} {{ 'table ' + table if table is defined and table is not none }} +{% endfor %} +{% endif %} +{% endmacro %} diff --git a/data/templates/squid/sg_acl.conf.tmpl b/data/templates/squid/sg_acl.conf.tmpl index cb1c3ccb0..ce72b173a 100644 --- a/data/templates/squid/sg_acl.conf.tmpl +++ b/data/templates/squid/sg_acl.conf.tmpl @@ -1,18 +1,18 @@ -### generated by service_webproxy.py ### -dbhome {{ squidguard_db_dir }} - -dest {{ category }}-{{ rule }} { -{% if list_type == 'domains' %} - domainlist {{ category }}/domains -{% elif list_type == 'urls' %} - urllist {{ category }}/urls -{% elif list_type == 'expressions' %} - expressionlist {{ category }}/expressions -{% endif %} -} - -acl { - default { - pass all - } -} +### generated by service_webproxy.py ### +dbhome {{ squidguard_db_dir }} + +dest {{ category }}-{{ rule }} { +{% if list_type == 'domains' %} + domainlist {{ category }}/domains +{% elif list_type == 'urls' %} + urllist {{ category }}/urls +{% elif list_type == 'expressions' %} + expressionlist {{ category }}/expressions +{% endif %} +} + +acl { + default { + pass all + } +} diff --git a/data/templates/squid/squidGuard.conf.tmpl b/data/templates/squid/squidGuard.conf.tmpl index 74de3a651..f530d1072 100644 --- a/data/templates/squid/squidGuard.conf.tmpl +++ b/data/templates/squid/squidGuard.conf.tmpl @@ -1,91 +1,91 @@ -### generated by service_webproxy.py ### - -{% macro sg_rule(category, log, db_dir) %} -{% set expressions = db_dir + '/' + category + '/expressions' %} -dest {{ category }}-default { - domainlist {{ category }}/domains - urllist {{ category }}/urls -{% if expressions | is_file %} - expressionlist {{ category }}/expressions -{% endif %} -{% if log is defined %} - log blacklist.log -{% endif %} -} -{% endmacro %} - -{% if url_filtering is defined and url_filtering.disable is not defined %} -{% if url_filtering.squidguard is defined and url_filtering.squidguard is not none %} -{% set sg_config = url_filtering.squidguard %} -{% set acl = namespace(value='local-ok-default') %} -{% set acl.value = acl.value + ' !in-addr' if sg_config.allow_ipaddr_url is not defined else acl.value %} -dbhome {{ squidguard_db_dir }} -logdir /var/log/squid - -rewrite safesearch { - s@(.*\.google\..*/(custom|search|images|groups|news)?.*q=.*)@\1\&safe=active@i - s@(.*\..*/yandsearch?.*text=.*)@\1\&fyandex=1@i - s@(.*\.yahoo\..*/search.*p=.*)@\1\&vm=r@i - s@(.*\.live\..*/.*q=.*)@\1\&adlt=strict@i - s@(.*\.msn\..*/.*q=.*)@\1\&adlt=strict@i - s@(.*\.bing\..*/search.*q=.*)@\1\&adlt=strict@i - log rewrite.log -} - -{% if sg_config.local_ok is defined and sg_config.local_ok is not none %} -{% set acl.value = acl.value + ' local-ok-default' %} -dest local-ok-default { - domainlist local-ok-default/domains -} -{% endif %} -{% if sg_config.local_ok_url is defined and sg_config.local_ok_url is not none %} -{% set acl.value = acl.value + ' local-ok-url-default' %} -dest local-ok-url-default { - urllist local-ok-url-default/urls -} -{% endif %} -{% if sg_config.local_block is defined and sg_config.local_block is not none %} -{% set acl.value = acl.value + ' !local-block-default' %} -dest local-block-default { - domainlist local-block-default/domains -} -{% endif %} -{% if sg_config.local_block_url is defined and sg_config.local_block_url is not none %} -{% set acl.value = acl.value + ' !local-block-url-default' %} -dest local-block-url-default { - urllist local-block-url-default/urls -} -{% endif %} -{% if sg_config.local_block_keyword is defined and sg_config.local_block_keyword is not none %} -{% set acl.value = acl.value + ' !local-block-keyword-default' %} -dest local-block-keyword-default { - expressionlist local-block-keyword-default/expressions -} -{% endif %} - -{% if sg_config.block_category is defined and sg_config.block_category is not none %} -{% for category in sg_config.block_category %} -{{ sg_rule(category, sg_config.log, squidguard_db_dir) }} -{% set acl.value = acl.value + ' !' + category + '-default' %} -{% endfor %} -{% endif %} -{% if sg_config.allow_category is defined and sg_config.allow_category is not none %} -{% for category in sg_config.allow_category %} -{{ sg_rule(category, False, squidguard_db_dir) }} -{% set acl.value = acl.value + ' ' + category + '-default' %} -{% endfor %} -{% endif %} -acl { - default { -{% if sg_config.enable_safe_search is defined %} - rewrite safesearch -{% endif %} - pass {{ acl.value }} {{ 'none' if sg_config.default_action is defined and sg_config.default_action == 'block' else 'allow' }} - redirect 302:http://{{ sg_config.redirect_url }} -{% if sg_config.log is defined and sg_config.log is not none %} - log blacklist.log -{% endif %} - } -} -{% endif %} -{% endif %} +### generated by service_webproxy.py ### + +{% macro sg_rule(category, log, db_dir) %} +{% set expressions = db_dir + '/' + category + '/expressions' %} +dest {{ category }}-default { + domainlist {{ category }}/domains + urllist {{ category }}/urls +{% if expressions | is_file %} + expressionlist {{ category }}/expressions +{% endif %} +{% if log is defined %} + log blacklist.log +{% endif %} +} +{% endmacro %} + +{% if url_filtering is defined and url_filtering.disable is not defined %} +{% if url_filtering.squidguard is defined and url_filtering.squidguard is not none %} +{% set sg_config = url_filtering.squidguard %} +{% set acl = namespace(value='local-ok-default') %} +{% set acl.value = acl.value + ' !in-addr' if sg_config.allow_ipaddr_url is not defined else acl.value %} +dbhome {{ squidguard_db_dir }} +logdir /var/log/squid + +rewrite safesearch { + s@(.*\.google\..*/(custom|search|images|groups|news)?.*q=.*)@\1\&safe=active@i + s@(.*\..*/yandsearch?.*text=.*)@\1\&fyandex=1@i + s@(.*\.yahoo\..*/search.*p=.*)@\1\&vm=r@i + s@(.*\.live\..*/.*q=.*)@\1\&adlt=strict@i + s@(.*\.msn\..*/.*q=.*)@\1\&adlt=strict@i + s@(.*\.bing\..*/search.*q=.*)@\1\&adlt=strict@i + log rewrite.log +} + +{% if sg_config.local_ok is defined and sg_config.local_ok is not none %} +{% set acl.value = acl.value + ' local-ok-default' %} +dest local-ok-default { + domainlist local-ok-default/domains +} +{% endif %} +{% if sg_config.local_ok_url is defined and sg_config.local_ok_url is not none %} +{% set acl.value = acl.value + ' local-ok-url-default' %} +dest local-ok-url-default { + urllist local-ok-url-default/urls +} +{% endif %} +{% if sg_config.local_block is defined and sg_config.local_block is not none %} +{% set acl.value = acl.value + ' !local-block-default' %} +dest local-block-default { + domainlist local-block-default/domains +} +{% endif %} +{% if sg_config.local_block_url is defined and sg_config.local_block_url is not none %} +{% set acl.value = acl.value + ' !local-block-url-default' %} +dest local-block-url-default { + urllist local-block-url-default/urls +} +{% endif %} +{% if sg_config.local_block_keyword is defined and sg_config.local_block_keyword is not none %} +{% set acl.value = acl.value + ' !local-block-keyword-default' %} +dest local-block-keyword-default { + expressionlist local-block-keyword-default/expressions +} +{% endif %} + +{% if sg_config.block_category is defined and sg_config.block_category is not none %} +{% for category in sg_config.block_category %} +{{ sg_rule(category, sg_config.log, squidguard_db_dir) }} +{% set acl.value = acl.value + ' !' + category + '-default' %} +{% endfor %} +{% endif %} +{% if sg_config.allow_category is defined and sg_config.allow_category is not none %} +{% for category in sg_config.allow_category %} +{{ sg_rule(category, False, squidguard_db_dir) }} +{% set acl.value = acl.value + ' ' + category + '-default' %} +{% endfor %} +{% endif %} +acl { + default { +{% if sg_config.enable_safe_search is defined %} + rewrite safesearch +{% endif %} + pass {{ acl.value }} {{ 'none' if sg_config.default_action is defined and sg_config.default_action == 'block' else 'allow' }} + redirect 302:http://{{ sg_config.redirect_url }} +{% if sg_config.log is defined and sg_config.log is not none %} + log blacklist.log +{% endif %} + } +} +{% endif %} +{% endif %} diff --git a/data/templates/system/ssh_config.tmpl b/data/templates/system/ssh_config.tmpl index 509bd5479..abc03f069 100644 --- a/data/templates/system/ssh_config.tmpl +++ b/data/templates/system/ssh_config.tmpl @@ -1,3 +1,3 @@ -{% if ssh_client is defined and ssh_client.source_address is defined and ssh_client.source_address is not none %} -BindAddress {{ ssh_client.source_address }} -{% endif %} +{% if ssh_client is defined and ssh_client.source_address is defined and ssh_client.source_address is not none %} +BindAddress {{ ssh_client.source_address }} +{% endif %} -- cgit v1.2.3 From dd291b2312f0fca49ae8ad6876e280bc46f45d2e Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Mon, 15 Feb 2021 17:23:33 +0100 Subject: bgp: T3311: remove remote-as from address-family When moving from Quagga to FRR the BGP address-family was extended by an invalid peer-group statement. FRR always moved a configured peer-group from the AFI level down to the neighbor level. With the migration to FRR reload we must take care about this by ourselves. --- .../include/bgp-afi-peer-group.xml.i | 7 - .../include/bgp-neighbor-afi-ipv4-unicast.xml.i | 1 - .../include/bgp-neighbor-afi-ipv6-unicast.xml.i | 1 - interface-definitions/include/bgp-shutdown.xml.i | 2 +- smoketest/configs/bgp-bfd-communities | 533 +++++++++++++++++++++ src/conf_mode/protocols_bgp.py | 33 +- src/migration-scripts/quagga/6-to-7 | 64 ++- 7 files changed, 606 insertions(+), 35 deletions(-) delete mode 100644 interface-definitions/include/bgp-afi-peer-group.xml.i create mode 100644 smoketest/configs/bgp-bfd-communities diff --git a/interface-definitions/include/bgp-afi-peer-group.xml.i b/interface-definitions/include/bgp-afi-peer-group.xml.i deleted file mode 100644 index c98a91030..000000000 --- a/interface-definitions/include/bgp-afi-peer-group.xml.i +++ /dev/null @@ -1,7 +0,0 @@ - - - - Peer group used for this neighbor - - - diff --git a/interface-definitions/include/bgp-neighbor-afi-ipv4-unicast.xml.i b/interface-definitions/include/bgp-neighbor-afi-ipv4-unicast.xml.i index 8f6cf06b1..ece277fbf 100644 --- a/interface-definitions/include/bgp-neighbor-afi-ipv4-unicast.xml.i +++ b/interface-definitions/include/bgp-neighbor-afi-ipv4-unicast.xml.i @@ -12,7 +12,6 @@ #include - #include #include #include diff --git a/interface-definitions/include/bgp-neighbor-afi-ipv6-unicast.xml.i b/interface-definitions/include/bgp-neighbor-afi-ipv6-unicast.xml.i index aea10c20c..e43c34113 100644 --- a/interface-definitions/include/bgp-neighbor-afi-ipv6-unicast.xml.i +++ b/interface-definitions/include/bgp-neighbor-afi-ipv6-unicast.xml.i @@ -12,7 +12,6 @@ #include - #include #include #include #include diff --git a/interface-definitions/include/bgp-shutdown.xml.i b/interface-definitions/include/bgp-shutdown.xml.i index 330120bba..fefbfcebb 100644 --- a/interface-definitions/include/bgp-shutdown.xml.i +++ b/interface-definitions/include/bgp-shutdown.xml.i @@ -1,7 +1,7 @@ - Administratively shut down peer-group + Administratively shut down this neighbor diff --git a/smoketest/configs/bgp-bfd-communities b/smoketest/configs/bgp-bfd-communities new file mode 100644 index 000000000..3b3056a51 --- /dev/null +++ b/smoketest/configs/bgp-bfd-communities @@ -0,0 +1,533 @@ +interfaces { + ethernet eth0 { + address 192.0.2.100/25 + address 2001:db8::ffff/64 + } + loopback lo { + } +} +policy { + large-community-list ANYCAST_ALL { + rule 10 { + action permit + description "Allow all anycast from anywhere" + regex "4242420696:100:.*" + } + } + large-community-list ANYCAST_INT { + rule 10 { + action permit + description "Allow all anycast from int" + regex 4242420696:100:1 + } + } + prefix-list BGP-BACKBONE-IN { + description "Inbound backbone routes from other sites" + rule 10 { + action deny + description "Block default route" + prefix 0.0.0.0/0 + } + rule 20 { + action deny + description "Block int primary" + ge 21 + prefix 192.168.0.0/20 + } + rule 30 { + action deny + description "Block loopbacks" + ge 25 + prefix 192.168.253.0/24 + } + rule 40 { + action deny + description "Block backbone peering" + ge 25 + prefix 192.168.254.0/24 + } + rule 999 { + action permit + description "Allow everything else" + ge 1 + prefix 0.0.0.0/0 + } + } + prefix-list BGP-BACKBONE-OUT { + description "Outbound backbone routes to other sites" + rule 10 { + action permit + description "Int primary" + ge 23 + prefix 192.168.0.0/20 + } + } + prefix-list GLOBAL { + description "Globally redistributed routes" + rule 10 { + action permit + prefix 192.168.100.1/32 + } + rule 20 { + action permit + prefix 192.168.7.128/25 + } + } + prefix-list6 BGP-BACKBONE-IN-V6 { + description "Inbound backbone routes from other sites" + rule 10 { + action deny + description "Block default route" + prefix ::/0 + } + rule 20 { + action deny + description "Block int primary" + ge 53 + prefix fd52:d62e:8011::/52 + } + rule 30 { + action deny + description "Block peering and stuff" + ge 53 + prefix fd52:d62e:8011:f000::/52 + } + rule 999 { + action permit + description "Allow everything else" + ge 1 + prefix ::/0 + } + } + prefix-list6 BGP-BACKBONE-OUT-V6 { + description "Outbound backbone routes to other sites" + rule 10 { + action permit + ge 64 + prefix fd52:d62e:8011::/52 + } + } + prefix-list6 GLOBAL-V6 { + description "Globally redistributed routes" + rule 10 { + action permit + ge 64 + prefix fd52:d62e:8011:2::/63 + } + } + route-map BGP-REDISTRIBUTE { + rule 10 { + action permit + description "Prepend AS and allow VPN and modem" + match { + ip { + address { + prefix-list GLOBAL + } + } + } + set { + as-path-prepend 4242420666 + } + } + rule 20 { + action permit + description "Allow VPN" + match { + ipv6 { + address { + prefix-list GLOBAL-V6 + } + } + } + } + } + route-map BGP-BACKBONE-IN { + rule 10 { + action permit + match { + ip { + address { + prefix-list BGP-BACKBONE-IN + } + } + } + } + rule 20 { + action permit + match { + ipv6 { + address { + prefix-list BGP-BACKBONE-IN-V6 + } + } + } + } + rule 30 { + action permit + match { + large-community { + large-community-list ANYCAST_ALL + } + } + } + } + route-map BGP-BACKBONE-OUT { + rule 10 { + action permit + match { + ip { + address { + prefix-list BGP-BACKBONE-OUT + } + } + } + } + rule 20 { + action permit + match { + ipv6 { + address { + prefix-list BGP-BACKBONE-OUT-V6 + } + } + } + } + rule 30 { + action permit + match { + large-community { + large-community-list ANYCAST_INT + } + } + set { + as-path-prepend 4242420666 + } + } + } +} +protocols { + bfd { + peer 192.168.253.1 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address 192.168.253.3 + } + } + peer 192.168.253.2 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address 192.168.253.3 + } + } + peer 192.168.253.6 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address 192.168.253.3 + } + } + peer 192.168.253.7 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address 192.168.253.3 + } + } + peer 192.168.253.12 { + interval { + receive 100 + transmit 100 + } + multihop + source { + address 192.168.253.3 + } + } + peer fd52:d62e:8011:fffe:192:168:253:1 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address fd52:d62e:8011:fffe:192:168:253:3 + } + } + peer fd52:d62e:8011:fffe:192:168:253:2 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address fd52:d62e:8011:fffe:192:168:253:3 + } + } + peer fd52:d62e:8011:fffe:192:168:253:6 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address fd52:d62e:8011:fffe:192:168:253:3 + } + } + peer fd52:d62e:8011:fffe:192:168:253:7 { + interval { + receive 50 + transmit 50 + } + multihop + source { + address fd52:d62e:8011:fffe:192:168:253:3 + } + } + peer fd52:d62e:8011:fffe:192:168:253:12 { + interval { + receive 100 + transmit 100 + } + multihop + source { + address fd52:d62e:8011:fffe:192:168:253:3 + } + } + } + bgp 4242420666 { + address-family { + ipv4-unicast { + redistribute { + connected { + route-map BGP-REDISTRIBUTE + } + static { + route-map BGP-REDISTRIBUTE + } + } + } + ipv6-unicast { + redistribute { + connected { + route-map BGP-REDISTRIBUTE + } + } + } + } + neighbor 192.168.253.1 { + peer-group INT + } + neighbor 192.168.253.2 { + peer-group INT + } + neighbor 192.168.253.6 { + peer-group DAL13 + } + neighbor 192.168.253.7 { + peer-group DAL13 + } + neighbor 192.168.253.12 { + address-family { + ipv4-unicast { + route-map { + export BGP-BACKBONE-OUT + import BGP-BACKBONE-IN + } + soft-reconfiguration { + inbound + } + } + } + bfd { + } + ebgp-multihop 2 + remote-as 4242420669 + update-source dum0 + } + neighbor fd52:d62e:8011:fffe:192:168:253:1 { + address-family { + ipv6-unicast { + peer-group INTv6 + } + } + } + neighbor fd52:d62e:8011:fffe:192:168:253:2 { + address-family { + ipv6-unicast { + peer-group INTv6 + } + } + } + neighbor fd52:d62e:8011:fffe:192:168:253:6 { + address-family { + ipv6-unicast { + peer-group DAL13v6 + } + } + } + neighbor fd52:d62e:8011:fffe:192:168:253:7 { + address-family { + ipv6-unicast { + peer-group DAL13v6 + } + } + } + neighbor fd52:d62e:8011:fffe:192:168:253:12 { + address-family { + ipv6-unicast { + route-map { + export BGP-BACKBONE-OUT + import BGP-BACKBONE-IN + } + soft-reconfiguration { + inbound + } + } + } + bfd { + } + ebgp-multihop 2 + remote-as 4242420669 + update-source dum0 + } + parameters { + confederation { + identifier 4242420696 + peers 4242420668 + peers 4242420669 + } + default { + no-ipv4-unicast + } + distance { + global { + external 220 + internal 220 + local 220 + } + } + graceful-restart { + } + } + peer-group DAL13 { + address-family { + ipv4-unicast { + route-map { + export BGP-BACKBONE-OUT + import BGP-BACKBONE-IN + } + soft-reconfiguration { + inbound + } + } + } + bfd + ebgp-multihop 2 + remote-as 4242420668 + update-source dum0 + } + peer-group DAL13v6 { + address-family { + ipv6-unicast { + route-map { + export BGP-BACKBONE-OUT + import BGP-BACKBONE-IN + } + soft-reconfiguration { + inbound + } + } + } + bfd + ebgp-multihop 2 + remote-as 4242420668 + update-source dum0 + } + peer-group INT { + address-family { + ipv4-unicast { + default-originate { + } + soft-reconfiguration { + inbound + } + } + } + bfd + remote-as 4242420666 + update-source dum0 + } + peer-group INTv6 { + address-family { + ipv6-unicast { + default-originate { + } + soft-reconfiguration { + inbound + } + } + } + bfd + remote-as 4242420666 + update-source dum0 + } + } +} +system { + config-management { + commit-revisions 200 + } + console { + device ttyS0 { + speed 115200 + } + } + host-name vyos + login { + user vyos { + authentication { + encrypted-password $6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/ + plaintext-password "" + } + level admin + } + } + ntp { + server 0.pool.ntp.org { + } + server 1.pool.ntp.org { + } + server 2.pool.ntp.org { + } + } + syslog { + global { + facility all { + level info + } + facility protocols { + level debug + } + } + } + time-zone Europe/Berlin +} + +/* Warning: Do not remove the following line. */ +/* === vyatta-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack-sync@1:conntrack@1:dhcp-relay@2:dhcp-server@5:dns-forwarding@1:firewall@5:ipsec@5:l2tp@1:mdns@1:nat@4:ntp@1:pptp@1:qos@1:quagga@6:snmp@1:ssh@1:system@10:vrrp@2:wanloadbalance@3:webgui@1:webproxy@1:webproxy@2:zone-policy@1" === */ +/* Release version: 1.2.6-S1 */ diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index 54352460c..b5bb018ae 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -54,6 +54,26 @@ def get_config(config=None): return bgp +def verify_remote_as(peer_config, asn_config): + if 'remote_as' in peer_config: + return peer_config['remote_as'] + + if 'peer_group' in peer_config: + peer_group_name = peer_config['peer_group'] + tmp = dict_search(f'peer_group.{peer_group_name}.remote_as', asn_config) + if tmp: return tmp + + if 'interface' in peer_config: + if 'remote_as' in peer_config['interface']: + return peer_config['interface']['remote_as'] + + if 'peer_group' in peer_config['interface']: + peer_group_name = peer_config['interface']['peer_group'] + tmp = dict_search(f'peer_group.{peer_group_name}.remote_as', asn_config) + if tmp: return tmp + + return None + def verify(bgp): if not bgp: return None @@ -79,18 +99,13 @@ def verify(bgp): raise ConfigError(f'Specified peer-group "{peer_group}" for '\ f'neighbor "{neighbor}" does not exist!') - # Some checks can/must only be done on a neighbor and nor a peer-group + + # Some checks can/must only be done on a neighbor and not a peer-group if neighbor == 'neighbor': # remote-as must be either set explicitly for the neighbor # or for the entire peer-group - if 'interface' in peer_config: - if 'remote_as' not in peer_config['interface']: - if 'peer_group' not in peer_config['interface'] or 'remote_as' not in asn_config['peer_group'][ peer_config['interface']['peer_group'] ]: - raise ConfigError('Remote AS must be set for neighbor or peer-group!') - - elif 'remote_as' not in peer_config: - if 'peer_group' not in peer_config or 'remote_as' not in asn_config['peer_group'][ peer_config['peer_group'] ]: - raise ConfigError('Remote AS must be set for neighbor or peer-group!') + if not verify_remote_as(peer_config, asn_config): + raise ConfigError(f'Neighbor "{peer}" remote-as must be set!') for afi in ['ipv4_unicast', 'ipv6_unicast', 'l2vpn_evpn']: # Bail out early if address family is not configured diff --git a/src/migration-scripts/quagga/6-to-7 b/src/migration-scripts/quagga/6-to-7 index f7aca0d2b..25cf5eebd 100755 --- a/src/migration-scripts/quagga/6-to-7 +++ b/src/migration-scripts/quagga/6-to-7 @@ -17,14 +17,17 @@ # - T3037, BGP address-family ipv6-unicast capability dynamic does not exist in # FRR, there is only a base, per neighbor dynamic capability, migrate config -import sys +from sys import argv +from sys import exit from vyos.configtree import ConfigTree +from vyos.template import is_ipv4 +from vyos.template import is_ipv6 -if (len(sys.argv) < 2): +if (len(argv) < 2): print("Must specify file name!") - sys.exit(1) + exit(1) -file_name = sys.argv[1] +file_name = argv[1] with open(file_name, 'r') as f: config_file = f.read() @@ -34,7 +37,7 @@ config = ConfigTree(config_file) if not config.exists(base): # Nothing to do - sys.exit(0) + exit(0) # Check if BGP is actually configured and obtain the ASN asn_list = config.list_nodes(base) @@ -55,30 +58,59 @@ if asn_list: config.delete(send_comm_path) cap_dynamic = False + peer_group = None for afi in ['ipv4-unicast', 'ipv6-unicast']: - afi_path = bgp_base + [neighbor_type, neighbor, 'address-family', afi, 'capability', 'dynamic'] - if config.exists(afi_path): + afi_path = bgp_base + [neighbor_type, neighbor, 'address-family', afi] + # Exit loop early if AFI does not exist + if not config.exists(afi_path): + continue + + cap_path = afi_path + ['capability', 'dynamic'] + if config.exists(cap_path): cap_dynamic = True - config.delete(afi_path) + config.delete(cap_path) + + # We have now successfully migrated the address-family + # specific dynamic capability to the neighbor/peer-group + # level. If this has been the only option under the + # address-family nodes, we can clean them up by checking if + # no other nodes are left under that tree and if so, delete + # the parent. + # + # We walk from the most inner node to the most outer one. + cleanup = -1 + while len(config.list_nodes(cap_path[:cleanup])) == 0: + config.delete(cap_path[:cleanup]) + cleanup -= 1 + + peer_group_path = afi_path + ['peer-group'] + if config.exists(peer_group_path): + if ((is_ipv4(neighbor) and afi == 'ipv4-unicast') or + (is_ipv6(neighbor) and afi == 'ipv6-unicast')): + peer_group = config.return_value(peer_group_path) + + config.delete(peer_group_path) - # We have now successfully migrated the address-family specific - # dynamic capability to the neighbor/peer-group level. If this - # has been the only option under the address-family nodes, we - # can clean them up by checking if no other nodes are left under - # that tree and if so, delete the parent. + # We have now successfully migrated the address-family + # specific peer-group to the neighbor level. If this has + # been the only option under the address-family nodes, we + # can clean them up by checking if no other nodes are left + # under that tree and if so, delete the parent. # # We walk from the most inner node to the most outer one. cleanup = -1 - while len(config.list_nodes(afi_path[:cleanup])) == 0: - config.delete(afi_path[:cleanup]) + while len(config.list_nodes(peer_group_path[:cleanup])) == 0: + config.delete(peer_group_path[:cleanup]) cleanup -= 1 if cap_dynamic: config.set(bgp_base + [neighbor_type, neighbor, 'capability', 'dynamic']) + if peer_group: + config.set(bgp_base + [neighbor_type, neighbor, 'peer-group'], value=peer_group) try: with open(file_name, 'w') as f: f.write(config.to_string()) except OSError as e: print("Failed to save the modified config: {}".format(e)) - sys.exit(1) + exit(1) -- cgit v1.2.3 From 82bdae42ceefb1132f8a98628fa9681543f4f269 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Mon, 15 Feb 2021 17:25:40 +0100 Subject: smoketest: bfd: ensure sessions are sourced from a valid local if .. if BFD connections will be source from invalid sources this will crash bfdd in FRR 7.3 --- smoketest/scripts/cli/test_protocols_bfd.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/smoketest/scripts/cli/test_protocols_bfd.py b/smoketest/scripts/cli/test_protocols_bfd.py index 044b4b92e..996a54a9d 100755 --- a/smoketest/scripts/cli/test_protocols_bfd.py +++ b/smoketest/scripts/cli/test_protocols_bfd.py @@ -25,28 +25,29 @@ from vyos.util import process_named_running PROCESS_NAME = 'bfdd' base_path = ['protocols', 'bfd'] +dum_if = 'dum1001' neighbor_config = { - '192.0.2.1' : { + '192.0.2.10' : { 'intv_rx' : '500', 'intv_tx' : '600', 'multihop' : '', 'source_addr': '192.0.2.254', }, - '192.0.2.2' : { + '192.0.2.20' : { 'echo_mode' : '', 'intv_echo' : '100', 'intv_mult' : '111', 'intv_rx' : '222', 'intv_tx' : '333', 'shutdown' : '', - 'source_intf': 'lo', + 'source_intf': dum_if, }, - '2001:db8::1' : { - 'source_addr': 'fe80::1', - 'source_intf': 'eth0', + '2001:db8::a' : { + 'source_addr': '2001:db8::1', + 'source_intf': dum_if, }, - '2001:db8::2' : { - 'source_addr': 'fe80::1', + '2001:db8::b' : { + 'source_addr': '2001:db8::1', 'multihop' : '', }, } @@ -60,8 +61,11 @@ def getBFDPeerconfig(peer): class TestProtocolsBFD(unittest.TestCase): def setUp(self): self.session = ConfigSession(os.getpid()) + self.session.set(['interfaces', 'dummy', dum_if, 'address', '192.0.2.1/24']) + self.session.set(['interfaces', 'dummy', dum_if, 'address', '2001:db8::1/64']) def tearDown(self): + self.session.delete(['interfaces', 'dummy', dum_if]) self.session.delete(base_path) self.session.commit() del self.session -- cgit v1.2.3 From 44596d08c374a80a9cf2bd31f3d937eaab8d872e Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Mon, 15 Feb 2021 18:03:10 +0100 Subject: GitHub: update help strings in PR template --- .github/PULL_REQUEST_TEMPLATE.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index cc5e2f536..923225ea8 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,8 +5,11 @@ ## Types of changes - - + - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Code style update (formatting, renaming) @@ -24,8 +27,14 @@ ## How to test - - + ## Checklist: -- cgit v1.2.3 From 3a32c507134c4599f343dda54ccf4e80ea62def4 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 14 Feb 2021 14:23:25 +0100 Subject: bfd: T3310: migrate to get_config_dict() and FRR reload --- data/configd-include.json | 1 + data/templates/frr/bfd.frr.tmpl | 37 +++--- interface-definitions/protocols-bfd.xml.in | 6 + src/conf_mode/protocols_bfd.py | 207 ++++++++--------------------- 4 files changed, 82 insertions(+), 169 deletions(-) diff --git a/data/configd-include.json b/data/configd-include.json index e50dbf1b2..aabd7232e 100644 --- a/data/configd-include.json +++ b/data/configd-include.json @@ -32,6 +32,7 @@ "nat66.py", "ntp.py", "policy-local-route.py", +"protocols_bfd.py", "protocols_bgp.py", "protocols_igmp.py", "protocols_isis.py", diff --git a/data/templates/frr/bfd.frr.tmpl b/data/templates/frr/bfd.frr.tmpl index 9e5ad3379..921d9b0bc 100644 --- a/data/templates/frr/bfd.frr.tmpl +++ b/data/templates/frr/bfd.frr.tmpl @@ -1,22 +1,23 @@ ! bfd -{% for peer in old_peers %} - no peer {{ peer.remote }}{% if peer.multihop %} multihop{% endif %}{% if peer.src_addr %} local-address {{ peer.src_addr }}{% endif %}{% if peer.src_if %} interface {{ peer.src_if }}{% endif %} - -{% endfor %} -! -{% for peer in new_peers %} - peer {{ peer.remote }}{% if peer.multihop %} multihop{% endif %}{% if peer.src_addr %} local-address {{ peer.src_addr }}{% endif %}{% if peer.src_if %} interface {{ peer.src_if }}{% endif %} - - detect-multiplier {{ peer.multiplier }} - receive-interval {{ peer.rx_interval }} - transmit-interval {{ peer.tx_interval }} -{% if peer.echo_mode %} - echo-mode -{% endif %} -{% if peer.echo_interval != '' %} - echo-interval {{ peer.echo_interval }} +{% if peer is defined and peer is not none %} +{% for peer_name, peer_config in peer.items() %} + peer {{ peer_name }}{{ ' multihop' if peer_config.multihop is defined }}{{ ' local-address ' + peer_config.source.address if peer_config.source is defined and peer_config.source.address is defined }}{{ ' interface ' + peer_config.source.interface if peer_config.source is defined and peer_config.source.interface is defined }} + detect-multiplier {{ peer_config.interval.multiplier }} + receive-interval {{ peer_config.interval.receive }} + transmit-interval {{ peer_config.interval.transmit }} +{% if peer_config.interval.echo_interval is defined and peer_config.interval.echo_interval is not none %} + echo-interval {{ peer_config.interval.echo_interval }} +{% endif %} +{% if peer_config.echo_mode is defined %} + echo-mode +{% endif %} +{% if peer_config.shutdown is defined %} + shutdown +{% else %} + no shutdown +{% endif %} + ! +{% endfor %} {% endif %} - {% if not peer.shutdown %}no {% endif %}shutdown -{% endfor %} ! diff --git a/interface-definitions/protocols-bfd.xml.in b/interface-definitions/protocols-bfd.xml.in index 8900e7955..6f82a5c2b 100644 --- a/interface-definitions/protocols-bfd.xml.in +++ b/interface-definitions/protocols-bfd.xml.in @@ -42,6 +42,9 @@ Local address to bind our peer listener to + + + ipv4 Local IPv4 address used to connect to the peer @@ -74,6 +77,7 @@ + 300 @@ -86,6 +90,7 @@ + 300 @@ -98,6 +103,7 @@ + 3 diff --git a/src/conf_mode/protocols_bfd.py b/src/conf_mode/protocols_bfd.py index d1e551cad..7737c6aa1 100755 --- a/src/conf_mode/protocols_bfd.py +++ b/src/conf_mode/protocols_bfd.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2019-2020 VyOS maintainers and contributors +# Copyright (C) 2019-2021 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 @@ -17,191 +17,96 @@ import os from sys import exit -from copy import deepcopy from vyos.config import Config +from vyos.configdict import dict_merge from vyos.template import is_ipv6 -from vyos.template import render +from vyos.template import render_to_string from vyos.util import call from vyos.validate import is_ipv6_link_local +from vyos.xml import defaults from vyos import ConfigError +from vyos import frr from vyos import airbag airbag.enable() -config_file = r'/tmp/bfd.frr' - -default_config_data = { - 'new_peers': [], - 'old_peers' : [] -} - -# get configuration for BFD peer from proposed or effective configuration -def get_bfd_peer_config(peer, conf_mode="proposed"): - conf = Config() - conf.set_level('protocols bfd peer {0}'.format(peer)) - - bfd_peer = { - 'remote': peer, - 'shutdown': False, - 'src_if': '', - 'src_addr': '', - 'multiplier': '3', - 'rx_interval': '300', - 'tx_interval': '300', - 'multihop': False, - 'echo_interval': '', - 'echo_mode': False, - } - - # Check if individual peer is disabled - if conf_mode == "effective" and conf.exists_effective('shutdown'): - bfd_peer['shutdown'] = True - if conf_mode == "proposed" and conf.exists('shutdown'): - bfd_peer['shutdown'] = True - - # Check if peer has a local source interface configured - if conf_mode == "effective" and conf.exists_effective('source interface'): - bfd_peer['src_if'] = conf.return_effective_value('source interface') - if conf_mode == "proposed" and conf.exists('source interface'): - bfd_peer['src_if'] = conf.return_value('source interface') - - # Check if peer has a local source address configured - this is mandatory for IPv6 - if conf_mode == "effective" and conf.exists_effective('source address'): - bfd_peer['src_addr'] = conf.return_effective_value('source address') - if conf_mode == "proposed" and conf.exists('source address'): - bfd_peer['src_addr'] = conf.return_value('source address') - - # Tell BFD daemon that we should expect packets with TTL less than 254 - # (because it will take more than one hop) and to listen on the multihop - # port (4784) - if conf_mode == "effective" and conf.exists_effective('multihop'): - bfd_peer['multihop'] = True - if conf_mode == "proposed" and conf.exists('multihop'): - bfd_peer['multihop'] = True - - # Configures the minimum interval that this system is capable of receiving - # control packets. The default value is 300 milliseconds. - if conf_mode == "effective" and conf.exists_effective('interval receive'): - bfd_peer['rx_interval'] = conf.return_effective_value('interval receive') - if conf_mode == "proposed" and conf.exists('interval receive'): - bfd_peer['rx_interval'] = conf.return_value('interval receive') - - # The minimum transmission interval (less jitter) that this system wants - # to use to send BFD control packets. - if conf_mode == "effective" and conf.exists_effective('interval transmit'): - bfd_peer['tx_interval'] = conf.return_effective_value('interval transmit') - if conf_mode == "proposed" and conf.exists('interval transmit'): - bfd_peer['tx_interval'] = conf.return_value('interval transmit') - - # Configures the detection multiplier to determine packet loss. The remote - # transmission interval will be multiplied by this value to determine the - # connection loss detection timer. The default value is 3. - if conf_mode == "effective" and conf.exists_effective('interval multiplier'): - bfd_peer['multiplier'] = conf.return_effective_value('interval multiplier') - if conf_mode == "proposed" and conf.exists('interval multiplier'): - bfd_peer['multiplier'] = conf.return_value('interval multiplier') - - # Configures the minimal echo receive transmission interval that this system is capable of handling - if conf_mode == "effective" and conf.exists_effective('interval echo-interval'): - bfd_peer['echo_interval'] = conf.return_effective_value('interval echo-interval') - if conf_mode == "proposed" and conf.exists('interval echo-interval'): - bfd_peer['echo_interval'] = conf.return_value('interval echo-interval') - - # Enables or disables the echo transmission mode - if conf_mode == "effective" and conf.exists_effective('echo-mode'): - bfd_peer['echo_mode'] = True - if conf_mode == "proposed" and conf.exists('echo-mode'): - bfd_peer['echo_mode'] = True - - return bfd_peer - -def get_config(): - bfd = deepcopy(default_config_data) - conf = Config() - if not (conf.exists('protocols bfd') or conf.exists_effective('protocols bfd')): - return None +def get_config(config=None): + if config: + conf = config else: - conf.set_level('protocols bfd') - - # as we have to use vtysh to talk to FRR we also need to know - # which peers are gone due to a config removal - thus we read in - # all peers (active or to delete) - for peer in conf.list_effective_nodes('peer'): - bfd['old_peers'].append(get_bfd_peer_config(peer, "effective")) - - for peer in conf.list_nodes('peer'): - bfd['new_peers'].append(get_bfd_peer_config(peer)) - - # find deleted peers - set_new_peers = set(conf.list_nodes('peer')) - set_old_peers = set(conf.list_effective_nodes('peer')) - bfd['deleted_peers'] = set_old_peers - set_new_peers + conf = Config() + base = ['protocols', 'bfd'] + bfd = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) + + # Bail out early if configuration tree does not exist + if not conf.exists(base): + return bfd + + if 'peer' in bfd: + # We have gathered the dict representation of the CLI, but there are + # default options which we need to update into the dictionary retrived. + # XXX: T2665: we currently have no nice way for defaults under tag + # nodes, thus we load the defaults "by hand" + default_values = defaults(base + ['peer']) + for peer in bfd['peer']: + bfd['peer'][peer] = dict_merge(default_values, bfd['peer'][peer]) return bfd def verify(bfd): - if bfd is None: + if not bfd or 'peer' not in bfd: return None - # some variables to use later - conf = Config() - - for peer in bfd['new_peers']: + for peer, peer_config in bfd['peer'].items(): # IPv6 link local peers require an explicit local address/interface - if is_ipv6_link_local(peer['remote']): - if not (peer['src_if'] and peer['src_addr']): + if is_ipv6_link_local(peer): + if 'source' not in peer_config or len(peer_config['source'] < 2): raise ConfigError('BFD IPv6 link-local peers require explicit local address and interface setting') # IPv6 peers require an explicit local address - if is_ipv6(peer['remote']): - if not peer['src_addr']: + if is_ipv6(peer): + if 'source' not in peer_config or 'address' not in peer_config['source']: raise ConfigError('BFD IPv6 peers require explicit local address setting') - # multihop require source address - if peer['multihop'] and not peer['src_addr']: - raise ConfigError('Multihop require source address') + if 'multihop' in peer_config: + # multihop require source address + if 'source' not in peer_config or 'address' not in peer_config['source']: + raise ConfigError('BFD multihop require source address') - # multihop and echo-mode cannot be used together - if peer['multihop'] and peer['echo_mode']: - raise ConfigError('Multihop and echo-mode cannot be used together') + # multihop and echo-mode cannot be used together + if 'echo_mode' in peer_config: + raise ConfigError('Multihop and echo-mode cannot be used together') - # multihop doesn't accept interface names - if peer['multihop'] and peer['src_if']: - raise ConfigError('Multihop and source interface cannot be used together') + # multihop doesn't accept interface names + if 'source' in peer_config and 'interface' in peer_config['source']: + raise ConfigError('Multihop and source interface cannot be used together') # echo interval can be configured only with enabled echo-mode - if peer['echo_interval'] != '' and not peer['echo_mode']: + if 'interval' in peer_config and 'echo_interval' in peer_config['interval'] and 'echo_mode' not in peer_config: raise ConfigError('echo-interval can be configured only with enabled echo-mode') - # check if we deleted peers are not used in configuration - if conf.exists('protocols bgp'): - bgp_as = conf.list_nodes('protocols bgp')[0] - - # check BGP neighbors - for peer in bfd['deleted_peers']: - if conf.exists('protocols bgp {0} neighbor {1} bfd'.format(bgp_as, peer)): - raise ConfigError('Cannot delete BFD peer {0}: it is used in BGP configuration'.format(peer)) - if conf.exists('protocols bgp {0} neighbor {1} peer-group'.format(bgp_as, peer)): - peer_group = conf.return_value('protocols bgp {0} neighbor {1} peer-group'.format(bgp_as, peer)) - if conf.exists('protocols bgp {0} peer-group {1} bfd'.format(bgp_as, peer_group)): - raise ConfigError('Cannot delete BFD peer {0}: it belongs to BGP peer-group {1} with enabled BFD'.format(peer, peer_group)) - return None def generate(bfd): - if bfd is None: + if not bfd: + bfd['new_frr_config'] = '' return None - render(config_file, 'frr/bfd.frr.tmpl', bfd) - return None + bfd['new_frr_config'] = render_to_string('frr/bfd.frr.tmpl', bfd) def apply(bfd): - if bfd is None: - return None - - call("vtysh -d bfdd -f " + config_file) - if os.path.exists(config_file): - os.remove(config_file) + # Save original configuration prior to starting any commit actions + frr_cfg = frr.FRRConfig() + frr_cfg.load_configuration() + frr_cfg.modify_section('bfd', '') + frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', bfd['new_frr_config']) + frr_cfg.commit_configuration() + + # If FRR config is blank, rerun the blank commit x times due to frr-reload + # behavior/bug not properly clearing out on one commit. + if bfd['new_frr_config'] == '': + for a in range(5): + frr_cfg.commit_configuration() return None -- cgit v1.2.3 From 3d3d09d6e5d7350b09709447ed4d7a7790e09b81 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Mon, 15 Feb 2021 20:16:02 +0100 Subject: bfd: T3310: implement peer profile support --- data/templates/frr/bfd.frr.tmpl | 29 ++++++- interface-definitions/include/bfd-common.xml.i | 72 ++++++++++++++++++ interface-definitions/protocols-bfd.xml.in | 100 +++++++------------------ smoketest/scripts/cli/test_protocols_bfd.py | 69 +++++++++++++++-- src/conf_mode/protocols_bfd.py | 71 +++++++++--------- 5 files changed, 223 insertions(+), 118 deletions(-) create mode 100644 interface-definitions/include/bfd-common.xml.i diff --git a/data/templates/frr/bfd.frr.tmpl b/data/templates/frr/bfd.frr.tmpl index 921d9b0bc..3b3d13f9d 100644 --- a/data/templates/frr/bfd.frr.tmpl +++ b/data/templates/frr/bfd.frr.tmpl @@ -1,15 +1,35 @@ ! bfd +{% if profile is defined and profile is not none %} +{% for profile_name, profile_config in profile.items() %} + profile {{ profile_name }} + detect-multiplier {{ profile_config.interval.multiplier }} + receive-interval {{ profile_config.interval.receive }} + transmit-interval {{ profile_config.interval.transmit }} +{% if profile_config.interval['echo-interval'] is defined and profile_config.interval['echo-interval'] is not none %} + echo-interval {{ profile_config.interval['echo-interval'] }} +{% endif %} +{% if profile_config['echo-mode'] is defined %} + echo-mode +{% endif %} +{% if profile_config.shutdown is defined %} + shutdown +{% else %} + no shutdown +{% endif %} + exit +{% endfor %} +{% endif %} {% if peer is defined and peer is not none %} {% for peer_name, peer_config in peer.items() %} peer {{ peer_name }}{{ ' multihop' if peer_config.multihop is defined }}{{ ' local-address ' + peer_config.source.address if peer_config.source is defined and peer_config.source.address is defined }}{{ ' interface ' + peer_config.source.interface if peer_config.source is defined and peer_config.source.interface is defined }} detect-multiplier {{ peer_config.interval.multiplier }} receive-interval {{ peer_config.interval.receive }} transmit-interval {{ peer_config.interval.transmit }} -{% if peer_config.interval.echo_interval is defined and peer_config.interval.echo_interval is not none %} - echo-interval {{ peer_config.interval.echo_interval }} +{% if peer_config.interval['echo-interval'] is defined and peer_config.interval['echo-interval'] is not none %} + echo-interval {{ peer_config.interval['echo-interval'] }} {% endif %} -{% if peer_config.echo_mode is defined %} +{% if peer_config['echo-mode'] is defined %} echo-mode {% endif %} {% if peer_config.shutdown is defined %} @@ -17,7 +37,8 @@ bfd {% else %} no shutdown {% endif %} - ! + exit {% endfor %} {% endif %} + exit ! diff --git a/interface-definitions/include/bfd-common.xml.i b/interface-definitions/include/bfd-common.xml.i new file mode 100644 index 000000000..ff73e4b20 --- /dev/null +++ b/interface-definitions/include/bfd-common.xml.i @@ -0,0 +1,72 @@ + + + + Enables the echo transmission mode + + + + + + Configure timer intervals + + + + + Minimum interval of receiving control packets + + 10-60000 + Interval in milliseconds + + + + + + 300 + + + + Minimum interval of transmitting control packets + + 10-60000 + Interval in milliseconds + + + + + + 300 + + + + Multiplier to determine packet loss + + 2-255 + Remote transmission interval will be multiplied by this value + + + + + + 3 + + + + Echo receive transmission interval + + 10-60000 + The minimal echo receive transmission interval that this system is capable of handling + + + + + + + + + + + Disable this peer + + + + diff --git a/interface-definitions/protocols-bfd.xml.in b/interface-definitions/protocols-bfd.xml.in index 6f82a5c2b..cc3c3bf12 100644 --- a/interface-definitions/protocols-bfd.xml.in +++ b/interface-definitions/protocols-bfd.xml.in @@ -11,7 +11,7 @@ - Configures a new BFD peer to listen and talk to + Configures BFD peer to listen and talk to ipv4 BFD peer IPv4 address @@ -26,6 +26,18 @@ + + + Use settings from BFD profile + + protocols bfd profile + + + txt + BFD profile name + + + Bind listener to specified interface/address, mandatory for IPv6 @@ -61,82 +73,28 @@ - - - Configure timer intervals - - - - - Minimum interval of receiving control packets - - 10-60000 - Interval in milliseconds - - - - - - 300 - - - - Minimum interval of transmitting control packets - - 10-60000 - Interval in milliseconds - - - - - - 300 - - - - Multiplier to determine packet loss - - 2-255 - Remote transmission interval will be multiplied by this value - - - - - - 3 - - - - Echo receive transmission interval - - 10-60000 - The minimal echo receive transmission interval that this system is capable of handling - - - - - - - - - - - Disable this peer - - - + #include Allow this BFD peer to not be directly connected - - - Enables the echo transmission mode - - - + + + + + Configure BFD profile used by individual peer + + txt + Name of BFD profile + + + ^[-_a-zA-Z0-9]{1,32}$ + + + + #include diff --git a/smoketest/scripts/cli/test_protocols_bfd.py b/smoketest/scripts/cli/test_protocols_bfd.py index 996a54a9d..80e5daa7c 100755 --- a/smoketest/scripts/cli/test_protocols_bfd.py +++ b/smoketest/scripts/cli/test_protocols_bfd.py @@ -26,7 +26,7 @@ PROCESS_NAME = 'bfdd' base_path = ['protocols', 'bfd'] dum_if = 'dum1001' -neighbor_config = { +peers = { '192.0.2.10' : { 'intv_rx' : '500', 'intv_tx' : '600', @@ -36,7 +36,7 @@ neighbor_config = { '192.0.2.20' : { 'echo_mode' : '', 'intv_echo' : '100', - 'intv_mult' : '111', + 'intv_mult' : '100', 'intv_rx' : '222', 'intv_tx' : '333', 'shutdown' : '', @@ -52,20 +52,35 @@ neighbor_config = { }, } +profiles = { + 'foo' : { + 'echo_mode' : '', + 'intv_echo' : '100', + 'intv_mult' : '101', + 'intv_rx' : '222', + 'intv_tx' : '333', + 'shutdown' : '', + }, + 'bar' : { + 'intv_mult' : '102', + 'intv_rx' : '444', + }, +} + def getFRRconfig(): return cmd('vtysh -c "show run" | sed -n "/^bfd/,/^!/p"') def getBFDPeerconfig(peer): return cmd(f'vtysh -c "show run" | sed -n "/^ {peer}/,/^!/p"') +def getBFDProfileconfig(profile): + return cmd(f'vtysh -c "show run" | sed -n "/^ {profile}/,/^!/p"') + class TestProtocolsBFD(unittest.TestCase): def setUp(self): self.session = ConfigSession(os.getpid()) - self.session.set(['interfaces', 'dummy', dum_if, 'address', '192.0.2.1/24']) - self.session.set(['interfaces', 'dummy', dum_if, 'address', '2001:db8::1/64']) def tearDown(self): - self.session.delete(['interfaces', 'dummy', dum_if]) self.session.delete(base_path) self.session.commit() del self.session @@ -73,8 +88,8 @@ class TestProtocolsBFD(unittest.TestCase): # Check for running process self.assertTrue(process_named_running(PROCESS_NAME)) - def test_bfd_simple(self): - for peer, peer_config in neighbor_config.items(): + def test_bfd_peer(self): + for peer, peer_config in peers.items(): if 'echo_mode' in peer_config: self.session.set(base_path + ['peer', peer, 'echo-mode']) if 'intv_echo' in peer_config: @@ -99,7 +114,7 @@ class TestProtocolsBFD(unittest.TestCase): # Verify FRR bgpd configuration frrconfig = getFRRconfig() - for peer, peer_config in neighbor_config.items(): + for peer, peer_config in peers.items(): tmp = f'peer {peer}' if 'multihop' in peer_config: tmp += f' multihop' @@ -124,5 +139,43 @@ class TestProtocolsBFD(unittest.TestCase): if 'shutdown' not in peer_config: self.assertIn(f' no shutdown', peerconfig) + def test_bfd_profile(self): + peer = '192.0.2.10' + + for profile, profile_config in profiles.items(): + if 'echo_mode' in profile_config: + self.session.set(base_path + ['profile', profile, 'echo-mode']) + if 'intv_echo' in profile_config: + self.session.set(base_path + ['profile', profile, 'interval', 'echo-interval', profile_config["intv_echo"]]) + if 'intv_mult' in profile_config: + self.session.set(base_path + ['profile', profile, 'interval', 'multiplier', profile_config["intv_mult"]]) + if 'intv_rx' in profile_config: + self.session.set(base_path + ['profile', profile, 'interval', 'receive', profile_config["intv_rx"]]) + if 'intv_tx' in profile_config: + self.session.set(base_path + ['profile', profile, 'interval', 'transmit', profile_config["intv_tx"]]) + if 'shutdown' in profile_config: + self.session.set(base_path + ['profile', profile, 'shutdown']) + + self.session.set(base_path + ['peer', peer, 'profile', list(profiles)[0]]) + + # commit changes + self.session.commit() + + # Verify FRR bgpd configuration + for profile, profile_config in profiles.items(): + config = getBFDProfileconfig(f'profile {profile}') + if 'echo_mode' in profile_config: + self.assertIn(f' echo-mode', config) + if 'intv_echo' in profile_config: + self.assertIn(f' echo-interval {profile_config["intv_echo"]}', config) + if 'intv_mult' in profile_config: + self.assertIn(f' detect-multiplier {profile_config["intv_mult"]}', config) + if 'intv_rx' in profile_config: + self.assertIn(f' receive-interval {profile_config["intv_rx"]}', config) + if 'intv_tx' in profile_config: + self.assertIn(f' transmit-interval {profile_config["intv_tx"]}', config) + if 'shutdown' not in profile_config: + self.assertIn(f' no shutdown', config) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/conf_mode/protocols_bfd.py b/src/conf_mode/protocols_bfd.py index 7737c6aa1..a43eed504 100755 --- a/src/conf_mode/protocols_bfd.py +++ b/src/conf_mode/protocols_bfd.py @@ -36,54 +36,55 @@ def get_config(config=None): else: conf = Config() base = ['protocols', 'bfd'] - bfd = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) + bfd = conf.get_config_dict(base, get_first_key=True) # Bail out early if configuration tree does not exist if not conf.exists(base): return bfd + # We have gathered the dict representation of the CLI, but there are + # default options which we need to update into the dictionary retrived. + # XXX: T2665: we currently have no nice way for defaults under tag + # nodes, thus we load the defaults "by hand" + default_values = defaults(base + ['peer']) if 'peer' in bfd: - # We have gathered the dict representation of the CLI, but there are - # default options which we need to update into the dictionary retrived. - # XXX: T2665: we currently have no nice way for defaults under tag - # nodes, thus we load the defaults "by hand" - default_values = defaults(base + ['peer']) for peer in bfd['peer']: bfd['peer'][peer] = dict_merge(default_values, bfd['peer'][peer]) + if 'profile' in bfd: + for profile in bfd['profile']: + bfd['profile'][profile] = dict_merge(default_values, bfd['profile'][profile]) + return bfd def verify(bfd): - if not bfd or 'peer' not in bfd: + if not bfd: return None - for peer, peer_config in bfd['peer'].items(): - # IPv6 link local peers require an explicit local address/interface - if is_ipv6_link_local(peer): - if 'source' not in peer_config or len(peer_config['source'] < 2): - raise ConfigError('BFD IPv6 link-local peers require explicit local address and interface setting') - - # IPv6 peers require an explicit local address - if is_ipv6(peer): - if 'source' not in peer_config or 'address' not in peer_config['source']: - raise ConfigError('BFD IPv6 peers require explicit local address setting') - - if 'multihop' in peer_config: - # multihop require source address - if 'source' not in peer_config or 'address' not in peer_config['source']: - raise ConfigError('BFD multihop require source address') - - # multihop and echo-mode cannot be used together - if 'echo_mode' in peer_config: - raise ConfigError('Multihop and echo-mode cannot be used together') - - # multihop doesn't accept interface names - if 'source' in peer_config and 'interface' in peer_config['source']: - raise ConfigError('Multihop and source interface cannot be used together') - - # echo interval can be configured only with enabled echo-mode - if 'interval' in peer_config and 'echo_interval' in peer_config['interval'] and 'echo_mode' not in peer_config: - raise ConfigError('echo-interval can be configured only with enabled echo-mode') + if 'peer' in bfd: + for peer, peer_config in bfd['peer'].items(): + # IPv6 link local peers require an explicit local address/interface + if is_ipv6_link_local(peer): + if 'source' not in peer_config or len(peer_config['source'] < 2): + raise ConfigError('BFD IPv6 link-local peers require explicit local address and interface setting') + + # IPv6 peers require an explicit local address + if is_ipv6(peer): + if 'source' not in peer_config or 'address' not in peer_config['source']: + raise ConfigError('BFD IPv6 peers require explicit local address setting') + + if 'multihop' in peer_config: + # multihop require source address + if 'source' not in peer_config or 'address' not in peer_config['source']: + raise ConfigError('BFD multihop require source address') + + # multihop and echo-mode cannot be used together + if 'echo_mode' in peer_config: + raise ConfigError('Multihop and echo-mode cannot be used together') + + # multihop doesn't accept interface names + if 'source' in peer_config and 'interface' in peer_config['source']: + raise ConfigError('Multihop and source interface cannot be used together') return None @@ -98,7 +99,7 @@ def apply(bfd): # Save original configuration prior to starting any commit actions frr_cfg = frr.FRRConfig() frr_cfg.load_configuration() - frr_cfg.modify_section('bfd', '') + frr_cfg.modify_section('^bfd', '') frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', bfd['new_frr_config']) frr_cfg.commit_configuration() -- cgit v1.2.3 From e9f581efe834dc27e78acff4a331fb9242440de5 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Mon, 15 Feb 2021 20:22:17 +0100 Subject: bgp: T1513: add per VRF vni support --- data/templates/frr/vrf.frr.tmpl | 3 +++ interface-definitions/include/vni.xml.i | 12 ++++++++++++ interface-definitions/interfaces-geneve.xml.in | 13 +------------ interface-definitions/interfaces-vxlan.xml.in | 13 +------------ interface-definitions/protocols-vrf.xml.in | 1 + 5 files changed, 18 insertions(+), 24 deletions(-) create mode 100644 interface-definitions/include/vni.xml.i diff --git a/data/templates/frr/vrf.frr.tmpl b/data/templates/frr/vrf.frr.tmpl index 0c8726908..8d3d8e9dd 100644 --- a/data/templates/frr/vrf.frr.tmpl +++ b/data/templates/frr/vrf.frr.tmpl @@ -3,6 +3,9 @@ {% if vrf is defined and vrf is not none %} {% for vrf_name, vrf_config in vrf.items() %} vrf {{ vrf_name }} +{% if vrf_config.vni is defined and vrf_config.vni is not none %} + vni {{ vrf_config.vni }} +{% endif %} {% if vrf_config.static is defined and vrf_config.static is not none %} {# IPv4 routes #} {% if vrf_config.static.route is defined and vrf_config.static.route is not none %} diff --git a/interface-definitions/include/vni.xml.i b/interface-definitions/include/vni.xml.i new file mode 100644 index 000000000..faff4c3c3 --- /dev/null +++ b/interface-definitions/include/vni.xml.i @@ -0,0 +1,12 @@ + + + Virtual Network Identifier + + 0-16777214 + VXLAN virtual network identifier + + + + + + diff --git a/interface-definitions/interfaces-geneve.xml.in b/interface-definitions/interfaces-geneve.xml.in index 0c776e3c3..1064b2c18 100644 --- a/interface-definitions/interfaces-geneve.xml.in +++ b/interface-definitions/interfaces-geneve.xml.in @@ -35,18 +35,7 @@ - - - Virtual Network Identifier - - 0-16777214 - GENEVE virtual network identifier - - - - - - + #include diff --git a/interface-definitions/interfaces-vxlan.xml.in b/interface-definitions/interfaces-vxlan.xml.in index f90a86274..234770971 100644 --- a/interface-definitions/interfaces-vxlan.xml.in +++ b/interface-definitions/interfaces-vxlan.xml.in @@ -73,18 +73,7 @@ 8472 - - - Virtual Network Identifier - - 0-16777214 - VXLAN virtual network identifier - - - - - - + #include diff --git a/interface-definitions/protocols-vrf.xml.in b/interface-definitions/protocols-vrf.xml.in index 81942d124..77297938b 100644 --- a/interface-definitions/protocols-vrf.xml.in +++ b/interface-definitions/protocols-vrf.xml.in @@ -27,6 +27,7 @@ #include + #include -- cgit v1.2.3 From 050f44ef1fba3cc23934a65df59ab3d1181cb5d0 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Tue, 16 Feb 2021 18:58:21 +0100 Subject: ospfv3: T3313: move interface related options to "protocols ospfv3 interface" --- data/templates/frr/ospfv3.frr.tmpl | 43 ++++++++ interface-definitions/protocols-ospfv3.xml.in | 130 ++++++++++++++----------- smoketest/scripts/cli/test_protocols_ospfv3.py | 63 ++++++++++-- src/conf_mode/protocols_ospf.py | 2 +- src/conf_mode/protocols_ospfv3.py | 12 ++- 5 files changed, 181 insertions(+), 69 deletions(-) diff --git a/data/templates/frr/ospfv3.frr.tmpl b/data/templates/frr/ospfv3.frr.tmpl index c63ef80dc..d08972a80 100644 --- a/data/templates/frr/ospfv3.frr.tmpl +++ b/data/templates/frr/ospfv3.frr.tmpl @@ -1,4 +1,47 @@ ! +{% if interface is defined and interface is not none %} +{% for iface, iface_config in interface.items() %} +interface {{ iface }} +{% if iface_config.cost is defined and iface_config.cost is not none %} + ipv6 ospf6 cost {{ iface_config.cost }} +{% endif %} +{% if iface_config.priority is defined and iface_config.priority is not none %} + ipv6 ospf6 priority {{ iface_config.priority }} +{% endif %} +{% if iface_config.hello_interval is defined and iface_config.hello_interval is not none %} + ipv6 ospf6 hello-interval {{ iface_config.hello_interval }} +{% endif %} +{% if iface_config.retransmit_interval is defined and iface_config.retransmit_interval is not none %} + ipv6 ospf6 retransmit-interval {{ iface_config.retransmit_interval }} +{% endif %} +{% if iface_config.transmit_delay is defined and iface_config.transmit_delay is not none %} + ipv6 ospf6 transmit-delay {{ iface_config.transmit_delay }} +{% endif %} +{% if iface_config.dead_interval is defined and iface_config.dead_interval is not none %} + ipv6 ospf6 dead-interval {{ iface_config.dead_interval }} +{% endif %} +{% if iface_config.bfd is defined %} + ipv6 ospf6 bfd +{% endif %} +{% if iface_config.mtu_ignore is defined %} + ipv6 ospf6 mtu-ignore +{% endif %} +{% if iface_config.ifmtu is defined and iface_config.ifmtu is not none %} + ipv6 ospf6 ifmtu {{ iface_config.ifmtu }} +{% endif %} +{% if iface_config.network is defined and iface_config.network is not none %} + ipv6 ospf6 network {{ iface_config.network }} +{% endif %} +{% if iface_config.instance_id is defined and iface_config.instance_id is not none %} + ipv6 ospf6 instance-id {{ iface_config.instance_id }} +{% endif %} +{% if iface_config.passive is defined %} + ipv6 ospf6 passive +{% endif %} +! +{% endfor %} +{% endif %} +! router ospf6 {% if area is defined and area is not none %} {% for area_id, area_config in area.items() %} diff --git a/interface-definitions/protocols-ospfv3.xml.in b/interface-definitions/protocols-ospfv3.xml.in index e28faa3cf..2559e2b03 100644 --- a/interface-definitions/protocols-ospfv3.xml.in +++ b/interface-definitions/protocols-ospfv3.xml.in @@ -41,7 +41,7 @@ - + Enable routing on an IPv6 interface @@ -54,63 +54,9 @@ + - - #include - #include - - - Interface MTU - - u32:1-65535 - Interface MTU - - - - - - - - - Instance Id (default: 0) - - u32:0-255 - Instance Id - - - - - - 0 - - - - Network type - - broadcast point-to-point - - - broadcast - Broadcast network type - - - point-to-point - Point-to-point network type - - - ^(broadcast|point-to-point)$ - - Must be broadcast or point-to-point - - - - - Disable forming of adjacency - - - - - + Specify IPv6 prefix (border routers only) @@ -201,6 +147,76 @@ + + + Enable routing on an IPv6 interface + + + + + txt + Interface used for routing information exchange + + + + + + + #include + #include + + + Interface MTU + + u32:1-65535 + Interface MTU + + + + + + + + + Instance Id (default: 0) + + u32:0-255 + Instance Id + + + + + + 0 + + + + Network type + + broadcast point-to-point + + + broadcast + Broadcast network type + + + point-to-point + Point-to-point network type + + + ^(broadcast|point-to-point)$ + + Must be broadcast or point-to-point + + + + + Disable forming of adjacency + + + + + OSPFv3 specific parameters diff --git a/smoketest/scripts/cli/test_protocols_ospfv3.py b/smoketest/scripts/cli/test_protocols_ospfv3.py index 297d5d996..754c4488f 100755 --- a/smoketest/scripts/cli/test_protocols_ospfv3.py +++ b/smoketest/scripts/cli/test_protocols_ospfv3.py @@ -25,10 +25,15 @@ from vyos.util import process_named_running PROCESS_NAME = 'ospf6d' base_path = ['protocols', 'ospfv3'] +router_id = '192.0.2.1' +default_area = '0' def getFRROSPFconfig(): return cmd('vtysh -c "show run" | sed -n "/router ospf6/,/^!/p"') +def getFRRIFconfig(iface): + return cmd(f'vtysh -c "show run" | sed -n "/^interface {iface}/,/^!/p"') + class TestProtocolsOSPFv3(unittest.TestCase): def setUp(self): self.session = ConfigSession(os.getpid()) @@ -43,23 +48,21 @@ class TestProtocolsOSPFv3(unittest.TestCase): def test_ospfv3_01_basic(self): - area = '0' seq = '10' prefix = '2001:db8::/32' acl_name = 'foo-acl-100' - router_id = '192.0.2.1' self.session.set(['policy', 'access-list6', acl_name, 'rule', seq, 'action', 'permit']) self.session.set(['policy', 'access-list6', acl_name, 'rule', seq, 'source', 'any']) self.session.set(base_path + ['parameters', 'router-id', router_id]) - self.session.set(base_path + ['area', area, 'range', prefix, 'advertise']) - self.session.set(base_path + ['area', area, 'export-list', acl_name]) - self.session.set(base_path + ['area', area, 'import-list', acl_name]) + self.session.set(base_path + ['area', default_area, 'range', prefix, 'advertise']) + self.session.set(base_path + ['area', default_area, 'export-list', acl_name]) + self.session.set(base_path + ['area', default_area, 'import-list', acl_name]) interfaces = Section.interfaces('ethernet') for interface in interfaces: - self.session.set(base_path + ['area', area, 'interface', interface]) + self.session.set(base_path + ['area', default_area, 'interface', interface]) # commit changes self.session.commit() @@ -67,13 +70,13 @@ class TestProtocolsOSPFv3(unittest.TestCase): # Verify FRR ospfd configuration frrconfig = getFRROSPFconfig() self.assertIn(f'router ospf6', frrconfig) - self.assertIn(f' area {area} range {prefix}', frrconfig) + self.assertIn(f' area {default_area} range {prefix}', frrconfig) self.assertIn(f' ospf6 router-id {router_id}', frrconfig) - self.assertIn(f' area {area} import-list {acl_name}', frrconfig) - self.assertIn(f' area {area} export-list {acl_name}', frrconfig) + self.assertIn(f' area {default_area} import-list {acl_name}', frrconfig) + self.assertIn(f' area {default_area} export-list {acl_name}', frrconfig) for interface in interfaces: - self.assertIn(f' interface {interface} area {area}', frrconfig) + self.assertIn(f' interface {interface} area {default_area}', frrconfig) self.session.delete(['policy', 'access-list6', acl_name]) @@ -118,6 +121,46 @@ class TestProtocolsOSPFv3(unittest.TestCase): for protocol in redistribute: self.assertIn(f' redistribute {protocol} route-map {route_map}', frrconfig) + def test_ospfv3_0104_interfaces(self): + + self.session.set(base_path + ['parameters', 'router-id', router_id]) + self.session.set(base_path + ['area', default_area]) + + cost = '100' + priority = '10' + interfaces = Section.interfaces('ethernet') + for interface in interfaces: + if_base = base_path + ['interface', interface] + self.session.set(if_base + ['bfd']) + self.session.set(if_base + ['cost', cost]) + self.session.set(if_base + ['instance-id', '0']) + self.session.set(if_base + ['mtu-ignore']) + self.session.set(if_base + ['network', 'point-to-point']) + self.session.set(if_base + ['passive']) + self.session.set(if_base + ['priority', priority]) + cost = str(int(cost) + 10) + priority = str(int(priority) + 5) + + # commit changes + self.session.commit() + + # Verify FRR ospfd configuration + frrconfig = getFRROSPFconfig() + self.assertIn(f'router ospf6', frrconfig) + + cost = '100' + priority = '10' + for interface in interfaces: + if_config = getFRRIFconfig(interface) + self.assertIn(f'interface {interface}', if_config) + self.assertIn(f' ipv6 ospf6 bfd', if_config) + self.assertIn(f' ipv6 ospf6 cost {cost}', if_config) + self.assertIn(f' ipv6 ospf6 mtu-ignore', if_config) + self.assertIn(f' ipv6 ospf6 network point-to-point', if_config) + self.assertIn(f' ipv6 ospf6 passive', if_config) + self.assertIn(f' ipv6 ospf6 priority {priority}', if_config) + cost = str(int(cost) + 10) + priority = str(int(priority) + 5) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py index 2ce0ab530..6d9eb828b 100755 --- a/src/conf_mode/protocols_ospf.py +++ b/src/conf_mode/protocols_ospf.py @@ -137,7 +137,7 @@ def apply(ospf): # Save original configuration prior to starting any commit actions frr_cfg = frr.FRRConfig() frr_cfg.load_configuration(frr_daemon) - frr_cfg.modify_section(r'interface \S+', '') + frr_cfg.modify_section(r'^interface \S+', '') frr_cfg.modify_section('^router ospf$', '') frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', ospf['new_frr_config']) frr_cfg.commit_configuration(frr_daemon) diff --git a/src/conf_mode/protocols_ospfv3.py b/src/conf_mode/protocols_ospfv3.py index 6c3aaf426..6f068b196 100755 --- a/src/conf_mode/protocols_ospfv3.py +++ b/src/conf_mode/protocols_ospfv3.py @@ -23,6 +23,7 @@ from vyos.configdict import dict_merge from vyos.configverify import verify_route_maps from vyos.template import render_to_string from vyos.util import call +from vyos.ifconfig import Interface from vyos.xml import defaults from vyos import ConfigError from vyos import frr @@ -57,6 +58,14 @@ def verify(ospfv3): return None verify_route_maps(ospfv3) + + if 'interface' in ospfv3: + for ifname, if_config in ospfv3['interface'].items(): + if 'ifmtu' in if_config: + mtu = Interface(ifname).get_mtu() + if int(if_config['ifmtu']) > int(mtu): + raise ConfigError(f'OSPFv3 ifmtu cannot go beyond physical MTU of "{mtu}"') + return None def generate(ospfv3): @@ -71,7 +80,8 @@ def apply(ospfv3): # Save original configuration prior to starting any commit actions frr_cfg = frr.FRRConfig() frr_cfg.load_configuration(frr_daemon) - frr_cfg.modify_section('router ospf6', '') + frr_cfg.modify_section(r'^interface \S+', '') + frr_cfg.modify_section('^router ospf6$', '') frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', ospfv3['new_frr_config']) frr_cfg.commit_configuration(frr_daemon) -- cgit v1.2.3 From 7f2b376cb07c2a0407daf2677defddc880ca907f Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Tue, 16 Feb 2021 19:04:48 +0100 Subject: bgp: T2100: always set "no bgp network import-check" In order to keep the current behavior when upgrading from 1.2 -> 1.3 -> 1.4 FRR requires us to set this option. This configuration modifies the behavior of the network statement. If you have this configured the underlying network must exist in the rib (default). If you have the [no] form configured then BGP will not check for the networks existence in the rib. For FRR versions 7.3 and before frr defaults for datacenter were the network must exist, traditional did not check for existence. For versions 7.4 and beyond both traditional and datacenter the network must exist. VyOS uses "traditional". --- data/templates/frr/bgp.frr.tmpl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/data/templates/frr/bgp.frr.tmpl b/data/templates/frr/bgp.frr.tmpl index bb8131730..4cb2ad092 100644 --- a/data/templates/frr/bgp.frr.tmpl +++ b/data/templates/frr/bgp.frr.tmpl @@ -176,8 +176,10 @@ ! router bgp {{ asn }} {# Disable eBGP policy by default until there is a CLI option #} -{# https://phabricator.vyos.net/T3183 & https://phabricator.vyos.net/T2100 #} +{# Workaround for T3183 until we have decided about a migration script #} no bgp ebgp-requires-policy +{# Workaround for T2100 until we have decided about a migration script #} + no bgp network import-check {% if address_family is defined and address_family is not none %} {% for afi, afi_config in address_family.items() %} ! -- cgit v1.2.3 From 0fb5cc02c6c16ef410c1b1f746c1fbfbc40a0da0 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Tue, 16 Feb 2021 19:14:35 +0100 Subject: ospf: T3047: support virtual-link interfaces on "passive-interface-exclude" This superseeds GitHub pull request #723 by implementing support to add an OSPF virtual-link interface which connects different areas to the "no passive-interface" configuration option when the system uses "passive-interface default". Setting "protocols ospf passive-interface-exclude vlink0" on the VyOS CLI will render the FRR OSPF configuration "no passive-interface VLINK0". --- data/templates/frr/ospf.frr.tmpl | 3 +++ interface-definitions/protocols-ospf.xml.in | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/data/templates/frr/ospf.frr.tmpl b/data/templates/frr/ospf.frr.tmpl index 7ca69eee6..140b6b406 100644 --- a/data/templates/frr/ospf.frr.tmpl +++ b/data/templates/frr/ospf.frr.tmpl @@ -159,6 +159,9 @@ router ospf passive-interface {{ interface }} {% endfor %} {% for interface in passive_interface_exclude if passive_interface_exclude is defined %} +{% if interface.startswith('vlink') %} +{% set interface = interface.upper() %} +{% endif %} no passive-interface {{ interface }} {% endfor %} {% if redistribute is defined and redistribute is not none %} diff --git a/interface-definitions/protocols-ospf.xml.in b/interface-definitions/protocols-ospf.xml.in index d0cfa14b1..4c480c71d 100644 --- a/interface-definitions/protocols-ospf.xml.in +++ b/interface-definitions/protocols-ospf.xml.in @@ -661,10 +661,15 @@ txt - Interface to be passive (i.e. suppress routing updates) + Interface to exclude when suppressing routing updates + + + vlinkN + Virtual-link interface to exclude when suppressing routing updates + ^(vlink[0-9]+)$ -- cgit v1.2.3 From 79ebf56dd18d62b5ff0ed8efadbc92bca2ebfffd Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Tue, 16 Feb 2021 22:01:19 +0100 Subject: bfd: T3310: use end to exit FRR scope We need to exit from the bfd context by end instead of exit, else FRR reload will get confused: frr-reload output: 168 2021-02-16 21:13:19,014 DEBUG: LINE ip prefix-list GLOBAL seq 10 permit 192.168.100.1/32: append to current_context_lines, ['bfd'] --- data/templates/frr/bfd.frr.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/templates/frr/bfd.frr.tmpl b/data/templates/frr/bfd.frr.tmpl index 3b3d13f9d..16f8be92c 100644 --- a/data/templates/frr/bfd.frr.tmpl +++ b/data/templates/frr/bfd.frr.tmpl @@ -40,5 +40,5 @@ bfd exit {% endfor %} {% endif %} - exit + end ! -- cgit v1.2.3 From 1a74e6b3ce061f3c866bcb3f119ee5c73b0c6796 Mon Sep 17 00:00:00 2001 From: sever-sever Date: Wed, 10 Feb 2021 21:07:30 +0000 Subject: squid: T3299: Add listen address 0.0.0.0 --- src/conf_mode/service_webproxy.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/conf_mode/service_webproxy.py b/src/conf_mode/service_webproxy.py index 8dfae348a..cbbd2e0bc 100755 --- a/src/conf_mode/service_webproxy.py +++ b/src/conf_mode/service_webproxy.py @@ -123,9 +123,6 @@ def verify(proxy): ldap_auth = dict_search('authentication.method', proxy) == 'ldap' for address, config in proxy['listen_address'].items(): - if not is_addr_assigned(address): - raise ConfigError( - f'listen-address "{address}" not assigned on any interface!') if ldap_auth and 'disable_transparent' not in config: raise ConfigError('Authentication can not be configured when ' \ 'proxy is in transparent mode') -- cgit v1.2.3 From 83bcd13775323bec35d018223029e9a8b13179c8 Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Wed, 17 Feb 2021 15:25:54 -0600 Subject: configsession: T3259: avoid deadlock when data fills stdout pipe If the subprocess is producing enough data (in this case showConfig on a large config file), then the construction: p = subprocess.Popen(.., stdout=subprocess.PIPE, ..) p.wait() will deadlock with the subprocess waiting for data to be consumed, while the Python process waits for its termination. So consume data, then wait for termination. --- python/vyos/configsession.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/vyos/configsession.py b/python/vyos/configsession.py index 82b9355a3..670e6c7fc 100644 --- a/python/vyos/configsession.py +++ b/python/vyos/configsession.py @@ -129,9 +129,9 @@ class ConfigSession(object): def __run_command(self, cmd_list): p = subprocess.Popen(cmd_list, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=self.__session_env) + (stdout_data, stderr_data) = p.communicate() + output = stdout_data.decode() result = p.wait() - output = p.stdout.read().decode() - p.communicate() if result != 0: raise ConfigSessionError(output) return output -- cgit v1.2.3 From 8f50b3dd94f41a11ce4d0bb06d3506caaf2864b8 Mon Sep 17 00:00:00 2001 From: John Estabrook Date: Wed, 17 Feb 2021 19:31:29 -0600 Subject: configd: T3302: redirect stdout/stderr from scripts to console --- src/services/vyos-configd | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/services/vyos-configd b/src/services/vyos-configd index 5b1ab1f1f..3bd516463 100755 --- a/src/services/vyos-configd +++ b/src/services/vyos-configd @@ -25,6 +25,7 @@ import logging import signal import importlib.util import zmq +from contextlib import redirect_stdout, redirect_stderr from vyos.defaults import directories from vyos.configsource import ConfigSourceString, ConfigSourceError @@ -104,27 +105,23 @@ conf_mode_scripts = dict(zip(imports, modules)) exclude_set = {key_name_from_file_name(f) for f in filenames if f not in include} include_set = {key_name_from_file_name(f) for f in filenames if f in include} -def explicit_print(t, m): - try: - with open(t, 'w') as f: - f.write(m) - f.write("\n") - f.flush() - except Exception: - pass def run_script(script, config) -> int: config.set_level([]) try: - c = script.get_config(config) - script.verify(c) - script.generate(c) - script.apply(c) + with open(session_tty, 'w') as f, redirect_stdout(f): + with redirect_stderr(f): + c = script.get_config(config) + script.verify(c) + script.generate(c) + script.apply(c) except ConfigError as e: logger.critical(e) - explicit_print(session_tty, str(e)) + with open(session_tty, 'w') as f, redirect_stdout(f): + print(f"{e}\n") return R_ERROR_COMMIT - except Exception: + except Exception as e: + logger.critical(e) return R_ERROR_DAEMON return R_SUCCESS -- cgit v1.2.3 From f67568bc2307706116f5509fca3a188dc4ab5d48 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Thu, 18 Feb 2021 08:44:05 +0100 Subject: validator: T3326: add missing interfaces (e.g. ppp and l2tpv3) --- src/op_mode/vtysh_wrapper.sh | 4 ++++ src/validators/interface-name | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100755 src/op_mode/vtysh_wrapper.sh diff --git a/src/op_mode/vtysh_wrapper.sh b/src/op_mode/vtysh_wrapper.sh new file mode 100755 index 000000000..47d88330b --- /dev/null +++ b/src/op_mode/vtysh_wrapper.sh @@ -0,0 +1,4 @@ +#!/bin/sh +declare -a tmp +tmp=$@ +vtysh -c "$tmp" diff --git a/src/validators/interface-name b/src/validators/interface-name index 32cd42fbd..8e337b401 100755 --- a/src/validators/interface-name +++ b/src/validators/interface-name @@ -17,7 +17,7 @@ import re import sys -pattern = '^(br|bond|dum|en|eth|gnv|peth|pppoe|tun|vti|vtun|vxlan|wg|wlan)[0-9]+|lo$' +pattern = '^(bond|br|dum|en|ersp|eth|gnv|lan|l2tp|l2tpeth|macsec|peth|ppp|pppoe|pptp|sstp|tun|vti|vtun|vxlan|wg|wlan|wlm)[0-9]+|lo$' if __name__ == '__main__': if len(sys.argv) != 2: -- cgit v1.2.3 From b576a95b1aa3e3c94139fe3f8355c5e4cf72a7c4 Mon Sep 17 00:00:00 2001 From: sever-sever Date: Fri, 19 Feb 2021 11:01:50 +0000 Subject: bgp: T3331: Fix set unsuppress-map for neighbor --- interface-definitions/include/bgp-afi-common.xml.i | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface-definitions/include/bgp-afi-common.xml.i b/interface-definitions/include/bgp-afi-common.xml.i index 1a824abfe..90c2753c8 100644 --- a/interface-definitions/include/bgp-afi-common.xml.i +++ b/interface-definitions/include/bgp-afi-common.xml.i @@ -132,7 +132,9 @@ Route-map to selectively unsuppress suppressed routes - + + policy route-map + -- cgit v1.2.3 From b5f67d4ea18dce4d9d5586d5a11590c6a45b3251 Mon Sep 17 00:00:00 2001 From: sever-sever Date: Fri, 19 Feb 2021 11:48:38 +0000 Subject: bgp: T3330: Fix capability orf prefix-list --- data/templates/frr/bgp.frr.tmpl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/data/templates/frr/bgp.frr.tmpl b/data/templates/frr/bgp.frr.tmpl index 4cb2ad092..08b6cb791 100644 --- a/data/templates/frr/bgp.frr.tmpl +++ b/data/templates/frr/bgp.frr.tmpl @@ -108,8 +108,11 @@ {% if afi_config.attribute_unchanged is defined and afi_config.attribute_unchanged is not none %} neighbor {{ neighbor }} attribute-unchanged {{ 'as-path ' if afi_config.attribute_unchanged.as_path is defined }}{{ 'med ' if afi_config.attribute_unchanged.med is defined }}{{ 'next-hop ' if afi_config.attribute_unchanged.next_hop is defined }} {% endif %} -{% if afi_config.capability is defined and afi_config.capability.orf is defined and afi_config.capability.orf.prefix_list is defined and afi_config.capability.orf.prefix_list is not none %} - neighbor {{ neighbor }} capability orf prefix-list {{ afi_config.capability.orf.prefix_list }} +{% if afi_config.capability is defined and afi_config.capability.orf is defined and afi_config.capability.orf.prefix_list is defined and afi_config.capability.orf.prefix_list.send is defined %} + neighbor {{ neighbor }} capability orf prefix-list send +{% endif %} +{% if afi_config.capability is defined and afi_config.capability.orf is defined and afi_config.capability.orf.prefix_list is defined and afi_config.capability.orf.prefix_list.receive is defined %} + neighbor {{ neighbor }} capability orf prefix-list receive {% endif %} {% if afi_config.default_originate is defined %} neighbor {{ neighbor }} default-originate {{ 'route-map ' + afi_config.default_originate.route_map if afi_config.default_originate.route_map is defined }} -- cgit v1.2.3 From baade8815bd18af7d0c64985fdb97bcad045432b Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Fri, 19 Feb 2021 21:39:10 +0100 Subject: bgp: T3332: fix UnboundLocalError when using route-reflector-client local variable 'peer_group' referenced before assignment. --- src/conf_mode/protocols_bgp.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index b5bb018ae..baf5c4159 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -142,10 +142,10 @@ def verify(bgp): if 'remote_as' in peer_config and asn != peer_config['remote_as']: raise ConfigError('route-reflector-client only supported for iBGP peers') else: - peer_group_as = dict_search(f'peer_group.{peer_group}.remote_as', asn_config) - if 'peer_group' in peer_config and peer_group_as != None and peer_group_as != asn: - raise ConfigError('route-reflector-client only supported for iBGP peers') - + if 'peer_group' in peer_config: + peer_group_as = dict_search(f'peer_group.{peer_group}.remote_as', asn_config) + if peer_group_as != None and peer_group_as != asn: + raise ConfigError('route-reflector-client only supported for iBGP peers') # Throw an error if a peer group is not configured for allow range for prefix in dict_search('listen.range', asn_config) or []: -- cgit v1.2.3 From 68f7d1474dec359f10d1b6b99d350110df47e136 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 20 Feb 2021 19:24:31 +0100 Subject: op-mode: bgp: T1513: add "show bgp" tree containing l2vpn evpn --- op-mode-definitions/include/bgp-afi-common.xml.i | 40 ++++ .../include/bgp-afi-ipv4-ipv6-common.xml.i | 243 +++++++++++++++++++ .../include/bgp-prefix-bestpath-multipath.xml.i | 20 ++ .../include/vtysh-generic-detail.xml.i | 8 + op-mode-definitions/show-bgp.xml.in | 262 +++++++++++++++++++++ op-mode-definitions/show-ip-bgp.xml.in | 228 +----------------- op-mode-definitions/show-ipv6-bgp.xml.in | 203 ---------------- 7 files changed, 579 insertions(+), 425 deletions(-) create mode 100644 op-mode-definitions/include/bgp-afi-common.xml.i create mode 100644 op-mode-definitions/include/bgp-afi-ipv4-ipv6-common.xml.i create mode 100644 op-mode-definitions/include/bgp-prefix-bestpath-multipath.xml.i create mode 100644 op-mode-definitions/include/vtysh-generic-detail.xml.i create mode 100644 op-mode-definitions/show-bgp.xml.in delete mode 100644 op-mode-definitions/show-ipv6-bgp.xml.in diff --git a/op-mode-definitions/include/bgp-afi-common.xml.i b/op-mode-definitions/include/bgp-afi-common.xml.i new file mode 100644 index 000000000..b496e910a --- /dev/null +++ b/op-mode-definitions/include/bgp-afi-common.xml.i @@ -0,0 +1,40 @@ + + + + Community number where AA and NN are (0-65535) + + AA:NN + + + + + + Exact match of the communities + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + List of large-community numbers + + AA:BB:CC + + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + RIB advertisement statistics + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Summary of BGP neighbor status + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + diff --git a/op-mode-definitions/include/bgp-afi-ipv4-ipv6-common.xml.i b/op-mode-definitions/include/bgp-afi-ipv4-ipv6-common.xml.i new file mode 100644 index 000000000..6de666603 --- /dev/null +++ b/op-mode-definitions/include/bgp-afi-ipv4-ipv6-common.xml.i @@ -0,0 +1,243 @@ + + + + Display routes matching the community + + + + + Should accept local VPN route if exported and imported into different VRF (well-known community) + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Should accept VPN route with local nexthop (well-known community) + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Inform EBGP peers to blackhole traffic to prefix (well-known community) + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Exact match of the communities + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Graceful shutdown (well-known community) + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Staled Long-lived Graceful Restart VPN route (well-known community) + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Do not send outside local AS (well-known community) + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Do not advertise to any peer (well-known community) + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Do not export to next AS (well-known community) + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Removed because Long-lived Graceful Restart was not enabled for VPN route (well-known community) + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Do not export to any peer (well-known community) + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + RT translated VPNv4 route filtering (well-known community) + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + RT translated VPNv6 route filtering (well-known community) + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + RT VPNv4 route filtering (well-known community) + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + RT VPNv6 route filtering (well-known community) + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Display routes matching the community-list + + 1-500 name + + + + + + Show BGP routes exactly matching specified community list + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Display detailed information about dampening + + + + + Display paths suppressed due to dampening + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Display flap statistics of routes + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Display detail of configured dampening parameters + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + + + Display routes conforming to the filter-list + + + + + + + + Show BGP routes matching the specified large-communities + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Detailed information on TCP and BGP neighbor connections + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Show detailed BGP IPv4 unicast neighbor information + + + + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Show routes advertised to a BGP neighbor + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Show dampened routes received from BGP neighbor + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Show flap statistics of the routes learned from BGP neighbor + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Show detailed prefix count information for BGP neighbor + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Show information received from BGP neighbor + + + + + Show prefixlist filter + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + + + Show received routes from BGP neighbor + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Show routes learned from BGP neighbor + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + + + Display routes conforming to the prefix-list + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Display routes matching the AS path regular expression + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Show BGP routes matching the specified route map + + policy route-map + + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + diff --git a/op-mode-definitions/include/bgp-prefix-bestpath-multipath.xml.i b/op-mode-definitions/include/bgp-prefix-bestpath-multipath.xml.i new file mode 100644 index 000000000..3bea5cf13 --- /dev/null +++ b/op-mode-definitions/include/bgp-prefix-bestpath-multipath.xml.i @@ -0,0 +1,20 @@ + + + + Display only the bestpath + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Display only multipaths + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Display route and more specific routes + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + diff --git a/op-mode-definitions/include/vtysh-generic-detail.xml.i b/op-mode-definitions/include/vtysh-generic-detail.xml.i new file mode 100644 index 000000000..9e1f90649 --- /dev/null +++ b/op-mode-definitions/include/vtysh-generic-detail.xml.i @@ -0,0 +1,8 @@ + + + + Detailed information + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + diff --git a/op-mode-definitions/show-bgp.xml.in b/op-mode-definitions/show-bgp.xml.in new file mode 100644 index 000000000..506af68b3 --- /dev/null +++ b/op-mode-definitions/show-bgp.xml.in @@ -0,0 +1,262 @@ + + + + + + + BGP information + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + #include + + + Network in the BGP routing table to display + + <x.x.x.x> <x.x.x.x/x> <h:h:h:h:h:h:h:h> <h:h:h:h:h:h:h:h/x> + + + + #include + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + IPv4 Address Family + + + #include + #include + + + + + Network in the BGP routing table to display + + <x.x.x.x> <x.x.x.x/x> <h:h:h:h:h:h:h:h> <h:h:h:h:h:h:h:h/x> + + + + #include + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + IPv6 Address Family + + + #include + #include + + + + + Layer 2 Virtual Private Network + + + + + Network in the BGP routing table to display + + <x.x.x.x> <x.x.x.x/x> <h:h:h:h:h:h:h:h> <h:h:h:h:h:h:h:h/x> + + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Ethernet Virtual Private Network + + + #include + + + Display information about all EVPN NLRIs + + + + + Display BGP Overlay Information for prefixes + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Display BGP tags for prefixes + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + + + Ethernet Segment + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + #include + + + + + Ethernet Segment per EVI + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + #include + + + VxLAN Network Identifier + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + + + Show import route target + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Show detailed BGP neighbor information + + + + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Show routes advertised to a BGP neighbor + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Show routes learned from BGP neighbor + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + + + Show detailed BGP neighbor information + + ASN:NN IPADDRESS:NN + + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Display BGP Overlay Information for prefixes + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Display BGP tags for prefixes + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + + + EVPN route information + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + #include + + + Specify Route type + + + + + EAD (Type-1) route + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + MAC-IP (Type-2) route + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Multicast (Type-3) route + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Ethernet Segment (Type-4) route + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Prefix (Type-5) route + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + EAD (Type-1) route + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Ethernet Segment (Type-4) route + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + MAC-IP (Type-2) route + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Multicast (Type-3) route + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + Prefix (Type-5) route + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + + + VXLAN Network Identifier + + 1-16777215 all + + + sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + + + + + + + + + diff --git a/op-mode-definitions/show-ip-bgp.xml.in b/op-mode-definitions/show-ip-bgp.xml.in index 311f9e6ae..690de0a1d 100644 --- a/op-mode-definitions/show-ip-bgp.xml.in +++ b/op-mode-definitions/show-ip-bgp.xml.in @@ -22,59 +22,21 @@ vtysh -c "show ip bgp cidr-only" - - - Show BGP routes matching the communities - - vtysh -c "show ip bgp community" - - - - Display routes matching the specified communities - - <AA:NN> local-AS no-advertise no-export - - - vtysh -c "show ip bgp community $5" - List all bgp community information vtysh -c "show ip bgp community-info" - - - Show BGP routes matching specified community list - - vtysh -c "show ip bgp community-list $5" - - - - Show BGP routes exactly matching specified community list - - vtysh -c "show ip bgp community-list $5 exact-match" - - - - - - Show dampened BGP paths - - vtysh -c "show ip bgp dampening dampened-paths" - - + #include + #include + - Show BGP information for specified word + + policy prefix-list + - vtysh -c "show ip bgp filter-list $5" - - - Show flap statistics of routes - - vtysh -c "show ip bgp dampening flap-statistics" - Show BGP IPv4 information @@ -120,12 +82,6 @@ - - - Show BGP information for specified word - - vtysh -c "show ip bgp filter-list $5" - Show detailed BGP IPv4 unicast neighbor information @@ -204,198 +160,26 @@ - - - Layer 2 Virtual Private Network - - - - - Ethernet Virtual Private Network - - - - - Display information about all EVPN NLRIs - - - - - Display BGP Overlay Information for prefixes - - vtysh -c "show ip bgp l2vpn evpn all overlay" - - - - Display BGP tags for prefixes - - vtysh -c "show ip bgp l2vpn evpn all tags" - - - - - - Show detailed BGP IPv4 unicast neighbor information - - - - - - - - Show routes advertised to a BGP neighbor - - vtysh -c "show ip bgp l2vpn evpn neighbor $7 advertised-routes" - - - - Show routes learned from BGP neighbor - - vtysh -c "show ip bgp l2vpn evpn neighbor $7 routes" - - - - - - Detailed info about dynamic update groups - - vtysh -c "show ip bgp l2vpn evpn update-groups" - - - - - - - - Show BGP routes matching the specified large-communities - - vtysh -c "show ip bgp large-community" - Show BGP large-community information vtysh -c "show ip bgp large-community-info" - - - Show BGP routes matching the specified large-community list - - vtysh -c "show ip bgp large-community-list $5" - Show BGP memory usage vtysh -c "show ip bgp memory" - - - Show detailed BGP IPv4 unicast neighbor information - - - - - vtysh -c "show ip bgp neighbors $5" - - - - Show routes advertised to a BGP neighbor - - vtysh -c "show ip bgp neighbor $5 advertised-routes" - - - - Show dampened routes received from BGP neighbor - - vtysh -c "show ip bgp neighbor $5 dampened-routes" - - - - Show flap statistics of the routes learned from BGP neighbor - - vtysh -c "show ip bgp neighbor $5 flap-statistics" - - - - Show detailed prefix count information for BGP neighbor - - vtysh -c "show ip bgp neighbor $5 prefix-counts" - - - - Show information received from BGP neighbor - - - - - Show prefixlist filter - - vtysh -c "show ip bgp neighbor $5 received prefix-filter" - - - - - - Show received routes from BGP neighbor - - vtysh -c "show ip bgp neighbor $5 received-routes" - - - - Show routes learned from BGP neighbor - - vtysh -c "show ip bgp neighbor $5 routes" - - - Show BGP path information vtysh -c "show ip bgp paths" - - - Show BGP routes matching the specified prefix list - - vtysh -c "show ip bgp prefix-list $5" - - - - Show BGP routes matching the specified AS path regular expression - - vtysh -c "show ip bgp regexp $5" - - - - Show BGP routes matching the specified route map - - vtysh -c "show ip bgp route-map $5" - - - - Show summary of BGP information - - vtysh -c "show ip bgp statistics" - - - - Show summary of BGP information - - vtysh -c "show ip bgp summary" - - - - Show BGP information for specified IP address or prefix - - <x.x.x.x> <x.x.x.x/x> - - - vtysh -c "show ip bgp $4" - diff --git a/op-mode-definitions/show-ipv6-bgp.xml.in b/op-mode-definitions/show-ipv6-bgp.xml.in deleted file mode 100644 index aad61b97a..000000000 --- a/op-mode-definitions/show-ipv6-bgp.xml.in +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - Show IPv6 routing information - - - - - Show Border Gateway Protocol (BGP) information - - vtysh -c "show bgp ipv6" - - - - Show summary of BGP neighbor status - - vtysh -c "show bgp ipv6 summary" - - - - Show routes matching AS path regular expression - - vtysh -c "show bgp ipv6 regexp $5" - - - - Show routes matching the IPv6 prefix-list name - - policy prefix-list6 - - - vtysh -c "show bgp ipv6 prefix-list $5" - - - - Show detailed information on TCP and BGP neighbor connections for given address - - - - - vtysh -c "show bgp ipv6 neighbor $5" - - - - Show routes advertised to a BGP neighbor - - vtysh -c "show bgp ipv6 neighbor $5 advertised-routes" - - - - Show routes filtered from a BGP neighbor - - vtysh -c "show bgp ipv6 neighbor $5 filtered-routes" - - - - Show dampened routes received from BGP neighbor - - vtysh -c "show bgp ipv6 neighbor $5 dampened-routes" - - - - Show flap statistics of the routes learned from BGP neighbor - - vtysh -c "show bgp ipv6 neighbor $5 flap-statistics" - - - - Show detailed prefix count information for BGP neighbor - - vtysh -c "show bgp ipv6 neighbor $5 prefix-counts" - - - - Show information received from BGP neighbor - - - - - Show prefixlist filter - - vtysh -c "show bgp ipv6 neighbor $5 received prefix-filter" - - - - - - Show received routes from BGP neighbor - - vtysh -c "show bgp ipv6 neighbor $5 received-routes" - - - - Show routes learned from BGP neighbor - - vtysh -c "show bgp ipv6 neighbor $5 routes" - - - - - - Show routes matching the large-community-list number or name - - vtysh -c "show bgp ipv6 large-community-list $5" - - - - Show routes matching the large-community-list number or name - - vtysh -c "show bgp ipv6 large-community-list $5 exact-match" - - - - - - Show routes matching the large-community-list number or name - - vtysh -c "show bgp ipv6 large-community-list $5" - - - - Show routes matching the large-community-list number or name - - vtysh -c "show bgp ipv6 large-community-list $5 exact-match" - - - - - - Show routes conforming to regular expression access list name - - vtysh -c "show bgp ipv6 filter-list $5" - - - - Show BGP information for specified community number - - <AA:NN> local-AS no-advertise no-export - - - vtysh -c "show bgp ipv6 community $5" - - - - Show routes from community that exactly matches the community number - - vtysh -c "show bgp ipv6 community $5 exact-match" - - - - - - Show routes matching the community-list number or name - - vtysh -c "show bgp ipv6 community-list $5" - - - - Show routes exactly matching the community-list name or number - - vtysh -c "show bgp ipv6 community-list $5 exact-match" - - - - - - Show BGP routes matching the specified route map - - policy route-map - - - vtysh -c "show bgp ipv6 route-map $5" - - - - - - Show BGP information for specified IP address or prefix - - <h:h:h:h:h:h:h:h> <h:h:h:h:h:h:h:h/x> - - - vtysh -c "show bgp ipv6 $4" - - - - Show route and more specific routes - - <h:h:h:h:h:h:h:h> <h:h:h:h:h:h:h:h/x> - - - vtysh -c "show bgp ipv6 $4 longer-prefixes" - - - - - - - - -- cgit v1.2.3 From fb2b3c48a47f2f6c28dbe7420eb1a1f691085db1 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 20 Feb 2021 19:52:22 +0100 Subject: op-mode: bgp: T1513: no need for "sudo" Commit 68f7d1474d ("op-mode: bgp: T1513: add "show bgp" tree containing l2vpn evpn") added the required XML definitions and a bash helper script. The helper always got invoked using "sudo" which is not necessary for vtysh. Calling "sudo" only slows down the system when e.g. RADIUS backed accounts are used. --- op-mode-definitions/include/bgp-afi-common.xml.i | 10 ++-- .../include/bgp-afi-ipv4-ipv6-common.xml.i | 68 +++++++++++----------- .../include/bgp-prefix-bestpath-multipath.xml.i | 6 +- .../include/vtysh-generic-detail.xml.i | 2 +- op-mode-definitions/show-bgp.xml.in | 56 +++++++++--------- 5 files changed, 71 insertions(+), 71 deletions(-) diff --git a/op-mode-definitions/include/bgp-afi-common.xml.i b/op-mode-definitions/include/bgp-afi-common.xml.i index b496e910a..06cfc42a5 100644 --- a/op-mode-definitions/include/bgp-afi-common.xml.i +++ b/op-mode-definitions/include/bgp-afi-common.xml.i @@ -11,10 +11,10 @@ Exact match of the communities - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ @@ -23,18 +23,18 @@ AA:BB:CC - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ RIB advertisement statistics - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Summary of BGP neighbor status - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ diff --git a/op-mode-definitions/include/bgp-afi-ipv4-ipv6-common.xml.i b/op-mode-definitions/include/bgp-afi-ipv4-ipv6-common.xml.i index 6de666603..dc0926375 100644 --- a/op-mode-definitions/include/bgp-afi-ipv4-ipv6-common.xml.i +++ b/op-mode-definitions/include/bgp-afi-ipv4-ipv6-common.xml.i @@ -8,94 +8,94 @@ Should accept local VPN route if exported and imported into different VRF (well-known community) - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Should accept VPN route with local nexthop (well-known community) - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Inform EBGP peers to blackhole traffic to prefix (well-known community) - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Exact match of the communities - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Graceful shutdown (well-known community) - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Staled Long-lived Graceful Restart VPN route (well-known community) - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Do not send outside local AS (well-known community) - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Do not advertise to any peer (well-known community) - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Do not export to next AS (well-known community) - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Removed because Long-lived Graceful Restart was not enabled for VPN route (well-known community) - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Do not export to any peer (well-known community) - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ RT translated VPNv4 route filtering (well-known community) - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ RT translated VPNv6 route filtering (well-known community) - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ RT VPNv4 route filtering (well-known community) - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ RT VPNv6 route filtering (well-known community) - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ @@ -109,10 +109,10 @@ Show BGP routes exactly matching specified community list - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ @@ -123,19 +123,19 @@ Display paths suppressed due to dampening - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Display flap statistics of routes - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Display detail of configured dampening parameters - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ @@ -151,13 +151,13 @@ Show BGP routes matching the specified large-communities - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Detailed information on TCP and BGP neighbor connections - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ @@ -166,31 +166,31 @@ - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Show routes advertised to a BGP neighbor - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Show dampened routes received from BGP neighbor - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Show flap statistics of the routes learned from BGP neighbor - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Show detailed prefix count information for BGP neighbor - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ @@ -201,7 +201,7 @@ Show prefixlist filter - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ @@ -209,13 +209,13 @@ Show received routes from BGP neighbor - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Show routes learned from BGP neighbor - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ @@ -223,13 +223,13 @@ Display routes conforming to the prefix-list - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Display routes matching the AS path regular expression - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ @@ -238,6 +238,6 @@ policy route-map - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ diff --git a/op-mode-definitions/include/bgp-prefix-bestpath-multipath.xml.i b/op-mode-definitions/include/bgp-prefix-bestpath-multipath.xml.i index 3bea5cf13..224fa6b45 100644 --- a/op-mode-definitions/include/bgp-prefix-bestpath-multipath.xml.i +++ b/op-mode-definitions/include/bgp-prefix-bestpath-multipath.xml.i @@ -3,18 +3,18 @@ Display only the bestpath - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Display only multipaths - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Display route and more specific routes - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ diff --git a/op-mode-definitions/include/vtysh-generic-detail.xml.i b/op-mode-definitions/include/vtysh-generic-detail.xml.i index 9e1f90649..5a3097a77 100644 --- a/op-mode-definitions/include/vtysh-generic-detail.xml.i +++ b/op-mode-definitions/include/vtysh-generic-detail.xml.i @@ -3,6 +3,6 @@ Detailed information - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ diff --git a/op-mode-definitions/show-bgp.xml.in b/op-mode-definitions/show-bgp.xml.in index 506af68b3..cd0c5a9e5 100644 --- a/op-mode-definitions/show-bgp.xml.in +++ b/op-mode-definitions/show-bgp.xml.in @@ -6,7 +6,7 @@ BGP information - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ #include @@ -19,7 +19,7 @@ #include - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ @@ -40,7 +40,7 @@ #include - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ @@ -63,7 +63,7 @@ <x.x.x.x> <x.x.x.x/x> <h:h:h:h:h:h:h:h> <h:h:h:h:h:h:h:h/x> - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ @@ -80,13 +80,13 @@ Display BGP Overlay Information for prefixes - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Display BGP tags for prefixes - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ @@ -94,7 +94,7 @@ Ethernet Segment - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ #include @@ -103,14 +103,14 @@ Ethernet Segment per EVI - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ #include VxLAN Network Identifier - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ @@ -118,7 +118,7 @@ Show import route target - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ @@ -127,19 +127,19 @@ - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Show routes advertised to a BGP neighbor - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Show routes learned from BGP neighbor - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ @@ -150,19 +150,19 @@ ASN:NN IPADDRESS:NN - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Display BGP Overlay Information for prefixes - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Display BGP tags for prefixes - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ @@ -170,7 +170,7 @@ EVPN route information - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ #include @@ -182,61 +182,61 @@ EAD (Type-1) route - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ MAC-IP (Type-2) route - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Multicast (Type-3) route - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Ethernet Segment (Type-4) route - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Prefix (Type-5) route - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ EAD (Type-1) route - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Ethernet Segment (Type-4) route - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ MAC-IP (Type-2) route - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Multicast (Type-3) route - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ Prefix (Type-5) route - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ @@ -247,7 +247,7 @@ 1-16777215 all - sudo ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ -- cgit v1.2.3 From 73c5ef5b91ff0c03fafbcef9f195e479987cc170 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 20 Feb 2021 20:41:53 +0100 Subject: vyos.ethtool: import helper class This helper class could be used to interact and retrieve information from ethtool. It is not used so far in production code. --- python/vyos/ethtool.py | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 python/vyos/ethtool.py diff --git a/python/vyos/ethtool.py b/python/vyos/ethtool.py new file mode 100644 index 000000000..e8a339d2f --- /dev/null +++ b/python/vyos/ethtool.py @@ -0,0 +1,80 @@ +# Copyright 2021 VyOS maintainers and contributors +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see . + +from vyos.util import cmd + +class Ethtool: + """ + Class is used to retrive and cache information about an ethernet adapter + """ + + # dictionary containing driver featurs, it will be populated on demand and + # the content will look like: + # { + # 'tls-hw-tx-offload': {'fixed': True, 'on': False}, + # 'tx-checksum-fcoe-crc': {'fixed': True, 'on': False}, + # 'tx-checksum-ip-generic': {'fixed': False, 'on': True}, + # 'tx-checksum-ipv4': {'fixed': True, 'on': False}, + # 'tx-checksum-ipv6': {'fixed': True, 'on': False}, + # 'tx-checksum-sctp': {'fixed': True, 'on': False}, + # 'tx-checksumming': {'fixed': False, 'on': True}, + # 'tx-esp-segmentation': {'fixed': True, 'on': False}, + # } + features = { } + + def __init__(self, ifname): + # Now populate features dictionaty + tmp = cmd(f'ethtool -k {ifname}') + # skip the first line, it only says: "Features for eth0": + for line in tmp.splitlines()[1:]: + if ":" in line: + key, value = [s.strip() for s in line.strip().split(":", 1)] + fixed = "fixed" in value + if fixed: + value = value.split()[0].strip() + self.features[key.strip()] = { + "on": value == "on", + "fixed": fixed + } + + def is_fixed_lro(self): + # in case of a missing configuration, rather return "fixed". In Ethtool + # terminology "fixed" means the setting can not be changed by the user. + return self.features.get('large-receive-offload', True).get('fixed', True) + + def is_fixed_gro(self): + # in case of a missing configuration, rather return "fixed". In Ethtool + # terminology "fixed" means the setting can not be changed by the user. + return self.features.get('generic-receive-offload', True).get('fixed', True) + + def is_fixed_gso(self): + # in case of a missing configuration, rather return "fixed". In Ethtool + # terminology "fixed" means the setting can not be changed by the user. + return self.features.get('generic-segmentation-offload', True).get('fixed', True) + + def is_fixed_sg(self): + # in case of a missing configuration, rather return "fixed". In Ethtool + # terminology "fixed" means the setting can not be changed by the user. + return self.features.get('scatter-gather', True).get('fixed', True) + + def is_fixed_tso(self): + # in case of a missing configuration, rather return "fixed". In Ethtool + # terminology "fixed" means the setting can not be changed by the user. + return self.features.get('tcp-segmentation-offload', True).get('fixed', True) + + def is_fixed_ufo(self): + # in case of a missing configuration, rather return "fixed". In Ethtool + # terminology "fixed" means the setting can not be changed by the user. + return self.features.get('udp-fragmentation-offload', True).get('fixed', True) -- cgit v1.2.3 From 3c64c79d7977869da3ca4dc70eb97ff9c6682e52 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 20 Feb 2021 20:51:43 +0100 Subject: ethernet: T3342: Xen vif driver requires sg offloading for MTU > 1500 bytes --- src/conf_mode/interfaces-ethernet.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/conf_mode/interfaces-ethernet.py b/src/conf_mode/interfaces-ethernet.py index e7f0cd6a5..bf4650773 100755 --- a/src/conf_mode/interfaces-ethernet.py +++ b/src/conf_mode/interfaces-ethernet.py @@ -76,10 +76,17 @@ def verify(ethernet): verify_mirror(ethernet) # verify offloading capabilities - if 'offload' in ethernet and 'rps' in ethernet['offload']: + if dict_search('offload.rps', ethernet) != None: if not os.path.exists(f'/sys/class/net/{ifname}/queues/rx-0/rps_cpus'): raise ConfigError('Interface does not suport RPS!') + driver = EthernetIf(ifname).get_driver_name() + # T3342 - Xen driver requires special treatment + if driver == "vif": + if int(ethernet['mtu']) > 1500 and dict_search('offload.sg', ethernet) == None: + raise ConfigError('Xen netback drivers requires scatter-gatter offloading '\ + 'for MTU size larger then 1500 bytes') + # XDP requires multiple TX queues if 'xdp' in ethernet: queues = glob(f'/sys/class/net/{ifname}/queues/tx-*') -- cgit v1.2.3 From b5763e329915435b411e360243839cb7817ff055 Mon Sep 17 00:00:00 2001 From: sever-sever Date: Fri, 19 Feb 2021 15:04:40 +0000 Subject: bgp: T3322: Fix timers for neighbor --- data/templates/frr/bgp.frr.tmpl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/data/templates/frr/bgp.frr.tmpl b/data/templates/frr/bgp.frr.tmpl index 4cb2ad092..6ba223196 100644 --- a/data/templates/frr/bgp.frr.tmpl +++ b/data/templates/frr/bgp.frr.tmpl @@ -58,6 +58,14 @@ {% if config.ttl_security is defined and config.ttl_security.hops is defined and config.ttl_security.hops is not none %} neighbor {{ neighbor }} ttl-security hops {{ config.ttl_security.hops }} {% endif %} +{% if config.timers is defined %} +{% if config.timers.connect is defined and config.timers.connect is not none %} + neighbor {{ neighbor }} timers connect {{ config.timers.connect }} +{% endif %} +{% if config.timers.holdtime is defined and config.timers.keepalive is defined and config.timers.holdtime is not none and config.timers.keepalive is not none %} + neighbor {{ neighbor }} timers {{ config.timers.keepalive }} {{ config.timers.holdtime }} +{% endif %} +{% endif %} {% if config.update_source is defined and config.update_source is not none %} neighbor {{ neighbor }} update-source {{ config.update_source }} {% endif %} -- cgit v1.2.3 From 65adcc1d80d06e0e76387de0b0c5c9d6c79d8f99 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 21 Feb 2021 17:24:57 +0100 Subject: console-server: T2490: do not use cli-shell-api in systemd unit (cherry picked from commit d5804b19d3ffecdd4fe6bd89d50ac84dabb549fd) --- data/templates/conserver/dropbear@.service.tmpl | 4 ++++ src/conf_mode/service_console-server.py | 23 +++++++++++++++++++---- src/systemd/dropbear@.service | 5 ++--- 3 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 data/templates/conserver/dropbear@.service.tmpl diff --git a/data/templates/conserver/dropbear@.service.tmpl b/data/templates/conserver/dropbear@.service.tmpl new file mode 100644 index 000000000..4bb73f751 --- /dev/null +++ b/data/templates/conserver/dropbear@.service.tmpl @@ -0,0 +1,4 @@ +[Service] +ExecStart= +ExecStart=/usr/sbin/dropbear -w -j -k -r /etc/dropbear/dropbear_rsa_host_key -c "/usr/bin/console {{ device }}" -P /run/conserver/dropbear.%I.pid -p %I +PIDFile=/run/conserver/dropbear.%I.pid diff --git a/src/conf_mode/service_console-server.py b/src/conf_mode/service_console-server.py index 0e5fc75b0..6e94a19ae 100755 --- a/src/conf_mode/service_console-server.py +++ b/src/conf_mode/service_console-server.py @@ -25,7 +25,8 @@ from vyos.util import call from vyos.xml import defaults from vyos import ConfigError -config_file = r'/run/conserver/conserver.cf' +config_file = '/run/conserver/conserver.cf' +dropbear_systemd_file = '/etc/systemd/system/dropbear@{port}.service.d/override.conf' def get_config(config=None): if config: @@ -75,9 +76,22 @@ def generate(proxy): return None render(config_file, 'conserver/conserver.conf.tmpl', proxy) + if 'device' in proxy: + for device in proxy['device']: + if 'ssh' not in proxy['device'][device]: + continue + + tmp = { + 'device' : device, + 'port' : proxy['device'][device]['ssh']['port'], + } + render(dropbear_systemd_file.format(**tmp), + 'conserver/dropbear@.service.tmpl', tmp) + return None def apply(proxy): + call('systemctl daemon-reload') call('systemctl stop dropbear@*.service conserver-server.service') if not proxy: @@ -89,9 +103,10 @@ def apply(proxy): if 'device' in proxy: for device in proxy['device']: - if 'ssh' in proxy['device'][device]: - port = proxy['device'][device]['ssh']['port'] - call(f'systemctl restart dropbear@{device}.service') + if 'ssh' not in proxy['device'][device]: + continue + port = proxy['device'][device]['ssh']['port'] + call(f'systemctl restart dropbear@{port}.service') return None diff --git a/src/systemd/dropbear@.service b/src/systemd/dropbear@.service index a3fde5708..acf926af9 100644 --- a/src/systemd/dropbear@.service +++ b/src/systemd/dropbear@.service @@ -8,9 +8,8 @@ StartLimitIntervalSec=0 [Service] Type=forking -ExecStartPre=/usr/bin/bash -c '/usr/bin/systemctl set-environment PORT=$(cli-shell-api returnActiveValue service console-server device "%I" ssh port)' -ExecStart=-/usr/sbin/dropbear -w -j -k -r /etc/dropbear/dropbear_rsa_host_key -c "/usr/bin/console %I" -P /run/conserver/dropbear.%I.pid -p ${PORT} -PIDFile=/run/conserver/dropbear.%I.pid +ExecStart=/usr/sbin/dropbear -w -j -k -r /etc/dropbear/dropbear_rsa_host_key -P /run/dropbear/dropbear.%I.pid -p %I +PIDFile=/run/dropbear/dropbear.%I.pid KillMode=process Restart=always RestartSec=10 -- cgit v1.2.3 From cf1156a60e1d03a752cde0baadbc9ac8118b2a52 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 21 Feb 2021 18:22:04 +0100 Subject: ethernet: T3163: probe driver for maximum rx/tx ring-buffer size --- python/vyos/ethtool.py | 21 +++++++++++++++++++++ src/conf_mode/interfaces-ethernet.py | 18 +++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/python/vyos/ethtool.py b/python/vyos/ethtool.py index e8a339d2f..cef7d476f 100644 --- a/python/vyos/ethtool.py +++ b/python/vyos/ethtool.py @@ -33,6 +33,7 @@ class Ethtool: # 'tx-esp-segmentation': {'fixed': True, 'on': False}, # } features = { } + ring_buffers = { } def __init__(self, ifname): # Now populate features dictionaty @@ -49,6 +50,16 @@ class Ethtool: "fixed": fixed } + tmp = cmd(f'ethtool -g {ifname}') + # We are only interested in line 2-5 which contains the device maximum + # ringbuffers + for line in tmp.splitlines()[2:6]: + if ':' in line: + key, value = [s.strip() for s in line.strip().split(":", 1)] + key = key.lower().replace(' ', '_') + self.ring_buffers[key] = int(value) + + def is_fixed_lro(self): # in case of a missing configuration, rather return "fixed". In Ethtool # terminology "fixed" means the setting can not be changed by the user. @@ -78,3 +89,13 @@ class Ethtool: # in case of a missing configuration, rather return "fixed". In Ethtool # terminology "fixed" means the setting can not be changed by the user. return self.features.get('udp-fragmentation-offload', True).get('fixed', True) + + def get_rx_buffer(self): + # in case of a missing configuration rather return a "small" + # buffer of only 512 bytes. + return self.ring_buffers.get('rx', '512') + + def get_tx_buffer(self): + # in case of a missing configuration rather return a "small" + # buffer of only 512 bytes. + return self.ring_buffers.get('tx', '512') diff --git a/src/conf_mode/interfaces-ethernet.py b/src/conf_mode/interfaces-ethernet.py index bf4650773..e82a3e0f1 100755 --- a/src/conf_mode/interfaces-ethernet.py +++ b/src/conf_mode/interfaces-ethernet.py @@ -30,6 +30,7 @@ from vyos.configverify import verify_mtu from vyos.configverify import verify_mtu_ipv6 from vyos.configverify import verify_vlan_config from vyos.configverify import verify_vrf +from vyos.ethtool import Ethtool from vyos.ifconfig import EthernetIf from vyos.template import render from vyos.util import call @@ -82,11 +83,26 @@ def verify(ethernet): driver = EthernetIf(ifname).get_driver_name() # T3342 - Xen driver requires special treatment - if driver == "vif": + if driver == 'vif': if int(ethernet['mtu']) > 1500 and dict_search('offload.sg', ethernet) == None: raise ConfigError('Xen netback drivers requires scatter-gatter offloading '\ 'for MTU size larger then 1500 bytes') + ethtool = Ethtool(ifname) + if 'ring_buffer' in ethernet: + max_rx = ethtool.get_rx_buffer() + max_tx = ethtool.get_tx_buffer() + + rx = dict_search('ring_buffer.rx', ethernet) + if rx and int(rx) > int(max_rx): + raise ConfigError(f'Driver only supports a maximum RX ring-buffer '\ + f'size of "{max_rx}" bytes!') + + tx = dict_search('ring_buffer.tx', ethernet) + if tx and int(tx) > int(max_tx): + raise ConfigError(f'Driver only supports a maximum TX ring-buffer '\ + f'size of "{max_tx}" bytes!') + # XDP requires multiple TX queues if 'xdp' in ethernet: queues = glob(f'/sys/class/net/{ifname}/queues/tx-*') -- cgit v1.2.3