From b17b6d8931b142dcd3e2ddc4e213929bfafe9948 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Fri, 29 Jan 2021 15:01:48 +0100 Subject: ospf: T3267: move "interface ip ospf" configuration to "protocols ospf interface" For easier maintenance and operability move the interface specific protocol setting of OSPF to the OSPF protocol section. This is now also in-line with IS-IS. This means to migrate: ethernet eth0 { vif 202 { ip { ospf { authentication { md5 { key-id 10 { md5-key vyosvyos } } } dead-interval 40 hello-interval 10 priority 1 retransmit-interval 5 transmit-delay 1 } } } } to protocols { ospf { interface eth0.201 { authentication { md5 { key-id 10 { md5-key vyosvyos } } } dead-interval 40 hello-interval 10 priority 1 retransmit-interval 5 transmit-delay 1 } } --- data/templates/frr/ospf.frr.tmpl | 46 ++++- .../include/ospf-authentication.xml.i | 45 +++++ interface-definitions/include/ospf-intervals.xml.i | 54 ++++++ interface-definitions/protocols-ospf.xml.in | 186 ++++++++++----------- src/conf_mode/protocols_ospf.py | 13 ++ src/migration-scripts/interfaces/19-to-20 | 82 +++++++++ 6 files changed, 327 insertions(+), 99 deletions(-) create mode 100644 interface-definitions/include/ospf-authentication.xml.i create mode 100644 interface-definitions/include/ospf-intervals.xml.i create mode 100755 src/migration-scripts/interfaces/19-to-20 diff --git a/data/templates/frr/ospf.frr.tmpl b/data/templates/frr/ospf.frr.tmpl index 07699290c..01a711259 100644 --- a/data/templates/frr/ospf.frr.tmpl +++ b/data/templates/frr/ospf.frr.tmpl @@ -1,4 +1,44 @@ ! +{% if interface is defined and interface is not none %} +{% for iface, iface_config in interface.items() %} +interface {{ iface }} +{% 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 }} +{% elif iface_config.authentication.md5 is defined %} + ip ospf authentication message-digest +{% if iface_config.authentication.md5.key_id is defined and iface_config.authentication.md5.key_id is not none %} +{% for key, key_config in iface_config.authentication.md5.key_id.items() %} + ip ospf message-digest-key {{ key }} md5 {{ key_config.md5_key }} +{% endfor %} +{% endif %} +{% endif %} +{% endif %} +{# interval configurations all have default values #} +{% if iface_config.hello_interval is defined and iface_config.hello_interval is not none %} + ip ospf hello-interval {{ iface_config.hello_interval }} +{% endif %} +{% if iface_config.retransmit_interval is defined and iface_config.retransmit_interval is not none %} + ip ospf retransmit-interval {{ iface_config.retransmit_interval }} +{% endif %} +{% if iface_config.transmit_delay is defined and iface_config.transmit_delay is not none %} + ip ospf transmit-delay {{ iface_config.transmit_delay }} +{% endif %} +{% if iface_config.dead_interval is defined and iface_config.dead_interval is not none %} + ip ospf dead-interval {{ iface_config.dead_interval }} +{% endif %} +{% if iface_config.bfd is defined %} + ip ospf bfd +{% endif %} +{% if iface_config.mtu_ignore is defined %} + ip ospf mtu-ignore +{% endif %} +{% if iface_config.network is defined and iface_config.network is not none %} + ip ospf network {{ iface_config.network }} +{% endif %} +{% endfor %} +{% endif %} +! router ospf {% if access_list is defined and access_list is not none %} {% for acl, acl_config in access_list.items() %} @@ -50,10 +90,8 @@ router ospf {% endfor %} {% endif %} {% endif %} -{% if link_config.dead_interval is defined and link_config.dead_interval is not none %} -{# The following values are default values #} - area {{ area_id }} virtual-link {{ link }} hello-interval {{ link_config.hello_interval }} retransmit-interval {{ link_config.retransmit_interval }} transmit-delay {{ link_config.retransmit_interval }} dead-interval {{ link_config.dead_interval }} -{% endif %} +{# The following values are default values #} + area {{ area_id }} virtual-link {{ link }} hello-interval {{ link_config.hello_interval }} retransmit-interval {{ link_config.retransmit_interval }} transmit-delay {{ link_config.transmit_delay }} dead-interval {{ link_config.dead_interval }} {% endfor %} {% endif %} {% endfor %} diff --git a/interface-definitions/include/ospf-authentication.xml.i b/interface-definitions/include/ospf-authentication.xml.i new file mode 100644 index 000000000..0963e5cc0 --- /dev/null +++ b/interface-definitions/include/ospf-authentication.xml.i @@ -0,0 +1,45 @@ + + + + Authentication + + + + + MD5 key id + + + + + MD5 key id + + u32:1-255 + MD5 key id + + + + + + MD5 authentication type + + txt + MD5 Key (16 characters or less) + + + + + + + + + + Plain text password + + txt + Plain text password (8 characters or less) + + + + + + diff --git a/interface-definitions/include/ospf-intervals.xml.i b/interface-definitions/include/ospf-intervals.xml.i new file mode 100644 index 000000000..e532bd14b --- /dev/null +++ b/interface-definitions/include/ospf-intervals.xml.i @@ -0,0 +1,54 @@ + + + + Interval after which a neighbor is declared dead (default: 40) + + u32:1-65535 + Neighbor dead interval (seconds) + + + + + + 40 + + + + Interval between hello packets (default: 10) + + u32:1-65535 + Hello interval (seconds) + + + + + + 10 + + + + Interval between retransmitting lost link state advertisements (default: 5) + + u32:1-65535 + Retransmit interval (seconds) + + + + + + 5 + + + + Link state transmit delay (default: 1) + + u32:1-65535 + Link state transmit delay (seconds) + + + + + + 1 + + diff --git a/interface-definitions/protocols-ospf.xml.in b/interface-definitions/protocols-ospf.xml.in index 074d0db63..1051e3741 100644 --- a/interface-definitions/protocols-ospf.xml.in +++ b/interface-definitions/protocols-ospf.xml.in @@ -275,101 +275,8 @@ - - - Authentication - - - - - MD5 key id - - - - - MD5 key id - - u32:1-255 - MD5 key id - - - - - - MD5 authentication type - - txt - MD5 Key (16 characters or less) - - - - - - - - - - Plain text password - - txt - Plain text password (8 characters or less) - - - - - - - - Interval after which a neighbor is declared dead (default: 40) - - u32:1-65535 - Neighbor dead interval (seconds) - - - - - - 40 - - - - Interval between hello packets (default: 10) - - u32:1-65535 - Hello interval (seconds) - - - - - - 10 - - - - Interval between retransmitting lost link state advertisements (default: 5) - - u32:1-65535 - Retransmit interval (seconds) - - - - - - 5 - - - - Link state transmit delay (default: 1) - - u32:1-65535 - Link state transmit delay (seconds) - - - - - - 1 - + #include + #include @@ -491,6 +398,95 @@ + + + Interface related configuration + + + + + + #include + #include + + + Bandwidth of interface (Megabit/sec) + + u32:1-100000 + Bandwidth in Megabit/sec (for calculating OSPF cost) + + + + + + + + + Enable Bidirectional Forwarding Detection (BFD) support + + + + + + Interface cost + + u32:1-65535 + OSPF interface cost + + + + + + + + + Disable Maximum Transmission Unit (MTU) mismatch detection + + + + + + Network type + + broadcast non-broadcast point-to-multipoint point-to-point + + + broadcast + Broadcast network type + + + non-broadcast + Non-broadcast network type + + + point-to-multipoint + Point-to-multipoint network type + + + point-to-point + Point-to-point network type + + + ^(broadcast|non-broadcast|point-to-multipoint|point-to-point)$ + + Must be broadcast, non-broadcast, point-to-multipoint or point-to-point + + + + + Router priority (default: 1) + + u32:0-255 + OSPF router priority cost + + + + + + 1 + + + Log changes in adjacency state diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py index 7c0ffbd27..a1ca7725f 100755 --- a/src/conf_mode/protocols_ospf.py +++ b/src/conf_mode/protocols_ospf.py @@ -21,6 +21,7 @@ from sys import exit 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 @@ -76,6 +77,7 @@ def get_config(config=None): # 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) @@ -94,6 +96,12 @@ def get_config(config=None): ospf['area'][area]['virtual_link'][virtual_link] = dict_merge( default_values, ospf['area'][area]['virtual_link'][virtual_link]) + if 'interface' in ospf: + default_values = defaults(base + ['interface']) + for interface in ospf['interface']: + ospf['interface'][interface] = dict_merge(default_values, + ospf['interface'][interface]) + # We also need some additional information from the config, prefix-lists # and route-maps for instance. They will be used in verify() base = ['policy'] @@ -108,6 +116,11 @@ def verify(ospf): return None verify_route_maps(ospf) + + if 'interface' in ospf: + for interface in ospf['interface']: + verify_interface_exists(interface) + return None def generate(ospf): diff --git a/src/migration-scripts/interfaces/19-to-20 b/src/migration-scripts/interfaces/19-to-20 new file mode 100755 index 000000000..7ea1ed267 --- /dev/null +++ b/src/migration-scripts/interfaces/19-to-20 @@ -0,0 +1,82 @@ +#!/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 . + +from sys import exit, argv +from vyos.configtree import ConfigTree + +if __name__ == '__main__': + if (len(argv) < 1): + print("Must specify file name!") + exit(1) + + file_name = argv[1] + with open(file_name, 'r') as f: + config_file = f.read() + + config = ConfigTree(config_file) + + # + # Migrate "interface ethernet eth0 ip ospf" to "protocols ospf interface eth0" + # + for type in config.list_nodes(['interfaces']): + for interface in config.list_nodes(['interfaces', type]): + + ip_ospf = ['interfaces', type, interface, 'ip', 'ospf'] + if config.exists(ip_ospf): + config.set(['protocols', 'ospf', 'interface']) + config.set_tag(['protocols', 'ospf', 'interface']) + config.copy(ip_ospf, ['protocols', 'ospf', 'interface', interface]) + config.delete(ip_ospf) + + vif_path = ['interfaces', type, interface, 'vif'] + if config.exists(vif_path): + for vif in config.list_nodes(vif_path): + vif_ospf_path = vif_path + [vif, 'ip', 'ospf'] + if config.exists(vif_ospf_path): + config.set(['protocols', 'ospf', 'interface']) + config.set_tag(['protocols', 'ospf', 'interface']) + config.copy(vif_ospf_path, ['protocols', 'ospf', 'interface', f'{interface}.{vif}']) + config.delete(vif_ospf_path) + + 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_ospf_path = vif_s_path + [vif_s, 'ip', 'ospf'] + if config.exists(vif_s_ospf_path): + config.set(['protocols', 'ospf', 'interface']) + config.set_tag(['protocols', 'ospf', 'interface']) + config.copy(vif_s_ospf_path, ['protocols', 'ospf', 'interface', f'{interface}.{vif_s}']) + + 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_ospf_path = vif_c_path + [vif_c, 'ip', 'ospf'] + print(vif_c_ospf_path) + if config.exists(vif_c_ospf_path): + config.set(['protocols', 'ospf', 'interface']) + config.set_tag(['protocols', 'ospf', 'interface']) + config.copy(vif_c_ospf_path, ['protocols', 'ospf', 'interface', f'{interface}.{vif_s}.{vif_c}']) + config.delete(vif_c_ospf_path) + + config.delete(vif_s_ospf_path) + + 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