diff options
Diffstat (limited to 'src/conf_mode')
-rwxr-xr-x | src/conf_mode/protocols_ospf.py | 16 | ||||
-rwxr-xr-x | src/conf_mode/protocols_static.py | 20 | ||||
-rwxr-xr-x | src/conf_mode/vrf.py | 38 |
3 files changed, 45 insertions, 29 deletions
diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py index ef2aeda7f..30246594a 100755 --- a/src/conf_mode/protocols_ospf.py +++ b/src/conf_mode/protocols_ospf.py @@ -57,6 +57,14 @@ def get_config(config=None): # instead of the VRF instance. if vrf: ospf['vrf'] = vrf + # As we no re-use this Python handler for both VRF and non VRF instances for + # OSPF we need to find out if any interfaces changed so properly adjust + # the FRR configuration and not by acctident change interfaces from a + # different VRF. + interfaces_removed = node_changed(conf, base + ['interface']) + if interfaces_removed: + ospf['interface_removed'] = list(interfaces_removed) + # Bail out early if configuration tree does not exist if not conf.exists(base): ospf.update({'deleted' : ''}) @@ -119,14 +127,6 @@ def get_config(config=None): ospf['interface'][interface] = dict_merge(default_values, ospf['interface'][interface]) - # As we no re-use this Python handler for both VRF and non VRF instances for - # OSPF we need to find out if any interfaces changed so properly adjust - # the FRR configuration and not by acctident change interfaces from a - # different VRF. - interfaces_removed = node_changed(conf, base + ['interface']) - if interfaces_removed: - ospf['interface_removed'] = list(interfaces_removed) - # We also need some additional information from the config, prefix-lists # and route-maps for instance. They will be used in verify() base = ['policy'] diff --git a/src/conf_mode/protocols_static.py b/src/conf_mode/protocols_static.py index 51b4acfc8..3314baf47 100755 --- a/src/conf_mode/protocols_static.py +++ b/src/conf_mode/protocols_static.py @@ -20,9 +20,10 @@ from sys import exit from sys import argv from vyos.config import Config +from vyos.configverify import verify_route_maps +from vyos.configverify import verify_vrf from vyos.template import render_to_string from vyos.util import call -from vyos.configverify import verify_route_maps from vyos import ConfigError from vyos import frr from vyos import airbag @@ -52,6 +53,23 @@ def get_config(config=None): def verify(static): verify_route_maps(static) + + for route in ['route', 'route6']: + # if there is no route(6) key in the dictionary we can immediately + # bail out early + if route not in static: + continue + + # When leaking routes to other VRFs we must ensure that the destination + # VRF exists + for prefix, prefix_options in static[route].items(): + # both the interface and next-hop CLI node can have a VRF subnode, + # thus we check this using a for loop + for type in ['interface', 'next_hop']: + if type in prefix_options: + for interface, interface_config in prefix_options[type].items(): + verify_vrf(interface_config) + return None def generate(static): diff --git a/src/conf_mode/vrf.py b/src/conf_mode/vrf.py index 6c6e219a5..414e514c5 100755 --- a/src/conf_mode/vrf.py +++ b/src/conf_mode/vrf.py @@ -23,17 +23,16 @@ from vyos.config import Config from vyos.configdict import node_changed from vyos.ifconfig import Interface from vyos.template import render +from vyos.util import call from vyos.util import cmd from vyos.util import dict_search +from vyos.util import get_interface_config from vyos import ConfigError from vyos import airbag airbag.enable() config_file = r'/etc/iproute2/rt_tables.d/vyos-vrf.conf' -def _cmd(command): - cmd(command, raising=ConfigError, message='Error changing VRF') - def list_rules(): command = 'ip -j -4 rule show' answer = loads(cmd(command)) @@ -111,8 +110,7 @@ def verify(vrf): # routing table id can't be changed - OS restriction if os.path.isdir(f'/sys/class/net/{name}'): - tmp = loads(cmd(f'ip -j -d link show {name}'))[0] - tmp = str(dict_search('linkinfo.info_data.table', tmp)) + tmp = str(dict_search('linkinfo.info_data.table', get_interface_config(name))) if tmp and tmp != config['table']: raise ConfigError(f'VRF "{name}" table id modification not possible!') @@ -140,14 +138,14 @@ def apply(vrf): bind_all = '0' if 'bind_to_all' in vrf: bind_all = '1' - _cmd(f'sysctl -wq net.ipv4.tcp_l3mdev_accept={bind_all}') - _cmd(f'sysctl -wq net.ipv4.udp_l3mdev_accept={bind_all}') + call(f'sysctl -wq net.ipv4.tcp_l3mdev_accept={bind_all}') + call(f'sysctl -wq net.ipv4.udp_l3mdev_accept={bind_all}') for tmp in (dict_search('vrf_remove', vrf) or []): if os.path.isdir(f'/sys/class/net/{tmp}'): - _cmd(f'ip -4 route del vrf {tmp} unreachable default metric 4278198272') - _cmd(f'ip -6 route del vrf {tmp} unreachable default metric 4278198272') - _cmd(f'ip link delete dev {tmp}') + call(f'ip -4 route del vrf {tmp} unreachable default metric 4278198272') + call(f'ip -6 route del vrf {tmp} unreachable default metric 4278198272') + call(f'ip link delete dev {tmp}') if 'name' in vrf: for name, config in vrf['name'].items(): @@ -156,16 +154,16 @@ def apply(vrf): if not os.path.isdir(f'/sys/class/net/{name}'): # For each VRF apart from your default context create a VRF # interface with a separate routing table - _cmd(f'ip link add {name} type vrf table {table}') + call(f'ip link add {name} type vrf table {table}') # The kernel Documentation/networking/vrf.txt also recommends # adding unreachable routes to the VRF routing tables so that routes # afterwards are taken. - _cmd(f'ip -4 route add vrf {name} unreachable default metric 4278198272') - _cmd(f'ip -6 route add vrf {name} unreachable default metric 4278198272') + call(f'ip -4 route add vrf {name} unreachable default metric 4278198272') + call(f'ip -6 route add vrf {name} unreachable default metric 4278198272') # We also should add proper loopback IP addresses to the newly # created VRFs for services bound to the loopback address (SNMP, NTP) - _cmd(f'ip -4 addr add 127.0.0.1/8 dev {name}') - _cmd(f'ip -6 addr add ::1/128 dev {name}') + call(f'ip -4 addr add 127.0.0.1/8 dev {name}') + call(f'ip -6 addr add ::1/128 dev {name}') # set VRF description for e.g. SNMP monitoring vrf_if = Interface(name) @@ -199,18 +197,18 @@ def apply(vrf): # change preference when VRFs are enabled and local lookup table is default if not local_pref and 'name' in vrf: for af in ['-4', '-6']: - _cmd(f'ip {af} rule add pref 32765 table local') - _cmd(f'ip {af} rule del pref 0') + call(f'ip {af} rule add pref 32765 table local') + call(f'ip {af} rule del pref 0') # return to default lookup preference when no VRF is configured if 'name' not in vrf: for af in ['-4', '-6']: - _cmd(f'ip {af} rule add pref 0 table local') - _cmd(f'ip {af} rule del pref 32765') + call(f'ip {af} rule add pref 0 table local') + call(f'ip {af} rule del pref 32765') # clean out l3mdev-table rule if present if 1000 in [r.get('priority') for r in list_rules() if r.get('priority') == 1000]: - _cmd(f'ip {af} rule del pref 1000') + call(f'ip {af} rule del pref 1000') return None |