From 8c7f469cc4463fe6b368c6310c4edafa67283571 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Thu, 11 Mar 2021 20:38:48 +0100 Subject: vrf: ospf: T2271: create individual OSPF process for specified VRF name VyOS CLI config: vrf red { ospf { default-information { originate { always } } default-metric 30 passive-interface default } } Will create the FRR configuration snippet: ! router ospf vrf red auto-cost reference-bandwidth 100 timers throttle spf 200 1000 10000 passive-interface default default-metric 30 default-information originate always ! --- data/templates/frr/ospf.frr.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'data/templates') diff --git a/data/templates/frr/ospf.frr.tmpl b/data/templates/frr/ospf.frr.tmpl index 140b6b406..a47c64c89 100644 --- a/data/templates/frr/ospf.frr.tmpl +++ b/data/templates/frr/ospf.frr.tmpl @@ -1,7 +1,7 @@ ! {% if interface is defined and interface is not none %} {% for iface, iface_config in interface.items() %} -interface {{ iface }} +interface {{ iface }} {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} {% if iface_config.authentication is defined and iface_config.authentication is not none %} {% if iface_config.authentication.plaintext_password is defined and iface_config.authentication.plaintext_password is not none %} ip ospf authentication-key {{ iface_config.authentication.plaintext_password }} @@ -50,7 +50,7 @@ interface {{ iface }} {% endfor %} {% endif %} ! -router ospf +router ospf {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} {% if access_list is defined and access_list is not none %} {% for acl, acl_config in access_list.items() %} {% for protocol in acl_config.export if acl_config.export is defined %} -- cgit v1.2.3 From f3ed5e7c57c123661b1b550823a467a34c161024 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Fri, 12 Mar 2021 19:49:18 +0100 Subject: vrf: bgp: T2271: create individual BGP process for specified VRF name The following VyOS CLI config vrf red { bgp 100 { neighbor 1.1.1.1 { peer-group foo } peer-group foo { passive password bar remote-as 200 } } } Will generaste the FRR configuration: ! router bgp 100 vrf red no bgp ebgp-requires-policy no bgp network import-check neighbor foo peer-group neighbor foo remote-as 200 neighbor foo password bar neighbor foo passive neighbor 1.1.1.1 peer-group foo ! --- data/templates/frr/bgp.frr.tmpl | 2 +- .../include/bgp/bgp-common-config.xml.i | 825 ++++++++++++++++++++ interface-definitions/protocols-bgp.xml.in | 829 +-------------------- interface-definitions/protocols-vrf.xml.in | 15 + src/conf_mode/protocols_bgp.py | 31 +- 5 files changed, 872 insertions(+), 830 deletions(-) create mode 100644 interface-definitions/include/bgp/bgp-common-config.xml.i (limited to 'data/templates') diff --git a/data/templates/frr/bgp.frr.tmpl b/data/templates/frr/bgp.frr.tmpl index f7aeaeb9d..30e1ec082 100644 --- a/data/templates/frr/bgp.frr.tmpl +++ b/data/templates/frr/bgp.frr.tmpl @@ -185,7 +185,7 @@ {% endif %} {% endmacro %} ! -router bgp {{ asn }} +router bgp {{ asn }} {{ 'vrf ' + vrf if vrf is defined and vrf is not none }} {% if parameters is defined and parameters.ebgp_requires_policy is defined %} bgp ebgp-requires-policy {% else %} diff --git a/interface-definitions/include/bgp/bgp-common-config.xml.i b/interface-definitions/include/bgp/bgp-common-config.xml.i new file mode 100644 index 000000000..b474e5240 --- /dev/null +++ b/interface-definitions/include/bgp/bgp-common-config.xml.i @@ -0,0 +1,825 @@ + + + + BGP address-family parameters + + + + + IPv4 BGP settings + + + + + BGP aggregate network + + ipv4net + BGP aggregate network + + + + + + + #include + + + + + BGP network + + ipv4net + BGP network + + + + + + + + + Network as a backdoor route + + + + #include + + + #include + + + Redistribute routes from other protocols into BGP + + + + + Redistribute connected routes into BGP + + + #include + + + + + Redistribute IS-IS routes into BGP + + + #include + + + + + Redistribute kernel routes into BGP + + + #include + + + + + Redistribute OSPF routes into BGP + + + #include + + + + + Redistribute RIP routes into BGP + + + #include + + + + + Redistribute static routes into BGP + + + #include + + + + + Redistribute non-main Kernel Routing Table + + + + + + + + + IPv6 BGP settings + + + + + BGP aggregate network + + ipv6net + Aggregate network + + + + + + + #include + + + + + BGP network + + ipv6net + Aggregate network + + + + + + + + + AS-path hopcount limit + + u32:0-255 + AS path hop count limit + + + + + + + #include + + + #include + + + Redistribute routes from other protocols into BGP + + + + + Redistribute connected routes into BGP + + + #include + + + + + Redistribute kernel routes into BGP + + + #include + + + + + Redistribute OSPFv3 routes into BGP + + + #include + + + + + Redistribute RIPng routes into BGP + + + #include + + + + + Redistribute static routes into BGP + + + #include + + + + + Redistribute non-main Kernel Routing Table + + + + + + + + + L2VPN EVPN BGP settings + + + + + Advertise All local VNIs + + + + #include + + + EVPN system primary IP + + ipv4 + IP address + + + + + + + + + Auto derivation of Route Target (RFC8365) + + + + + + Specify handling for BUM packets + + + + + Do not flood any BUM packets + + + + + + Flood BUM packets using head-end replication + + + + + + + + VXLAN Network Identifier + + u32:1-16777215 + VNI number + + + + + + + #include + + + + + + + + + Listen for and accept BGP dynamic neighbors from range + + + + + Maximum number of dynamic neighbors that can be created + + u32:1-5000 + BGP neighbor limit + + + + + + + + + BGP dynamic neighbors listen range + + ipv4net + IPv4 dynamic neighbors listen range + + + ipv6net + IPv6 dynamic neighbors listen range + + + + + + + + #include + + + + + + + BGP neighbor + + ipv4 + BGP neighbor IP address + + + ipv6 + BGP neighbor IPv6 address + + + txt + Interface name + + + + + + + + + + + Parameters relating to IPv4 or IPv6 routes + + + #include + #include + #include + + + + + Minimum interval for sending routing updates + + u32:0-600 + Advertisement interval in seconds + + + + + + + #include + #include + #include + #include + #include + #include + + + Interface parameters + + + #include + #include + + + Enable BGP with v6 link-local only + + + #include + #include + + + + + #include + #include + #include + #include + #include + + + Neighbor BGP port + + u32:1-65535 + Neighbor BGP port number + + + + + + + #include + #include + + + Enable strict capability negotiation + + + + + + Neighbor timers + + + + + BGP connect timer for this neighbor + + u32:1-65535 + Connect timer in seconds + + + 0 + Disable connect timer + + + + + + + #include + #include + + + #include + #include + + + + + BGP parameters + + + + + Always compare MEDs from different neighbors + + + + + + Default bestpath selection mechanism + + + + + AS-path attribute comparison parameters + + + + + Compare AS-path lengths including confederation sets and sequences + + + + + + Ignore AS-path length in selecting a route + + + + + + Allow load sharing across routes that have different AS paths (but same length) + + + + + + + + Compare the router-id for identical EBGP paths + + + + + + MED attribute comparison parameters + + + + + Compare MEDs among confederation paths + + + + + + Treat missing route as a MED as the least preferred one + + + + + + + + + + Route-reflector cluster-id + + ipv4 + Route-reflector cluster-id + + + + + + + + + AS confederation parameters + + + + + Confederation AS identifier [REQUIRED] + + u32:1-4294967294 + Confederation AS id + + + + + + + + + Peer ASs in the BGP confederation + + u32:1-4294967294 + Peer AS number + + + + + + + + + + + Enable route-flap dampening + + + + + Half-life time for dampening [REQUIRED] + + u32:1-45 + Half-life penalty in minutes + + + + + + + + + Maximum duration to suppress a stable route [REQUIRED] + + u32:1-255 + Maximum suppress duration in minutes + + + + + + + + + Threshold to start reusing a route [REQUIRED] + + u32:1-20000 + Re-use penalty points + + + + + + + + + When to start suppressing a route [REQUIRED] + + u32:1-20000 + Start-suppress penalty points + + + + + + + + + + + BGP defaults + + + + + Default local preference + + u32 + Local preference + + + + + + + + + Deactivate IPv4 unicast for a peer by default + + + + + + + + Compare MEDs between different peers in the same AS + + + + + + Administratives distances for BGP routes + + + + + Global administratives distances for BGP routes + + + + + Administrative distance for external BGP routes + + u32:1-255 + Administrative distance for external BGP routes + + + + + + + + + Administrative distance for internal BGP routes + + u32:1-255 + Administrative distance for internal BGP routes + + + + + + + + + Administrative distance for local BGP routes + + u32:1-255 + Administrative distance for internal BGP routes + + + + + + + + + + + Administrative distance for a specific BGP prefix + + ipv4net + Administrative distance for a specific BGP prefix + + + + + + + + + Administrative distance for prefix + + u32:1-255 + Administrative distance for external BGP routes + + + + + + + + + + + + + Require in and out policy for eBGP peers (RFC8212) + + + + + + Graceful restart capability parameters + + + + + Maximum time to hold onto restarting neighbors stale paths + + u32:1-3600 + Hold time in seconds + + + + + + + + + + + Graceful shutdown + + + + + + Log neighbor up/down changes and reset reason + + + + + + Enable IGP route check for network statements + + + + + + Disable client to client route reflection + + + + + + Disable immediate session reset on peer link down event + + + + + + BGP router id + + ipv4 + BGP router id + + + + + + + + + + + BGP peer-group + + + + + BGP peer-group address-family parameters + + + #include + #include + #include + + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + +#include + + + BGP protocol timers + + + #include + #include + + + diff --git a/interface-definitions/protocols-bgp.xml.in b/interface-definitions/protocols-bgp.xml.in index a6d2a24f4..cf897d04f 100644 --- a/interface-definitions/protocols-bgp.xml.in +++ b/interface-definitions/protocols-bgp.xml.in @@ -1,844 +1,21 @@ - Border Gateway Protocol (BGP) + 820 u32:1-4294967294 - AS number + Autonomous System Number - 820 - - - BGP address-family parameters - - - - - IPv4 BGP settings - - - - - BGP aggregate network - - ipv4net - BGP aggregate network - - - - - - - #include - - - - - BGP network - - ipv4net - BGP network - - - - - - - - - Network as a backdoor route - - - - #include - - - #include - - - Redistribute routes from other protocols into BGP - - - - - Redistribute connected routes into BGP - - - #include - - - - - Redistribute IS-IS routes into BGP - - - #include - - - - - Redistribute kernel routes into BGP - - - #include - - - - - Redistribute OSPF routes into BGP - - - #include - - - - - Redistribute RIP routes into BGP - - - #include - - - - - Redistribute static routes into BGP - - - #include - - - - - Redistribute non-main Kernel Routing Table - - - - - - - - - IPv6 BGP settings - - - - - BGP aggregate network - - ipv6net - Aggregate network - - - - - - - #include - - - - - BGP network - - ipv6net - Aggregate network - - - - - - - - - AS-path hopcount limit - - u32:0-255 - AS path hop count limit - - - - - - - #include - - - #include - - - Redistribute routes from other protocols into BGP - - - - - Redistribute connected routes into BGP - - - #include - - - - - Redistribute kernel routes into BGP - - - #include - - - - - Redistribute OSPFv3 routes into BGP - - - #include - - - - - Redistribute RIPng routes into BGP - - - #include - - - - - Redistribute static routes into BGP - - - #include - - - - - Redistribute non-main Kernel Routing Table - - - - - - - - - L2VPN EVPN BGP settings - - - - - Advertise All local VNIs - - - - #include - - - EVPN system primary IP - - ipv4 - IP address - - - - - - - - - Auto derivation of Route Target (RFC8365) - - - - - - Specify handling for BUM packets - - - - - Do not flood any BUM packets - - - - - - Flood BUM packets using head-end replication - - - - - - - - VXLAN Network Identifier - - u32:1-16777215 - VNI number - - - - - - - #include - - - - - - - - - Listen for and accept BGP dynamic neighbors from range - - - - - Maximum number of dynamic neighbors that can be created - - u32:1-5000 - BGP neighbor limit - - - - - - - - - BGP dynamic neighbors listen range - - ipv4net - IPv4 dynamic neighbors listen range - - - ipv6net - IPv6 dynamic neighbors listen range - - - - - - - - #include - - - - - - - BGP neighbor - - ipv4 - BGP neighbor IP address - - - ipv6 - BGP neighbor IPv6 address - - - txt - Interface name - - - - - - - - - - - Parameters relating to IPv4 or IPv6 routes - - - #include - #include - #include - - - - - Minimum interval for sending routing updates - - u32:0-600 - Advertisement interval in seconds - - - - - - - #include - #include - #include - #include - #include - #include - - - Interface parameters - - - #include - #include - - - Enable BGP with v6 link-local only - - - #include - #include - - - - - #include - #include - #include - #include - #include - - - Neighbor BGP port - - u32:1-65535 - Neighbor BGP port number - - - - - - - #include - #include - - - Enable strict capability negotiation - - - - - - Neighbor timers - - - - - BGP connect timer for this neighbor - - u32:1-65535 - Connect timer in seconds - - - 0 - Disable connect timer - - - - - - - #include - #include - - - #include - #include - - - - - BGP parameters - - - - - Always compare MEDs from different neighbors - - - - - - Default bestpath selection mechanism - - - - - AS-path attribute comparison parameters - - - - - Compare AS-path lengths including confederation sets and sequences - - - - - - Ignore AS-path length in selecting a route - - - - - - Allow load sharing across routes that have different AS paths (but same length) - - - - - - - - Compare the router-id for identical EBGP paths - - - - - - MED attribute comparison parameters - - - - - Compare MEDs among confederation paths - - - - - - Treat missing route as a MED as the least preferred one - - - - - - - - - - Route-reflector cluster-id - - ipv4 - Route-reflector cluster-id - - - - - - - - - AS confederation parameters - - - - - Confederation AS identifier [REQUIRED] - - u32:1-4294967294 - Confederation AS id - - - - - - - - - Peer ASs in the BGP confederation - - u32:1-4294967294 - Peer AS number - - - - - - - - - - - Enable route-flap dampening - - - - - Half-life time for dampening [REQUIRED] - - u32:1-45 - Half-life penalty in minutes - - - - - - - - - Maximum duration to suppress a stable route [REQUIRED] - - u32:1-255 - Maximum suppress duration in minutes - - - - - - - - - Threshold to start reusing a route [REQUIRED] - - u32:1-20000 - Re-use penalty points - - - - - - - - - When to start suppressing a route [REQUIRED] - - u32:1-20000 - Start-suppress penalty points - - - - - - - - - - - BGP defaults - - - - - Default local preference - - u32 - Local preference - - - - - - - - - Deactivate IPv4 unicast for a peer by default - - - - - - - - Compare MEDs between different peers in the same AS - - - - - - Administratives distances for BGP routes - - - - - Global administratives distances for BGP routes - - - - - Administrative distance for external BGP routes - - u32:1-255 - Administrative distance for external BGP routes - - - - - - - - - Administrative distance for internal BGP routes - - u32:1-255 - Administrative distance for internal BGP routes - - - - - - - - - Administrative distance for local BGP routes - - u32:1-255 - Administrative distance for internal BGP routes - - - - - - - - - - - Administrative distance for a specific BGP prefix - - ipv4net - Administrative distance for a specific BGP prefix - - - - - - - - - Administrative distance for prefix - - u32:1-255 - Administrative distance for external BGP routes - - - - - - - - - - - - - Require in and out policy for eBGP peers (RFC8212) - - - - - - Graceful restart capability parameters - - - - - Maximum time to hold onto restarting neighbors stale paths - - u32:1-3600 - Hold time in seconds - - - - - - - - - - - Graceful shutdown - - - - - - Log neighbor up/down changes and reset reason - - - - - - Enable IGP route check for network statements - - - - - - Disable client to client route reflection - - - - - - Disable immediate session reset on peer link down event - - - - - - BGP router id - - ipv4 - BGP router id - - - - - - - - - - - BGP peer-group - - - - - BGP peer-group address-family parameters - - - #include - #include - #include - - - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - - - #include - - - BGP protocol timers - - - #include - #include - - + #include diff --git a/interface-definitions/protocols-vrf.xml.in b/interface-definitions/protocols-vrf.xml.in index e9ef5dc2a..e40edb16c 100644 --- a/interface-definitions/protocols-vrf.xml.in +++ b/interface-definitions/protocols-vrf.xml.in @@ -27,6 +27,21 @@ #include + + + Border Gateway Protocol (BGP) + + u32:1-4294967294 + Autonomous System Number + + + + + + + #include + + Open Shortest Path First (OSPF) diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index 7dede74a1..34b829f08 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -17,9 +17,11 @@ import os from sys import exit +from sys import argv from vyos.config import Config from vyos.configdict import dict_merge +from vyos.configverify import verify_vrf from vyos.template import is_ip from vyos.template import render_to_string from vyos.util import call @@ -37,11 +39,25 @@ def get_config(config=None): conf = config else: conf = Config() - base = ['protocols', 'bgp'] + + vrf = None + if len(argv) > 1: + vrf = argv[1] + + base_path = ['protocols', 'bgp'] + + # eqivalent of the C foo ? 'a' : 'b' statement + base = vrf and ['protocols', 'vrf', vrf, 'bgp'] or base_path bgp = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) + # Assign the name of our VRF context. This MUST be done before the return + # statement below, else on deletion we will delete the default instance + # instead of the VRF instance. + if vrf: bgp[asn]['vrf'] = vrf + # Bail out early if configuration tree does not exist if not conf.exists(base): + bgp.update({'deleted' : ''}) return bgp # We also need some additional information from the config, @@ -85,6 +101,9 @@ def verify(bgp): raise ConfigError('Only one BGP AS number can be defined!') for asn, asn_config in bgp.items(): + + verify_vrf(asn_config) + # Common verification for both peer-group and neighbor statements for neighbor in ['neighbor', 'peer_group']: # bail out early if there is no neighbor or peer-group statement @@ -175,7 +194,7 @@ def verify(bgp): return None def generate(bgp): - if not bgp: + if not bgp or 'deleted' in bgp: bgp['new_frr_config'] = '' return None @@ -191,7 +210,13 @@ 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 \d+$', '') + + if 'vrf' in bgp: + vrf = bgp['vrf'] + frr_cfg.modify_section(f'^router bgp \d+ vrf {vrf}$', '') + else: + frr_cfg.modify_section('^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) -- cgit v1.2.3 From 548d9057e3ed66852bb2be62fe770c265712b4f3 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 13 Mar 2021 21:08:38 +0100 Subject: vrf: T3344: move dynamic routing protocols under "vrf name protocols" Instead of having the dynamic routing protocols OSPF and BGP residing under the "protocols vrf [ospf|bgp]" nodes, rather move them directly under the "vrf name protocols [ospf|bgp]" node. Now all VRF related parts are placed under the same root node. This eases the verify steps tremendously, as we do not need to check wheter a VRF eists or not, it will always exist as we operate under a child node. --- data/configd-include.json | 1 - data/templates/frr/static.frr.tmpl | 17 ++- data/templates/frr/vrf.frr.tmpl | 25 ---- interface-definitions/protocols-vrf.xml.in | 58 --------- interface-definitions/vrf.xml.in | 47 ++++++- smoketest/configs/vrf-bgp | 166 +++++++++++++++++++++++++ smoketest/configs/vrf-ospf | 145 +++++++++++++++++++++ smoketest/scripts/cli/test_protocols_bgp.py | 34 ++++- smoketest/scripts/cli/test_protocols_ospf.py | 19 +-- smoketest/scripts/cli/test_protocols_static.py | 54 +++++--- smoketest/scripts/cli/test_vrf.py | 6 - src/conf_mode/protocols_bgp.py | 24 ++-- src/conf_mode/protocols_ospf.py | 4 +- src/conf_mode/protocols_static.py | 24 +++- src/conf_mode/protocols_vrf.py | 72 ----------- src/migration-scripts/vrf/1-to-2 | 61 +++++++++ 16 files changed, 542 insertions(+), 215 deletions(-) delete mode 100644 data/templates/frr/vrf.frr.tmpl delete mode 100644 interface-definitions/protocols-vrf.xml.in create mode 100644 smoketest/configs/vrf-bgp create mode 100644 smoketest/configs/vrf-ospf delete mode 100755 src/conf_mode/protocols_vrf.py create mode 100755 src/migration-scripts/vrf/1-to-2 (limited to 'data/templates') diff --git a/data/configd-include.json b/data/configd-include.json index aabd7232e..eed858363 100644 --- a/data/configd-include.json +++ b/data/configd-include.json @@ -44,7 +44,6 @@ "protocols_ripng.py", "protocols_static.py", "protocols_static_multicast.py", -"protocols_vrf.py", "salt-minion.py", "service_console-server.py", "service_ids_fastnetmon.py", diff --git a/data/templates/frr/static.frr.tmpl b/data/templates/frr/static.frr.tmpl index bb0ec80a5..db59a44c2 100644 --- a/data/templates/frr/static.frr.tmpl +++ b/data/templates/frr/static.frr.tmpl @@ -1,18 +1,29 @@ {% from 'frr/static_routes_macro.j2' import static_routes %} ! +{% set ip_prefix = 'ip' %} +{% set ipv6_prefix = 'ipv6' %} +{% if vrf is defined and vrf is not none %} +{# We need to add an additional whitespace in front of the prefix #} +{# when VRFs are in use, thus we use a variable for prefix handling #} +{% set ip_prefix = ' ip' %} +{% set ipv6_prefix = ' ipv6' %} +vrf {{ vrf }} +{% endif %} {# IPv4 routing #} {% if route is defined and route is not none %} {% for prefix, prefix_config in route.items() %} -{{ static_routes('ip', prefix, prefix_config) }} +{{ static_routes(ip_prefix, prefix, prefix_config) }} {%- endfor -%} {% endif %} -! {# IPv6 routing #} {% if route6 is defined and route6 is not none %} {% for prefix, prefix_config in route6.items() %} -{{ static_routes('ipv6', prefix, prefix_config) }} +{{ static_routes(ipv6_prefix, prefix, prefix_config) }} {%- endfor -%} {% endif %} +{% if vrf is defined and vrf is not none %} + exit-vrf +{% endif %} ! {# Policy route tables #} {% if table is defined and table is not none %} diff --git a/data/templates/frr/vrf.frr.tmpl b/data/templates/frr/vrf.frr.tmpl deleted file mode 100644 index 8d3d8e9dd..000000000 --- a/data/templates/frr/vrf.frr.tmpl +++ /dev/null @@ -1,25 +0,0 @@ -{% from 'frr/static_routes_macro.j2' import static_routes %} -! -{% 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 %} -{% for prefix, prefix_config in vrf_config.static.route.items() %} - {{ static_routes('ip', prefix, prefix_config) }} -{%- endfor -%} -{% endif %} -{# IPv6 routes #} -{% if vrf_config.static.route6 is defined and vrf_config.static.route6 is not none %} -{% for prefix, prefix_config in vrf_config.static.route6.items() %} - {{ static_routes('ipv6', prefix, prefix_config) }} -{%- endfor -%} -{% endif %} -{% endif %} -{% endfor %} -{% endif %} -! diff --git a/interface-definitions/protocols-vrf.xml.in b/interface-definitions/protocols-vrf.xml.in deleted file mode 100644 index e40edb16c..000000000 --- a/interface-definitions/protocols-vrf.xml.in +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - Name of VRF to add route for - - vrf name - - - txt - VRF instance name - - - - - VRF instance name must be 15 characters or less and can not\nbe named as regular network interfaces.\n - - - - - Static route parameters - - - #include - #include - - - - - Border Gateway Protocol (BGP) - - u32:1-4294967294 - Autonomous System Number - - - - - - - #include - - - - - Open Shortest Path First (OSPF) - - - #include - - - #include - - - - - diff --git a/interface-definitions/vrf.xml.in b/interface-definitions/vrf.xml.in index eca9e75a7..50a693248 100644 --- a/interface-definitions/vrf.xml.in +++ b/interface-definitions/vrf.xml.in @@ -15,17 +15,58 @@ - VRF instance name + Virtual Routing and Forwarding instance VRF instance name must be 15 characters or less and can not\nbe named as regular network interfaces.\n txt - Instance name + VRF instance name + #include + #include + + + Routing protocol parameters + + + + + Static route parameters + + + #include + #include + + + + + Border Gateway Protocol (BGP) + + u32:1-4294967294 + Autonomous System Number + + + + + + + #include + + + + + Open Shortest Path First (OSPF) + + + #include + + + + Routing table associated with this instance @@ -39,8 +80,6 @@ VRF routing table must be in range from 100 to 2147483647 - #include - #include diff --git a/smoketest/configs/vrf-bgp b/smoketest/configs/vrf-bgp new file mode 100644 index 000000000..4ad372a36 --- /dev/null +++ b/smoketest/configs/vrf-bgp @@ -0,0 +1,166 @@ +interfaces { + ethernet eth0 { + address 192.0.2.1/24 + } + ethernet eth1 { + vrf black + } + ethernet eth2 { + vrf black + } +} +protocols { + ospf { + area 0 { + network 192.0.2.0/24 + } + interface eth0 { + authentication { + md5 { + key-id 10 { + md5-key ospfkey + } + } + } + } + log-adjacency-changes { + } + parameters { + abr-type cisco + router-id 1.2.3.4 + } + passive-interface default + passive-interface-exclude eth0 + } +} +system { + config-management { + commit-revisions 100 + } + console { + device ttyS0 { + speed 115200 + } + } + host-name vyos + login { + user vyos { + authentication { + encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0 + plaintext-password "" + } + } + } + nt + 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 +} +vrf { + name black { + protocols { + bgp 65000 { + address-family { + ipv4-unicast { + network 10.0.150.0/23 { + } + } + ipv6-unicast { + network 2001:db8:200::/40 { + } + } + } + neighbor 10.0.151.222 { + disable-send-community { + extended + standard + } + address-family { + ipv4-unicast { + default-originate { + } + soft-reconfiguration { + inbound + } + } + } + capability { + dynamic + } + remote-as 65010 + } + neighbor 10.0.151.252 { + peer-group VYOSv4 + } + neighbor 10.0.151.254 { + peer-group VYOSv4 + } + neighbor 2001:db8:200:ffff::3 { + peer-group VYOSv6 + } + neighbor 2001:db8:200:ffff::a { + peer-group VYOSv6 + } + neighbor 2001:db8:200:ff::101:2 { + remote-as 65010 + } + parameters { + default { + no-ipv4-unicast + } + log-neighbor-changes + router-id 10.0.151.251 + } + peer-group VYOSv4 { + address-family { + ipv4-unicast { + nexthop-self { + } + } + } + capability { + dynamic + } + remote-as 65000 + update-source dum0 + } + peer-group VYOSv6 { + address-family { + ipv6-unicast { + nexthop-self { + } + } + } + capability { + dynamic + } + remote-as 65000 + update-source dum0 + } + } + + } + table 2000 + } +} + + +// Warning: Do not remove the following line. +// vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@2:conntrack-sync@1:dhcp-relay@2:dhcp-server@5:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@20:ipoe-server@1:ipsec@5:l2tp@3:lldp@1:mdns@1:nat@5:nat66@1:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@9:rpki@1:salt@1:snmp@2:ssh@2:sstp@3:system@20:vrf@2:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1" +// Release version: 1.4-rolling-202103130218 diff --git a/smoketest/configs/vrf-ospf b/smoketest/configs/vrf-ospf new file mode 100644 index 000000000..7855e86bf --- /dev/null +++ b/smoketest/configs/vrf-ospf @@ -0,0 +1,145 @@ +interfaces { + ethernet eth0 { + address 192.0.2.1/24 + } + ethernet eth1 { + vrf red + } + ethernet eth2 { + vrf blue + } +} +protocols { + ospf { + area 0 { + network 192.0.2.0/24 + } + interface eth0 { + authentication { + md5 { + key-id 10 { + md5-key ospfkey + } + } + } + } + log-adjacency-changes { + } + parameters { + abr-type cisco + router-id 1.2.3.4 + } + passive-interface default + passive-interface-exclude eth0 + } +} +system { + config-management { + commit-revisions 100 + } + console { + device ttyS0 { + speed 115200 + } + } + host-name vyos + login { + user vyos { + authentication { + encrypted-password $6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0 + plaintext-password "" + } + } + } + nt + 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 +} +vrf { + name blue { + protocols { + ospf { + area 0 { + network 172.18.201.0/24 + } + interface eth2 { + authentication { + md5 { + key-id 30 { + md5-key vyoskey456 + } + } + } + dead-interval 40 + hello-interval 10 + priority 1 + retransmit-interval 5 + transmit-delay 1 + } + log-adjacency-changes { + } + parameters { + abr-type cisco + router-id 5.6.7.8 + } + passive-interface default + passive-interface-exclude eth2 + } + } + table 2000 + } + name red { + protocols { + ospf { + area 0 { + network 172.18.202.0/24 + } + interface eth1 { + authentication { + md5 { + key-id 20 { + md5-key vyoskey123 + } + } + } + dead-interval 40 + hello-interval 10 + priority 1 + retransmit-interval 5 + transmit-delay 1 + } + log-adjacency-changes { + } + parameters { + abr-type cisco + router-id 9.10.11.12 + } + passive-interface default + passive-interface-exclude eth1 + } + } + table 1000 + } +} + + +// Warning: Do not remove the following line. +// vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@2:conntrack-sync@1:dhcp-relay@2:dhcp-server@5:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@20:ipoe-server@1:ipsec@5:l2tp@3:lldp@1:mdns@1:nat@5:nat66@1:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@9:rpki@1:salt@1:snmp@2:ssh@2:sstp@3:system@20:vrf@2:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1" +// Release version: 1.4-rolling-202103130218 diff --git a/smoketest/scripts/cli/test_protocols_bgp.py b/smoketest/scripts/cli/test_protocols_bgp.py index 9aa1541cf..7d397b55e 100755 --- a/smoketest/scripts/cli/test_protocols_bgp.py +++ b/smoketest/scripts/cli/test_protocols_bgp.py @@ -128,17 +128,19 @@ peer_group_config = { }, } -def getFRRBGPconfig(): - return cmd(f'vtysh -c "show run" | sed -n "/^router bgp {ASN}/,/^!/p"') +def getFRRBGPconfig(vrf=None): + if vrf: + return cmd(f'vtysh -c "show run" | sed -n "/^router bgp {ASN} vrf {vrf}$/,/^!/p"') + return cmd(f'vtysh -c "show run" | sed -n "/^router bgp {ASN}$/,/^!/p"') def getFRRBgpAfiConfig(afi): - return cmd(f'vtysh -c "show run" | sed -n "/^router bgp {ASN}/,/^!/p" | sed -n "/^ address-family {afi} unicast/,/^ exit-address-family/p"') + return cmd(f'vtysh -c "show run" | sed -n "/^router bgp {ASN}$/,/^!/p" | sed -n "/^ address-family {afi} unicast/,/^ exit-address-family/p"') def getFRRBGPVNIconfig(vni): - return cmd(f'vtysh -c "show run" | sed -n "/^ vni {vni}/,/^!/p"') + 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): @@ -551,5 +553,27 @@ class TestProtocolsBGP(unittest.TestCase): self.assertIn(f' advertise-default-gw', vniconfig) self.assertIn(f' advertise-svi-ip', vniconfig) + def test_bgp_08_vrf_simple(self): + router_id = '127.0.0.3' + vrfs = ['red', 'green', 'blue'] + # It is safe to assume that when the basic VRF test works, all + # other OSPF related features work, as we entirely inherit the CLI + # templates and Jinja2 FRR template. + table = '1000' + for vrf in vrfs: + vrf_base = ['vrf', 'name', vrf] + self.session.set(vrf_base + ['table', table]) + self.session.set(vrf_base + ['protocols', 'bgp', ASN, 'parameters', 'router-id', router_id]) + table = str(int(table) + 1000) + + self.session.commit() + + for vrf in vrfs: + # Verify FRR bgpd configuration + frrconfig = getFRRBGPconfig(vrf) + + self.assertIn(f'router bgp {ASN} vrf {vrf}', frrconfig) + self.assertIn(f' bgp router-id {router_id}', frrconfig) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_protocols_ospf.py b/smoketest/scripts/cli/test_protocols_ospf.py index 683ca12b8..532d84cc8 100755 --- a/smoketest/scripts/cli/test_protocols_ospf.py +++ b/smoketest/scripts/cli/test_protocols_ospf.py @@ -29,8 +29,8 @@ route_map = 'foo-bar-baz10' def getFRRconfig(vrf=None): if vrf: - return cmd(f'vtysh -c "show run" | sed -n "/^router ospf vrf {vrf}/,/^!/p"') - return cmd('vtysh -c "show run" | sed -n "/^router ospf/,/^!/p"') + return cmd(f'vtysh -c "show run" | sed -n "/^router ospf vrf {vrf}$/,/^!/p"') + return cmd('vtysh -c "show run" | sed -n "/^router ospf$/,/^!/p"') def getFRRInterfaceConfig(interface): return cmd(f'vtysh -c "show run" | sed -n "/^interface {interface}$/,/^!/p"') @@ -237,6 +237,7 @@ class TestProtocolsOSPF(unittest.TestCase): else: self.assertIn(f' redistribute {protocol} metric {metric} metric-type {metric_type} route-map {route_map}', frrconfig) + def test_ospf_09_virtual_link(self): networks = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'] area = '10' @@ -279,6 +280,7 @@ class TestProtocolsOSPF(unittest.TestCase): for network in networks: self.assertIn(f' network {network} area {area}', frrconfig) + def test_ospf_10_interface_configureation(self): interfaces = Section.interfaces('ethernet') password = 'vyos1234' @@ -310,17 +312,21 @@ class TestProtocolsOSPF(unittest.TestCase): self.assertIn(f' ip ospf priority {priority}', config) self.assertIn(f' bandwidth {bandwidth}', config) - def test_ospf_01_11_vrfs(self): + + def test_ospf_11_vrfs(self): vrfs = ['red', 'green', 'blue'] # It is safe to assume that when the basic VRF test works, all # other OSPF related features work, as we entirely inherit the CLI # templates and Jinja2 FRR template. table = '1000' for vrf in vrfs: - self.session.set(['vrf', 'name', vrf, 'table', table]) - self.session.set(['protocols', 'vrf', vrf, 'ospf']) + vrf_base = ['vrf', 'name', vrf] + self.session.set(vrf_base + ['table', table]) + self.session.set(vrf_base + ['protocols', 'ospf']) table = str(int(table) + 1000) + # Also set a default VRF OSPF config + self.session.set(base_path) self.session.commit() # Verify FRR ospfd configuration @@ -335,9 +341,8 @@ class TestProtocolsOSPF(unittest.TestCase): self.assertIn(f' auto-cost reference-bandwidth 100', frrconfig) self.assertIn(f' timers throttle spf 200 1000 10000', frrconfig) # defaults - self.session.delete(['protocols', 'vrf', vrf]) self.session.delete(['vrf', 'name', vrf]) if __name__ == '__main__': - unittest.main(verbosity=2, failfast=True) + unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_protocols_static.py b/smoketest/scripts/cli/test_protocols_static.py index cf591f060..e68b86024 100755 --- a/smoketest/scripts/cli/test_protocols_static.py +++ b/smoketest/scripts/cli/test_protocols_static.py @@ -21,6 +21,7 @@ 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 get_json_iface_options base_path = ['protocols', 'static'] vrf_path = ['protocols', 'vrf'] @@ -85,7 +86,6 @@ routes = { }, } -vrfs = ['red', 'green', 'blue'] tables = ['80', '81', '82'] class StaticRouteTest(unittest.TestCase): @@ -99,9 +99,6 @@ class StaticRouteTest(unittest.TestCase): route_type = 'route6' self.session.delete(base_path + [route_type, route]) - for vrf in vrfs: - self.session.delete(vrf_path + [vrf]) - for table in tables: self.session.delete(base_path + ['table', table]) @@ -290,47 +287,65 @@ class StaticRouteTest(unittest.TestCase): def test_protocols_vrf_static(self): - for vrf in vrfs: + # Create VRF instances and apply the static routes from above to FRR. + # Re-read the configured routes and match them if they are programmed + # properly. This also includes VRF leaking + vrfs = { + 'red' : { 'table' : '1000' }, + 'green' : { 'table' : '2000' }, + 'blue' : { 'table' : '3000' }, + } + + for vrf, vrf_config in vrfs.items(): + vrf_base_path = ['vrf', 'name', vrf] + self.session.set(vrf_base_path + ['table', vrf_config['table']]) + for route, route_config in routes.items(): route_type = 'route' if is_ipv6(route): route_type = 'route6' - base = vrf_path + [vrf, 'static', route_type, route] + route_base_path = vrf_base_path + ['protocols', 'static', route_type, route] if 'next_hop' in route_config: for next_hop, next_hop_config in route_config['next_hop'].items(): - self.session.set(base + ['next-hop', next_hop]) + self.session.set(route_base_path + ['next-hop', next_hop]) if 'disable' in next_hop_config: - self.session.set(base + ['next-hop', next_hop, 'disable']) + self.session.set(route_base_path + ['next-hop', next_hop, 'disable']) if 'distance' in next_hop_config: - self.session.set(base + ['next-hop', next_hop, 'distance', next_hop_config['distance']]) + self.session.set(route_base_path + ['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']]) + self.session.set(route_base_path + ['next-hop', next_hop, 'interface', next_hop_config['interface']]) if 'vrf' in next_hop_config: - self.session.set(base + ['next-hop', next_hop, 'vrf', next_hop_config['vrf']]) + self.session.set(route_base_path + ['next-hop', next_hop, 'vrf', next_hop_config['vrf']]) if 'interface' in route_config: for interface, interface_config in route_config['interface'].items(): - self.session.set(base + ['interface', interface]) + self.session.set(route_base_path + ['interface', interface]) if 'disable' in interface_config: - self.session.set(base + ['interface', interface, 'disable']) + self.session.set(route_base_path + ['interface', interface, 'disable']) if 'distance' in interface_config: - self.session.set(base + ['interface', interface, 'distance', interface_config['distance']]) + self.session.set(route_base_path + ['interface', interface, 'distance', interface_config['distance']]) if 'vrf' in interface_config: - self.session.set(base + ['interface', interface, 'vrf', interface_config['vrf']]) + self.session.set(route_base_path + ['interface', interface, 'vrf', interface_config['vrf']]) if 'blackhole' in route_config: - self.session.set(base + ['blackhole']) + self.session.set(route_base_path + ['blackhole']) if 'distance' in route_config['blackhole']: - self.session.set(base + ['blackhole', 'distance', route_config['blackhole']['distance']]) + self.session.set(route_base_path + ['blackhole', 'distance', route_config['blackhole']['distance']]) if 'tag' in route_config['blackhole']: - self.session.set(base + ['blackhole', 'tag', route_config['blackhole']['tag']]) + self.session.set(route_base_path + ['blackhole', 'tag', route_config['blackhole']['tag']]) # commit changes self.session.commit() - for vrf in vrfs: + for vrf, vrf_config in vrfs.items(): + tmp = get_json_iface_options(vrf) + + # Compare VRF table ID + self.assertEqual(tmp['linkinfo']['info_data']['table'], int(vrf_config['table'])) + self.assertEqual(tmp['linkinfo']['info_kind'], 'vrf') + # Verify FRR bgpd configuration frrconfig = getFRRCconfig(vrf) self.assertIn(f'vrf {vrf}', frrconfig) @@ -380,6 +395,7 @@ class StaticRouteTest(unittest.TestCase): self.assertIn(tmp, frrconfig) + self.session.delete(['vrf']) if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/smoketest/scripts/cli/test_vrf.py b/smoketest/scripts/cli/test_vrf.py index 8e977d407..aac115663 100755 --- a/smoketest/scripts/cli/test_vrf.py +++ b/smoketest/scripts/cli/test_vrf.py @@ -33,12 +33,6 @@ from vyos.validate import is_intf_addr_assigned base_path = ['vrf'] vrfs = ['red', 'green', 'blue', 'foo-bar', 'baz_foo'] -def get_vrf_ipv4_routes(vrf): - return json.loads(cmd(f'ip -4 -j route show vrf {vrf}')) - -def get_vrf_ipv6_routes(vrf): - return json.loads(cmd(f'ip -6 -j route show vrf {vrf}')) - class VRFTest(unittest.TestCase): _interfaces = [] diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py index 34b829f08..43ca37f9d 100755 --- a/src/conf_mode/protocols_bgp.py +++ b/src/conf_mode/protocols_bgp.py @@ -21,7 +21,6 @@ from sys import argv from vyos.config import Config from vyos.configdict import dict_merge -from vyos.configverify import verify_vrf from vyos.template import is_ip from vyos.template import render_to_string from vyos.util import call @@ -47,15 +46,14 @@ def get_config(config=None): base_path = ['protocols', 'bgp'] # eqivalent of the C foo ? 'a' : 'b' statement - base = vrf and ['protocols', 'vrf', vrf, 'bgp'] or base_path + base = vrf and ['vrf', 'name', vrf, 'protocols', 'bgp'] or base_path bgp = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) # Assign the name of our VRF context. This MUST be done before the return # statement below, else on deletion we will delete the default instance # instead of the VRF instance. - if vrf: bgp[asn]['vrf'] = vrf + if vrf: bgp.update({'vrf' : vrf}) - # Bail out early if configuration tree does not exist if not conf.exists(base): bgp.update({'deleted' : ''}) return bgp @@ -96,13 +94,19 @@ def verify(bgp): if not bgp: return None - # Check if declared more than one ASN - if len(bgp) > 1: - raise ConfigError('Only one BGP AS number can be defined!') + # FRR bgpd only supports one Autonomous System Number, verify this! + asn = 0 + for key in bgp: + if key.isnumeric(): + asn +=1 + if asn > 1: + raise ConfigError('Only one BGP AS number can be defined!') for asn, asn_config in bgp.items(): - - verify_vrf(asn_config) + # Workaround for https://phabricator.vyos.net/T1711 + # We also have a vrf, and deleted key now - so we can only veriy "numbers" + if not asn.isnumeric(): + continue # Common verification for both peer-group and neighbor statements for neighbor in ['neighbor', 'peer_group']: @@ -202,6 +206,8 @@ def generate(bgp): # of the config dict asn = list(bgp.keys())[0] bgp[asn]['asn'] = asn + if 'vrf' in bgp: + bgp[asn]['vrf'] = bgp['vrf'] bgp['new_frr_config'] = render_to_string('frr/bgp.frr.tmpl', bgp[asn]) return None diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py index 8c2372bd9..e0dc4e7bf 100755 --- a/src/conf_mode/protocols_ospf.py +++ b/src/conf_mode/protocols_ospf.py @@ -24,7 +24,6 @@ from vyos.configdict import dict_merge from vyos.configdict import node_changed from vyos.configverify import verify_route_maps from vyos.configverify import verify_interface_exists -from vyos.configverify import verify_vrf from vyos.template import render_to_string from vyos.util import call from vyos.util import dict_search @@ -50,7 +49,7 @@ def get_config(config=None): base_path = ['protocols', 'ospf'] # eqivalent of the C foo ? 'a' : 'b' statement - base = vrf and ['protocols', 'vrf', vrf, 'ospf'] or base_path + base = vrf and ['vrf', 'name', vrf, 'protocols', 'ospf'] or base_path ospf = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) # Assign the name of our VRF context. This MUST be done before the return @@ -141,7 +140,6 @@ def verify(ospf): if not ospf: return None - verify_vrf(ospf) verify_route_maps(ospf) if 'interface' in ospf: diff --git a/src/conf_mode/protocols_static.py b/src/conf_mode/protocols_static.py index 5d101b33e..51b4acfc8 100755 --- a/src/conf_mode/protocols_static.py +++ b/src/conf_mode/protocols_static.py @@ -17,6 +17,7 @@ import os from sys import exit +from sys import argv from vyos.config import Config from vyos.template import render_to_string @@ -34,8 +35,19 @@ def get_config(config=None): conf = config else: conf = Config() - base = ['protocols', 'static'] + + vrf = None + if len(argv) > 1: + vrf = argv[1] + + base_path = ['protocols', 'static'] + # eqivalent of the C foo ? 'a' : 'b' statement + base = vrf and ['vrf', 'name', vrf, 'protocols', 'static'] or base_path static = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) + + # Assign the name of our VRF context + if vrf: static['vrf'] = vrf + return static def verify(static): @@ -50,8 +62,14 @@ def apply(static): # Save original configuration prior to starting any commit actions frr_cfg = frr.FRRConfig() frr_cfg.load_configuration(frr_daemon) - frr_cfg.modify_section(r'^ip route .*', '') - frr_cfg.modify_section(r'^ipv6 route .*', '') + + if 'vrf' in static: + vrf = static['vrf'] + frr_cfg.modify_section(f'^vrf {vrf}$', '') + else: + 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']) frr_cfg.commit_configuration(frr_daemon) diff --git a/src/conf_mode/protocols_vrf.py b/src/conf_mode/protocols_vrf.py deleted file mode 100755 index 227e7d5e1..000000000 --- a/src/conf_mode/protocols_vrf.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/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.template import render_to_string -from vyos.util import call -from vyos import ConfigError -from vyos import frr -from vyos import airbag -airbag.enable() - -frr_daemon = 'staticd' - -def get_config(config=None): - if config: - conf = config - else: - conf = Config() - base = ['protocols', 'vrf'] - vrf = conf.get_config_dict(base, key_mangling=('-', '_')) - return vrf - -def verify(vrf): - - return None - -def generate(vrf): - vrf['new_frr_config'] = render_to_string('frr/vrf.frr.tmpl', vrf) - return None - -def apply(vrf): - # Save original configuration prior to starting any commit actions - frr_cfg = frr.FRRConfig() - 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']) - 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 vrf['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) diff --git a/src/migration-scripts/vrf/1-to-2 b/src/migration-scripts/vrf/1-to-2 new file mode 100755 index 000000000..20128e957 --- /dev/null +++ b/src/migration-scripts/vrf/1-to-2 @@ -0,0 +1,61 @@ +#!/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 . + +# - T3344: migrate routing options from "protocols vrf" to "vrf protocols" + +from sys import argv +from sys import exit +from vyos.configtree import ConfigTree + +if (len(argv) < 2): + print("Must specify file name!") + exit(1) + +file_name = argv[1] + +with open(file_name, 'r') as f: + config_file = f.read() + +base = ['protocols', 'vrf'] +config = ConfigTree(config_file) + +if not config.exists(base): + # Nothing to do + exit(0) + +vrf_base = ['vrf', 'name'] +config.set(vrf_base) +config.set_tag(vrf_base) + +# Copy all existing static routes to the new base node under "vrf name protocols static" +for vrf in config.list_nodes(base): + static_base = base + [vrf, 'static'] + if not config.exists(static_base): + continue + + new_static_base = vrf_base + [vrf, 'protocols'] + config.set(new_static_base) + config.copy(static_base, new_static_base + ['static']) + +# Now delete the old configuration +config.delete(base) + +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)) + exit(1) -- cgit v1.2.3