diff options
author | Viacheslav Hletenko <v.gletenko@vyos.io> | 2020-06-22 23:04:57 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-22 22:04:57 +0200 |
commit | a8ae4f46a5d0e059f2ca1181c7730b81179160f8 (patch) | |
tree | cf94ee90a6bd70fc4bcb65a01bc7d485ab4238cc | |
parent | 7945c491fb7ed2ba7462dd2e12051ad8ce9b7e56 (diff) | |
download | vyos-1x-a8ae4f46a5d0e059f2ca1181c7730b81179160f8.tar.gz vyos-1x-a8ae4f46a5d0e059f2ca1181c7730b81179160f8.zip |
rip: T2547: rewriten implementation in Python and XML
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | data/templates/frr/rip.frr.tmpl | 143 | ||||
-rw-r--r-- | interface-definitions/protocols-rip.xml.in | 2 | ||||
-rwxr-xr-x | src/conf_mode/protocols_rip.py | 317 |
4 files changed, 461 insertions, 2 deletions
@@ -73,7 +73,6 @@ interface_definitions: $(BUILD_DIR) $(obj) rm -f $(TMPL_DIR)/interfaces/wirelessmodem/node.tag/ipv6/node.def rm -f $(TMPL_DIR)/protocols/node.def rm -rf $(TMPL_DIR)/protocols/nbgp - rm -rf $(TMPL_DIR)/protocols/nrip rm -rf $(TMPL_DIR)/protocols/isis rm -f $(TMPL_DIR)/protocols/static/node.def rm -f $(TMPL_DIR)/system/node.def diff --git a/data/templates/frr/rip.frr.tmpl b/data/templates/frr/rip.frr.tmpl new file mode 100644 index 000000000..60bc686bd --- /dev/null +++ b/data/templates/frr/rip.frr.tmpl @@ -0,0 +1,143 @@ +! +{% if rip_conf -%} +router rip +{% if old_default_distance -%} +no distance {{old_default_distance}} +{% endif -%} +{% if default_distance -%} +distance {{default_distance}} +{% endif -%} +{% if old_default_originate -%} +no default-information originate +{% endif -%} +{% if default_originate -%} +default-information originate +{% endif -%} +{% if old_rip.default_metric -%} +no default-metric {{old_rip.default_metric}} +{% endif -%} +{% if rip.default_metric -%} +default-metric {{rip.default_metric}} +{% endif -%} +{% for protocol in old_rip.redist -%} +{% if old_rip.redist[protocol]['metric'] and old_rip.redist[protocol]['route_map'] -%} +no redistribute {{protocol}} metric {{rip.redist[protocol]['metric']}} route-map {{rip.redist[protocol]['route_map']}} +{% elif old_rip.redist[protocol]['metric'] -%} +no redistribute {{protocol}} metric {{old_rip.redist[protocol]['metric']}} +{% elif old_rip.redist[protocol]['route_map'] -%} +no redistribute {{protocol}} route-map {{old_rip.redist[protocol]['route_map']}} +{% else -%} +no redistribute {{protocol}} +{% endif -%} +{% endfor -%} +{% for protocol in rip.redist -%} +{% if rip.redist[protocol]['metric'] and rip.redist[protocol]['route_map'] -%} +redistribute {{protocol}} metric {{rip.redist[protocol]['metric']}} route-map {{rip.redist[protocol]['route_map']}} +{% elif rip.redist[protocol]['metric'] -%} +redistribute {{protocol}} metric {{rip.redist[protocol]['metric']}} +{% elif rip.redist[protocol]['route_map'] -%} +redistribute {{protocol}} route-map {{rip.redist[protocol]['route_map']}} +{% else -%} +redistribute {{protocol}} +{% endif -%} +{% endfor -%} +{% for iface in old_rip.distribute -%} +{% if old_rip.distribute[iface].iface_access_list_in -%} +no distribute-list {{old_rip.distribute[iface].iface_access_list_in}} in {{iface}} +{% endif -%} +{% if old_rip.distribute[iface].iface_access_list_out -%} +no distribute-list {{old_rip.distribute[iface].iface_access_list_out}} out {{iface}} +{% endif -%} +{% if old_rip.distribute[iface].iface_prefix_list_in -%} +no distribute-list prefix {{old_rip.distribute[iface].iface_prefix_list_in}} in {{iface}} +{% endif -%} +{% if old_rip.distribute[iface].iface_prefix_list_out -%} +no distribute-list prefix {{old_rip.distribute[iface].iface_prefix_list_out}} out {{iface}} +{% endif -%} +{% endfor -%} +{% for iface in rip.distribute -%} +{% if rip.distribute[iface].iface_access_list_in -%} +distribute-list {{rip.distribute[iface].iface_access_list_in}} in {{iface}} +{% endif -%} +{% if rip.distribute[iface].iface_access_list_out -%} +distribute-list {{rip.distribute[iface].iface_access_list_out}} out {{iface}} +{% endif -%} +{% if rip.distribute[iface].iface_prefix_list_in -%} +distribute-list prefix {{rip.distribute[iface].iface_prefix_list_in}} in {{iface}} +{% endif -%} +{% if rip.distribute[iface].iface_prefix_list_out -%} +distribute-list prefix {{rip.distribute[iface].iface_prefix_list_out}} out {{iface}} +{% endif -%} +{% endfor -%} +{% if old_rip.dist_acl_in -%} +no distribute-list {{old_rip.dist_acl_in}} in +{% endif -%} +{% if rip.dist_acl_in -%} +distribute-list {{rip.dist_acl_in}} in +{% endif -%} +{% if old_rip.dist_acl_out -%} +no distribute-list {{old_rip.dist_acl_out}} out +{% endif -%} +{% if rip.dist_acl_out -%} +distribute-list {{rip.dist_acl_out}} out +{% endif -%} +{% if old_rip.dist_prfx_in -%} +no distribute-list prefix {{old_rip.dist_prfx_in}} in +{% endif -%} +{% if rip.dist_prfx_in -%} +distribute-list prefix {{rip.dist_prfx_in}} in +{% endif -%} +{% if old_rip.dist_prfx_out -%} +no distribute-list prefix {{old_rip.dist_prfx_out}} out +{% endif -%} +{% if rip.dist_prfx_out -%} +distribute-list prefix {{rip.dist_prfx_out}} out +{% endif -%} +{% for network in old_rip.networks -%} +no network {{network}} +{% endfor -%} +{% for network in rip.networks -%} +network {{network}} +{% endfor -%} +{% for iface in old_rip.ifaces -%} +no network {{iface}} +{% endfor -%} +{% for iface in rip.ifaces -%} +network {{iface}} +{% endfor -%} +{% for neighbor in old_rip.neighbors -%} +no neighbor {{neighbor}} +{% endfor -%} +{% for neighbor in rip.neighbors -%} +neighbor {{neighbor}} +{% endfor -%} +{% for net in rip.net_distance -%} +{% if rip.net_distance[net].access_list and rip.net_distance[net].distance -%} +distance {{rip.net_distance[net].distance}} {{net}} {{rip.net_distance[net].access_list}} +{% else -%} +distance {{rip.net_distance[net].distance}} {{net}} +{% endif -%} +{% endfor -%} +{% for passive_iface in old_rip.passive_iface -%} +no passive-interface {{passive_iface}} +{% endfor -%} +{% for passive_iface in rip.passive_iface -%} +passive-interface {{passive_iface}} +{% endfor -%} +{% for route in old_rip.route -%} +no route {{route}} +{% endfor -%} +{% for route in rip.route -%} +route {{route}} +{% endfor -%} +{% if old_rip.timer_update or old_rip.timer_timeout or old_rip.timer_garbage -%} +no timers basic +{% endif -%} +{% if rip.timer_update or rip.timer_timeout or rip.timer_garbage -%} +timers basic {{rip.timer_update}} {{rip.timer_timeout}} {{rip.timer_garbage}} +{% endif -%} +! +{% else -%} +no router rip +! +{% endif -%} diff --git a/interface-definitions/protocols-rip.xml.in b/interface-definitions/protocols-rip.xml.in index a9c295f4c..107f0e0d5 100644 --- a/interface-definitions/protocols-rip.xml.in +++ b/interface-definitions/protocols-rip.xml.in @@ -2,7 +2,7 @@ <interfaceDefinition> <node name="protocols"> <children> - <node name="nrip" owner="${vyos_conf_scripts_dir}/protocols_rip.py"> + <node name="rip" owner="${vyos_conf_scripts_dir}/protocols_rip.py"> <properties> <help>Routing Information Protocol (RIP) parameters</help> </properties> diff --git a/src/conf_mode/protocols_rip.py b/src/conf_mode/protocols_rip.py new file mode 100755 index 000000000..c5ac26806 --- /dev/null +++ b/src/conf_mode/protocols_rip.py @@ -0,0 +1,317 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020 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 <http://www.gnu.org/licenses/>. + +import os + +from sys import exit + +from vyos import ConfigError +from vyos.config import Config +from vyos.util import call +from vyos.template import render + +from vyos import airbag +airbag.enable() + +config_file = r'/tmp/ripd.frr' + +def get_config(): + conf = Config() + base = ['protocols', 'rip'] + rip_conf = { + 'rip_conf' : False, + 'default_distance' : [], + 'default_originate' : False, + 'old_rip' : { + 'default_metric' : [], + 'distribute' : {}, + 'neighbors' : {}, + 'networks' : {}, + 'net_distance' : {}, + 'passive_iface' : {}, + 'redist' : {}, + 'route' : {}, + 'ifaces' : {}, + 'timer_garbage' : 120, + 'timer_timeout' : 180, + 'timer_update' : 30 + }, + 'rip' : { + 'default_metric' : None, + 'distribute' : {}, + 'neighbors' : {}, + 'networks' : {}, + 'net_distance' : {}, + 'passive_iface' : {}, + 'redist' : {}, + 'route' : {}, + 'ifaces' : {}, + 'timer_garbage' : 120, + 'timer_timeout' : 180, + 'timer_update' : 30 + } + } + + if not (conf.exists(base) or conf.exists_effective(base)): + return None + + if conf.exists(base): + rip_conf['rip_conf'] = True + + conf.set_level(base) + + # Get default distance + if conf.exists_effective('default-distance'): + rip_conf['old_default_distance'] = conf.return_effective_value('default-distance') + + if conf.exists('default-distance'): + rip_conf['default_distance'] = conf.return_value('default-distance') + + # Get default information originate (originate default route) + if conf.exists_effective('default-information originate'): + rip_conf['old_default_originate'] = True + + if conf.exists('default-information originate'): + rip_conf['default_originate'] = True + + # Get default-metric + if conf.exists_effective('default-metric'): + rip_conf['old_rip']['default_metric'] = conf.return_effective_value('default-metric') + + if conf.exists('default-metric'): + rip_conf['rip']['default_metric'] = conf.return_value('default-metric') + + # Get distribute list interface old_rip + for dist_iface in conf.list_effective_nodes('distribute-list interface'): + # Set level 'distribute-list interface ethX' + conf.set_level((str(base)) + ' distribute-list interface ' + dist_iface) + rip_conf['rip']['distribute'].update({ + dist_iface : { + 'iface_access_list_in': conf.return_effective_value('access-list in'.format(dist_iface)), + 'iface_access_list_out': conf.return_effective_value('access-list out'.format(dist_iface)), + 'iface_prefix_list_in': conf.return_effective_value('prefix-list in'.format(dist_iface)), + 'iface_prefix_list_out': conf.return_effective_value('prefix-list out'.format(dist_iface)) + } + }) + + # Access-list in old_rip + if conf.exists_effective('access-list in'.format(dist_iface)): + rip_conf['old_rip']['iface_access_list_in'] = conf.return_effective_value('access-list in'.format(dist_iface)) + # Access-list out old_rip + if conf.exists_effective('access-list out'.format(dist_iface)): + rip_conf['old_rip']['iface_access_list_out'] = conf.return_effective_value('access-list out'.format(dist_iface)) + # Prefix-list in old_rip + if conf.exists_effective('prefix-list in'.format(dist_iface)): + rip_conf['old_rip']['iface_prefix_list_in'] = conf.return_effective_value('prefix-list in'.format(dist_iface)) + # Prefix-list out old_rip + if conf.exists_effective('prefix-list out'.format(dist_iface)): + rip_conf['old_rip']['iface_prefix_list_out'] = conf.return_effective_value('prefix-list out'.format(dist_iface)) + + conf.set_level(base) + + # Get distribute list interface + for dist_iface in conf.list_nodes('distribute-list interface'): + # Set level 'distribute-list interface ethX' + conf.set_level((str(base)) + ' distribute-list interface ' + dist_iface) + rip_conf['rip']['distribute'].update({ + dist_iface : { + 'iface_access_list_in': conf.return_value('access-list in'.format(dist_iface)), + 'iface_access_list_out': conf.return_value('access-list out'.format(dist_iface)), + 'iface_prefix_list_in': conf.return_value('prefix-list in'.format(dist_iface)), + 'iface_prefix_list_out': conf.return_value('prefix-list out'.format(dist_iface)) + } + }) + + # Access-list in + if conf.exists('access-list in'.format(dist_iface)): + rip_conf['rip']['iface_access_list_in'] = conf.return_value('access-list in'.format(dist_iface)) + # Access-list out + if conf.exists('access-list out'.format(dist_iface)): + rip_conf['rip']['iface_access_list_out'] = conf.return_value('access-list out'.format(dist_iface)) + # Prefix-list in + if conf.exists('prefix-list in'.format(dist_iface)): + rip_conf['rip']['iface_prefix_list_in'] = conf.return_value('prefix-list in'.format(dist_iface)) + # Prefix-list out + if conf.exists('prefix-list out'.format(dist_iface)): + rip_conf['rip']['iface_prefix_list_out'] = conf.return_value('prefix-list out'.format(dist_iface)) + + conf.set_level((str(base)) + ' distribute-list') + + # Get distribute list, access-list in + if conf.exists_effective('access-list in'): + rip_conf['old_rip']['dist_acl_in'] = conf.return_effective_value('access-list in') + + if conf.exists('access-list in'): + rip_conf['rip']['dist_acl_in'] = conf.return_value('access-list in') + + # Get distribute list, access-list out + if conf.exists_effective('access-list out'): + rip_conf['old_rip']['dist_acl_out'] = conf.return_effective_value('access-list out') + + if conf.exists('access-list out'): + rip_conf['rip']['dist_acl_out'] = conf.return_value('access-list out') + + # Get ditstribute list, prefix-list in + if conf.exists_effective('prefix-list in'): + rip_conf['old_rip']['dist_prfx_in'] = conf.return_effective_value('prefix-list in') + + if conf.exists('prefix-list in'): + rip_conf['rip']['dist_prfx_in'] = conf.return_value('prefix-list in') + + # Get distribute list, prefix-list out + if conf.exists_effective('prefix-list out'): + rip_conf['old_rip']['dist_prfx_out'] = conf.return_effective_value('prefix-list out') + + if conf.exists('prefix-list out'): + rip_conf['rip']['dist_prfx_out'] = conf.return_value('prefix-list out') + + conf.set_level(base) + + # Get network Interfaces + if conf.exists_effective('interface'): + rip_conf['old_rip']['ifaces'] = conf.return_effective_values('interface') + + if conf.exists('interface'): + rip_conf['rip']['ifaces'] = conf.return_values('interface') + + # Get neighbors + if conf.exists_effective('neighbor'): + rip_conf['old_rip']['neighbors'] = conf.return_effective_values('neighbor') + + if conf.exists('neighbor'): + rip_conf['rip']['neighbors'] = conf.return_values('neighbor') + + # Get networks + if conf.exists_effective('network'): + rip_conf['old_rip']['networks'] = conf.return_effective_values('network') + + if conf.exists('network'): + rip_conf['rip']['networks'] = conf.return_values('network') + + # Get network-distance old_rip + for net_dist in conf.list_effective_nodes('network-distance'): + rip_conf['old_rip']['net_distance'].update({ + net_dist : { + 'access_list' : conf.return_effective_value('network-distance {0} access-list'.format(net_dist)), + 'distance' : conf.return_effective_value('network-distance {0} distance'.format(net_dist)), + } + }) + + # Get network-distance + for net_dist in conf.list_nodes('network-distance'): + rip_conf['rip']['net_distance'].update({ + net_dist : { + 'access_list' : conf.return_value('network-distance {0} access-list'.format(net_dist)), + 'distance' : conf.return_value('network-distance {0} distance'.format(net_dist)), + } + }) + + # Get passive-interface + if conf.exists_effective('passive-interface'): + rip_conf['old_rip']['passive_iface'] = conf.return_effective_values('passive-interface') + + if conf.exists('passive-interface'): + rip_conf['rip']['passive_iface'] = conf.return_values('passive-interface') + + # Get redistribute for old_rip + for protocol in conf.list_effective_nodes('redistribute'): + rip_conf['old_rip']['redist'].update({ + protocol : { + 'metric' : conf.return_effective_value('redistribute {0} metric'.format(protocol)), + 'route_map' : conf.return_effective_value('redistribute {0} route-map'.format(protocol)), + } + }) + + # Get redistribute + for protocol in conf.list_nodes('redistribute'): + rip_conf['rip']['redist'].update({ + protocol : { + 'metric' : conf.return_value('redistribute {0} metric'.format(protocol)), + 'route_map' : conf.return_value('redistribute {0} route-map'.format(protocol)), + } + }) + + conf.set_level(base) + + # Get route + if conf.exists_effective('route'): + rip_conf['old_rip']['route'] = conf.return_effective_values('route') + + if conf.exists('route'): + rip_conf['rip']['route'] = conf.return_values('route') + + # Get timers garbage + if conf.exists_effective('timers garbage-collection'): + rip_conf['old_rip']['timer_garbage'] = conf.return_effective_value('timers garbage-collection') + + if conf.exists('timers garbage-collection'): + rip_conf['rip']['timer_garbage'] = conf.return_value('timers garbage-collection') + + # Get timers timeout + if conf.exists_effective('timers timeout'): + rip_conf['old_rip']['timer_timeout'] = conf.return_effective_value('timers timeout') + + if conf.exists('timers timeout'): + rip_conf['rip']['timer_timeout'] = conf.return_value('timers timeout') + + # Get timers update + if conf.exists_effective('timers update'): + rip_conf['old_rip']['timer_update'] = conf.return_effective_value('timers update') + + if conf.exists('timers update'): + rip_conf['rip']['timer_update'] = conf.return_value('timers update') + + return rip_conf + +def verify(rip): + if rip is None: + return None + + # Check for network. If network-distance acl is set and distance not set + for net in rip['rip']['net_distance']: + if not rip['rip']['net_distance'][net]['distance']: + raise ConfigError(f"Must specify distance for network {net}") + +def generate(rip): + if rip is None: + return None + + render(config_file, 'frr/rip.frr.tmpl', rip) + return None + +def apply(rip): + if rip is None: + return None + + if os.path.exists(config_file): + call("sudo vtysh -d ripd -f " + config_file) + os.remove(config_file) + else: + print("File {0} not found".format(config_file)) + + + return None + +if __name__ == '__main__': + try: + c = get_config() + verify(c) + generate(c) + apply(c) + except ConfigError as e: + print(e) + exit(1) + |