From 9abc02edcc237760f1f8aa1b3f08d7f4d18f866c Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Sun, 12 Nov 2023 18:30:15 +0100 Subject: pim: T5733: add missing FRR PIM related features Migrate CLI configuration retrival to common get_config_dict(). In addition add new functionality to VyOS that is PIM related and already available in FRR. --- data/templates/frr/pimd.frr.j2 | 95 ++++++++---- interface-definitions/protocols-pim.xml.in | 188 +++++++++++++++++++++++- op-mode-definitions/show-ip-pim.xml.in | 114 +++++++++++++-- python/vyos/frr.py | 6 +- smoketest/scripts/cli/base_interfaces_test.py | 4 - smoketest/scripts/cli/base_vyostest_shim.py | 5 +- smoketest/scripts/cli/test_protocols_pim.py | 101 +++++++++++++ src/conf_mode/protocols_pim.py | 203 ++++++++++++-------------- src/op_mode/restart_frr.py | 4 +- 9 files changed, 551 insertions(+), 169 deletions(-) create mode 100755 smoketest/scripts/cli/test_protocols_pim.py diff --git a/data/templates/frr/pimd.frr.j2 b/data/templates/frr/pimd.frr.j2 index cb2f2aa98..4841efd15 100644 --- a/data/templates/frr/pimd.frr.j2 +++ b/data/templates/frr/pimd.frr.j2 @@ -1,34 +1,75 @@ +{% if interface is vyos_defined %} +{% for iface, iface_config in interface.items() %} ! -{% for rp_addr in old_pim.rp %} -{% for group in old_pim.rp[rp_addr] %} -no ip pim rp {{ rp_addr }} {{ group }} +interface {{ iface }} + ip pim +{% if iface_config.bfd is vyos_defined %} + ip pim bfd {{ 'profile ' ~ iface_config.bfd.profile if iface_config.bfd.profile is vyos_defined }} +{% endif %} +{% if iface_config.no_bsm is vyos_defined %} + no ip pim bsm +{% endif %} +{% if iface_config.dr_priority is vyos_defined %} + ip pim drpriority {{ iface_config.dr_priority }} +{% endif %} +{% if iface_config.hello is vyos_defined %} + ip pim hello {{ iface_config.hello }} +{% endif %} +{% if iface_config.no_unicast_bsm is vyos_defined %} + no ip pim unicast-bsm +{% endif %} +{% if iface_config.passive is vyos_defined %} + ip pim passive +{% endif %} +{% if iface_config.source_address is vyos_defined %} + ip pim use-source {{ iface_config.source_address }} +{% endif %} +{% if iface_config.igmp is vyos_defined %} + ip igmp +{% endif %} +{% if iface_config.igmp.version is vyos_defined %} + ip igmp version {{ iface_config.igmp.version }} +{% endif %} +exit {% endfor %} -{% endfor %} -{% if old_pim.rp_keep_alive %} -no ip pim rp keep-alive-timer {{ old_pim.rp_keep_alive }} {% endif %} -{% for iface in old_pim.ifaces %} -interface {{ iface }} -no ip pim -! -{% endfor %} -{% for iface in pim.ifaces %} -interface {{ iface }} -ip pim -{% if pim.ifaces[iface].dr_prio %} -ip pim drpriority {{ pim.ifaces[iface].dr_prio }} -{% endif %} -{% if pim.ifaces[iface].hello %} -ip pim hello {{ pim.ifaces[iface].hello }} -{% endif %} ! -{% endfor %} -{% for rp_addr in pim.rp %} -{% for group in pim.rp[rp_addr] %} -ip pim rp {{ rp_addr }} {{ group }} +{% if ecmp is vyos_defined %} +ip pim ecmp {{ 'rebalance' if ecmp.rebalance is vyos_defined }} +{% endif %} +{% if join_prune_interval is vyos_defined %} +ip pim join-prune-interval {{ join_prune_interval }} +{% endif %} +{% if keep_alive_timer is vyos_defined %} +ip pim rp keep-alive-timer {{ keep_alive_timer }} +{% endif %} +{% if packets is vyos_defined %} +ip pim packets {{ packets }} +{% endif %} +{% if register_accept_list is vyos_defined %} +ip pim register-accept-list {{ register_accept_list }} +{% endif %} +{% if register_suppress_time is vyos_defined %} +ip pim register-suppress-time {{ register_suppress_time }} +{% endif %} +{% if rp.address is vyos_defined %} +{% for address, address_config in rp.address.items() %} +{% for group in address_config.group %} +ip pim rp {{ address }} {{ group }} +{% endfor %} {% endfor %} -{% endfor %} -{% if pim.rp_keep_alive %} -ip pim rp keep-alive-timer {{ pim.rp_keep_alive }} +{% endif %} +{% if send_v6_secondary is vyos_defined %} +ip pim send-v6-secondary +{% endif %} +{% if spt_switchover.infinity_and_beyond is vyos_defined %} +ip pim spt-switchover infinity-and-beyond {{ 'prefix-list ' ~ spt_switchover.infinity_and_beyond.prefix_list if spt_switchover.infinity_and_beyond.prefix_list is defined }} +{% endif %} +{% if ssm is vyos_defined %} +ip pim ssm {{ ssm }} +{% endif %} +! +{% if igmp.watermark_warn is vyos_defined %} +ip igmp watermark-warn {{ igmp.watermark_warn }} {% endif %} ! diff --git a/interface-definitions/protocols-pim.xml.in b/interface-definitions/protocols-pim.xml.in index e9475930c..733279aa4 100644 --- a/interface-definitions/protocols-pim.xml.in +++ b/interface-definitions/protocols-pim.xml.in @@ -15,8 +15,24 @@ + + #include + + #include + + + Do not process bootstrap messages + + + + + + Do not process unicast bootstrap messages + + + Designated Router Election Priority @@ -41,8 +57,134 @@ + + + Internet Group Management Protocol (IGMP) options + + + + + Interface IGMP version + + 2 + IGMP version 2 + + + 3 + IGMP version 3 + + + + + + 3 + + + + + + Disable sending and receiving PIM control packets on the interface + + + + #include + + + Enable PIM ECMP + + + + + Enable PIM ECMP Rebalance + + + + + + + + Internet Group Management Protocol (IGMP) options + + + + + Configure group limit for watermark warning + + u32:1-65535 + Group count to generate watermark warning + + + + + + + + + + + Join Prune Send Interval + + u32:1-65535 + Interval in seconds + + + + + + 60 + + + + Keep alive Timer + + u32:1-65535 + Keep alive Timer in seconds + + + + + + 210 + + + + Packets to process at once + + u32:1-255 + Number of packets + + + + + + 3 + + + + Only accept registers from a specific source prefix list + + txt + Prefix-list to apply + + + policy prefix-list + + + + + + Register Suppress Timer + + u32:1-65535 + In seconds + + + + + + Rendezvous Point @@ -75,16 +217,48 @@ - + - Keep alive Timer + Send v6 secondary addresses + + + + + + Send v6 secondary addresses + + + + + Never switch to SPT Tree + + + + + Prefix-List to control which groups to switch + + txt + Prefix-list to apply + + + policy prefix-list + + + + + + + + + + Source-Specific Multicast + + policy prefix-list + - u32:31-60000 - Keep alive Timer in seconds + txt + Prefix-list to apply - - - diff --git a/op-mode-definitions/show-ip-pim.xml.in b/op-mode-definitions/show-ip-pim.xml.in index fa317a944..3e0bff064 100644 --- a/op-mode-definitions/show-ip-pim.xml.in +++ b/op-mode-definitions/show-ip-pim.xml.in @@ -9,59 +9,143 @@ Show PIM (Protocol Independent Multicast) information + + + PIM interfaces assert + + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + PIM interface internal assert state + + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + PIM interface assert metric + + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + PIM interface assert winner metric + + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + PIM cached bsm packets information + + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + PIM boot-strap router information + + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + PIM cached group-rp mappings information + + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + PIM downstream channel info + + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + PIM multicast group type + + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + PIM interfaces information - vtysh -c "show ip pim interface" + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ PIM join information - vtysh -c "show ip pim join" + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + PIM interface local-membership + + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ PIM neighbor information - vtysh -c "show ip pim neighbor" + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ PIM cached nexthop rpf information - vtysh -c "show ip pim nexthop" + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + PIM rendezvous point information + + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + PIM reverse path forwarding information + + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + PIM neighbor addresses + + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ PIM state information - vtysh -c "show ip pim state" + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ PIM statistics - vtysh -c "show ip pim statistics" + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ + + + + PIM upstream information + + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ - + - PIM RP (Rendevous Point) information + PIM upstream join-desired - vtysh -c "show ip pim rp-info" + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ - + - PIM cached source rpf information + PIM upstream source reverse path forwarding - vtysh -c "show ip pim rpf" + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ - + - PIM upstream information + VXLAN BUM groups - vtysh -c "show ip pim upstream" + ${vyos_op_scripts_dir}/vtysh_wrapper.sh $@ diff --git a/python/vyos/frr.py b/python/vyos/frr.py index ad5c207f5..a01d967e4 100644 --- a/python/vyos/frr.py +++ b/python/vyos/frr.py @@ -86,12 +86,8 @@ ch2 = logging.StreamHandler(stream=sys.stdout) LOG.addHandler(ch) LOG.addHandler(ch2) -# Full list of FRR 9.0/stable daemons for reference -#_frr_daemons = ['zebra', 'staticd', 'bgpd', 'ospfd', 'ospf6d', 'ripd', 'ripngd', -# 'isisd', 'pim6d', 'ldpd', 'eigrpd', 'babeld', 'sharpd', 'bfdd', -# 'fabricd', 'pathd'] _frr_daemons = ['zebra', 'staticd', 'bgpd', 'ospfd', 'ospf6d', 'ripd', 'ripngd', - 'isisd', 'pim6d', 'ldpd', 'babeld', 'bfdd'] + 'isisd', 'pimd', 'pim6d', 'ldpd', 'eigrpd', 'babeld', 'bfdd'] path_vtysh = '/usr/bin/vtysh' path_frr_reload = '/usr/lib/frr/frr-reload.py' diff --git a/smoketest/scripts/cli/base_interfaces_test.py b/smoketest/scripts/cli/base_interfaces_test.py index 51ccbc9e6..73b4e9764 100644 --- a/smoketest/scripts/cli/base_interfaces_test.py +++ b/smoketest/scripts/cli/base_interfaces_test.py @@ -12,9 +12,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import os -import unittest - from binascii import hexlify from netifaces import AF_INET @@ -24,7 +21,6 @@ from netifaces import interfaces from base_vyostest_shim import VyOSUnitTestSHIM -from vyos.configsession import ConfigSession from vyos.configsession import ConfigSessionError from vyos.defaults import directories from vyos.ifconfig import Interface diff --git a/smoketest/scripts/cli/base_vyostest_shim.py b/smoketest/scripts/cli/base_vyostest_shim.py index f694f539d..140642806 100644 --- a/smoketest/scripts/cli/base_vyostest_shim.py +++ b/smoketest/scripts/cli/base_vyostest_shim.py @@ -78,9 +78,10 @@ class VyOSUnitTestSHIM: while run(f'sudo lsof -nP {commit_lock}') == 0: sleep(0.250) - def getFRRconfig(self, string, end='$', endsection='^!', daemon=''): + def getFRRconfig(self, string=None, end='$', endsection='^!', daemon=''): """ Retrieve current "running configuration" from FRR """ - command = f'vtysh -c "show run {daemon} no-header" | sed -n "/^{string}{end}/,/{endsection}/p"' + command = f'vtysh -c "show run {daemon} no-header"' + if string: command += f' | sed -n "/^{string}{end}/,/{endsection}/p"' out = cmd(command) if self.debug: import pprint diff --git a/smoketest/scripts/cli/test_protocols_pim.py b/smoketest/scripts/cli/test_protocols_pim.py new file mode 100755 index 000000000..07c806126 --- /dev/null +++ b/smoketest/scripts/cli/test_protocols_pim.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 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 +# 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 unittest + +from base_vyostest_shim import VyOSUnitTestSHIM + +from vyos.configsession import ConfigSessionError +from vyos.ifconfig import Section +from vyos.utils.process import process_named_running + +PROCESS_NAME = 'pimd' +base_path = ['protocols', 'pim'] + +class TestProtocolsPIM(VyOSUnitTestSHIM.TestCase): + def tearDown(self): + # pimd process must be running + self.assertTrue(process_named_running(PROCESS_NAME)) + + self.cli_delete(base_path) + self.cli_commit() + + # pimd process must be stopped by now + self.assertFalse(process_named_running(PROCESS_NAME)) + + def test_01_pim_basic(self): + rp = '127.0.0.1' + group = '224.0.0.0/4' + hello = '100' + dr_priority = '64' + + self.cli_set(base_path + ['rp', 'address', rp, 'group', group]) + + interfaces = Section.interfaces('ethernet') + for interface in interfaces: + self.cli_set(base_path + ['interface', interface , 'bfd']) + self.cli_set(base_path + ['interface', interface , 'dr-priority', dr_priority]) + self.cli_set(base_path + ['interface', interface , 'hello', hello]) + self.cli_set(base_path + ['interface', interface , 'no-bsm']) + self.cli_set(base_path + ['interface', interface , 'no-unicast-bsm']) + self.cli_set(base_path + ['interface', interface , 'passive']) + + # commit changes + self.cli_commit() + + # Verify FRR pimd configuration + frrconfig = self.getFRRconfig(daemon=PROCESS_NAME) + self.assertIn(f'ip pim rp {rp} {group}', frrconfig) + + for interface in interfaces: + frrconfig = self.getFRRconfig(f'interface {interface}', daemon=PROCESS_NAME) + self.assertIn(f'interface {interface}', frrconfig) + self.assertIn(f' ip pim', frrconfig) + self.assertIn(f' ip pim bfd', frrconfig) + self.assertIn(f' ip pim drpriority {dr_priority}', frrconfig) + self.assertIn(f' ip pim hello {hello}', frrconfig) + self.assertIn(f' no ip pim bsm', frrconfig) + self.assertIn(f' no ip pim unicast-bsm', frrconfig) + self.assertIn(f' ip pim passive', frrconfig) + + self.cli_commit() + + def test_02_pim_igmp_proxy(self): + igmp_proxy = ['protocols', 'igmp-proxy'] + rp = '127.0.0.1' + group = '224.0.0.0/4' + hello = '100' + dr_priority = '64' + + self.cli_set(base_path) + self.cli_set(igmp_proxy) + + # check validate() - can not set both IGMP proxy and PIM + with self.assertRaises(ConfigSessionError): + self.cli_commit() + + self.cli_delete(igmp_proxy) + + self.cli_set(base_path + ['rp', 'address', rp, 'group', group]) + interfaces = Section.interfaces('ethernet') + for interface in interfaces: + self.cli_set(base_path + ['interface', interface , 'bfd']) + + # commit changes + self.cli_commit() + +if __name__ == '__main__': + unittest.main(verbosity=2, failfast=True) diff --git a/src/conf_mode/protocols_pim.py b/src/conf_mode/protocols_pim.py index 0aaa0d2c6..89db69b87 100755 --- a/src/conf_mode/protocols_pim.py +++ b/src/conf_mode/protocols_pim.py @@ -16,144 +16,135 @@ import os -from ipaddress import IPv4Address +from ipaddress import IPv4Network +from signal import SIGTERM from sys import exit from vyos.config import Config -from vyos import ConfigError +from vyos.config import config_dict_merge +from vyos.configdict import dict_merge +from vyos.configdict import node_changed +from vyos.utils.dict import dict_search from vyos.utils.process import process_named_running from vyos.utils.process import call -from vyos.template import render -from signal import SIGTERM - +from vyos.template import render_to_string +from vyos import ConfigError +from vyos import frr from vyos import airbag airbag.enable() -# Required to use the full path to pimd, in another case daemon will not be started -pimd_cmd = f'/usr/lib/frr/pimd -d -F traditional --daemon -A 127.0.0.1' - -config_file = r'/tmp/pimd.frr' - def get_config(config=None): if config: conf = config else: conf = Config() - pim_conf = { - 'pim_conf' : False, - 'igmp_conf' : False, - 'igmp_proxy_conf' : False, - 'old_pim' : { - 'ifaces' : {}, - 'rp' : {} - }, - 'pim' : { - 'ifaces' : {}, - 'rp' : {} - } - } - if not (conf.exists('protocols pim') or conf.exists_effective('protocols pim')): - return None - - if conf.exists('protocols igmp-proxy'): - pim_conf['igmp_proxy_conf'] = True - - if conf.exists('protocols igmp'): - pim_conf['igmp_conf'] = True - - if conf.exists('protocols pim'): - pim_conf['pim_conf'] = True - - conf.set_level('protocols pim') - # Get interfaces - for iface in conf.list_effective_nodes('interface'): - pim_conf['old_pim']['ifaces'].update({ - iface : { - 'hello' : conf.return_effective_value('interface {0} hello'.format(iface)), - 'dr_prio' : conf.return_effective_value('interface {0} dr-priority'.format(iface)) - } - }) - - for iface in conf.list_nodes('interface'): - pim_conf['pim']['ifaces'].update({ - iface : { - 'hello' : conf.return_value('interface {0} hello'.format(iface)), - 'dr_prio' : conf.return_value('interface {0} dr-priority'.format(iface)), - } - }) - - conf.set_level('protocols pim rp') - - # Get RPs addresses - for rp_addr in conf.list_effective_nodes('address'): - pim_conf['old_pim']['rp'][rp_addr] = conf.return_effective_values('address {0} group'.format(rp_addr)) - - for rp_addr in conf.list_nodes('address'): - pim_conf['pim']['rp'][rp_addr] = conf.return_values('address {0} group'.format(rp_addr)) - - # Get RP keep-alive-timer - if conf.exists_effective('rp keep-alive-timer'): - pim_conf['old_pim']['rp_keep_alive'] = conf.return_effective_value('rp keep-alive-timer') - if conf.exists('rp keep-alive-timer'): - pim_conf['pim']['rp_keep_alive'] = conf.return_value('rp keep-alive-timer') - - return pim_conf + base = ['protocols', 'pim'] + + pim = conf.get_config_dict(base, key_mangling=('-', '_'), + get_first_key=True, no_tag_node_value_mangle=True) + + # We can not run both IGMP proxy and PIM at the same time - get IGMP + # proxy status + if conf.exists(['protocols', 'igmp-proxy']): + pim.update({'igmp_proxy_enabled' : {}}) + + # FRR has VRF support for different routing daemons. As interfaces belong + # to VRFs - or the global VRF, we need to check for changed interfaces so + # that they will be properly rendered for the FRR config. Also this eases + # removal of interfaces from the running configuration. + interfaces_removed = node_changed(conf, base + ['interface']) + if interfaces_removed: + pim['interface_removed'] = list(interfaces_removed) + + # 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): + pim.update({'deleted' : ''}) + return pim + + # We have gathered the dict representation of the CLI, but there are default + # options which we need to update into the dictionary retrived. + default_values = conf.get_config_defaults(**pim.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 + # originate comes with a default metric-type of 2, which will enable the + # entire default-information originate tree, even when not set via CLI so we + # need to check this first and probably drop that key. + for interface in pim.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 'igmp' not in pim['interface'][interface]: + del default_values['interface'][interface]['igmp'] + + pim = config_dict_merge(default_values, pim) + return pim def verify(pim): - if pim is None: + if not pim or 'deleted' in pim: return None - if pim['pim_conf']: - # Check conflict with IGMP-Proxy - if pim['igmp_proxy_conf']: - raise ConfigError(f"IGMP proxy and PIM cannot be both configured at the same time") + if 'igmp_proxy_enabled' in pim: + raise ConfigError('IGMP proxy and PIM cannot be configured at the same time!') - # Check interfaces - if not pim['pim']['ifaces']: - raise ConfigError(f"PIM require defined interfaces!") + if 'interface' not in pim: + raise ConfigError('PIM require defined interfaces!') - if not pim['pim']['rp']: - raise ConfigError(f"RP address required") + if dict_search('rp.address', pim) == None: + raise ConfigError('PIM rendezvous point needs to be defined!') - # Check unique multicast groups - uniq_groups = [] - for rp_addr in pim['pim']['rp']: - if not pim['pim']['rp'][rp_addr]: - raise ConfigError(f"Group should be specified for RP " + rp_addr) - for group in pim['pim']['rp'][rp_addr]: - if (group in uniq_groups): - raise ConfigError(f"Group range " + group + " specified cannot exact match another") + # Check unique multicast groups + unique = [] + for address, address_config in pim['rp']['address'].items(): + if 'group' not in address_config: + raise ConfigError(f'PIM rendezvous point group should be defined for "{address}"!') - # Check, is this multicast group - gr_addr = group.split('/') - if IPv4Address(gr_addr[0]) < IPv4Address('224.0.0.0'): - raise ConfigError(group + " not a multicast group") - - uniq_groups.extend(pim['pim']['rp'][rp_addr]) + # Check if it is a multicast group + for gr_addr in address_config['group']: + if not IPv4Network(gr_addr).is_multicast: + raise ConfigError(f'PIM rendezvous point group "{gr_addr}" is not a multicast group!') + if gr_addr in unique: + raise ConfigError('PIM rendezvous point group must be unique!') + unique.append(gr_addr) def generate(pim): - if pim is None: + if not pim or 'deleted' in pim: return None - - render(config_file, 'frr/pimd.frr.j2', pim) + pim['frr_pimd_config'] = render_to_string('frr/pimd.frr.j2', pim) return None def apply(pim): - if pim is None: + pim_daemon = 'pimd' + pim_pid = process_named_running(pim_daemon) + + if not pim or 'deleted' in pim: + if 'deleted' in pim: + os.kill(int(pim_pid), SIGTERM) + return None - pim_pid = process_named_running('pimd') - if pim['igmp_conf'] or pim['pim_conf']: - if not pim_pid: - call(pimd_cmd) + if not pim_pid: + call('/usr/lib/frr/pimd -d -F traditional --daemon -A 127.0.0.1') + + # Save original configuration prior to starting any commit actions + frr_cfg = frr.FRRConfig() + + frr_cfg.load_configuration(pim_daemon) + frr_cfg.modify_section(f'^ip pim') + frr_cfg.modify_section(f'^ip igmp') - if os.path.exists(config_file): - call("vtysh -d pimd -f " + config_file) - os.remove(config_file) - elif pim_pid: - os.kill(int(pim_pid), SIGTERM) + for key in ['interface', 'interface_removed']: + if key not in pim: + continue + for interface in pim[key]: + frr_cfg.modify_section(f'^interface {interface}', stop_pattern='^exit', remove_stop_mark=True) + if 'frr_pimd_config' in pim: + frr_cfg.add_before(frr.default_add_before, pim['frr_pimd_config']) + frr_cfg.commit_configuration(pim_daemon) return None if __name__ == '__main__': diff --git a/src/op_mode/restart_frr.py b/src/op_mode/restart_frr.py index 820a3846c..8841b0eca 100755 --- a/src/op_mode/restart_frr.py +++ b/src/op_mode/restart_frr.py @@ -139,9 +139,7 @@ def _reload_config(daemon): # define program arguments cmd_args_parser = argparse.ArgumentParser(description='restart frr daemons') cmd_args_parser.add_argument('--action', choices=['restart'], required=True, help='action to frr daemons') -# Full list of FRR 9.0/stable daemons for reference -#cmd_args_parser.add_argument('--daemon', choices=['zebra', 'staticd', 'bgpd', 'ospfd', 'ospf6d', 'ripd', 'ripngd', 'isisd', 'pim6d', 'ldpd', 'eigrpd', 'babeld', 'sharpd', 'bfdd', 'fabricd', 'pathd'], required=False, nargs='*', help='select single or multiple daemons') -cmd_args_parser.add_argument('--daemon', choices=['zebra', 'staticd', 'bgpd', 'ospfd', 'ospf6d', 'ripd', 'ripngd', 'isisd', 'pim6d', 'ldpd', 'babeld', 'bfdd'], required=False, nargs='*', help='select single or multiple daemons') +cmd_args_parser.add_argument('--daemon', choices=['zebra', 'staticd', 'bgpd', 'eigrpd', 'ospfd', 'ospf6d', 'ripd', 'ripngd', 'isisd', 'pimd', 'pim6d', 'ldpd', 'babeld', 'bfdd'], required=False, nargs='*', help='select single or multiple daemons') # parse arguments cmd_args = cmd_args_parser.parse_args() -- cgit v1.2.3