Skip to content

Commit 4992cc2

Browse files
authored
Merge pull request FRRouting#18260 from opensourcerouting/pim6-ssm
pimd: add support for group range prefix-list filter for v6
2 parents 6f257e9 + 990d045 commit 4992cc2

File tree

7 files changed

+228
-0
lines changed

7 files changed

+228
-0
lines changed

doc/user/pimv6.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,12 @@ PIMv6 Router
175175
notifications to the kernel. This command is vrf aware, to configure for a
176176
vrf, specify the vrf in the router pim6 block.
177177

178+
.. clicmd:: ssm prefix-list WORD
179+
180+
Specify a range of group addresses via a prefix-list that forces pim to
181+
never do SM over. This command is vrf aware, to configure for a vrf, specify
182+
the vrf in the router pim block.
183+
178184
.. clicmd:: ssmpingd [X:X::X:X]
179185

180186
Enable ipv6 ssmpingd configuration. A network level management tool

pimd/pim6_cmd.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include "pim_addr.h"
2929
#include "pim_nht.h"
3030
#include "pim_bsm.h"
31+
#include "pim_ssm.h"
32+
#include "pim_util.h"
3133
#include "pim_iface.h"
3234
#include "pim_zebra.h"
3335
#include "pim_instance.h"
@@ -1479,6 +1481,26 @@ DEFPY_ATTR(no_ipv6_ssmpingd,
14791481
return ret;
14801482
}
14811483

