mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
pimd: add proxy join/prune functionality
Use existing igmp static join infrastructure. Add an enum to distinguish static from proxy joins. Signed-off-by: Barry A. Trent <barry.trent@atcorp.com>
This commit is contained in:
parent
9b68853e0d
commit
f4d3222d10
|
@ -1294,7 +1294,8 @@ static int gm_join_sock(const char *ifname, ifindex_t ifindex,
|
|||
}
|
||||
|
||||
static struct gm_join *gm_join_new(struct interface *ifp, pim_addr group_addr,
|
||||
pim_addr source_addr)
|
||||
pim_addr source_addr,
|
||||
enum gm_join_type join_type)
|
||||
{
|
||||
struct pim_interface *pim_ifp;
|
||||
struct gm_join *ij;
|
||||
|
@ -1317,6 +1318,7 @@ static struct gm_join *gm_join_new(struct interface *ifp, pim_addr group_addr,
|
|||
ij->sock_fd = join_fd;
|
||||
ij->group_addr = group_addr;
|
||||
ij->source_addr = source_addr;
|
||||
ij->join_type = join_type;
|
||||
ij->sock_creation = pim_time_monotonic_sec();
|
||||
|
||||
listnode_add(pim_ifp->gm_join_list, ij);
|
||||
|
@ -1353,7 +1355,7 @@ static struct static_group *static_group_new(struct interface *ifp,
|
|||
}
|
||||
|
||||
ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr,
|
||||
pim_addr source_addr)
|
||||
pim_addr source_addr, enum gm_join_type join_type)
|
||||
{
|
||||
struct pim_interface *pim_ifp;
|
||||
struct gm_join *ij;
|
||||
|
@ -1375,10 +1377,13 @@ ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr,
|
|||
* group
|
||||
*/
|
||||
if (ij) {
|
||||
/* turn an existing join into a "both" join */
|
||||
if (ij->join_type != join_type)
|
||||
ij->join_type = GM_JOIN_BOTH;
|
||||
return ferr_ok();
|
||||
}
|
||||
|
||||
if (!gm_join_new(ifp, group_addr, source_addr)) {
|
||||
if (!gm_join_new(ifp, group_addr, source_addr, join_type)) {
|
||||
return ferr_cfg_invalid("can't join (%pPA,%pPA) on interface %s",
|
||||
&source_addr, &group_addr, ifp->name);
|
||||
}
|
||||
|
@ -1394,7 +1399,7 @@ 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)
|
||||
pim_addr source_addr, enum gm_join_type join_type)
|
||||
{
|
||||
struct pim_interface *pim_ifp;
|
||||
struct gm_join *ij;
|
||||
|
@ -1420,6 +1425,20 @@ int pim_if_gm_join_del(struct interface *ifp, pim_addr group_addr,
|
|||
return -3;
|
||||
}
|
||||
|
||||
if (ij->join_type != join_type) {
|
||||
if (ij->join_type != GM_JOIN_BOTH) {
|
||||
zlog_warn("%s: wrong " GM
|
||||
" gm_join_type %pPAs source %pPAs on interface %s",
|
||||
__func__, &group_addr, &source_addr,
|
||||
ifp->name);
|
||||
return -4;
|
||||
}
|
||||
/* drop back to a single join type from current setting of GM_JOIN_BOTH */
|
||||
ij->join_type = (join_type == GM_JOIN_STATIC ? GM_JOIN_PROXY
|
||||
: GM_JOIN_STATIC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (close(ij->sock_fd)) {
|
||||
zlog_warn(
|
||||
"%s: failure closing sock_fd=%d for " GM
|
||||
|
@ -1456,7 +1475,8 @@ static void pim_if_gm_join_del_all(struct interface *ifp)
|
|||
return;
|
||||
|
||||
for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node, nextnode, ij))
|
||||
pim_if_gm_join_del(ifp, ij->group_addr, ij->source_addr);
|
||||
pim_if_gm_join_del(ifp, ij->group_addr, ij->source_addr,
|
||||
GM_JOIN_STATIC);
|
||||
}
|
||||
|
||||
ferr_r pim_if_static_group_add(struct interface *ifp, pim_addr group_addr,
|
||||
|
@ -1562,6 +1582,55 @@ static void pim_if_static_group_del_all(struct interface *ifp)
|
|||
stgrp->source_addr);
|
||||
}
|
||||
|
||||
void pim_if_gm_proxy_init(struct pim_instance *pim, struct interface *oif)
|
||||
{
|
||||
struct interface *ifp;
|
||||
|
||||
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
||||
struct pim_interface *pim_ifp = ifp->info;
|
||||
struct listnode *source_node, *group_node;
|
||||
struct gm_group *group;
|
||||
struct gm_source *src;
|
||||
|
||||
if (!pim_ifp)
|
||||
continue;
|
||||
|
||||
if (ifp == oif) /* skip the source interface */
|
||||
continue;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, group_node,
|
||||
group)) {
|
||||
for (ALL_LIST_ELEMENTS_RO(group->group_source_list,
|
||||
source_node, src)) {
|
||||
pim_if_gm_join_add(oif, group->group_addr,
|
||||
src->source_addr,
|
||||
GM_JOIN_PROXY);
|
||||
}
|
||||
}
|
||||
} /* scan interfaces */
|
||||
}
|
||||
|
||||
void pim_if_gm_proxy_finis(struct pim_instance *pim, struct interface *ifp)
|
||||
{
|
||||
struct pim_interface *pim_ifp = ifp->info;
|
||||
struct listnode *join_node;
|
||||
struct listnode *next_join_node;
|
||||
struct gm_join *join;
|
||||
|
||||
if (!pim_ifp) {
|
||||
zlog_warn("%s: multicast not enabled on interface %s", __func__,
|
||||
ifp->name);
|
||||
return;
|
||||
}
|
||||
|
||||
for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, join_node, next_join_node,
|
||||
join)) {
|
||||
if (join)
|
||||
pim_if_gm_join_del(ifp, join->group_addr,
|
||||
join->source_addr, GM_JOIN_PROXY);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
RFC 4601
|
||||
|
||||
|
|
|
@ -220,9 +220,11 @@ int pim_if_t_override_msec(struct interface *ifp);
|
|||
pim_addr pim_find_primary_addr(struct interface *ifp);
|
||||
|
||||
ferr_r pim_if_gm_join_add(struct interface *ifp, pim_addr group_addr,
|
||||
pim_addr source_addr);
|
||||
pim_addr source_addr, enum gm_join_type join_type);
|
||||
int pim_if_gm_join_del(struct interface *ifp, pim_addr group_addr,
|
||||
pim_addr source_addr);
|
||||
pim_addr source_addr, enum gm_join_type join_type);
|
||||
void pim_if_gm_proxy_init(struct pim_instance *pim, struct interface *oif);
|
||||
void pim_if_gm_proxy_finis(struct pim_instance *pim, struct interface *ifp);
|
||||
|
||||
ferr_r pim_if_static_group_add(struct interface *ifp, pim_addr group_addr,
|
||||
pim_addr source_addr);
|
||||
|
|
|
@ -213,15 +213,17 @@ void igmp_source_forward_stop(struct gm_source *source)
|
|||
IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
|
||||
}
|
||||
|
||||
group = source->source_group;
|
||||
pim_oif = group->interface->info;
|
||||
|
||||
/* Prevent IGMP interface from removing multicast route multiple
|
||||
times */
|
||||
if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
|
||||
tib_sg_proxy_join_prune_check(pim_oif->pim, sg,
|
||||
group->interface, false);
|
||||
return;
|
||||
}
|
||||
|
||||
group = source->source_group;
|
||||
pim_oif = group->interface->info;
|
||||
|
||||
tib_sg_gm_prune(pim_oif->pim, sg, group->interface,
|
||||
&source->source_channel_oil);
|
||||
IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
|
||||
|
|
|
@ -51,10 +51,13 @@
|
|||
output |= *((ptr) + 1); \
|
||||
} while (0)
|
||||
|
||||
enum gm_join_type { GM_JOIN_STATIC = 0, GM_JOIN_PROXY = 1, GM_JOIN_BOTH = 2 };
|
||||
|
||||
struct gm_join {
|
||||
pim_addr group_addr;
|
||||
pim_addr source_addr;
|
||||
int sock_fd;
|
||||
enum gm_join_type join_type;
|
||||
time_t sock_creation;
|
||||
};
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "lib_errors.h"
|
||||
#include "pim_util.h"
|
||||
#include "pim6_mld.h"
|
||||
#include "pim_igmp.h"
|
||||
|
||||
#if PIM_IPV == 6
|
||||
#define pim6_msdp_err(funcname, argtype) \
|
||||
|
@ -3400,6 +3401,11 @@ int lib_interface_gmp_address_family_proxy_modify(struct nb_cb_modify_args *args
|
|||
if (pim_ifp)
|
||||
pim_ifp->gm_proxy = yang_dnode_get_bool(args->dnode,
|
||||
NULL);
|
||||
|
||||
if (pim_ifp->gm_proxy)
|
||||
pim_if_gm_proxy_init(pim_ifp->pim, ifp);
|
||||
else
|
||||
pim_if_gm_proxy_finis(pim_ifp->pim, ifp);
|
||||
}
|
||||
return NB_OK;
|
||||
}
|
||||
|
@ -3454,7 +3460,8 @@ int lib_interface_gmp_address_family_join_group_create(
|
|||
"./source-addr");
|
||||
yang_dnode_get_pimaddr(&group_addr, args->dnode,
|
||||
"./group-addr");
|
||||
result = pim_if_gm_join_add(ifp, group_addr, source_addr);
|
||||
result = pim_if_gm_join_add(ifp, group_addr, source_addr,
|
||||
GM_JOIN_STATIC);
|
||||
if (result) {
|
||||
snprintf(args->errmsg, args->errmsg_len,
|
||||
"Failure joining " GM " group");
|
||||
|
@ -3483,7 +3490,8 @@ int lib_interface_gmp_address_family_join_group_destroy(
|
|||
"./source-addr");
|
||||
yang_dnode_get_pimaddr(&group_addr, args->dnode,
|
||||
"./group-addr");
|
||||
result = pim_if_gm_join_del(ifp, group_addr, source_addr);
|
||||
result = pim_if_gm_join_del(ifp, group_addr, source_addr,
|
||||
GM_JOIN_STATIC);
|
||||
|
||||
if (result) {
|
||||
snprintf(args->errmsg, args->errmsg_len,
|
||||
|
|
|
@ -78,6 +78,31 @@ tib_sg_oil_setup(struct pim_instance *pim, pim_sgaddr sg, struct interface *oif)
|
|||
return pim_channel_oil_add(pim, &sg, __func__);
|
||||
}
|
||||
|
||||
void tib_sg_proxy_join_prune_check(struct pim_instance *pim, pim_sgaddr sg,
|
||||
struct interface *oif, bool join)
|
||||
{
|
||||
struct interface *ifp;
|
||||
|
||||
FOR_ALL_INTERFACES (pim->vrf, ifp) {
|
||||
struct pim_interface *pim_ifp = ifp->info;
|
||||
|
||||
if (!pim_ifp)
|
||||
continue;
|
||||
|
||||
if (ifp == oif) /* skip the source interface */
|
||||
continue;
|
||||
|
||||
if (pim_ifp->gm_enable && pim_ifp->gm_proxy) {
|
||||
if (join)
|
||||
pim_if_gm_join_add(ifp, sg.grp, sg.src,
|
||||
GM_JOIN_PROXY);
|
||||
else
|
||||
pim_if_gm_join_del(ifp, sg.grp, sg.src,
|
||||
GM_JOIN_PROXY);
|
||||
}
|
||||
} /* scan interfaces */
|
||||
}
|
||||
|
||||
bool tib_sg_gm_join(struct pim_instance *pim, pim_sgaddr sg,
|
||||
struct interface *oif, struct channel_oil **oilp)
|
||||
{
|
||||
|
@ -95,6 +120,8 @@ bool tib_sg_gm_join(struct pim_instance *pim, pim_sgaddr sg,
|
|||
if (!*oilp)
|
||||
return false;
|
||||
|
||||
tib_sg_proxy_join_prune_check(pim, sg, oif, true);
|
||||
|
||||
if (PIM_I_am_DR(pim_oif) || PIM_I_am_DualActive(pim_oif)) {
|
||||
int result;
|
||||
|
||||
|
@ -137,6 +164,8 @@ void tib_sg_gm_prune(struct pim_instance *pim, pim_sgaddr sg,
|
|||
{
|
||||
int result;
|
||||
|
||||
tib_sg_proxy_join_prune_check(pim, sg, oif, false);
|
||||
|
||||
/*
|
||||
It appears that in certain circumstances that
|
||||
igmp_source_forward_stop is called when IGMP forwarding
|
||||
|
|
|
@ -16,5 +16,8 @@ extern bool tib_sg_gm_join(struct pim_instance *pim, pim_sgaddr sg,
|
|||
struct interface *oif, struct channel_oil **oilp);
|
||||
extern void tib_sg_gm_prune(struct pim_instance *pim, pim_sgaddr sg,
|
||||
struct interface *oif, struct channel_oil **oilp);
|
||||
extern void tib_sg_proxy_join_prune_check(struct pim_instance *pim,
|
||||
pim_sgaddr sg, struct interface *oif,
|
||||
bool join);
|
||||
|
||||
#endif /* _FRR_PIM_GLUE_H */
|
||||
|
|
Loading…
Reference in a new issue