-
Notifications
You must be signed in to change notification settings - Fork 335
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Currently VyOS has `protocol igmp` option to enable IGMP querier and reports through FRR's pimd. I would like to add support for IPv6 as well since FRR's IPv6 multicast functionality has significantly improved. Enabling both MLD and IGMP on a VyOS router will allow us to turn on multicast snooping on layer-3 switches in dual-stack networks. Example commands: ``` // Enable on interface eth0 set protocols pim6 interface eth0 // Explicitly join multicast group ff18::1234 on interface eth1 set protocols pim6 interface eth1 mld join ff18::1234 // Explicitly join source-specific multicast group ff38::5678 with source address 2001:db8::1 on interface eth1 set protocols pim6 interface eth1 mld join ff38::5678 source 2001:db8::1 ```
- Loading branch information
Showing
6 changed files
with
399 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
! | ||
{% if interface is vyos_defined %} | ||
{% for iface, iface_config in interface.items() %} | ||
interface {{ iface }} | ||
{% if iface_config.mld is vyos_defined and iface_config.mld.disable is not vyos_defined %} | ||
ipv6 mld | ||
{% if iface_config.mld.version is vyos_defined %} | ||
ipv6 mld version {{ iface_config.mld.version }} | ||
{% endif %} | ||
{% if iface_config.mld.interval is vyos_defined %} | ||
ipv6 mld query-interval {{ iface_config.mld.interval }} | ||
{% endif %} | ||
{% if iface_config.mld.max_response_time is vyos_defined %} | ||
ipv6 mld query-max-response-time {{ iface_config.mld.max_response_time // 100 }} | ||
{% endif %} | ||
{% if iface_config.mld.last_member_query_count is vyos_defined %} | ||
ipv6 mld last-member-query-count {{ iface_config.mld.last_member_query_count }} | ||
{% endif %} | ||
{% if iface_config.mld.last_member_query_interval is vyos_defined %} | ||
ipv6 mld last-member-query-interval {{ iface_config.mld.last_member_query_interval // 100 }} | ||
{% endif %} | ||
{% if iface_config.mld.join is vyos_defined %} | ||
{% for group, group_config in iface_config.mld.join.items() %} | ||
{% if group_config.source is vyos_defined %} | ||
{% for source in group_config.source %} | ||
ipv6 mld join {{ group }} {{ source }} | ||
{% endfor %} | ||
{% else %} | ||
ipv6 mld join {{ group }} | ||
{% endif %} | ||
{% endfor %} | ||
{% endif %} | ||
{% endif %} | ||
exit | ||
! | ||
{% endfor %} | ||
! | ||
{% endif %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
<?xml version="1.0"?> | ||
<!-- Protocol Independent Multicast for IPv6 (PIMv6) configuration --> | ||
<interfaceDefinition> | ||
<node name="protocols"> | ||
<children> | ||
<node name="pim6" owner="${vyos_conf_scripts_dir}/protocols_pim6.py"> | ||
<properties> | ||
<help>Protocol Independent Multicast for IPv6 (PIMv6)</help> | ||
<priority>400</priority> | ||
</properties> | ||
<children> | ||
<tagNode name="interface"> | ||
<properties> | ||
<help>PIMv6 interface</help> | ||
<completionHelp> | ||
<script>${vyos_completion_dir}/list_interfaces</script> | ||
</completionHelp> | ||
</properties> | ||
<children> | ||
<node name="mld"> | ||
<properties> | ||
<help>Multicast Listener Discovery (MLD)</help> | ||
</properties> | ||
<children> | ||
#include <include/generic-disable-node.xml.i> | ||
<tagNode name="join"> | ||
<properties> | ||
<help>MLD join multicast group</help> | ||
<valueHelp> | ||
<format>ipv6</format> | ||
<description>Multicast group address</description> | ||
</valueHelp> | ||
<constraint> | ||
<validator name="ipv6-address"/> | ||
</constraint> | ||
</properties> | ||
<children> | ||
<leafNode name="source"> | ||
<properties> | ||
<help>Source address</help> | ||
<valueHelp> | ||
<format>ipv6</format> | ||
<description>Source address</description> | ||
</valueHelp> | ||
<completionHelp> | ||
<script>${vyos_completion_dir}/list_local_ips.sh --ipv6</script> | ||
</completionHelp> | ||
<constraint> | ||
<validator name="ipv6-address"/> | ||
</constraint> | ||
<multi/> | ||
</properties> | ||
</leafNode> | ||
</children> | ||
</tagNode> | ||
<leafNode name="version"> | ||
<properties> | ||
<help>MLD version</help> | ||
<completionHelp> | ||
<list>1 2</list> | ||
</completionHelp> | ||
<valueHelp> | ||
<format>1</format> | ||
<description>MLD version 1</description> | ||
</valueHelp> | ||
<valueHelp> | ||
<format>2</format> | ||
<description>MLD version 2</description> | ||
</valueHelp> | ||
<constraint> | ||
<validator name="numeric" argument="--range 1-2"/> | ||
</constraint> | ||
</properties> | ||
<defaultValue>2</defaultValue> | ||
</leafNode> | ||
<leafNode name="interval"> | ||
<properties> | ||
<help>Query interval</help> | ||
<valueHelp> | ||
<format>u32:1-65535</format> | ||
<description>Query interval in seconds</description> | ||
</valueHelp> | ||
<constraint> | ||
<validator name="numeric" argument="--range 1-65535"/> | ||
</constraint> | ||
</properties> | ||
</leafNode> | ||
<leafNode name="max-response-time"> | ||
<properties> | ||
<help>Max query response time</help> | ||
<valueHelp> | ||
<format>u32:100-6553500</format> | ||
<description>Query response value in milliseconds</description> | ||
</valueHelp> | ||
<constraint> | ||
<validator name="numeric" argument="--range 100-6553500"/> | ||
</constraint> | ||
</properties> | ||
</leafNode> | ||
<leafNode name="last-member-query-count"> | ||
<properties> | ||
<help>Last member query count</help> | ||
<valueHelp> | ||
<format>u32:1-255</format> | ||
<description>Count</description> | ||
</valueHelp> | ||
<constraint> | ||
<validator name="numeric" argument="--range 1-255"/> | ||
</constraint> | ||
</properties> | ||
</leafNode> | ||
<leafNode name="last-member-query-interval"> | ||
<properties> | ||
<help>Last member query interval</help> | ||
<valueHelp> | ||
<format>u32:100-6553500</format> | ||
<description>Last member query interval in milliseconds</description> | ||
</valueHelp> | ||
<constraint> | ||
<validator name="numeric" argument="--range 100-6553500"/> | ||
</constraint> | ||
</properties> | ||
</leafNode> | ||
</children> | ||
</node> | ||
</children> | ||
</tagNode> | ||
</children> | ||
</node> | ||
</children> | ||
</node> | ||
</interfaceDefinition> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
#!/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/>. | ||
|
||
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 = 'pim6d' | ||
base_path = ['protocols', 'pim6'] | ||
|
||
|
||
class TestProtocolsPIMv6(VyOSUnitTestSHIM.TestCase): | ||
def tearDown(self): | ||
# Check for running process | ||
self.assertTrue(process_named_running(PROCESS_NAME)) | ||
self.cli_delete(base_path) | ||
self.cli_commit() | ||
|
||
def test_pim6_01_defaults(self): | ||
# commit changes | ||
self.cli_set(base_path) | ||
self.cli_commit() | ||
|
||
interfaces = Section.interfaces('ethernet') | ||
|
||
# Verify FRR pim6d configuration | ||
for interface in interfaces: | ||
config = self.getFRRconfig( | ||
f'interface {interface}', daemon=PROCESS_NAME) | ||
self.assertIn(f'interface {interface}', config) | ||
self.assertNotIn(f' ipv6 mld', config) | ||
|
||
def test_pim6_02_mld_simple(self): | ||
# commit changes | ||
interfaces = Section.interfaces('ethernet') | ||
|
||
for interface in interfaces: | ||
self.cli_set(base_path + ['interface', interface]) | ||
|
||
self.cli_commit() | ||
|
||
# Verify FRR pim6d configuration | ||
for interface in interfaces: | ||
config = self.getFRRconfig( | ||
f'interface {interface}', daemon=PROCESS_NAME) | ||
self.assertIn(f'interface {interface}', config) | ||
self.assertIn(f' ipv6 mld', config) | ||
self.assertNotIn(f' ipv6 mld version 1', config) | ||
|
||
# Change to MLD version 1 | ||
for interface in interfaces: | ||
self.cli_set(base_path + ['interface', | ||
interface, 'mld', 'version', '1']) | ||
|
||
self.cli_commit() | ||
|
||
# Verify FRR pim6d configuration | ||
for interface in interfaces: | ||
config = self.getFRRconfig( | ||
f'interface {interface}', daemon=PROCESS_NAME) | ||
self.assertIn(f'interface {interface}', config) | ||
self.assertIn(f' ipv6 mld', config) | ||
self.assertIn(f' ipv6 mld version 1', config) | ||
|
||
def test_pim6_03_mld_join(self): | ||
# commit changes | ||
interfaces = Section.interfaces('ethernet') | ||
|
||
# Use an invalid multiple group address | ||
for interface in interfaces: | ||
self.cli_set(base_path + ['interface', | ||
interface, 'mld', 'join', 'fd00::1234']) | ||
|
||
with self.assertRaises(ConfigSessionError): | ||
self.cli_commit() | ||
self.cli_delete(base_path + ['interface']) | ||
|
||
# Use a valid multiple group address | ||
for interface in interfaces: | ||
self.cli_set(base_path + ['interface', | ||
interface, 'mld', 'join', 'ff18::1234']) | ||
|
||
self.cli_commit() | ||
|
||
# Verify FRR pim6d configuration | ||
for interface in interfaces: | ||
config = self.getFRRconfig( | ||
f'interface {interface}', daemon=PROCESS_NAME) | ||
self.assertIn(f'interface {interface}', config) | ||
self.assertIn(f' ipv6 mld join ff18::1234', config) | ||
|
||
# Join a source-specific multicast group | ||
for interface in interfaces: | ||
self.cli_set(base_path + ['interface', interface, | ||
'mld', 'join', 'ff38::5678', '2001:db8::5678']) | ||
|
||
self.cli_commit() | ||
|
||
# Verify FRR pim6d configuration | ||
for interface in interfaces: | ||
config = self.getFRRconfig( | ||
f'interface {interface}', daemon=PROCESS_NAME) | ||
self.assertIn(f'interface {interface}', config) | ||
self.assertIn(f' ipv6 mld join ff38::5678 2001:db8::5678', config) | ||
|
||
|
||
if __name__ == '__main__': | ||
unittest.main(verbosity=2) |
Oops, something went wrong.