forked from Mirror/frr
pimd, yang: Implement igmp static-group command
This will add a static IGMP group that does not rely on an underlying socket join which sends traffic to the cpu unneccesarily. Instead, the groups are joined directly without any IGMP interactions. New command is under interfaces, 'ip igmp static-group ...'. Added an alias for 'ip igmp join ...' to 'ip igmp join-group'. Moved IGMP join groups to new yang list "join-group" and reused the "static-group" list for the IGMP static groups. Signed-off-by: Nathan Bahr <nbahr@atcorp.com>
This commit is contained in:
parent
aa9d66e922
commit
0cb1bf7873
|
@ -1363,46 +1363,57 @@ 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]",
|
||||
IPV6_STR
|
||||
IFACE_MLD_STR
|
||||
"MLD join multicast group\n"
|
||||
"Multicast group address\n"
|
||||
"Source address\n")
|
||||
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")
|
||||
{
|
||||
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);
|
||||
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 : "::"));
|
||||
}
|
||||
|
||||
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]",
|
||||
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");
|
||||
|
||||
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
|
||||
"Static multicast group\n"
|
||||
"Multicast group address\n"
|
||||
"Source address\n")
|
||||
{
|
||||
char xpath[XPATH_MAXLEN];
|
||||
|
@ -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);
|
||||
|
|
262
pimd/pim_cmd.c
262
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,
|
||||
|
@ -4890,71 +5047,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"));
|
||||
}
|
||||
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");
|
||||
|
||||
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")
|
||||
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")
|
||||
{
|
||||
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);
|
||||
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,
|
||||
|
@ -8268,7 +8401,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);
|
||||
|
@ -8328,7 +8462,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);
|
||||
|
|
166
pimd/pim_iface.c
166
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)
|
||||
{
|
||||
|
@ -1379,7 +1435,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;
|
||||
|
@ -1401,6 +1456,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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -413,6 +413,13 @@ const struct frr_yang_module_info frr_gmp_info = {
|
|||
.modify = lib_interface_gmp_address_family_robustness_variable_modify,
|
||||
}
|
||||
},
|
||||
{
|
||||
.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 = {
|
||||
|
@ -425,4 +432,3 @@ const struct frr_yang_module_info frr_gmp_info = {
|
|||
},
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -175,6 +175,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(
|
||||
|
@ -212,8 +216,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_ */
|
||||
|
|
|
@ -2821,9 +2821,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;
|
||||
|
@ -2881,7 +2881,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;
|
||||
|
@ -2916,3 +2916,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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -147,11 +147,28 @@ module frr-gmp {
|
|||
expected packet loss on a network.";
|
||||
}
|
||||
|
||||
list join-group {
|
||||
key "group-addr source-addr";
|
||||
description
|
||||
"A static GMP join, (*,G) or (S,G).
|
||||
The version of IGMP must be 3 to support (S,G).";
|
||||
|
||||
leaf group-addr {
|
||||
type rt-types:ip-multicast-group-address;
|
||||
description
|
||||
"Multicast group address.";
|
||||
}
|
||||
leaf source-addr {
|
||||
type inet:ip-address;
|
||||
description
|
||||
"Multicast source address.";
|
||||
}
|
||||
}
|
||||
|
||||
list static-group {
|
||||
key "group-addr source-addr";
|
||||
description
|
||||
"A static multicast route, (*,G) or (S,G).
|
||||
The version of IGMP must be 3 to support (S,G).";
|
||||
"A static multicast group without GMP, (*,G) or (S,G).";
|
||||
|
||||
leaf group-addr {
|
||||
type rt-types:ip-multicast-group-address;
|
||||
|
|
Loading…
Reference in a new issue