diff options
| -rw-r--r-- | data/configd-include.json | 1 | ||||
| -rw-r--r-- | data/templates/frr/igmp.frr.j2 | 41 | ||||
| -rw-r--r-- | data/templates/frr/pimd.frr.j2 | 17 | ||||
| -rw-r--r-- | interface-definitions/include/source-address-ipv4-multi.xml.i | 18 | ||||
| -rw-r--r-- | interface-definitions/include/version/pim-version.xml.i | 3 | ||||
| -rw-r--r-- | interface-definitions/protocols-igmp.xml.in | 95 | ||||
| -rw-r--r-- | interface-definitions/protocols-pim.xml.in | 43 | ||||
| -rw-r--r-- | interface-definitions/xml-component-version.xml.in | 1 | ||||
| -rw-r--r-- | op-mode-definitions/show-ip-igmp.xml.in | 12 | ||||
| -rw-r--r-- | smoketest/config-tests/igmp-pim-small | 17 | ||||
| -rw-r--r-- | smoketest/configs/igmp-pim-small | 84 | ||||
| -rwxr-xr-x | smoketest/scripts/cli/test_protocols_pim.py | 47 | ||||
| -rwxr-xr-x | src/conf_mode/protocols_igmp.py | 140 | ||||
| -rwxr-xr-x | src/conf_mode/protocols_pim.py | 34 | ||||
| -rwxr-xr-x | src/migration-scripts/pim/0-to-1 | 72 | 
15 files changed, 322 insertions, 303 deletions
| diff --git a/data/configd-include.json b/data/configd-include.json index 84bc1f14e..a762a6d4c 100644 --- a/data/configd-include.json +++ b/data/configd-include.json @@ -44,7 +44,6 @@  "policy-local-route.py",  "protocols_bfd.py",  "protocols_bgp.py", -"protocols_igmp.py",  "protocols_isis.py",  "protocols_mpls.py",  "protocols_nhrp.py", diff --git a/data/templates/frr/igmp.frr.j2 b/data/templates/frr/igmp.frr.j2 deleted file mode 100644 index b75884484..000000000 --- a/data/templates/frr/igmp.frr.j2 +++ /dev/null @@ -1,41 +0,0 @@ -! -{% for iface in old_ifaces %} -interface {{ iface }} -{%     for group in old_ifaces[iface].gr_join %} -{%         if old_ifaces[iface].gr_join[group] %} -{%             for source in old_ifaces[iface].gr_join[group] %} - no ip igmp join {{ group }} {{ source }} -{%             endfor %} -{%         else %} - no ip igmp join {{ group }} -{%         endif %} -{%     endfor %} - no ip igmp -! -{% endfor %} -{% for interface, interface_config in ifaces.items() %} -interface {{ interface }} -{%     if interface_config.version %} - ip igmp version {{ interface_config.version }} -{%     else %} -{# IGMP default version 3 #} - ip igmp -{%     endif %} -{%     if interface_config.query_interval %} - ip igmp query-interval {{ interface_config.query_interval }} -{%     endif %} -{%     if interface_config.query_max_resp_time %} - ip igmp query-max-response-time {{ interface_config.query_max_resp_time }} -{%     endif %} -{%     for group, sources in interface_config.gr_join.items() %} -{%         if sources is vyos_defined %} -{%             for source in sources %} - ip igmp join {{ group }} {{ source }} -{%             endfor %} -{%         else %} - ip igmp join {{ group }} -{%         endif %} -{%     endfor %} -! -{% endfor %} -! diff --git a/data/templates/frr/pimd.frr.j2 b/data/templates/frr/pimd.frr.j2 index 7d6ddf8d4..97c5ff58b 100644 --- a/data/templates/frr/pimd.frr.j2 +++ b/data/templates/frr/pimd.frr.j2 @@ -27,9 +27,26 @@ interface {{ iface }}  {%         if iface_config.igmp is vyos_defined %}   ip igmp  {%         endif %} +{%         if iface_config.igmp.query_interval %} + ip igmp query-interval {{ iface_config.igmp.query_interval }} +{%         endif %} +{%         if iface_config.igmp.query_max_response_time %} + ip igmp query-max-response-time {{ iface_config.igmp.query_max_response_time }} +{%         endif %}  {%         if iface_config.igmp.version is vyos_defined %}   ip igmp version {{ iface_config.igmp.version }}  {%         endif %} +{%         if iface_config.igmp.join is vyos_defined %} +{%             for join, join_config in iface_config.igmp.join.items() %} +{%                 if join_config.source_address is vyos_defined %} +{%                     for source_address in join_config.source_address %} + ip igmp join {{ join }} {{ source_address }} +{%                     endfor %} +{%                 else %} + ip igmp join {{ join }} +{%                 endif %} +{%             endfor %} +{%         endif %}  exit  {%     endfor %}  {% endif %} diff --git a/interface-definitions/include/source-address-ipv4-multi.xml.i b/interface-definitions/include/source-address-ipv4-multi.xml.i new file mode 100644 index 000000000..319a118f3 --- /dev/null +++ b/interface-definitions/include/source-address-ipv4-multi.xml.i @@ -0,0 +1,18 @@ +<!-- include start from source-address-ipv4-multi.xml.i --> +<leafNode name="source-address"> +  <properties> +    <help>IPv4 source address used to initiate connection</help> +    <completionHelp> +      <script>${vyos_completion_dir}/list_local_ips.sh --ipv4</script> +    </completionHelp> +    <valueHelp> +      <format>ipv4</format> +      <description>IPv4 source address</description> +    </valueHelp> +    <constraint> +      <validator name="ipv4-address"/> +    </constraint> +    <multi/> +  </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/include/version/pim-version.xml.i b/interface-definitions/include/version/pim-version.xml.i new file mode 100644 index 000000000..24cc38cdf --- /dev/null +++ b/interface-definitions/include/version/pim-version.xml.i @@ -0,0 +1,3 @@ +<!-- include start from include/version/pim-version.xml.i --> +<syntaxVersion component='pim' version='1'></syntaxVersion> +<!-- include end --> diff --git a/interface-definitions/protocols-igmp.xml.in b/interface-definitions/protocols-igmp.xml.in deleted file mode 100644 index a055db71e..000000000 --- a/interface-definitions/protocols-igmp.xml.in +++ /dev/null @@ -1,95 +0,0 @@ -<?xml version="1.0"?> -<!-- Internet Group Management Protocol (IGMP) configuration --> -<interfaceDefinition> -  <node name="protocols"> -    <children> -      <node name="igmp" owner="${vyos_conf_scripts_dir}/protocols_igmp.py"> -        <properties> -          <help>Internet Group Management Protocol (IGMP)</help> -        </properties> -        <children> -          <tagNode name="interface"> -            <properties> -              <help>IGMP interface</help> -              <completionHelp> -                <script>${vyos_completion_dir}/list_interfaces</script> -              </completionHelp> -            </properties> -            <children> -              <tagNode name="join"> -                <properties> -                  <help>IGMP join multicast group</help> -                  <valueHelp> -                    <format>ipv4</format> -                    <description>Multicast group address</description> -                  </valueHelp> -                  <constraint> -                    <validator name="ipv4-address"/> -                  </constraint> -                </properties> -                <children> -                  <leafNode name="source"> -                    <properties> -                      <help>Source address</help> -                      <valueHelp> -                        <format>ipv4</format> -                        <description>Source address</description> -                      </valueHelp> -                      <constraint> -                        <validator name="ipv4-address"/> -                      </constraint> -                      <multi/> -                    </properties> -                  </leafNode> -                </children> -              </tagNode> -              <leafNode name="version"> -                <properties> -                  <help>IGMP version</help> -                  <completionHelp> -                    <list>2 3</list> -                  </completionHelp> -                  <valueHelp> -                    <format>2</format> -                    <description>IGMP version 2</description> -                  </valueHelp> -                 <valueHelp> -                    <format>3</format> -                    <description>IGMP version 3</description> -                  </valueHelp> -                  <constraint> -                    <validator name="numeric" argument="--range 2-3"/> -                  </constraint> -                </properties> -              </leafNode> -              <leafNode name="query-interval"> -                <properties> -                  <help>IGMP host query interval</help> -                  <valueHelp> -                    <format>u32:1-1800</format> -                    <description>Query interval in seconds</description> -                  </valueHelp> -                  <constraint> -                    <validator name="numeric" argument="--range 1-1800"/> -                  </constraint> -                </properties> -              </leafNode> -              <leafNode name="query-max-response-time"> -                <properties> -                  <help>IGMP max query response time</help> -                  <valueHelp> -                    <format>u32:10-250</format> -                    <description>Query response value in deci-seconds</description> -                  </valueHelp> -                  <constraint> -                    <validator name="numeric" argument="--range 10-250"/> -                  </constraint> -                </properties> -              </leafNode> -            </children> -          </tagNode> -        </children> -      </node> -    </children> -  </node> -</interfaceDefinition> diff --git a/interface-definitions/protocols-pim.xml.in b/interface-definitions/protocols-pim.xml.in index 02a8a6f5e..c1fa1b489 100644 --- a/interface-definitions/protocols-pim.xml.in +++ b/interface-definitions/protocols-pim.xml.in @@ -5,7 +5,7 @@      <children>        <node name="pim" owner="${vyos_conf_scripts_dir}/protocols_pim.py">          <properties> -          <help>Protocol Independent Multicast (PIM)</help> +          <help>Protocol Independent Multicast (PIM) and IGMP</help>            <priority>400</priority>          </properties>          <children> @@ -31,11 +31,50 @@                  <help>Internet Group Management Protocol (IGMP) options</help>                </properties>                <children> +                <tagNode name="join"> +                  <properties> +                    <help>IGMP join multicast group</help> +                    <valueHelp> +                      <format>ipv4</format> +                      <description>Multicast group address</description> +                    </valueHelp> +                    <constraint> +                      <validator name="ipv4-address"/> +                    </constraint> +                  </properties> +                  <children> +                    #include <include/source-address-ipv4-multi.xml.i> +                  </children> +                </tagNode> +                <leafNode name="query-interval"> +                  <properties> +                    <help>IGMP host query interval</help> +                    <valueHelp> +                      <format>u32:1-1800</format> +                      <description>Query interval in seconds</description> +                    </valueHelp> +                    <constraint> +                      <validator name="numeric" argument="--range 1-1800"/> +                    </constraint> +                  </properties> +                </leafNode> +                <leafNode name="query-max-response-time"> +                  <properties> +                    <help>IGMP max query response time</help> +                    <valueHelp> +                      <format>u32:10-250</format> +                      <description>Query response value in deci-seconds</description> +                    </valueHelp> +                    <constraint> +                      <validator name="numeric" argument="--range 10-250"/> +                    </constraint> +                  </properties> +                </leafNode>                  <leafNode name="version">                    <properties>                      <help>Interface IGMP version</help>                      <completionHelp> -                      <list>1 2</list> +                      <list>2 3</list>                      </completionHelp>                      <valueHelp>                        <format>2</format> diff --git a/interface-definitions/xml-component-version.xml.in b/interface-definitions/xml-component-version.xml.in index cae3423dc..10a1be242 100644 --- a/interface-definitions/xml-component-version.xml.in +++ b/interface-definitions/xml-component-version.xml.in @@ -30,6 +30,7 @@    #include <include/version/ntp-version.xml.i>    #include <include/version/openconnect-version.xml.i>    #include <include/version/ospf-version.xml.i> +  #include <include/version/pim-version.xml.i>    #include <include/version/policy-version.xml.i>    #include <include/version/pppoe-server-version.xml.i>    #include <include/version/pptp-version.xml.i> diff --git a/op-mode-definitions/show-ip-igmp.xml.in b/op-mode-definitions/show-ip-igmp.xml.in index 855c5d508..1fd86ba54 100644 --- a/op-mode-definitions/show-ip-igmp.xml.in +++ b/op-mode-definitions/show-ip-igmp.xml.in @@ -13,31 +13,31 @@                  <properties>                    <help>IGMP groups information</help>                  </properties> -                <command>vtysh -c "show ip igmp groups"</command> +                <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>                </leafNode> -              <leafNode name="interfaces"> +              <leafNode name="interface">                  <properties>                    <help>IGMP interfaces information</help>                  </properties> -                <command>vtysh -c "show ip igmp interface"</command> +                <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>                </leafNode>                <leafNode name="join">                  <properties>                    <help>IGMP static join information</help>                  </properties> -                <command>vtysh -c "show ip igmp join"</command> +                <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>                </leafNode>                <leafNode name="sources">                  <properties>                    <help>IGMP sources information</help>                  </properties> -                <command>vtysh -c "show ip igmp sources"</command> +                <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>                </leafNode>                <leafNode name="statistics">                  <properties>                    <help>IGMP statistics</help>                  </properties> -                <command>vtysh -c "show ip igmp statistics"</command> +                <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>                </leafNode>              </children>            </node> diff --git a/smoketest/config-tests/igmp-pim-small b/smoketest/config-tests/igmp-pim-small new file mode 100644 index 000000000..207c17d45 --- /dev/null +++ b/smoketest/config-tests/igmp-pim-small @@ -0,0 +1,17 @@ +set interfaces ethernet eth1 address '100.64.0.1/24' +set interfaces ethernet eth2 address '172.16.0.2/24' +set protocols pim interface eth1 igmp join 224.1.0.0 source-address '1.1.1.1' +set protocols pim interface eth1 igmp join 224.1.0.0 source-address '1.1.1.2' +set protocols pim interface eth1 igmp query-interval '1000' +set protocols pim interface eth1 igmp query-max-response-time '30' +set protocols pim interface eth1 igmp version '2' +set protocols pim interface eth2 +set protocols pim rp address 172.16.255.1 group '224.0.0.0/4' +set service ntp server 0.pool.ntp.org +set service ntp server 1.pool.ntp.org +set service ntp server 2.pool.ntp.org +set system domain-name 'vyos.io' +set system host-name 'vyos' +set system login user vyos authentication encrypted-password '$6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/' +set system login user vyos authentication plaintext-password '' +set system console device ttyS0 speed '115200' diff --git a/smoketest/configs/igmp-pim-small b/smoketest/configs/igmp-pim-small new file mode 100644 index 000000000..f433ff8d7 --- /dev/null +++ b/smoketest/configs/igmp-pim-small @@ -0,0 +1,84 @@ +interfaces { +    ethernet eth0 { +        duplex auto +        speed auto +    } +    ethernet eth1 { +        address 100.64.0.1/24 +        duplex auto +        speed auto +    } +    ethernet eth2 { +        address 172.16.0.2/24 +        duplex auto +        speed auto +    } +} +protocols { +    igmp { +        interface eth1 { +            join 224.1.0.0 { +                source 1.1.1.1 +                source 1.1.1.2 +            } +            query-interval 1000 +            query-max-response-time 30 +            version 2 +        } +    } +    pim { +        interface eth1 { +        } +        interface eth2 { +        } +        rp { +            address 172.16.255.1 { +                group 224.0.0.0/4 +            } +        } +    } +} +system { +    config-management { +        commit-revisions 200 +    } +    console { +        device ttyS0 { +            speed 115200 +        } +    } +    domain-name vyos.io +    host-name vyos +    login { +        user vyos { +            authentication { +                encrypted-password $6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/ +                plaintext-password "" +            } +        } +    } +    ntp { +        server 0.pool.ntp.org { +        } +        server 1.pool.ntp.org { +        } +        server 2.pool.ntp.org { +        } +    } +    syslog { +        global { +            facility all { +                level info +            } +            facility protocols { +                level debug +            } +        } +    } +    time-zone Europe/Berlin +} + + +// Warning: Do not remove the following line. +// vyos-config-version: "broadcast-relay@1:cluster@1:config-management@1:conntrack@1:conntrack-sync@1:dhcp-relay@2:dhcp-server@5:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@18:ipoe-server@1:ipsec@5:l2tp@3:lldp@1:mdns@1:nat@5:ntp@1:pppoe-server@5:pptp@2:qos@1:quagga@7:rpki@1:salt@1:snmp@2:ssh@2:sstp@3:system@20:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1" +// Release version: 1.3.0 diff --git a/smoketest/scripts/cli/test_protocols_pim.py b/smoketest/scripts/cli/test_protocols_pim.py index 07c806126..ef134b195 100755 --- a/smoketest/scripts/cli/test_protocols_pim.py +++ b/smoketest/scripts/cli/test_protocols_pim.py @@ -77,8 +77,6 @@ class TestProtocolsPIM(VyOSUnitTestSHIM.TestCase):          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) @@ -97,5 +95,50 @@ class TestProtocolsPIM(VyOSUnitTestSHIM.TestCase):          # commit changes          self.cli_commit() +    def test_03_igmp(self): +        watermark_warning = '2000' +        query_interval = '1000' +        query_max_response_time = '200' +        version = '2' + +        igmp_join = { +            '224.1.1.1' : { 'source' : ['1.1.1.1', '2.2.2.2', '3.3.3.3'] }, +            '224.1.2.2' : { 'source' : [] }, +            '224.1.3.3' : {}, +        } + +        self.cli_set(base_path + ['igmp', 'watermark-warning', watermark_warning]) +        interfaces = Section.interfaces('ethernet') +        for interface in interfaces: +            self.cli_set(base_path + ['interface', interface , 'igmp', 'version', version]) +            self.cli_set(base_path + ['interface', interface , 'igmp', 'query-interval', query_interval]) +            self.cli_set(base_path + ['interface', interface , 'igmp', 'query-max-response-time', query_max_response_time]) + +            for join, join_config in igmp_join.items(): +                self.cli_set(base_path + ['interface', interface , 'igmp', 'join', join]) +                if 'source' in join_config: +                    for source in join_config['source']: +                        self.cli_set(base_path + ['interface', interface , 'igmp', 'join', join, 'source-address', source]) + +        self.cli_commit() + +        frrconfig = self.getFRRconfig(daemon=PROCESS_NAME) +        self.assertIn(f'ip igmp watermark-warn {watermark_warning}', frrconfig) + +        for interface in interfaces: +            frrconfig = self.getFRRconfig(f'interface {interface}', daemon=PROCESS_NAME) +            self.assertIn(f'interface {interface}', frrconfig) +            self.assertIn(f' ip igmp', frrconfig) +            self.assertIn(f' ip igmp version {version}', frrconfig) +            self.assertIn(f' ip igmp query-interval {query_interval}', frrconfig) +            self.assertIn(f' ip igmp query-max-response-time {query_max_response_time}', frrconfig) + +            for join, join_config in igmp_join.items(): +                if 'source' in join_config: +                    for source in join_config['source']: +                        self.assertIn(f' ip igmp join {join} {source}', frrconfig) +                else: +                    self.assertIn(f' ip igmp join {join}', frrconfig) +  if __name__ == '__main__':      unittest.main(verbosity=2, failfast=True) diff --git a/src/conf_mode/protocols_igmp.py b/src/conf_mode/protocols_igmp.py deleted file mode 100755 index 435189025..000000000 --- a/src/conf_mode/protocols_igmp.py +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2020-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 <http://www.gnu.org/licenses/>. - -import os - -from ipaddress import IPv4Address -from sys import exit - -from vyos import ConfigError -from vyos.config import Config -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 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/igmp.frr' - -def get_config(config=None): -    if config: -        conf = config -    else: -        conf = Config() -    igmp_conf = { -        'igmp_conf' : False, -        'pim_conf'  : False, -        'igmp_proxy_conf' : False, -        'old_ifaces'    : {}, -        'ifaces'    : {} -    } -    if not (conf.exists('protocols igmp') or conf.exists_effective('protocols igmp')): -        return None - -    if conf.exists('protocols igmp-proxy'): -        igmp_conf['igmp_proxy_conf'] = True - -    if conf.exists('protocols pim'): -        igmp_conf['pim_conf'] = True - -    if conf.exists('protocols igmp'): -        igmp_conf['igmp_conf'] = True - -    conf.set_level('protocols igmp') - -    # # Get interfaces -    for iface in conf.list_effective_nodes('interface'): -        igmp_conf['old_ifaces'].update({ -            iface : { -                'version' : conf.return_effective_value('interface {0} version'.format(iface)), -                'query_interval' : conf.return_effective_value('interface {0} query-interval'.format(iface)), -                'query_max_resp_time' : conf.return_effective_value('interface {0} query-max-response-time'.format(iface)), -                'gr_join' : {} -            } -        }) -        for gr_join in conf.list_effective_nodes('interface {0} join'.format(iface)): -            igmp_conf['old_ifaces'][iface]['gr_join'][gr_join] = conf.return_effective_values('interface {0} join {1} source'.format(iface, gr_join)) - -    for iface in conf.list_nodes('interface'): -        igmp_conf['ifaces'].update({ -            iface : { -                'version' : conf.return_value('interface {0} version'.format(iface)), -                'query_interval' : conf.return_value('interface {0} query-interval'.format(iface)), -                'query_max_resp_time' : conf.return_value('interface {0} query-max-response-time'.format(iface)), -                'gr_join' : {} -            } -        }) -        for gr_join in conf.list_nodes('interface {0} join'.format(iface)): -            igmp_conf['ifaces'][iface]['gr_join'][gr_join] = conf.return_values('interface {0} join {1} source'.format(iface, gr_join)) - -    return igmp_conf - -def verify(igmp): -    if igmp is None: -        return None - -    if igmp['igmp_conf']: -        # Check conflict with IGMP-Proxy -        if igmp['igmp_proxy_conf']: -            raise ConfigError(f"IGMP proxy and PIM cannot be both configured at the same time") - -        # Check interfaces -        if not igmp['ifaces']: -            raise ConfigError(f"IGMP require defined interfaces!") -        # Check, is this multicast group -        for intfc in igmp['ifaces']: -            for gr_addr in igmp['ifaces'][intfc]['gr_join']: -                if not IPv4Address(gr_addr).is_multicast: -                    raise ConfigError(gr_addr + " not a multicast group") - -def generate(igmp): -    if igmp is None: -        return None - -    render(config_file, 'frr/igmp.frr.j2', igmp) -    return None - -def apply(igmp): -    if igmp is None: -        return None - -    pim_pid = process_named_running('pimd') -    if igmp['igmp_conf'] or igmp['pim_conf']: -        if not pim_pid: -            call(pimd_cmd) - -        if os.path.exists(config_file): -            call(f'vtysh -d pimd -f {config_file}') -            os.remove(config_file) -    elif pim_pid: -        os.kill(int(pim_pid), SIGTERM) - -    return None - -if __name__ == '__main__': -    try: -        c = get_config() -        verify(c) -        generate(c) -        apply(c) -    except ConfigError as e: -        print(e) -        exit(1) diff --git a/src/conf_mode/protocols_pim.py b/src/conf_mode/protocols_pim.py index 89db69b87..fbe95c404 100755 --- a/src/conf_mode/protocols_pim.py +++ b/src/conf_mode/protocols_pim.py @@ -93,22 +93,24 @@ def verify(pim):      if 'interface' not in pim:          raise ConfigError('PIM require defined interfaces!') -    if dict_search('rp.address', pim) == None: -        raise ConfigError('PIM rendezvous point needs to be defined!') - -    # 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 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) +    if 'rp' in pim: +        if 'address' not in pim['rp']: +            raise ConfigError('PIM rendezvous point needs to be defined!') + +        # Check unique multicast groups +        unique = [] +        pim_base_error = 'PIM rendezvous point group' +        for address, address_config in pim['rp']['address'].items(): +            if 'group' not in address_config: +                raise ConfigError(f'{pim_base_error} should be defined for "{address}"!') + +            # 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_base_error} "{gr_addr}" is not a multicast group!') +                if gr_addr in unique: +                    raise ConfigError(f'{pim_base_error} must be unique!') +                unique.append(gr_addr)  def generate(pim):      if not pim or 'deleted' in pim: diff --git a/src/migration-scripts/pim/0-to-1 b/src/migration-scripts/pim/0-to-1 new file mode 100755 index 000000000..bf8af733c --- /dev/null +++ b/src/migration-scripts/pim/0-to-1 @@ -0,0 +1,72 @@ +#!/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 <http://www.gnu.org/licenses/>. + +# T5736: igmp: migrate "protocols igmp" to "protocols pim" + +import sys +from vyos.configtree import ConfigTree + +if len(sys.argv) < 2: +    print("Must specify file name!") +    sys.exit(1) + +file_name = sys.argv[1] + +with open(file_name, 'r') as f: +    config_file = f.read() + +config = ConfigTree(config_file) + +base = ['protocols', 'igmp'] +pim_base = ['protocols', 'pim'] +if not config.exists(base): +    # Nothing to do +    sys.exit(0) + +for interface in config.list_nodes(base + ['interface']): +    base_igmp_iface = base + ['interface', interface] +    pim_base_iface = pim_base + ['interface', interface] + +    # Create IGMP note under PIM interface +    if not config.exists(pim_base_iface + ['igmp']): +        config.set(pim_base_iface + ['igmp']) + +    if config.exists(base_igmp_iface + ['join']): +        config.copy(base_igmp_iface + ['join'], pim_base_iface + ['igmp', 'join']) +        config.set_tag(pim_base_iface + ['igmp', 'join']) + +        new_join_base = pim_base_iface + ['igmp', 'join'] +        for address in config.list_nodes(new_join_base): +            if config.exists(new_join_base + [address, 'source']): +                config.rename(new_join_base + [address, 'source'], 'source-address') + +    if config.exists(base_igmp_iface + ['query-interval']): +        config.copy(base_igmp_iface + ['query-interval'], pim_base_iface + ['igmp', 'query-interval']) + +    if config.exists(base_igmp_iface + ['query-max-response-time']): +        config.copy(base_igmp_iface + ['query-max-response-time'], pim_base_iface + ['igmp', 'query-max-response-time']) + +    if config.exists(base_igmp_iface + ['version']): +        config.copy(base_igmp_iface + ['version'], pim_base_iface + ['igmp', 'version']) + +config.delete(base) + +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)) +    sys.exit(1) | 
