summaryrefslogtreecommitdiff
path: root/src/conf_mode/protocols_ospf.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/conf_mode/protocols_ospf.py')
-rwxr-xr-xsrc/conf_mode/protocols_ospf.py101
1 files changed, 32 insertions, 69 deletions
diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py
index 0582d32be..cddd3765e 100755
--- a/src/conf_mode/protocols_ospf.py
+++ b/src/conf_mode/protocols_ospf.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2023 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
@@ -20,6 +20,7 @@ from sys import exit
from sys import argv
from vyos.config import Config
+from vyos.config import config_dict_merge
from vyos.configdict import dict_merge
from vyos.configdict import node_changed
from vyos.configverify import verify_common_route_maps
@@ -27,9 +28,8 @@ from vyos.configverify import verify_route_map
from vyos.configverify import verify_interface_exists
from vyos.configverify import verify_access_list
from vyos.template import render_to_string
-from vyos.util import dict_search
-from vyos.util import get_interface_config
-from vyos.xml import defaults
+from vyos.utils.dict import dict_search
+from vyos.utils.network import get_interface_config
from vyos import ConfigError
from vyos import frr
from vyos import airbag
@@ -65,17 +65,15 @@ def get_config(config=None):
if interfaces_removed:
ospf['interface_removed'] = list(interfaces_removed)
- # Bail out early if configuration tree does not exist
+ # Bail out early if configuration tree does no longer exist. this must
+ # be done after retrieving the list of interfaces to be removed.
if not conf.exists(base):
ospf.update({'deleted' : ''})
return ospf
# We have gathered the dict representation of the CLI, but there are default
# options which we need to update into the dictionary retrived.
- # XXX: Note that we can not call defaults(base), as defaults does not work
- # on an instance of a tag node. As we use the exact same CLI definition for
- # both the non-vrf and vrf version this is absolutely safe!
- default_values = defaults(base_path)
+ default_values = conf.get_config_defaults(**ospf.kwargs, recursive=True)
# We have to cleanup the default dict, as default values could enable features
# which are not explicitly enabled on the CLI. Example: default-information
@@ -84,60 +82,27 @@ def get_config(config=None):
# need to check this first and probably drop that key.
if dict_search('default_information.originate', ospf) is None:
del default_values['default_information']
- if dict_search('area.area_type.nssa', ospf) is None:
- del default_values['area']['area_type']['nssa']
if 'mpls_te' not in ospf:
del default_values['mpls_te']
+ if 'graceful_restart' not in ospf:
+ del default_values['graceful_restart']
+ for area_num in default_values.get('area', []):
+ if dict_search(f'area.{area_num}.area_type.nssa', ospf) is None:
+ del default_values['area'][area_num]['area_type']['nssa']
- for protocol in ['bgp', 'connected', 'isis', 'kernel', 'rip', 'static', 'table']:
- # table is a tagNode thus we need to clean out all occurances for the
- # default values and load them in later individually
- if protocol == 'table':
- del default_values['redistribute']['table']
- continue
+ for protocol in ['babel', 'bgp', 'connected', 'isis', 'kernel', 'rip', 'static']:
if dict_search(f'redistribute.{protocol}', ospf) is None:
del default_values['redistribute'][protocol]
- # XXX: T2665: we currently have no nice way for defaults under tag nodes,
- # clean them out and add them manually :(
- del default_values['neighbor']
- del default_values['area']['virtual_link']
- del default_values['interface']
-
- # merge in remaining default values
- ospf = dict_merge(default_values, ospf)
-
- if 'neighbor' in ospf:
- default_values = defaults(base + ['neighbor'])
- for neighbor in ospf['neighbor']:
- ospf['neighbor'][neighbor] = dict_merge(default_values, ospf['neighbor'][neighbor])
-
- if 'area' in ospf:
- default_values = defaults(base + ['area', 'virtual-link'])
- for area, area_config in ospf['area'].items():
- if 'virtual_link' in area_config:
- for virtual_link in area_config['virtual_link']:
- ospf['area'][area]['virtual_link'][virtual_link] = dict_merge(
- default_values, ospf['area'][area]['virtual_link'][virtual_link])
+ for interface in ospf.get('interface', []):
+ # We need to reload the defaults on every pass b/c of
+ # hello-multiplier dependency on dead-interval
+ # If hello-multiplier is set, we need to remove the default from
+ # dead-interval.
+ if 'hello_multiplier' in ospf['interface'][interface]:
+ del default_values['interface'][interface]['dead_interval']
- if 'interface' in ospf:
- for interface in ospf['interface']:
- # We need to reload the defaults on every pass b/c of
- # hello-multiplier dependency on dead-interval
- default_values = defaults(base + ['interface'])
- # If hello-multiplier is set, we need to remove the default from
- # dead-interval.
- if 'hello_multiplier' in ospf['interface'][interface]:
- del default_values['dead_interval']
-
- ospf['interface'][interface] = dict_merge(default_values,
- ospf['interface'][interface])
-
- if 'redistribute' in ospf and 'table' in ospf['redistribute']:
- default_values = defaults(base + ['redistribute', 'table'])
- for table in ospf['redistribute']['table']:
- ospf['redistribute']['table'][table] = dict_merge(default_values,
- ospf['redistribute']['table'][table])
+ ospf = config_dict_merge(default_values, ospf)
# We also need some additional information from the config, prefix-lists
# and route-maps for instance. They will be used in verify().
@@ -196,7 +161,7 @@ def verify(ospf):
vrf = ospf['vrf']
tmp = get_interface_config(interface)
if 'master' not in tmp or tmp['master'] != vrf:
- raise ConfigError(f'Interface {interface} is not a member of VRF {vrf}!')
+ raise ConfigError(f'Interface "{interface}" is not a member of VRF "{vrf}"!')
# Segment routing checks
if dict_search('segment_routing.global_block', ospf):
@@ -234,7 +199,7 @@ def verify(ospf):
if list(set(global_range) & set(local_range)):
raise ConfigError(f'Segment-Routing Global Block ({g_low_label_value}/{g_high_label_value}) '\
f'conflicts with Local Block ({l_low_label_value}/{l_high_label_value})!')
-
+
# Check for a blank or invalid value per prefix
if dict_search('segment_routing.prefix', ospf):
for prefix, prefix_config in ospf['segment_routing']['prefix'].items():
@@ -250,31 +215,28 @@ def verify(ospf):
raise ConfigError(f'Segment routing prefix {prefix} cannot have both explicit-null '\
f'and no-php-flag configured at the same time.')
+ # Check route summarisation
+ if 'summary_address' in ospf:
+ for prefix, prefix_options in ospf['summary_address'].items():
+ if {'tag', 'no_advertise'} <= set(prefix_options):
+ raise ConfigError(f'Can not set both "tag" and "no-advertise" for Type-5 '\
+ f'and Type-7 route summarisation of "{prefix}"!')
+
return None
def generate(ospf):
if not ospf or 'deleted' in ospf:
return None
- ospf['protocol'] = 'ospf' # required for frr/vrf.route-map.frr.j2
- ospf['frr_zebra_config'] = render_to_string('frr/vrf.route-map.frr.j2', ospf)
ospf['frr_ospfd_config'] = render_to_string('frr/ospfd.frr.j2', ospf)
return None
def apply(ospf):
ospf_daemon = 'ospfd'
- zebra_daemon = 'zebra'
# Save original configuration prior to starting any commit actions
frr_cfg = frr.FRRConfig()
- # The route-map used for the FIB (zebra) is part of the zebra daemon
- frr_cfg.load_configuration(zebra_daemon)
- frr_cfg.modify_section('(\s+)?ip protocol ospf route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)')
- if 'frr_zebra_config' in ospf:
- frr_cfg.add_before(frr.default_add_before, ospf['frr_zebra_config'])
- frr_cfg.commit_configuration(zebra_daemon)
-
# Generate empty helper string which can be ammended to FRR commands, it
# will be either empty (default VRF) or contain the "vrf <name" statement
vrf = ''
@@ -288,10 +250,11 @@ def apply(ospf):
if key not in ospf:
continue
for interface in ospf[key]:
- frr_cfg.modify_section(f'^interface {interface}{vrf}', stop_pattern='^exit', remove_stop_mark=True)
+ frr_cfg.modify_section(f'^interface {interface}', stop_pattern='^exit', remove_stop_mark=True)
if 'frr_ospfd_config' in ospf:
frr_cfg.add_before(frr.default_add_before, ospf['frr_ospfd_config'])
+
frr_cfg.commit_configuration(ospf_daemon)
return None