1484+
DEFPY_YANG(ipv6_pim_ssm,
1485+
ipv6_pim_ssm_cmd,
1486+
"[no] ssm prefix-list PREFIXLIST6_NAME$plist",
1487+
NO_STR
1488+
"Source Specific Multicast\n"
1489+
"Group range prefix-list filter\n"
1490+
"Name of a prefix-list\n")
1491+
{
1492+
char ssm_plist_xpath[XPATH_MAXLEN];
1493+
1494+
snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list");
1495+
1496+
if (no)
1497+
nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, NULL);
1498+
else
1499+
nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_MODIFY, plist);
1500+
1501+
return nb_cli_apply_changes(vty, NULL);
1502+
}
1503+
14821504
DEFPY_YANG_HIDDEN (interface_ipv6_mld_join,
14831505
interface_ipv6_mld_join_cmd,
14841506
"[no] ipv6 mld join X:X::X:X$grp [X:X::X:X]$src",
@@ -2433,6 +2455,79 @@ DEFPY (show_ipv6_pim_bsrp,
24332455
return pim_show_group_rp_mappings_info_helper(vrf, vty, !!json);
24342456
}
24352457

2458+
DEFPY(show_ipv6_pim_ssm_range,
2459+
show_ipv6_pim_ssm_range_cmd,
2460+
"show ipv6 pim [vrf NAME$vrf_name] group-type [json$json]",
2461+
SHOW_STR
2462+
IPV6_STR
2463+
PIM_STR
2464+
VRF_CMD_HELP_STR
2465+
"PIM group type\n"
2466+
JSON_STR)
2467+
{
2468+
struct pim_instance *pim;
2469+
const char *range_str;
2470+
struct pim_ssm *ssm;
2471+
struct vrf *vrf = NULL;
2472+
2473+
if (vrf_name)
2474+
vrf = vrf_lookup_by_name(vrf_name);
2475+
if (vrf == NULL)
2476+
vrf = vrf_lookup_by_id(VRF_DEFAULT);
2477+
2478+
pim = vrf->info;
2479+
ssm = pim->ssm_info;
2480+
range_str = ssm->plist_name ? ssm->plist_name : PIM6_SSM_STANDARD_RANGE;
2481+
if (json) {
2482+
struct json_object *json_root;
2483+
2484+
json_root = json_object_new_object();
2485+
json_object_string_add(json_root, "ssmGroups", range_str);
2486+
vty_json(vty, json_root);
2487+
} else
2488+
vty_out(vty, "SSM group range : %s\n", range_str);
2489+
2490+
return CMD_SUCCESS;
2491+
}
2492+
2493+
DEFPY(show_ipv6_pim_group_type,
2494+
show_ipv6_pim_group_type_cmd,
2495+
"show ipv6 pim [vrf NAME$vrf_name] group-type X:X::X:X$group [json$json]",
2496+
SHOW_STR
2497+
IP_STR
2498+
PIM_STR
2499+
VRF_CMD_HELP_STR
2500+
"multicast group type\n"
2501+
"group address\n"
2502+
JSON_STR)
2503+
{
2504+
struct pim_instance *pim;
2505+
const char *type_str;
2506+
struct vrf *vrf = NULL;
2507+
2508+
if (vrf_name)
2509+
vrf = vrf_lookup_by_name(vrf_name);
2510+
if (vrf == NULL)
2511+
vrf = vrf_lookup_by_id(VRF_DEFAULT);
2512+
2513+
pim = vrf->info;
2514+
if (pim_is_group_ff00_8(group))
2515+
type_str = pim_is_grp_ssm(pim, group) ? "SSM" : "ASM";
2516+
else
2517+
type_str = "not-multicast";
2518+
2519+
if (json) {
2520+
struct json_object *json_root;
2521+
2522+
json_root = json_object_new_object();
2523+
json_object_string_add(json_root, "groupType", type_str);
2524+
vty_json(vty, json_root);
2525+
} else
2526+
vty_out(vty, "Group type : %s\n", type_str);
2527+
2528+
return CMD_SUCCESS;
2529+
}
2530+
24362531
DEFPY(clear_ipv6_mld_interfaces,
24372532
clear_ipv6_mld_interfaces_cmd,
24382533
"clear ipv6 mld [vrf NAME$vrf_name] interfaces",
@@ -2957,6 +3052,7 @@ void pim_cmd_init(void)
29573052
install_element(PIM6_NODE, &pim6_embedded_rp_group_list_cmd);
29583053
install_element(PIM6_NODE, &pim6_embedded_rp_limit_cmd);
29593054

3055+
install_element(PIM6_NODE, &ipv6_pim_ssm_cmd);
29603056
install_element(PIM6_NODE, &pim6_ssmpingd_cmd);
29613057
install_element(PIM6_NODE, &no_pim6_ssmpingd_cmd);
29623058
install_element(PIM6_NODE, &pim6_bsr_candidate_rp_cmd);
@@ -3061,6 +3157,8 @@ void pim_cmd_init(void)
30613157
install_element(VIEW_NODE, &show_ipv6_pim_bsr_cmd);
30623158
install_element(VIEW_NODE, &show_ipv6_pim_bsm_db_cmd);
30633159
install_element(VIEW_NODE, &show_ipv6_pim_bsrp_cmd);
3160+
install_element(VIEW_NODE, &show_ipv6_pim_ssm_range_cmd);
3161+
install_element(VIEW_NODE, &show_ipv6_pim_group_type_cmd);
30643162
install_element(ENABLE_NODE, &clear_ipv6_mld_interfaces_cmd);
30653163
install_element(ENABLE_NODE, &clear_ipv6_pim_statistics_cmd);
30663164
install_element(ENABLE_NODE, &clear_ipv6_mroute_cmd);

pimd/pim_ssm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#define PIM_SSM_H
88

99
#define PIM_SSM_STANDARD_RANGE "232.0.0.0/8"
10+
#define PIM6_SSM_STANDARD_RANGE "FF30::/32"
1011

1112
struct pim_instance;
1213

pimd/pim_util.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,20 @@ int pim_is_group_224_4(struct in_addr group_addr)
129129
return prefix_match(&group_all, &group);
130130
}
131131

132+
bool pim_is_group_ff00_8(struct in6_addr group_address)
133+
{
134+
struct prefix group_all = { .family = AF_INET6,
135+
.prefixlen = 8,
136+
.u.prefix6.s6_addr = { 0xFF } };
137+
struct prefix group;
138+
139+
group.family = AF_INET6;
140+
group.u.prefix6 = group_address;
141+
group.prefixlen = IPV6_MAX_BITLEN;
142+
143+
return prefix_match(&group_all, &group);
144+
}
145+
132146
static bool pim_cisco_match(const struct filter *filter, const struct in_addr *source,
133147
const struct in_addr *group)
134148
{

pimd/pim_util.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ void pim_pkt_dump(const char *label, const uint8_t *buf, int size);
2323

2424
int pim_is_group_224_0_0_0_24(struct in_addr group_addr);
2525
int pim_is_group_224_4(struct in_addr group_addr);
26+
bool pim_is_group_ff00_8(struct in6_addr group_address);
2627
enum filter_type pim_access_list_apply(struct access_list *access, const struct in_addr *source,
2728
const struct in_addr *group);
2829
bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp, pim_addr *src);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
log commands
2+
!
3+
ip prefix-list pim-ssm permit 230.0.0.0/8
4+
!
5+
ipv6 prefix-list pim6-ssm permit ff35::/32
6+
!
7+
router pim
8+
ssm prefix-list pim-ssm
9+
exit
10+
!
11+
router pim6
12+
ssm prefix-list pim6-ssm
13+
exit
14+
!
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#!/usr/bin/env python
2+
# SPDX-License-Identifier: ISC
3+
4+
#
5+
# test_multicast_ssm_topo1.py
6+
# Part of NetDEF Topology Tests
7+
#
8+
# Copyright (c) 2025 by
9+
# Network Device Education Foundation, Inc. ("NetDEF")
10+
#
11+
12+
"""
13+
test_multicast_ssm_topo1.py: Test PIM SSM configuration.
14+
"""
15+
16+
import os
17+
import sys
18+
import json
19+
from functools import partial
20+
import re
21+
import pytest
22+
23+
# Save the Current Working Directory to find configuration files.
24+
CWD = os.path.dirname(os.path.realpath(__file__))
25+
sys.path.append(os.path.join(CWD, "../"))
26+
27+
# pylint: disable=C0413
28+
# Import topogen and topotest helpers
29+
from lib import topotest
30+
31+
# Required to instantiate the topology builder class.
32+
from lib.topogen import Topogen, TopoRouter, get_topogen
33+
from lib.topolog import logger
34+
35+
pytestmark = [pytest.mark.pimd]
36+
37+
38+
def build_topo(tgen):
39+
tgen.add_router(f"r1")
40+
41+
42+
def setup_module(mod):
43+
"Sets up the pytest environment"
44+
tgen = Topogen(build_topo, mod.__name__)
45+
tgen.start_topology()
46+
47+
tgen.gears["r1"].load_frr_config(os.path.join(CWD, f"r1/frr.conf"))
48+
tgen.start_router()
49+
50+
51+
def teardown_module():
52+
"Teardown the pytest environment"
53+
tgen = get_topogen()
54+
tgen.stop_topology()
55+
56+
57+
def test_multicast_ssm():
58+
"Test SSM group"
59+
pim_test = [
60+
{"address": "229.0.0.100", "type": "ASM"},
61+
{"address": "230.0.0.100", "type": "SSM"}
62+
]
63+
pim6_test = [
64+
{"address": "FF32::100", "type": "ASM"},
65+
{"address": "FF35::100", "type": "SSM"}
66+
]
67+
68+
tgen = get_topogen()
69+
if tgen.routers_have_failure():
70+
pytest.skip(tgen.errors)
71+
72+
router = tgen.gears["r1"]
73+
74+
for test in pim_test:
75+
output = router.vtysh_cmd(f"show ip pim group-type {test['address']} json", isjson=True)
76+
assert test["type"] == output["groupType"], "Wrong group type"
77+
78+
for test in pim6_test:
79+
output = router.vtysh_cmd(f"show ipv6 pim group-type {test['address']} json", isjson=True)
80+
assert test["type"] == output["groupType"], "Wrong group type"
81+
82+
83+
def test_memory_leak():
84+
"Run the memory leak test and report results."
85+
tgen = get_topogen()
86+
if not tgen.is_memleak_enabled():
87+
pytest.skip("Memory leak test/report is disabled")
88+
89+
tgen.report_memory_leaks()
90+
91+
92+
if __name__ == "__main__":
93+
args = ["-s"] + sys.argv[1:]
94+
sys.exit(pytest.main(args))

0 commit comments

Comments
 (0)