Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add igmp proxy support #16861

Merged
merged 6 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions doc/user/pim.rst
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,12 @@ is in a vrf, enter the interface command with the vrf keyword at the end.
Add a static multicast group or source-group on an interface. This will behave
as if there is a receiver on this interface without any IGMP reports.

.. clicmd:: ip igmp proxy

Tell pim to send proxy IGMP reports for joins occuring on all other
interfaces on this interface. Join-groups on other interfaces will
also be proxied. The default version is v3.

.. clicmd:: ip igmp query-interval (1-65535)

Set the IGMP query interval that PIM will use.
Expand Down Expand Up @@ -475,6 +481,10 @@ cause great confusion.

Display IGMP group retransmission information.

.. clicmd:: show ip igmp [vrf NAME] proxy [json]

Display IGMP proxy join information.

.. clicmd:: show ip igmp [vrf NAME] sources [json]

Display IGMP sources information.
Expand Down
79 changes: 76 additions & 3 deletions pimd/pim_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
}

static void igmp_show_interface_join(struct pim_instance *pim, struct vty *vty,
bool uj)
bool uj, enum gm_join_type join_type)
{
struct interface *ifp;
time_t now;
Expand Down Expand Up @@ -612,6 +612,10 @@ static void igmp_show_interface_join(struct pim_instance *pim, struct vty *vty,
char source_str[INET_ADDRSTRLEN];
char uptime[10];

if (ij->join_type != join_type &&
ij->join_type != GM_JOIN_BOTH)
continue;

pim_time_uptime(uptime, sizeof(uptime),
now - ij->sock_creation);
pim_inet4_dump("<grp?>", ij->group_addr, group_str,
Expand Down Expand Up @@ -1784,7 +1788,7 @@ DEFUN (show_ip_igmp_join,
if (!vrf)
return CMD_WARNING;

igmp_show_interface_join(vrf->info, vty, uj);
igmp_show_interface_join(vrf->info, vty, uj, GM_JOIN_STATIC);

return CMD_SUCCESS;
}
Expand Down Expand Up @@ -1822,7 +1826,61 @@ DEFUN (show_ip_igmp_join_vrf_all,
first = false;
} else
vty_out(vty, "VRF: %s\n", vrf->name);
igmp_show_interface_join(vrf->info, vty, uj);
igmp_show_interface_join(vrf->info, vty, uj, GM_JOIN_STATIC);
}
if (uj)
vty_out(vty, "}\n");

return CMD_SUCCESS;
}

DEFUN (show_ip_igmp_proxy,
show_ip_igmp_proxy_cmd,
"show ip igmp [vrf NAME] proxy [json]",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could easily be combined with show_ip_igmp_join_cmd since they both do the same thing, just passing a different type.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I talked to Jafar about this and he prefers to leave them separate, both for clarity and also because the proxy command may expand in the future. If it does, we'll just have to pull them apart again.

SHOW_STR
IP_STR
IGMP_STR
VRF_CMD_HELP_STR
"IGMP proxy join 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_join(vrf->info, vty, uj, GM_JOIN_PROXY);

return CMD_SUCCESS;
}

DEFUN (show_ip_igmp_proxy_vrf_all,
show_ip_igmp_proxy_vrf_all_cmd,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, merge with the other show that does basically the same thing.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

"show ip igmp vrf all proxy [json]",
SHOW_STR
IP_STR
IGMP_STR
VRF_CMD_HELP_STR
"IGMP proxy join 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_join(vrf->info, vty, uj, GM_JOIN_PROXY);
}
if (uj)
vty_out(vty, "}\n");
Expand Down Expand Up @@ -5756,6 +5814,18 @@ DEFUN (interface_no_ip_pim_hello,
return pim_process_no_ip_pim_hello_cmd(vty);
}

DEFPY (interface_ip_igmp_proxy,
interface_ip_igmp_proxy_cmd,
"[no] ip igmp proxy",
NO_STR
IP_STR
IGMP_STR
"Proxy IGMP join/prune operations\n")
{
return pim_process_ip_gmp_proxy_cmd(vty, !no);
}


DEFUN (debug_igmp,
debug_igmp_cmd,
"debug igmp",
Expand Down Expand Up @@ -8718,6 +8788,7 @@ void pim_cmd_init(void)
&interface_ip_igmp_last_member_query_interval_cmd);
install_element(INTERFACE_NODE,
&interface_no_ip_igmp_last_member_query_interval_cmd);
install_element(INTERFACE_NODE, &interface_ip_igmp_proxy_cmd);
install_element(INTERFACE_NODE, &interface_ip_pim_activeactive_cmd);
install_element(INTERFACE_NODE, &interface_ip_pim_ssm_cmd);
install_element(INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd);
Expand Down Expand Up @@ -8761,6 +8832,8 @@ void pim_cmd_init(void)
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_proxy_cmd);
install_element(VIEW_NODE, &show_ip_igmp_proxy_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);
Expand Down
11 changes: 11 additions & 0 deletions pimd/pim_cmd_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,17 @@ int pim_process_no_ip_pim_boundary_oil_cmd(struct vty *vty)
FRR_PIM_AF_XPATH_VAL);
}

int pim_process_ip_gmp_proxy_cmd(struct vty *vty, bool enable)
{
if (enable)
nb_cli_enqueue_change(vty, "./proxy", NB_OP_MODIFY, "true");
else
nb_cli_enqueue_change(vty, "./proxy", NB_OP_DESTROY, NULL);

return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH,
FRR_PIM_AF_XPATH_VAL);
}

int pim_process_ip_mroute_cmd(struct vty *vty, const char *interface,
const char *group_str, const char *source_str)
{
Expand Down
1 change: 1 addition & 0 deletions pimd/pim_cmd_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ int pim_process_no_ip_pim_hello_cmd(struct vty *vty);
int pim_process_ip_pim_activeactive_cmd(struct vty *vty, const char *no);
int pim_process_ip_pim_boundary_oil_cmd(struct vty *vty, const char *oil);
int pim_process_no_ip_pim_boundary_oil_cmd(struct vty *vty);
int pim_process_ip_gmp_proxy_cmd(struct vty *vty, bool enable);
int pim_process_ip_mroute_cmd(struct vty *vty, const char *interface,
const char *group_str, const char *source_str);
int pim_process_no_ip_mroute_cmd(struct vty *vty, const char *interface,
Expand Down
79 changes: 74 additions & 5 deletions pimd/pim_iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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);
}
Expand All @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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

Expand Down
7 changes: 5 additions & 2 deletions pimd/pim_iface.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ struct pim_interface {
bool pim_passive_enable : 1;

bool gm_enable : 1;
bool gm_proxy : 1; /* proxy IGMP joins/prunes */

ifindex_t mroute_vif_index;
struct pim_instance *pim;
Expand Down Expand Up @@ -219,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);
Expand Down
8 changes: 5 additions & 3 deletions pimd/pim_igmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions pimd/pim_igmp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down
8 changes: 7 additions & 1 deletion pimd/pim_nb.c
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,13 @@ const struct frr_yang_module_info frr_gmp_info = {
.destroy = lib_interface_gmp_address_family_join_group_destroy,
}
},
{
{
.xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/proxy",
.cbs = {
.modify = lib_interface_gmp_address_family_proxy_modify,
}
},
{
.xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/static-group",
.cbs = {
.create = lib_interface_gmp_address_family_static_group_create,
Expand Down
1 change: 1 addition & 0 deletions pimd/pim_nb.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ 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_proxy_modify(struct nb_cb_modify_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(
Expand Down
Loading
Loading