summaryrefslogtreecommitdiffstats
path: root/pimd
diff options
context:
space:
mode:
authorDonald Sharp <donaldsharp72@gmail.com>2024-08-22 17:32:56 +0200
committerGitHub <noreply@github.com>2024-08-22 17:32:56 +0200
commit05c17eff06536e750d43829ccded5c9e8f0f9ca4 (patch)
tree5cafbf2d7a2d501cc51f998d941ef7c11ccf300a /pimd
parentMerge pull request #16613 from donaldsharp/weight_issues (diff)
parenttests: Added new topotest for pim igmp static groups (diff)
downloadfrr-05c17eff06536e750d43829ccded5c9e8f0f9ca4.tar.xz
frr-05c17eff06536e750d43829ccded5c9e8f0f9ca4.zip
Merge pull request #16450 from nabahr/static_joins
PIM: Implement static IGMP joins without an IGMP report
Diffstat (limited to 'pimd')
-rw-r--r--pimd/pim6_cmd.c82
-rw-r--r--pimd/pim_cmd.c266
-rw-r--r--pimd/pim_iface.c166
-rw-r--r--pimd/pim_iface.h6
-rw-r--r--pimd/pim_igmp.h6
-rw-r--r--pimd/pim_memory.c1
-rw-r--r--pimd/pim_memory.h1
-rw-r--r--pimd/pim_nb.c8
-rw-r--r--pimd/pim_nb.h11
-rw-r--r--pimd/pim_nb_config.c97
-rw-r--r--pimd/pim_vty.c49
11 files changed, 578 insertions, 115 deletions
diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c
index 99f147471..f7a4e0e48 100644
--- a/pimd/pim6_cmd.c
+++ b/pimd/pim6_cmd.c
@@ -1363,45 +1363,56 @@ DEFPY_ATTR(no_ipv6_ssmpingd,
return ret;
}
-DEFPY (interface_ipv6_mld_join,
- interface_ipv6_mld_join_cmd,
- "ipv6 mld join X:X::X:X$group [X:X::X:X$source]",
+DEFPY_YANG_HIDDEN (interface_ipv6_mld_join,
+ interface_ipv6_mld_join_cmd,
+ "[no] ipv6 mld join X:X::X:X$grp [X:X::X:X]$src",
+ NO_STR
+ IPV6_STR
+ IFACE_MLD_STR
+ "MLD join multicast group\n"
+ "Multicast group address\n"
+ "Source address\n")
+{
+ nb_cli_enqueue_change(vty, ".", (!no ? NB_OP_CREATE : NB_OP_DESTROY),
+ NULL);
+ return nb_cli_apply_changes(vty, FRR_GMP_JOIN_GROUP_XPATH,
+ "frr-routing:ipv6", grp_str,
+ (src_str ? src_str : "::"));
+}
+ALIAS (interface_ipv6_mld_join,
+ interface_ipv6_mld_join_group_cmd,
+ "[no] ipv6 mld join-group X:X::X:X$grp [X:X::X:X]$src",
+ NO_STR
IPV6_STR
IFACE_MLD_STR
"MLD join multicast group\n"
"Multicast group address\n"
- "Source address\n")
-{
- char xpath[XPATH_MAXLEN];
-
- if (!IN6_IS_ADDR_MULTICAST(&group)) {
- vty_out(vty, "Invalid Multicast Address\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (source_str) {
- if (IPV6_ADDR_SAME(&source, &in6addr_any)) {
- vty_out(vty, "Bad source address %s\n", source_str);
- return CMD_WARNING_CONFIG_FAILED;
- }
- } else
- source_str = "::";
-
- snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH, "frr-routing:ipv6",
- group_str, source_str);
-
- nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
-
- return nb_cli_apply_changes(vty, NULL);
-}
-
-DEFPY (interface_no_ipv6_mld_join,
- interface_no_ipv6_mld_join_cmd,
- "no ipv6 mld join X:X::X:X$group [X:X::X:X$source]",
+ "Source address\n");
+
+DEFPY_YANG (interface_ipv6_mld_static_group,
+ interface_ipv6_mld_static_group_cmd,
+ "[no] ipv6 mld static-group X:X::X:X$grp [X:X::X:X]$src",
+ NO_STR
+ IPV6_STR
+ IFACE_MLD_STR
+ "Static multicast group\n"
+ "Multicast group address\n"
+ "Source address\n")
+{
+ nb_cli_enqueue_change(vty, ".", (!no ? NB_OP_CREATE : NB_OP_DESTROY),
+ NULL);
+ return nb_cli_apply_changes(vty, FRR_GMP_STATIC_GROUP_XPATH,
+ "frr-routing:ipv6", grp_str,
+ (src_str ? src_str : "::"));
+}
+
+DEFPY (interface_no_ipv6_mld_static_group,
+ interface_no_ipv6_mld_static_group_cmd,
+ "no ipv6 mld static-group X:X::X:X$group [X:X::X:X$source]",
NO_STR
IPV6_STR
IFACE_MLD_STR
- "MLD join multicast group\n"
+ "Static multicast group\n"
"Multicast group address\n"
"Source address\n")
{
@@ -1415,8 +1426,8 @@ DEFPY (interface_no_ipv6_mld_join,
} else
source_str = "::";
- snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH, "frr-routing:ipv6",
- group_str, source_str);
+ snprintf(xpath, sizeof(xpath), FRR_GMP_STATIC_GROUP_XPATH,
+ "frr-routing:ipv6", group_str, source_str);
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
@@ -2669,7 +2680,8 @@ void pim_cmd_init(void)
install_element(INTERFACE_NODE, &interface_ipv6_mld_cmd);
install_element(INTERFACE_NODE, &interface_no_ipv6_mld_cmd);
install_element(INTERFACE_NODE, &interface_ipv6_mld_join_cmd);
- install_element(INTERFACE_NODE, &interface_no_ipv6_mld_join_cmd);
+ install_element(INTERFACE_NODE, &interface_ipv6_mld_join_group_cmd);
+ install_element(INTERFACE_NODE, &interface_ipv6_mld_static_group_cmd);
install_element(INTERFACE_NODE, &interface_ipv6_mld_version_cmd);
install_element(INTERFACE_NODE, &interface_no_ipv6_mld_version_cmd);
install_element(INTERFACE_NODE, &interface_ipv6_mld_query_interval_cmd);
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index f57048c70..633c46966 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -682,6 +682,91 @@ static void igmp_show_interface_join(struct pim_instance *pim, struct vty *vty,
vty_json(vty, json);
}
+static void igmp_show_interface_static_group(struct pim_instance *pim,
+ struct vty *vty, bool uj)
+{
+ struct interface *ifp;
+ json_object *json = NULL;
+ json_object *json_iface = NULL;
+ json_object *json_grp = NULL;
+ json_object *json_grp_arr = NULL;
+
+ if (uj) {
+ json = json_object_new_object();
+ json_object_string_add(json, "vrf",
+ vrf_id_to_name(pim->vrf->vrf_id));
+ } else {
+ vty_out(vty,
+ "Interface Address Source Group\n");
+ }
+
+ FOR_ALL_INTERFACES (pim->vrf, ifp) {
+ struct pim_interface *pim_ifp;
+ struct listnode *node;
+ struct static_group *stgrp;
+ struct in_addr pri_addr;
+ char pri_addr_str[INET_ADDRSTRLEN];
+
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp)
+ continue;
+
+ if (!pim_ifp->static_group_list)
+ continue;
+
+ pri_addr = pim_find_primary_addr(ifp);
+ pim_inet4_dump("<pri?>", pri_addr, pri_addr_str,
+ sizeof(pri_addr_str));
+
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->static_group_list, node,
+ stgrp)) {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<grp?>", stgrp->group_addr, group_str,
+ sizeof(group_str));
+ pim_inet4_dump("<src?>", stgrp->source_addr, source_str,
+ sizeof(source_str));
+
+ if (uj) {
+ json_object_object_get_ex(json, ifp->name,
+ &json_iface);
+
+ if (!json_iface) {
+ json_iface = json_object_new_object();
+ json_object_string_add(json_iface,
+ "name",
+ ifp->name);
+ json_object_object_add(json, ifp->name,
+ json_iface);
+ json_grp_arr = json_object_new_array();
+ json_object_object_add(json_iface,
+ "groups",
+ json_grp_arr);
+ }
+
+ json_grp = json_object_new_object();
+ json_object_string_add(json_grp, "source",
+ source_str);
+ json_object_string_add(json_grp, "group",
+ group_str);
+ json_object_string_add(json_grp, "primaryAddr",
+ pri_addr_str);
+ json_object_array_add(json_grp_arr, json_grp);
+ } else {
+ vty_out(vty, "%-16s %-15s %-15s %-15s\n",
+ ifp->name, pri_addr_str, source_str,
+ group_str);
+ }
+ } /* for (pim_ifp->static_group_list) */
+
+ } /* for (iflist) */
+
+ if (uj)
+ vty_json(vty, json);
+}
+
static void igmp_show_statistics(struct pim_instance *pim, struct vty *vty,
const char *ifname, bool uj)
{
@@ -1724,6 +1809,15 @@ DEFUN (show_ip_igmp_join,
return CMD_SUCCESS;
}
+ALIAS (show_ip_igmp_join,
+ show_ip_igmp_join_group_cmd,
+ "show ip igmp [vrf NAME] join-group [json]",
+ SHOW_STR
+ IP_STR
+ IGMP_STR
+ VRF_CMD_HELP_STR
+ "IGMP static join information\n"
+ JSON_STR);
DEFUN (show_ip_igmp_join_vrf_all,
show_ip_igmp_join_vrf_all_cmd,
@@ -1756,6 +1850,69 @@ DEFUN (show_ip_igmp_join_vrf_all,
return CMD_SUCCESS;
}
+ALIAS (show_ip_igmp_join_vrf_all,
+ show_ip_igmp_join_group_vrf_all_cmd,
+ "show ip igmp vrf all join-group [json]",
+ SHOW_STR
+ IP_STR
+ IGMP_STR
+ VRF_CMD_HELP_STR
+ "IGMP static join information\n"
+ JSON_STR);
+
+DEFUN (show_ip_igmp_static_group,
+ show_ip_igmp_static_group_cmd,
+ "show ip igmp [vrf NAME] static-group [json]",
+ SHOW_STR
+ IP_STR
+ IGMP_STR
+ VRF_CMD_HELP_STR
+ "Static group information\n"
+ JSON_STR)
+{
+ int idx = 2;
+ bool uj = use_json(argc, argv);
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx, uj);
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ igmp_show_interface_static_group(vrf->info, vty, uj);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_igmp_static_group_vrf_all,
+ show_ip_igmp_static_group_vrf_all_cmd,
+ "show ip igmp vrf all static-group [json]",
+ SHOW_STR
+ IP_STR
+ IGMP_STR
+ VRF_CMD_HELP_STR
+ "Static group information\n"
+ JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+ struct vrf *vrf;
+ bool first = true;
+
+ if (uj)
+ vty_out(vty, "{ ");
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ if (uj) {
+ if (!first)
+ vty_out(vty, ", ");
+ vty_out(vty, " \"%s\": ", vrf->name);
+ first = false;
+ } else
+ vty_out(vty, "VRF: %s\n", vrf->name);
+ igmp_show_interface_static_group(vrf->info, vty, uj);
+ }
+ if (uj)
+ vty_out(vty, "}\n");
+
+ return CMD_SUCCESS;
+}
DEFPY(show_ip_igmp_groups,
show_ip_igmp_groups_cmd,
@@ -4924,71 +5081,47 @@ DEFUN (interface_no_ip_igmp,
"frr-routing:ipv4");
}
-DEFUN (interface_ip_igmp_join,
- interface_ip_igmp_join_cmd,
- "ip igmp join A.B.C.D [A.B.C.D]",
- IP_STR
- IFACE_IGMP_STR
- "IGMP join multicast group\n"
- "Multicast group address\n"
- "Source address\n")
+DEFPY_YANG_HIDDEN (interface_ip_igmp_join,
+ interface_ip_igmp_join_cmd,
+ "[no] ip igmp join A.B.C.D$grp [A.B.C.D]$src",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR
+ "IGMP join multicast group\n"
+ "Multicast group address\n"
+ "Source address\n")
{
- int idx_group = 3;
- int idx_source = 4;
- const char *source_str;
- char xpath[XPATH_MAXLEN];
-
- if (argc == 5) {
- source_str = argv[idx_source]->arg;
-
- if (strcmp(source_str, "0.0.0.0") == 0) {
- vty_out(vty, "Bad source address %s\n",
- argv[idx_source]->arg);
- return CMD_WARNING_CONFIG_FAILED;
- }
- } else
- source_str = "0.0.0.0";
-
- snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH,
- "frr-routing:ipv4", argv[idx_group]->arg, source_str);
-
- nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
-
- return nb_cli_apply_changes(vty, NULL);
+ nb_cli_enqueue_change(vty, ".", (!no ? NB_OP_CREATE : NB_OP_DESTROY),
+ NULL);
+ return nb_cli_apply_changes(vty, FRR_GMP_JOIN_GROUP_XPATH,
+ "frr-routing:ipv4", grp_str,
+ (src_str ? src_str : "0.0.0.0"));
}
-
-DEFUN (interface_no_ip_igmp_join,
- interface_no_ip_igmp_join_cmd,
- "no ip igmp join A.B.C.D [A.B.C.D]",
- NO_STR
- IP_STR
- IFACE_IGMP_STR
- "IGMP join multicast group\n"
- "Multicast group address\n"
- "Source address\n")
-{
- int idx_group = 4;
- int idx_source = 5;
- const char *source_str;
- char xpath[XPATH_MAXLEN];
-
- if (argc == 6) {
- source_str = argv[idx_source]->arg;
-
- if (strcmp(source_str, "0.0.0.0") == 0) {
- vty_out(vty, "Bad source address %s\n",
- argv[idx_source]->arg);
- return CMD_WARNING_CONFIG_FAILED;
- }
- } else
- source_str = "0.0.0.0";
-
- snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH,
- "frr-routing:ipv4", argv[idx_group]->arg, source_str);
-
- nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
-
- return nb_cli_apply_changes(vty, NULL);
+ALIAS(interface_ip_igmp_join,
+ interface_ip_igmp_join_group_cmd,
+ "[no] ip igmp join-group A.B.C.D$grp [A.B.C.D]$src",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR
+ "IGMP join multicast group\n"
+ "Multicast group address\n"
+ "Source address\n");
+
+DEFPY_YANG (interface_ip_igmp_static_group,
+ interface_ip_igmp_static_group_cmd,
+ "[no] ip igmp static-group A.B.C.D$grp [A.B.C.D]$src",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR
+ "Static multicast group\n"
+ "Multicast group address\n"
+ "Source address\n")
+{
+ nb_cli_enqueue_change(vty, ".", (!no ? NB_OP_CREATE : NB_OP_DESTROY),
+ NULL);
+ return nb_cli_apply_changes(vty, FRR_GMP_STATIC_GROUP_XPATH,
+ "frr-routing:ipv4", grp_str,
+ (src_str ? src_str : "0.0.0.0"));
}
DEFUN (interface_ip_igmp_query_interval,
@@ -8420,7 +8553,8 @@ void pim_cmd_init(void)
install_element(INTERFACE_NODE, &interface_ip_igmp_cmd);
install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd);
install_element(INTERFACE_NODE, &interface_ip_igmp_join_cmd);
- install_element(INTERFACE_NODE, &interface_no_ip_igmp_join_cmd);
+ install_element(INTERFACE_NODE, &interface_ip_igmp_join_group_cmd);
+ install_element(INTERFACE_NODE, &interface_ip_igmp_static_group_cmd);
install_element(INTERFACE_NODE, &interface_ip_igmp_version_cmd);
install_element(INTERFACE_NODE, &interface_no_ip_igmp_version_cmd);
install_element(INTERFACE_NODE, &interface_ip_igmp_query_interval_cmd);
@@ -8480,7 +8614,11 @@ void pim_cmd_init(void)
install_element(VIEW_NODE, &show_ip_igmp_interface_cmd);
install_element(VIEW_NODE, &show_ip_igmp_interface_vrf_all_cmd);
install_element(VIEW_NODE, &show_ip_igmp_join_cmd);
+ install_element(VIEW_NODE, &show_ip_igmp_join_group_cmd);
install_element(VIEW_NODE, &show_ip_igmp_join_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_igmp_join_group_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_igmp_static_group_cmd);
+ install_element(VIEW_NODE, &show_ip_igmp_static_group_vrf_all_cmd);
install_element(VIEW_NODE, &show_ip_igmp_groups_cmd);
install_element(VIEW_NODE, &show_ip_igmp_groups_vrf_all_cmd);
install_element(VIEW_NODE, &show_ip_igmp_groups_retransmissions_cmd);
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index cdcca0ebe..45a2435ae 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -37,10 +37,12 @@
#include "pim_jp_agg.h"
#include "pim_igmp_join.h"
#include "pim_vxlan.h"
+#include "pim_tib.h"
#include "pim6_mld.h"
static void pim_if_gm_join_del_all(struct interface *ifp);
+static void pim_if_static_group_del_all(struct interface *ifp);
static int gm_join_sock(const char *ifname, ifindex_t ifindex,
pim_addr group_addr, pim_addr source_addr,
@@ -144,6 +146,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool gm, bool pim,
pim_ifp->gm_enable = gm;
pim_ifp->gm_join_list = NULL;
+ pim_ifp->static_group_list = NULL;
pim_ifp->pim_neighbor_list = NULL;
pim_ifp->upstream_switch_list = NULL;
pim_ifp->pim_generation_id = 0;
@@ -188,9 +191,11 @@ void pim_if_delete(struct interface *ifp)
assert(pim_ifp);
pim_ifp->pim->mcast_if_count--;
- if (pim_ifp->gm_join_list) {
+ if (pim_ifp->gm_join_list)
pim_if_gm_join_del_all(ifp);
- }
+
+ if (pim_ifp->static_group_list)
+ pim_if_static_group_del_all(ifp);
pim_ifchannel_delete_all(ifp);
#if PIM_IPV == 4
@@ -1218,6 +1223,11 @@ static void gm_join_free(struct gm_join *ij)
XFREE(MTYPE_PIM_IGMP_JOIN, ij);
}
+static void static_group_free(struct static_group *stgrp)
+{
+ XFREE(MTYPE_PIM_STATIC_GROUP, stgrp);
+}
+
static struct gm_join *gm_join_find(struct list *join_list, pim_addr group_addr,
pim_addr source_addr)
{
@@ -1232,7 +1242,25 @@ static struct gm_join *gm_join_find(struct list *join_list, pim_addr group_addr,
return ij;
}
- return 0;
+ return NULL;
+}
+
+static struct static_group *static_group_find(struct list *static_group_list,
+ pim_addr group_addr,
+ pim_addr source_addr)
+{
+ struct listnode *node;
+ struct static_group *stgrp;
+
+ assert(static_group_list);
+
+ for (ALL_LIST_ELEMENTS_RO(static_group_list, node, stgrp)) {
+ if ((!pim_addr_cmp(group_addr, stgrp->group_addr)) &&
+ (!pim_addr_cmp(source_addr, stgrp->source_addr)))
+ return stgrp;
+ }
+
+ return NULL;
}
static int gm_join_sock(const char *ifname, ifindex_t ifindex,
@@ -1296,6 +1324,34 @@ static struct gm_join *gm_join_new(struct interface *ifp, pim_addr group_addr,
return ij;
}
+static struct static_group *static_group_new(struct interface *ifp,
+ pim_addr group_addr,
+ pim_addr source_addr)
+{
+ struct pim_interface *pim_ifp;
+ struct static_group *stgrp;
+ pim_sgaddr sg;
+
+ pim_ifp = ifp->info;
+ assert(pim_ifp);
+
+ stgrp = XCALLOC(MTYPE_PIM_STATIC_GROUP, sizeof(*stgrp));
+
+ stgrp->group_addr = group_addr;
+ stgrp->source_addr = source_addr;
+ stgrp->oilp = NULL;
+
+ memset(&sg, 0, sizeof(sg));
+ sg.src = source_addr;
+ sg.grp = group_addr;
+
+ tib_sg_gm_join(pim_ifp->pim, sg, ifp, &(stgrp->oilp));
+
+ listnode_add(pim_ifp->static_group_list, stgrp);
+
+ return stgrp;
+}
+
ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr,
pim_addr source_addr)
{
@@ -1382,7 +1438,6 @@ int pim_if_gm_join_del(struct interface *ifp, pim_addr group_addr,
return 0;
}
-__attribute__((unused))
static void pim_if_gm_join_del_all(struct interface *ifp)
{
struct pim_interface *pim_ifp;
@@ -1404,6 +1459,109 @@ static void pim_if_gm_join_del_all(struct interface *ifp)
pim_if_gm_join_del(ifp, ij->group_addr, ij->source_addr);
}
+ferr_r pim_if_static_group_add(struct interface *ifp, pim_addr group_addr,
+ pim_addr source_addr)
+{
+ struct pim_interface *pim_ifp;
+ struct static_group *stgrp;
+
+ pim_ifp = ifp->info;
+ if (!pim_ifp) {
+ return ferr_cfg_invalid("multicast not enabled on interface %s",
+ ifp->name);
+ }
+
+ if (!pim_ifp->static_group_list) {
+ pim_ifp->static_group_list = list_new();
+ pim_ifp->static_group_list->del =
+ (void (*)(void *))static_group_free;
+ }
+
+ stgrp = static_group_find(pim_ifp->static_group_list, group_addr,
+ source_addr);
+
+ /* This interface has already been configured with this static group
+ */
+ if (stgrp)
+ return ferr_ok();
+
+ (void)static_group_new(ifp, group_addr, source_addr);
+
+ if (PIM_DEBUG_GM_EVENTS) {
+ zlog_debug("%s: Added static group (S,G)=(%pPA,%pPA) on interface %s",
+ __func__, &source_addr, &group_addr, ifp->name);
+ }
+
+ return ferr_ok();
+}
+
+int pim_if_static_group_del(struct interface *ifp, pim_addr group_addr,
+ pim_addr source_addr)
+{
+ struct pim_interface *pim_ifp;
+ struct static_group *stgrp;
+ pim_sgaddr sg;
+
+ pim_ifp = ifp->info;
+ if (!pim_ifp) {
+ zlog_warn("%s: multicast not enabled on interface %s", __func__,
+ ifp->name);
+ return -1;
+ }
+
+ if (!pim_ifp->static_group_list) {
+ zlog_warn("%s: no static groups on interface %s", __func__,
+ ifp->name);
+ return -2;
+ }
+
+ stgrp = static_group_find(pim_ifp->static_group_list, group_addr,
+ source_addr);
+ if (!stgrp) {
+ zlog_warn("%s: could not find static group %pPAs source %pPAs on interface %s",
+ __func__, &group_addr, &source_addr, ifp->name);
+ return -3;
+ }
+
+ memset(&sg, 0, sizeof(sg));
+ sg.src = source_addr;
+ sg.grp = group_addr;
+
+ tib_sg_gm_prune(pim_ifp->pim, sg, ifp, &(stgrp->oilp));
+
+ listnode_delete(pim_ifp->static_group_list, stgrp);
+ static_group_free(stgrp);
+ if (listcount(pim_ifp->static_group_list) < 1) {
+ list_delete(&pim_ifp->static_group_list);
+ pim_ifp->static_group_list = 0;
+ }
+
+ return 0;
+}
+
+static void pim_if_static_group_del_all(struct interface *ifp)
+{
+ struct pim_interface *pim_ifp;
+ struct listnode *node;
+ struct listnode *nextnode;
+ struct static_group *stgrp;
+
+ pim_ifp = ifp->info;
+ if (!pim_ifp) {
+ zlog_warn("%s: multicast not enabled on interface %s", __func__,
+ ifp->name);
+ return;
+ }
+
+ if (!pim_ifp->static_group_list)
+ return;
+
+ for (ALL_LIST_ELEMENTS(pim_ifp->static_group_list, node, nextnode,
+ stgrp))
+ pim_if_static_group_del(ifp, stgrp->group_addr,
+ stgrp->source_addr);
+}
+
/*
RFC 4601
diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h
index 0312f719d..4d2037966 100644
--- a/pimd/pim_iface.h
+++ b/pimd/pim_iface.h
@@ -98,6 +98,7 @@ struct pim_interface {
*/
struct list *gm_socket_list; /* list of struct IGMP or MLD sock */
struct list *gm_join_list; /* list of struct IGMP or MLD join */
+ struct list *static_group_list; /* list of struct static group */
struct list *gm_group_list; /* list of struct IGMP or MLD group */
struct hash *gm_group_hash;
@@ -222,6 +223,11 @@ ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr,
int pim_if_gm_join_del(struct interface *ifp, pim_addr group_addr,
pim_addr source_addr);
+ferr_r pim_if_static_group_add(struct interface *ifp, pim_addr group_addr,
+ pim_addr source_addr);
+int pim_if_static_group_del(struct interface *ifp, pim_addr group_addr,
+ pim_addr source_addr);
+
void pim_if_update_could_assert(struct interface *ifp);
void pim_if_assert_on_neighbor_down(struct interface *ifp, pim_addr neigh_addr);
diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h
index a1f19b3c6..de0ec01a6 100644
--- a/pimd/pim_igmp.h
+++ b/pimd/pim_igmp.h
@@ -58,6 +58,12 @@ struct gm_join {
time_t sock_creation;
};
+struct static_group {
+ pim_addr group_addr;
+ pim_addr source_addr;
+ struct channel_oil *oilp;
+};
+
struct gm_sock {
int fd;
struct interface *interface;
diff --git a/pimd/pim_memory.c b/pimd/pim_memory.c
index 604e24482..2c35bc647 100644
--- a/pimd/pim_memory.c
+++ b/pimd/pim_memory.c
@@ -14,6 +14,7 @@ DEFINE_MGROUP(PIMD, "pimd");
DEFINE_MTYPE(PIMD, PIM_CHANNEL_OIL, "PIM SSM (S,G) channel OIL");
DEFINE_MTYPE(PIMD, PIM_INTERFACE, "PIM interface");
DEFINE_MTYPE(PIMD, PIM_IGMP_JOIN, "PIM interface IGMP static join");
+DEFINE_MTYPE(PIMD, PIM_STATIC_GROUP, "PIM interface IGMP static group");
DEFINE_MTYPE(PIMD, PIM_IGMP_SOCKET, "PIM interface IGMP socket");
DEFINE_MTYPE(PIMD, PIM_IGMP_GROUP, "PIM interface IGMP group");
DEFINE_MTYPE(PIMD, PIM_IGMP_GROUP_SOURCE, "PIM interface IGMP source");
diff --git a/pimd/pim_memory.h b/pimd/pim_memory.h
index 353e09a71..b44d3e191 100644
--- a/pimd/pim_memory.h
+++ b/pimd/pim_memory.h
@@ -13,6 +13,7 @@ DECLARE_MGROUP(PIMD);
DECLARE_MTYPE(PIM_CHANNEL_OIL);
DECLARE_MTYPE(PIM_INTERFACE);
DECLARE_MTYPE(PIM_IGMP_JOIN);
+DECLARE_MTYPE(PIM_STATIC_GROUP);
DECLARE_MTYPE(PIM_IGMP_SOCKET);
DECLARE_MTYPE(PIM_IGMP_GROUP);
DECLARE_MTYPE(PIM_IGMP_GROUP_SOURCE);
diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c
index 72b5bdefc..c154c18af 100644
--- a/pimd/pim_nb.c
+++ b/pimd/pim_nb.c
@@ -441,6 +441,13 @@ const struct frr_yang_module_info frr_gmp_info = {
}
},
{
+ .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/join-group",
+ .cbs = {
+ .create = lib_interface_gmp_address_family_join_group_create,
+ .destroy = lib_interface_gmp_address_family_join_group_destroy,
+ }
+ },
+ {
.xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/static-group",
.cbs = {
.create = lib_interface_gmp_address_family_static_group_create,
@@ -452,4 +459,3 @@ const struct frr_yang_module_info frr_gmp_info = {
},
}
};
-
diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h
index 3c7ab49ab..fc4c11cea 100644
--- a/pimd/pim_nb.h
+++ b/pimd/pim_nb.h
@@ -182,6 +182,10 @@ int lib_interface_gmp_address_family_last_member_query_interval_modify(
struct nb_cb_modify_args *args);
int lib_interface_gmp_address_family_robustness_variable_modify(
struct nb_cb_modify_args *args);
+int lib_interface_gmp_address_family_join_group_create(
+ struct nb_cb_create_args *args);
+int lib_interface_gmp_address_family_join_group_destroy(
+ struct nb_cb_destroy_args *args);
int lib_interface_gmp_address_family_static_group_create(
struct nb_cb_create_args *args);
int lib_interface_gmp_address_family_static_group_destroy(
@@ -219,8 +223,11 @@ int routing_control_plane_protocols_name_validate(
"./frr-gmp:gmp/address-family[address-family='%s']"
#define FRR_GMP_ENABLE_XPATH \
"%s/frr-gmp:gmp/address-family[address-family='%s']/enable"
-#define FRR_GMP_JOIN_XPATH \
- "./frr-gmp:gmp/address-family[address-family='%s']/" \
+#define FRR_GMP_JOIN_GROUP_XPATH \
+ "./frr-gmp:gmp/address-family[address-family='%s']/" \
+ "join-group[group-addr='%s'][source-addr='%s']"
+#define FRR_GMP_STATIC_GROUP_XPATH \
+ "./frr-gmp:gmp/address-family[address-family='%s']/" \
"static-group[group-addr='%s'][source-addr='%s']"
#endif /* _FRR_PIM_NB_H_ */
diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c
index bc7338ce1..037bfea78 100644
--- a/pimd/pim_nb_config.c
+++ b/pimd/pim_nb_config.c
@@ -2989,9 +2989,9 @@ int lib_interface_gmp_address_family_robustness_variable_modify(
}
/*
- * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/static-group
+ * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/join-group
*/
-int lib_interface_gmp_address_family_static_group_create(
+int lib_interface_gmp_address_family_join_group_create(
struct nb_cb_create_args *args)
{
struct interface *ifp;
@@ -3049,7 +3049,7 @@ int lib_interface_gmp_address_family_static_group_create(
return NB_OK;
}
-int lib_interface_gmp_address_family_static_group_destroy(
+int lib_interface_gmp_address_family_join_group_destroy(
struct nb_cb_destroy_args *args)
{
struct interface *ifp;
@@ -3084,3 +3084,94 @@ int lib_interface_gmp_address_family_static_group_destroy(
return NB_OK;
}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/static-group
+ */
+int lib_interface_gmp_address_family_static_group_create(
+ struct nb_cb_create_args *args)
+{
+ struct interface *ifp;
+ pim_addr source_addr;
+ pim_addr group_addr;
+ int result;
+ const char *ifp_name;
+ const struct lyd_node *if_dnode;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ if_dnode = yang_dnode_get_parent(args->dnode, "interface");
+ if (!is_pim_interface(if_dnode)) {
+ ifp_name = yang_dnode_get_string(if_dnode, "name");
+ snprintf(args->errmsg, args->errmsg_len,
+ "multicast not enabled on interface %s",
+ ifp_name);
+ return NB_ERR_VALIDATION;
+ }
+
+ yang_dnode_get_pimaddr(&group_addr, args->dnode, "./group-addr");
+#if PIM_IPV == 4
+ if (pim_is_group_224_0_0_0_24(group_addr)) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "Groups within 224.0.0.0/24 are reserved and cannot be joined");
+ return NB_ERR_VALIDATION;
+ }
+#else
+ if (ipv6_mcast_reserved(&group_addr)) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "Groups within ffx2::/16 are reserved and cannot be joined");
+ return NB_ERR_VALIDATION;
+ }
+#endif
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ yang_dnode_get_pimaddr(&source_addr, args->dnode,
+ "./source-addr");
+ yang_dnode_get_pimaddr(&group_addr, args->dnode, "./group-addr");
+ result = pim_if_static_group_add(ifp, group_addr, source_addr);
+ if (result) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "Failure adding static group");
+ return NB_ERR_INCONSISTENCY;
+ }
+ }
+ return NB_OK;
+}
+
+int lib_interface_gmp_address_family_static_group_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct interface *ifp;
+ pim_addr source_addr;
+ pim_addr group_addr;
+ int result;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ yang_dnode_get_pimaddr(&source_addr, args->dnode,
+ "./source-addr");
+ yang_dnode_get_pimaddr(&group_addr, args->dnode, "./group-addr");
+ result = pim_if_static_group_del(ifp, group_addr, source_addr);
+
+ if (result) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "%% Failure removing static group %pPAs %pPAs on interface %s: %d",
+ &source_addr, &group_addr, ifp->name, result);
+
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ break;
+ }
+
+ return NB_OK;
+}
diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c
index 1910a6849..9cf4bb3e8 100644
--- a/pimd/pim_vty.c
+++ b/pimd/pim_vty.c
@@ -306,21 +306,38 @@ static int gm_config_write(struct vty *vty, int writes,
++writes;
}
- /* IF ip igmp join */
+ /* IF ip igmp join-group */
if (pim_ifp->gm_join_list) {
struct listnode *node;
struct gm_join *ij;
for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_join_list, node, ij)) {
if (pim_addr_is_any(ij->source_addr))
- vty_out(vty, " ip igmp join %pPAs\n",
+ vty_out(vty, " ip igmp join-group %pPAs\n",
&ij->group_addr);
else
- vty_out(vty, " ip igmp join %pPAs %pPAs\n",
+ vty_out(vty, " ip igmp join-group %pPAs %pPAs\n",
&ij->group_addr, &ij->source_addr);
++writes;
}
}
+ /* IF ip igmp static-group */
+ if (pim_ifp->static_group_list) {
+ struct listnode *node;
+ struct static_group *stgrp;
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->static_group_list, node,
+ stgrp)) {
+ if (pim_addr_is_any(stgrp->source_addr))
+ vty_out(vty, " ip igmp static-group %pPAs\n",
+ &stgrp->group_addr);
+ else
+ vty_out(vty,
+ " ip igmp static-group %pPAs %pPAs\n",
+ &stgrp->group_addr, &stgrp->source_addr);
+ ++writes;
+ }
+ }
+
return writes;
}
#else
@@ -358,21 +375,41 @@ static int gm_config_write(struct vty *vty, int writes,
vty_out(vty, " ipv6 mld last-member-query-interval %d\n",
pim_ifp->gm_specific_query_max_response_time_dsec);
- /* IF ipv6 mld join */
+ /* IF ipv6 mld join-group */
if (pim_ifp->gm_join_list) {
struct listnode *node;
struct gm_join *ij;
+
for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_join_list, node, ij)) {
if (pim_addr_is_any(ij->source_addr))
- vty_out(vty, " ipv6 mld join %pPAs\n",
+ vty_out(vty, " ipv6 mld join-group %pPAs\n",
&ij->group_addr);
else
- vty_out(vty, " ipv6 mld join %pPAs %pPAs\n",
+ vty_out(vty,
+ " ipv6 mld join-group %pPAs %pPAs\n",
&ij->group_addr, &ij->source_addr);
++writes;
}
}
+ /* IF ipv6 mld static-group */
+ if (pim_ifp->static_group_list) {
+ struct listnode *node;
+ struct static_group *stgrp;
+
+ for (ALL_LIST_ELEMENTS_RO(pim_ifp->static_group_list, node,
+ stgrp)) {
+ if (pim_addr_is_any(stgrp->source_addr))
+ vty_out(vty, " ipv6 mld static-group %pPAs\n",
+ &stgrp->group_addr);
+ else
+ vty_out(vty,
+ " ipv6 mld static-group %pPAs %pPAs\n",
+ &stgrp->group_addr, &stgrp->source_addr);
+ ++writes;
+ }
+ }
+
return writes;
}
#endif