summaryrefslogtreecommitdiff
path: root/pimd
diff options
context:
space:
mode:
Diffstat (limited to 'pimd')
-rw-r--r--pimd/pim6_cmd.c111
-rw-r--r--pimd/pim6_mld.c114
-rw-r--r--pimd/pim6_mld.h2
-rw-r--r--pimd/pim_cmd.c83
-rw-r--r--pimd/pim_iface.c3
-rw-r--r--pimd/pim_iface.h6
-rw-r--r--pimd/pim_ifchannel.c12
-rw-r--r--pimd/pim_igmp.c8
-rw-r--r--pimd/pim_igmpv3.c33
-rw-r--r--pimd/pim_memory.c1
-rw-r--r--pimd/pim_memory.h1
-rw-r--r--pimd/pim_msdp.c2
-rw-r--r--pimd/pim_nb.c27
-rw-r--r--pimd/pim_nb.h5
-rw-r--r--pimd/pim_nb_config.c159
-rw-r--r--pimd/pim_pim.c38
-rw-r--r--pimd/pim_register.c19
-rw-r--r--pimd/pim_upstream.c2
-rw-r--r--pimd/pim_vty.c26
19 files changed, 622 insertions, 30 deletions
diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c
index 12493b7dbb..8297911828 100644
--- a/pimd/pim6_cmd.c
+++ b/pimd/pim6_cmd.c
@@ -1612,6 +1612,56 @@ DEFPY (interface_no_ipv6_mld_version,
"frr-routing:ipv6");
}
+DEFPY_YANG(interface_ipv6_mld_limits,
+ interface_ipv6_mld_limits_cmd,
+ "[no] ipv6 mld <max-sources$do_src (0-4294967295)$val"
+ "|max-groups$do_grp (0-4294967295)$val>",
+ NO_STR
+ IPV6_STR
+ IFACE_MLD_STR
+ "Limit number of MLDv2 sources to track\n"
+ "Permitted number of sources\n"
+ "Limit number of MLD group memberships to track\n"
+ "Permitted number of groups\n")
+{
+ const char *xpath;
+
+ assert(do_src || do_grp);
+ if (do_src)
+ xpath = "./max-sources";
+ else
+ xpath = "./max-groups";
+
+ if (no)
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ else
+ nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, val_str);
+
+ return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, FRR_PIM_AF_XPATH_VAL);
+}
+
+ALIAS_YANG(interface_ipv6_mld_limits,
+ no_interface_ipv6_mld_limits_cmd,
+ "no ipv6 mld <max-sources$do_src|max-groups$do_grp>",
+ NO_STR
+ IPV6_STR
+ IFACE_MLD_STR
+ "Limit number of MLDv2 sources to track\n"
+ "Limit number of MLD group memberships to track\n")
+
+DEFPY_YANG(interface_ipv6_mld_immediate_leave,
+ interface_ipv6_mld_immediate_leave_cmd,
+ "[no] ipv6 mld immediate-leave",
+ NO_STR
+ IPV6_STR
+ IFACE_MLD_STR
+ "Immediately drop group memberships on receiving Leave (MLDv1 only)\n")
+{
+ nb_cli_enqueue_change(vty, "./immediate-leave", NB_OP_MODIFY, no ? "false" : "true");
+
+ return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, FRR_PIM_AF_XPATH_VAL);
+}
+
DEFPY (interface_ipv6_mld_query_interval,
interface_ipv6_mld_query_interval_cmd,
"ipv6 mld query-interval (1-65535)$q_interval",
@@ -1753,6 +1803,34 @@ DEFPY (interface_no_ipv6_mld_last_member_query_interval,
return gm_process_no_last_member_query_interval_cmd(vty);
}
+DEFPY_YANG(interface_ipv6_pim_neighbor_prefix_list,
+ interface_ipv6_pim_neighbor_prefix_list_cmd,
+ "[no] ipv6 pim allowed-neighbors prefix-list PREFIXLIST6_NAME$prefix_list",
+ NO_STR
+ IP_STR
+ PIM_STR
+ "Restrict allowed PIM neighbors\n"
+ "Use prefix-list to filter neighbors\n"
+ "Name of a prefix-list\n")
+{
+ if (no)
+ nb_cli_enqueue_change(vty, "./neighbor-filter-prefix-list", NB_OP_DESTROY, NULL);
+ else
+ nb_cli_enqueue_change(vty, "./neighbor-filter-prefix-list", NB_OP_MODIFY,
+ prefix_list);
+
+ return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, FRR_PIM_AF_XPATH_VAL);
+}
+
+ALIAS(interface_ipv6_pim_neighbor_prefix_list,
+ interface_no_ipv6_pim_neighbor_prefix_list_cmd,
+ "no ipv6 pim allowed-neighbors [prefix-list]",
+ NO_STR
+ IP_STR
+ PIM_STR
+ "Restrict allowed PIM neighbors\n"
+ "Use prefix-list to filter neighbors\n")
+
DEFPY (show_ipv6_pim_rp,
show_ipv6_pim_rp_cmd,
"show ipv6 pim [vrf NAME] rp-info [X:X::X:X/M$group] [json$json]",
@@ -2341,6 +2419,32 @@ DEFPY (show_ipv6_pim_bsrp,
return pim_show_group_rp_mappings_info_helper(vrf, vty, !!json);
}
+DEFPY(clear_ipv6_mld_interfaces,
+ clear_ipv6_mld_interfaces_cmd,
+ "clear ipv6 mld [vrf NAME$vrf_name] interfaces",
+ CLEAR_STR
+ IPV6_STR
+ "MLD clear commands\n"
+ VRF_CMD_HELP_STR
+ "Reset MLD interfaces\n")
+{
+ struct interface *ifp;
+ struct vrf *vrf;
+
+ vrf = vrf_name ? vrf_lookup_by_name(vrf_name) : vrf_lookup_by_id(VRF_DEFAULT);
+ if (!vrf) {
+ vty_out(vty, "Specified VRF: %s does not exist\n", vrf_name);
+ return CMD_WARNING;
+ }
+
+ FOR_ALL_INTERFACES (vrf, ifp)
+ pim_if_addr_del_all(ifp);
+ FOR_ALL_INTERFACES (vrf, ifp)
+ pim_if_addr_add_all(ifp);
+
+ return CMD_SUCCESS;
+}
+
DEFPY (clear_ipv6_pim_statistics,
clear_ipv6_pim_statistics_cmd,
"clear ipv6 pim statistics [vrf NAME]$name",
@@ -2865,6 +2969,9 @@ void pim_cmd_init(void)
install_element(INTERFACE_NODE, &interface_no_ipv6_pim_boundary_oil_cmd);
install_element(INTERFACE_NODE, &interface_ipv6_mroute_cmd);
install_element(INTERFACE_NODE, &interface_no_ipv6_mroute_cmd);
+ install_element(INTERFACE_NODE, &interface_ipv6_mld_limits_cmd);
+ install_element(INTERFACE_NODE, &no_interface_ipv6_mld_limits_cmd);
+
/* Install BSM command */
install_element(INTERFACE_NODE, &ipv6_pim_bsm_cmd);
install_element(INTERFACE_NODE, &no_ipv6_pim_bsm_cmd);
@@ -2878,6 +2985,7 @@ void pim_cmd_init(void)
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_immediate_leave_cmd);
install_element(INTERFACE_NODE, &interface_ipv6_mld_query_interval_cmd);
install_element(INTERFACE_NODE,
&interface_no_ipv6_mld_query_interval_cmd);
@@ -2893,6 +3001,8 @@ void pim_cmd_init(void)
&interface_ipv6_mld_last_member_query_interval_cmd);
install_element(INTERFACE_NODE,
&interface_no_ipv6_mld_last_member_query_interval_cmd);
+ install_element(INTERFACE_NODE, &interface_ipv6_pim_neighbor_prefix_list_cmd);
+ install_element(INTERFACE_NODE, &interface_no_ipv6_pim_neighbor_prefix_list_cmd);
install_element(VIEW_NODE, &show_ipv6_pim_rp_cmd);
install_element(VIEW_NODE, &show_ipv6_pim_rp_vrf_all_cmd);
@@ -2935,6 +3045,7 @@ void pim_cmd_init(void)
install_element(VIEW_NODE, &show_ipv6_pim_bsr_cmd);
install_element(VIEW_NODE, &show_ipv6_pim_bsm_db_cmd);
install_element(VIEW_NODE, &show_ipv6_pim_bsrp_cmd);
+ install_element(ENABLE_NODE, &clear_ipv6_mld_interfaces_cmd);
install_element(ENABLE_NODE, &clear_ipv6_pim_statistics_cmd);
install_element(ENABLE_NODE, &clear_ipv6_mroute_cmd);
install_element(ENABLE_NODE, &clear_ipv6_pim_oil_cmd);
diff --git a/pimd/pim6_mld.c b/pimd/pim6_mld.c
index acfb0c3af3..2546166d0a 100644
--- a/pimd/pim6_mld.c
+++ b/pimd/pim6_mld.c
@@ -190,11 +190,26 @@ static struct gm_sg *gm_sg_find(struct gm_if *gm_ifp, pim_addr grp,
return gm_sgs_find(gm_ifp->sgs, &ref);
}
+static bool gm_sg_has_group(struct gm_sgs_head *sgs, const pim_addr group)
+{
+ struct gm_sg *sg;
+
+ frr_each (gm_sgs, sgs, sg)
+ if (pim_addr_cmp(sg->sgaddr.grp, group) == 0)
+ return true;
+
+ return false;
+}
+
static struct gm_sg *gm_sg_make(struct gm_if *gm_ifp, pim_addr grp,
pim_addr src)
{
struct gm_sg *ret, *prev;
+ /* Count all unique group members. */
+ if (!gm_sg_has_group(gm_ifp->sgs, grp))
+ gm_ifp->groups_count++;
+
ret = XCALLOC(MTYPE_GM_SG, sizeof(*ret));
ret->sgaddr.grp = grp;
ret->sgaddr.src = src;
@@ -212,6 +227,47 @@ static struct gm_sg *gm_sg_make(struct gm_if *gm_ifp, pim_addr grp,
return ret;
}
+static size_t gm_sg_source_count(struct gm_sgs_head *sgs, const pim_addr group)
+{
+ struct gm_sg *sg;
+ size_t source_count;
+
+ source_count = 0;
+ frr_each (gm_sgs, sgs, sg)
+ if (pim_addr_cmp(sg->sgaddr.grp, group) == 0)
+ source_count++;
+
+ return source_count;
+}
+
+static bool gm_sg_limit_reached(struct gm_if *gm_if, const pim_addr source, const pim_addr group)
+{
+ const struct pim_interface *pim_interface = gm_if->ifp->info;
+
+ if (!gm_sg_has_group(gm_if->sgs, group)) {
+ if (gm_if->groups_count >= pim_interface->gm_group_limit) {
+ if (PIM_DEBUG_GM_TRACE)
+ zlog_debug("interface %s has reached group limit (%u), refusing to add group %pPA",
+ gm_if->ifp->name, pim_interface->gm_group_limit, &group);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ if (gm_sg_source_count(gm_if->sgs, group) >= pim_interface->gm_source_limit) {
+ if (PIM_DEBUG_GM_TRACE) {
+ zlog_debug("interface %s has reached source limit (%u), refusing to add source %pPA (group %pPA)",
+ gm_if->ifp->name, pim_interface->gm_source_limit, &source,
+ &group);
+ }
+ return true;
+ }
+
+ return false;
+}
+
/*
* interface -> packets, sorted by expiry (because add_tail insert order)
*/
@@ -392,18 +448,23 @@ static void gm_sg_update(struct gm_sg *sg, bool has_expired)
desired == GM_SG_NOPRUNE_EXPIRING) {
struct gm_query_timers timers;
- timers.qrv = gm_ifp->cur_qrv;
- timers.max_resp_ms = gm_ifp->cur_max_resp;
- timers.qqic_ms = gm_ifp->cur_query_intv_trig;
- timers.fuzz = gm_ifp->cfg_timing_fuzz;
+ if (!pim_ifp->gmp_immediate_leave) {
+ timers.qrv = gm_ifp->cur_qrv;
+ timers.max_resp_ms = gm_ifp->cur_max_resp;
+ timers.qqic_ms = gm_ifp->cur_query_intv_trig;
+ timers.fuzz = gm_ifp->cfg_timing_fuzz;
+
+ gm_expiry_calc(&timers);
+ } else
+ memset(&timers.expire_wait, 0, sizeof(timers.expire_wait));
- gm_expiry_calc(&timers);
gm_sg_timer_start(gm_ifp, sg, timers.expire_wait);
EVENT_OFF(sg->t_sg_query);
sg->query_sbit = false;
/* Trigger the specific queries only for querier. */
- if (IPV6_ADDR_SAME(&gm_ifp->querier, &pim_ifp->ll_lowest)) {
+ if (!pim_ifp->gmp_immediate_leave &&
+ IPV6_ADDR_SAME(&gm_ifp->querier, &pim_ifp->ll_lowest)) {
sg->n_query = gm_ifp->cur_lmqc;
gm_trigger_specific(sg);
}
@@ -471,6 +532,11 @@ static void gm_sg_update(struct gm_sg *sg, bool has_expired)
zlog_debug(log_sg(sg, "dropping"));
gm_sgs_del(gm_ifp->sgs, sg);
+
+ /* Decrement unique group members counter. */
+ if (!gm_sg_has_group(gm_ifp->sgs, sg->sgaddr.grp))
+ gm_ifp->groups_count--;
+
gm_sg_free(sg);
}
}
@@ -634,8 +700,12 @@ static void gm_handle_v2_pass1(struct gm_packet_state *pkt,
case MLD_RECTYPE_CHANGE_TO_EXCLUDE:
/* this always replaces or creates state */
is_excl = true;
- if (!grp)
+ if (!grp) {
+ if (gm_sg_limit_reached(pkt->iface, PIMADDR_ANY, rechdr->grp))
+ return;
+
grp = gm_sg_make(pkt->iface, rechdr->grp, PIMADDR_ANY);
+ }
item = gm_packet_sg_setup(pkt, grp, is_excl, false);
item->n_exclude = n_src;
@@ -700,9 +770,13 @@ static void gm_handle_v2_pass1(struct gm_packet_state *pkt,
struct gm_sg *sg;
sg = gm_sg_find(pkt->iface, rechdr->grp, rechdr->srcs[j]);
- if (!sg)
+ if (!sg) {
+ if (gm_sg_limit_reached(pkt->iface, rechdr->srcs[j], rechdr->grp))
+ return;
+
sg = gm_sg_make(pkt->iface, rechdr->grp,
rechdr->srcs[j]);
+ }
gm_packet_sg_setup(pkt, sg, is_excl, true);
}
@@ -952,6 +1026,10 @@ static void gm_handle_v1_report(struct gm_if *gm_ifp,
hdr = (struct mld_v1_pkt *)data;
+ if (!gm_sg_has_group(gm_ifp->sgs, hdr->grp) &&
+ gm_sg_limit_reached(gm_ifp, PIMADDR_ANY, hdr->grp))
+ return;
+
max_entries = 1;
pkt = XCALLOC(MTYPE_GM_STATE,
offsetof(struct gm_packet_state, items[max_entries]));
@@ -1029,11 +1107,24 @@ static void gm_handle_v1_leave(struct gm_if *gm_ifp,
if (grp) {
old_grp = gm_packet_sg_find(grp, GM_SUB_POS, subscriber);
if (old_grp) {
+ const struct pim_interface *pim_ifp = gm_ifp->ifp->info;
+ struct gm_packet_sg *item;
+
gm_packet_sg_drop(old_grp);
- gm_sg_update(grp, false);
-/* TODO "need S,G PRUNE => NO_INFO transition here" */
+ /*
+ * If immediate leave drop others subscribers and proceed
+ * to expire the MLD join.
+ */
+ if (pim_ifp->gmp_immediate_leave) {
+ frr_each_safe (gm_packet_sg_subs, grp->subs_positive, item) {
+ gm_packet_sg_drop(item);
+ }
+ gm_sg_update(grp, true);
+ } else
+ gm_sg_update(grp, false);
+ /* TODO "need S,G PRUNE => NO_INFO transition here" */
}
}
@@ -1255,6 +1346,9 @@ static void gm_handle_q_groupsrc(struct gm_if *gm_ifp,
for (i = 0; i < n_src; i++) {
sg = gm_sg_find(gm_ifp, grp, srcs[i]);
+ if (sg == NULL)
+ continue;
+
GM_UPDATE_SG_STATE(sg);
gm_sg_timer_start(gm_ifp, sg, timers->expire_wait);
}
diff --git a/pimd/pim6_mld.h b/pimd/pim6_mld.h
index 183ab2fc50..c5a9708961 100644
--- a/pimd/pim6_mld.h
+++ b/pimd/pim6_mld.h
@@ -350,6 +350,8 @@ struct gm_if {
struct gm_subscribers_head subscribers[1];
struct gm_packet_expires_head expires[1];
+ size_t groups_count;
+
struct timeval started;
struct gm_if_stats stats;
};
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index a1ad261869..f838c401e3 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -5656,6 +5656,56 @@ DEFUN (interface_no_ip_igmp_last_member_query_interval,
return gm_process_no_last_member_query_interval_cmd(vty);
}
+DEFPY_YANG(interface_ip_igmp_limits,
+ interface_ip_igmp_limits_cmd,
+ "[no] ip igmp <max-sources$do_src (0-4294967295)$val"
+ "|max-groups$do_grp (0-4294967295)$val>",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR
+ "Limit number of IGMPv3 sources to track\n"
+ "Permitted number of sources\n"
+ "Limit number of IGMP group memberships to track\n"
+ "Permitted number of groups\n")
+{
+ const char *xpath;
+
+ assert(do_src || do_grp);
+ if (do_src)
+ xpath = "./max-sources";
+ else
+ xpath = "./max-groups";
+
+ if (no)
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ else
+ nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, val_str);
+
+ return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, FRR_PIM_AF_XPATH_VAL);
+}
+
+ALIAS_YANG(interface_ip_igmp_limits,
+ no_interface_ip_igmp_limits_cmd,
+ "no ip igmp <max-sources$do_src|max-groups$do_grp>",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR
+ "Limit number of IGMPv3 sources to track\n"
+ "Limit number of IGMP group memberships to track\n")
+
+DEFPY_YANG(interface_ip_igmp_immediate_leave,
+ interface_ip_igmp_immediate_leave_cmd,
+ "[no] ip igmp immediate-leave",
+ NO_STR
+ IP_STR
+ IFACE_IGMP_STR
+ "Immediately drop group memberships on receiving Leave (IGMPv2 only)\n")
+{
+ nb_cli_enqueue_change(vty, "./immediate-leave", NB_OP_MODIFY, no ? "false" : "true");
+
+ return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, FRR_PIM_AF_XPATH_VAL);
+}
+
DEFUN (interface_ip_pim_drprio,
interface_ip_pim_drprio_cmd,
"ip pim drpriority (0-4294967295)",
@@ -5985,6 +6035,34 @@ DEFPY (interface_ip_igmp_proxy,
}
+DEFPY_YANG(interface_ip_pim_neighbor_prefix_list,
+ interface_ip_pim_neighbor_prefix_list_cmd,
+ "[no] ip pim allowed-neighbors prefix-list WORD",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Restrict allowed PIM neighbors\n"
+ "Use prefix-list to filter neighbors\n"
+ "Name of a prefix-list\n")
+{
+ if (no)
+ nb_cli_enqueue_change(vty, "./neighbor-filter-prefix-list", NB_OP_DESTROY, NULL);
+ else
+ nb_cli_enqueue_change(vty, "./neighbor-filter-prefix-list", NB_OP_MODIFY,
+ prefix_list);
+
+ return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, FRR_PIM_AF_XPATH_VAL);
+}
+
+ALIAS (interface_ip_pim_neighbor_prefix_list,
+ interface_no_ip_pim_neighbor_prefix_list_cmd,
+ "no ip pim allowed-neighbors [prefix-list]",
+ NO_STR
+ IP_STR
+ "pim multicast routing\n"
+ "Restrict allowed PIM neighbors\n"
+ "Use prefix-list to filter neighbors\n")
+
DEFUN (debug_igmp,
debug_igmp_cmd,
"debug igmp",
@@ -9101,6 +9179,9 @@ void pim_cmd_init(void)
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_igmp_limits_cmd);
+ install_element(INTERFACE_NODE, &no_interface_ip_igmp_limits_cmd);
+ install_element(INTERFACE_NODE, &interface_ip_igmp_immediate_leave_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);
@@ -9116,6 +9197,8 @@ void pim_cmd_init(void)
install_element(INTERFACE_NODE, &interface_no_ip_pim_boundary_oil_cmd);
install_element(INTERFACE_NODE, &interface_ip_pim_boundary_acl_cmd);
install_element(INTERFACE_NODE, &interface_ip_igmp_query_generate_cmd);
+ install_element(INTERFACE_NODE, &interface_ip_pim_neighbor_prefix_list_cmd);
+ install_element(INTERFACE_NODE, &interface_no_ip_pim_neighbor_prefix_list_cmd);
// Static mroutes NEB
install_element(INTERFACE_NODE, &interface_ip_mroute_cmd);
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index 9316cebc0a..3408574cae 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -128,6 +128,8 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool gm, bool pim,
pim_ifp->gm_specific_query_max_response_time_dsec =
GM_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
pim_ifp->gm_last_member_query_count = GM_DEFAULT_ROBUSTNESS_VARIABLE;
+ pim_ifp->gm_group_limit = UINT32_MAX;
+ pim_ifp->gm_source_limit = UINT32_MAX;
/* BSM config on interface: true by default */
pim_ifp->bsm_enable = true;
@@ -216,6 +218,7 @@ void pim_if_delete(struct interface *ifp)
if (pim_ifp->bfd_config.profile)
XFREE(MTYPE_TMP, pim_ifp->bfd_config.profile);
+ XFREE(MTYPE_PIM_PLIST_NAME, pim_ifp->nbr_plist);
XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
ifp->info = NULL;
diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h
index 90a81a21d0..b0befcfcba 100644
--- a/pimd/pim_iface.h
+++ b/pimd/pim_iface.h
@@ -105,6 +105,11 @@ struct pim_interface {
struct gm_if *mld;
+ uint32_t gm_source_limit, gm_group_limit;
+
+ /* IGMPv2 only/MLDv1 only immediate leave */
+ bool gmp_immediate_leave;
+
int pim_sock_fd; /* PIM socket file descriptor */
struct event *t_pim_sock_read; /* thread for reading PIM socket */
int64_t pim_sock_creation; /* timestamp of PIM socket creation */
@@ -116,6 +121,7 @@ struct pim_interface {
uint32_t pim_generation_id;
uint16_t pim_propagation_delay_msec; /* config */
uint16_t pim_override_interval_msec; /* config */
+ char *nbr_plist;
struct list *pim_neighbor_list; /* list of struct pim_neighbor */
struct list *upstream_switch_list;
struct pim_ifchannel_rb ifchannel_rb;
diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c
index 1791502b94..d55d2a958a 100644
--- a/pimd/pim_ifchannel.c
+++ b/pimd/pim_ifchannel.c
@@ -239,10 +239,16 @@ void pim_ifchannel_delete_all(struct interface *ifp)
void delete_on_noinfo(struct pim_ifchannel *ch)
{
- if (ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO
- && ch->ifjoin_state == PIM_IFJOIN_NOINFO
- && ch->t_ifjoin_expiry_timer == NULL)
+ struct pim_upstream *up = ch->upstream;
+ /*
+ * (S,G) with no active traffic, KAT expires, PPT expries,
+ * channel state is NoInfo
+ */
+ if (ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO &&
+ ch->ifjoin_state == PIM_IFJOIN_NOINFO &&
+ (ch->t_ifjoin_expiry_timer == NULL || (up && !pim_upstream_is_kat_running(up)))) {
pim_ifchannel_delete(ch);
+ }
}
void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch,
diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c
index 12f424248f..b1b4566499 100644
--- a/pimd/pim_igmp.c
+++ b/pimd/pim_igmp.c
@@ -1416,6 +1416,14 @@ struct gm_group *igmp_add_group_by_addr(struct gm_sock *igmp,
__func__, &group_addr);
return NULL;
}
+
+ if (listcount(pim_ifp->gm_group_list) >= pim_ifp->gm_group_limit) {
+ if (PIM_DEBUG_GM_TRACE)
+ zlog_debug("interface %s has reached group limit (%u), refusing to add group %pI4",
+ igmp->interface->name, pim_ifp->gm_group_limit, &group_addr);
+ return NULL;
+ }
+
/*
Non-existant group is created as INCLUDE {empty}:
diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c
index 7348d8130f..2de2b32688 100644
--- a/pimd/pim_igmpv3.c
+++ b/pimd/pim_igmpv3.c
@@ -423,6 +423,7 @@ struct gm_source *igmp_find_source_by_addr(struct gm_group *group,
struct gm_source *igmp_get_source_by_addr(struct gm_group *group,
struct in_addr src_addr, bool *new)
{
+ const struct pim_interface *pim_interface = group->interface->info;
struct gm_source *src;
if (new)
@@ -432,6 +433,14 @@ struct gm_source *igmp_get_source_by_addr(struct gm_group *group,
if (src)
return src;
+ if (listcount(group->group_source_list) >= pim_interface->gm_source_limit) {
+ if (PIM_DEBUG_GM_TRACE)
+ zlog_debug("interface %s has reached source limit (%u), refusing to add source %pI4 (group %pI4)",
+ group->interface->name, pim_interface->gm_source_limit,
+ &src_addr, &group->group_addr);
+ return NULL;
+ }
+
if (PIM_DEBUG_GM_TRACE) {
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
@@ -719,9 +728,25 @@ static void toin_incl(struct gm_group *group, int num_sources,
static void toin_excl(struct gm_group *group, int num_sources,
struct in_addr *sources)
{
+ struct listnode *src_node, *src_next;
+ struct pim_interface *pim_ifp = group->interface->info;
int num_sources_tosend;
int i;
+ if (group->igmp_version == 2 && pim_ifp->gmp_immediate_leave) {
+ struct gm_source *src;
+
+ if (PIM_DEBUG_GM_TRACE)
+ zlog_debug("IGMP(v2) Immediate-leave group %pI4 on %s", &group->group_addr,
+ group->interface->name);
+
+ igmp_group_timer_on(group, 0, group->interface->name);
+
+ for (ALL_LIST_ELEMENTS(group->group_source_list, src_node, src_next, src))
+ igmp_source_delete(src);
+ return;
+ }
+
/* Set SEND flag for X (sources with timer > 0) */
num_sources_tosend = source_mark_send_flag_by_timer(group);
@@ -1487,7 +1512,9 @@ void igmp_group_timer_lower_to_lmqt(struct gm_group *group)
pim_ifp = ifp->info;
ifname = ifp->name;
- lmqi_dsec = pim_ifp->gm_specific_query_max_response_time_dsec;
+ lmqi_dsec = pim_ifp->gmp_immediate_leave
+ ? 0
+ : pim_ifp->gm_specific_query_max_response_time_dsec;
lmqc = pim_ifp->gm_last_member_query_count;
lmqt_msec = PIM_IGMP_LMQT_MSEC(
lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */
@@ -1522,7 +1549,9 @@ void igmp_source_timer_lower_to_lmqt(struct gm_source *source)
pim_ifp = ifp->info;
ifname = ifp->name;
- lmqi_dsec = pim_ifp->gm_specific_query_max_response_time_dsec;
+ lmqi_dsec = pim_ifp->gmp_immediate_leave
+ ? 0
+ : pim_ifp->gm_specific_query_max_response_time_dsec;
lmqc = pim_ifp->gm_last_member_query_count;
lmqt_msec = PIM_IGMP_LMQT_MSEC(
lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */
diff --git a/pimd/pim_memory.c b/pimd/pim_memory.c
index 2c35bc6473..f918cbd146 100644
--- a/pimd/pim_memory.c
+++ b/pimd/pim_memory.c
@@ -26,6 +26,7 @@ DEFINE_MTYPE(PIMD, PIM_STATIC_ROUTE, "PIM Static Route");
DEFINE_MTYPE(PIMD, PIM_RP, "PIM RP info");
DEFINE_MTYPE(PIMD, PIM_FILTER_NAME, "PIM RP filter info");
DEFINE_MTYPE(PIMD, PIM_MSDP_PEER, "PIM MSDP peer");
+DEFINE_MTYPE(PIMD, PIM_MSDP_FILTER_NAME, "PIM MSDP peer filter name");
DEFINE_MTYPE(PIMD, PIM_MSDP_MG_NAME, "PIM MSDP mesh-group name");
DEFINE_MTYPE(PIMD, PIM_MSDP_AUTH_KEY, "PIM MSDP authentication key");
DEFINE_MTYPE(PIMD, PIM_MSDP_SA, "PIM MSDP source-active cache");
diff --git a/pimd/pim_memory.h b/pimd/pim_memory.h
index b44d3e191a..5c9bdad50c 100644
--- a/pimd/pim_memory.h
+++ b/pimd/pim_memory.h
@@ -25,6 +25,7 @@ DECLARE_MTYPE(PIM_STATIC_ROUTE);
DECLARE_MTYPE(PIM_RP);
DECLARE_MTYPE(PIM_FILTER_NAME);
DECLARE_MTYPE(PIM_MSDP_PEER);
+DECLARE_MTYPE(PIM_MSDP_FILTER_NAME);
DECLARE_MTYPE(PIM_MSDP_MG_NAME);
DECLARE_MTYPE(PIM_MSDP_SA);
DECLARE_MTYPE(PIM_MSDP_MG);
diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c
index 46d5f4881f..1fd27d383e 100644
--- a/pimd/pim_msdp.c
+++ b/pimd/pim_msdp.c
@@ -1095,6 +1095,8 @@ static void pim_msdp_peer_free(struct pim_msdp_peer *mp)
if (mp->auth_listen_sock != -1)
close(mp->auth_listen_sock);
+ XFREE(MTYPE_PIM_MSDP_FILTER_NAME, mp->acl_in);
+ XFREE(MTYPE_PIM_MSDP_FILTER_NAME, mp->acl_out);
XFREE(MTYPE_PIM_MSDP_MG_NAME, mp->mesh_group_name);
mp->pim = NULL;
diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c
index ea9ce3cecb..9a2fc5f3cd 100644
--- a/pimd/pim_nb.c
+++ b/pimd/pim_nb.c
@@ -315,6 +315,13 @@ const struct frr_yang_module_info frr_pim_info = {
}
},
{
+ .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/neighbor-filter-prefix-list",
+ .cbs = {
+ .modify = lib_interface_pim_address_family_nbr_plist_modify,
+ .destroy = lib_interface_pim_address_family_nbr_plist_destroy,
+ }
+ },
+ {
.xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/bfd",
.cbs = {
.create = lib_interface_pim_address_family_bfd_create,
@@ -725,13 +732,31 @@ 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/max-sources",
+ .cbs = {
+ .modify = lib_interface_gm_max_sources_modify,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/max-groups",
+ .cbs = {
+ .modify = lib_interface_gm_max_groups_modify,
+ }
+ },
{
.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/immediate-leave",
+ .cbs = {
+ .modify = lib_interface_gmp_immediate_leave_modify,
+ }
+ },
+ {
.xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/static-group",
.cbs = {
.create = lib_interface_gmp_address_family_static_group_create,
diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h
index a15c6e6d9f..e9faf875b0 100644
--- a/pimd/pim_nb.h
+++ b/pimd/pim_nb.h
@@ -110,6 +110,8 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mc
struct nb_cb_modify_args *args);
int lib_interface_pim_address_family_dr_priority_modify(
struct nb_cb_modify_args *args);
+int lib_interface_pim_address_family_nbr_plist_modify(struct nb_cb_modify_args *args);
+int lib_interface_pim_address_family_nbr_plist_destroy(struct nb_cb_destroy_args *args);
int lib_interface_pim_address_family_create(struct nb_cb_create_args *args);
int lib_interface_pim_address_family_destroy(struct nb_cb_destroy_args *args);
int lib_interface_pim_address_family_pim_enable_modify(
@@ -287,6 +289,9 @@ int lib_interface_gmp_address_family_static_group_create(
struct nb_cb_create_args *args);
int lib_interface_gmp_address_family_static_group_destroy(
struct nb_cb_destroy_args *args);
+int lib_interface_gm_max_sources_modify(struct nb_cb_modify_args *args);
+int lib_interface_gm_max_groups_modify(struct nb_cb_modify_args *args);
+int lib_interface_gmp_immediate_leave_modify(struct nb_cb_modify_args *args);
/*
* Callback registered with routing_nb lib to validate only
diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c
index 51f0615884..1be5e9cb88 100644
--- a/pimd/pim_nb_config.c
+++ b/pimd/pim_nb_config.c
@@ -1564,8 +1564,8 @@ int pim_msdp_peer_sa_filter_in_modify(struct nb_cb_modify_args *args)
break;
case NB_EV_APPLY:
mp = nb_running_get_entry(args->dnode, NULL, true);
- XFREE(MTYPE_TMP, mp->acl_in);
- mp->acl_in = XSTRDUP(MTYPE_TMP,
+ XFREE(MTYPE_PIM_MSDP_FILTER_NAME, mp->acl_in);
+ mp->acl_in = XSTRDUP(MTYPE_PIM_MSDP_FILTER_NAME,
yang_dnode_get_string(args->dnode, NULL));
break;
}
@@ -1585,7 +1585,7 @@ int pim_msdp_peer_sa_filter_in_destroy(struct nb_cb_destroy_args *args)
break;
case NB_EV_APPLY:
mp = nb_running_get_entry(args->dnode, NULL, true);
- XFREE(MTYPE_TMP, mp->acl_in);
+ XFREE(MTYPE_PIM_MSDP_FILTER_NAME, mp->acl_in);
break;
}
@@ -1608,8 +1608,8 @@ int pim_msdp_peer_sa_filter_out_modify(struct nb_cb_modify_args *args)
break;
case NB_EV_APPLY:
mp = nb_running_get_entry(args->dnode, NULL, true);
- XFREE(MTYPE_TMP, mp->acl_out);
- mp->acl_out = XSTRDUP(MTYPE_TMP,
+ XFREE(MTYPE_PIM_MSDP_FILTER_NAME, mp->acl_out);
+ mp->acl_out = XSTRDUP(MTYPE_PIM_MSDP_FILTER_NAME,
yang_dnode_get_string(args->dnode, NULL));
break;
}
@@ -1629,7 +1629,7 @@ int pim_msdp_peer_sa_filter_out_destroy(struct nb_cb_destroy_args *args)
break;
case NB_EV_APPLY:
mp = nb_running_get_entry(args->dnode, NULL, true);
- XFREE(MTYPE_TMP, mp->acl_out);
+ XFREE(MTYPE_PIM_MSDP_FILTER_NAME, mp->acl_out);
break;
}
@@ -2043,6 +2043,11 @@ int lib_interface_pim_address_family_pim_enable_modify(struct nb_cb_modify_args
ifp->name);
return NB_ERR_INCONSISTENCY;
}
+
+ /* Trigger election in case it was never run before */
+ pim_ifp = ifp->info;
+ if (pim_addr_is_any(pim_ifp->pim_dr_addr))
+ pim_if_dr_election(ifp);
} else {
pim_ifp = ifp->info;
if (!pim_ifp)
@@ -2076,6 +2081,10 @@ int lib_interface_pim_address_family_pim_passive_enable_modify(
pim_ifp = ifp->info;
pim_ifp->pim_passive_enable =
yang_dnode_get_bool(args->dnode, NULL);
+
+ /* Trigger election in case it was never run before */
+ if (pim_ifp->pim_passive_enable && pim_addr_is_any(pim_ifp->pim_dr_addr))
+ pim_if_dr_election(ifp);
break;
}
@@ -2154,6 +2163,55 @@ int lib_interface_pim_address_family_hello_holdtime_destroy(
return NB_OK;
}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/neighbor-filter-prefix-list
+ */
+int lib_interface_pim_address_family_nbr_plist_modify(struct nb_cb_modify_args *args)
+{
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ const char *plist;
+
+ plist = yang_dnode_get_string(args->dnode, NULL);
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_ABORT:
+ case NB_EV_PREPARE:
+ break;
+ case NB_EV_APPLY:
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ pim_ifp = ifp->info;
+
+ XFREE(MTYPE_PIM_PLIST_NAME, pim_ifp->nbr_plist);
+ pim_ifp->nbr_plist = XSTRDUP(MTYPE_PIM_PLIST_NAME, plist);
+ break;
+ }
+
+ return NB_OK;
+}
+
+int lib_interface_pim_address_family_nbr_plist_destroy(struct nb_cb_destroy_args *args)
+{
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_ABORT:
+ case NB_EV_PREPARE:
+ break;
+ case NB_EV_APPLY:
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ pim_ifp = ifp->info;
+ XFREE(MTYPE_PIM_PLIST_NAME, pim_ifp->nbr_plist);
+ break;
+ }
+
+ return NB_OK;
+}
+
/*
* XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/bfd
*/
@@ -4388,6 +4446,72 @@ int lib_interface_gmp_address_family_last_member_query_interval_modify(
}
/*
+ * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/max-groups
+ */
+int lib_interface_gm_max_groups_modify(struct nb_cb_modify_args *args)
+{
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ 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;
+ }
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ pim_ifp = ifp->info;
+ pim_ifp->gm_group_limit = yang_dnode_get_uint32(args->dnode, NULL);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/max-sources
+ */
+int lib_interface_gm_max_sources_modify(struct nb_cb_modify_args *args)
+{
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ 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;
+ }
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ ifp = nb_running_get_entry(args->dnode, NULL, true);
+ pim_ifp = ifp->info;
+ pim_ifp->gm_source_limit = yang_dnode_get_uint32(args->dnode, NULL);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/robustness-variable
*/
int lib_interface_gmp_address_family_robustness_variable_modify(
@@ -4418,6 +4542,29 @@ int lib_interface_gmp_address_family_robustness_variable_modify(
}
/*
+ * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/immediate-leave
+ */
+int lib_interface_gmp_immediate_leave_modify(struct nb_cb_modify_args *args)
+{
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+
+ 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);
+ pim_ifp = ifp->info;
+ pim_ifp->gmp_immediate_leave = yang_dnode_get_bool(args->dnode, NULL);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/proxy
*/
int lib_interface_gmp_address_family_proxy_modify(struct nb_cb_modify_args *args)
diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c
index a41bbacea7..fb78e39022 100644
--- a/pimd/pim_pim.c
+++ b/pimd/pim_pim.c
@@ -149,6 +149,9 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
uint32_t pim_msg_len = 0;
uint16_t pim_checksum; /* received checksum */
uint16_t checksum; /* computed checksum */
+ struct pim_interface *pim_ifp = ifp->info;
+ struct prefix src_prefix;
+ struct prefix_list *nbr_plist = NULL;
struct pim_neighbor *neigh;
struct pim_msg_header *header;
bool no_fwd;
@@ -205,6 +208,41 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len,
return -1;
}
+ switch (header->type) {
+ case PIM_MSG_TYPE_HELLO:
+ case PIM_MSG_TYPE_JOIN_PRUNE:
+ case PIM_MSG_TYPE_ASSERT:
+ if (pim_ifp == NULL || pim_ifp->nbr_plist == NULL)
+ break;
+
+ nbr_plist = prefix_list_lookup(PIM_AFI, pim_ifp->nbr_plist);
+
+#if PIM_IPV == 4
+ src_prefix.family = AF_INET;
+ src_prefix.prefixlen = IPV4_MAX_BITLEN;
+ src_prefix.u.prefix4 = sg.src;
+#else
+ src_prefix.family = AF_INET6;
+ src_prefix.prefixlen = IPV6_MAX_BITLEN;
+ src_prefix.u.prefix6 = sg.src;
+#endif
+
+ if (nbr_plist &&
+ prefix_list_apply_ext(nbr_plist, NULL, &src_prefix, true) == PREFIX_PERMIT)
+ break;
+
+#if PIM_IPV == 4
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug("neighbor filter rejects packet %pI4 -> %pI4 on %s",
+ &ip_hdr->ip_src, &ip_hdr->ip_dst, ifp->name);
+#else
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug("neighbor filter rejects packet %pI6 -> %pI6 on %s", &sg.src,
+ &sg.grp, ifp->name);
+#endif
+ return -1;
+ }
+
/* save received checksum */
pim_checksum = header->checksum;
diff --git a/pimd/pim_register.c b/pimd/pim_register.c
index f776a59b7f..29e658ef16 100644
--- a/pimd/pim_register.c
+++ b/pimd/pim_register.c
@@ -186,8 +186,9 @@ int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size)
*/
for (ALL_LIST_ELEMENTS_RO(up->sources, up_node, child)) {
if (PIM_DEBUG_PIM_REG)
- zlog_debug("Executing Reg stop for %s",
- child->sg_str);
+ zlog_debug(
+ "Executing Reg stop for upstream child %s",
+ child->sg_str);
pim_reg_stop_upstream(pim, child);
}
@@ -208,8 +209,9 @@ int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size)
frr_each (rb_pim_upstream, &pim->upstream_head, up) {
if (pim_addr_cmp(up->sg.grp, sg.grp) == 0) {
if (PIM_DEBUG_PIM_REG)
- zlog_debug("Executing Reg stop for %s",
- up->sg_str);
+ zlog_debug(
+ "Executing Reg stop for upstream %s",
+ up->sg_str);
pim_reg_stop_upstream(pim, up);
}
}
@@ -682,9 +684,12 @@ int pim_register_recv(struct interface *ifp, pim_addr dest_addr,
}
}
- if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE)
- || ((SwitchToSptDesiredOnRp(pim, &sg))
- && pim_upstream_inherited_olist(pim, upstream) == 0)) {
+ if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) ||
+ (PIM_UPSTREAM_FLAG_TEST_FHR(upstream->flags) && i_am_rp) ||
+ ((SwitchToSptDesiredOnRp(pim, &sg)) &&
+ pim_upstream_inherited_olist(pim, upstream) == 0)) {
+ zlog_debug("sending pim register stop message : %s ",
+ upstream->sg_str);
pim_register_stop_send(ifp, &sg, dest_addr, src_addr);
sentRegisterStop = 1;
} else {
diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c
index c94b99d323..e4603ff946 100644
--- a/pimd/pim_upstream.c
+++ b/pimd/pim_upstream.c
@@ -312,7 +312,7 @@ static void on_join_timer(struct event *t)
}
/*
- * In the case of a HFR we will not ahve anyone to send this to.
+ * In the case of a FHR we will not ahve anyone to send this to.
*/
if (PIM_UPSTREAM_FLAG_TEST_FHR(up->flags))
return;
diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c
index a972a38c72..e37703be2b 100644
--- a/pimd/pim_vty.c
+++ b/pimd/pim_vty.c
@@ -457,6 +457,32 @@ int pim_config_write(struct vty *vty, int writes, struct interface *ifp,
++writes;
}
+ /* IF igmp/mld max-sources */
+ if (pim_ifp->gm_source_limit != UINT32_MAX) {
+ vty_out(vty, " " PIM_AF_NAME " " GM_AF_DBG " max-sources %u\n",
+ pim_ifp->gm_source_limit);
+ ++writes;
+ }
+
+ /* IF igmp/mld max-groups */
+ if (pim_ifp->gm_group_limit != UINT32_MAX) {
+ vty_out(vty, " " PIM_AF_NAME " " GM_AF_DBG " max-groups %u\n",
+ pim_ifp->gm_group_limit);
+ ++writes;
+ }
+
+ /* IF ip/ipv6 igmp/mld immediate-leave */
+ if (pim_ifp->gmp_immediate_leave) {
+ vty_out(vty, " " PIM_AF_NAME " " GM_AF_DBG " immediate-leave\n");
+ ++writes;
+ }
+
+ if (pim_ifp->nbr_plist) {
+ vty_out(vty, " " PIM_AF_NAME " pim allowed-neighbors prefix-list %s\n",
+ pim_ifp->nbr_plist);
+ ++writes;
+ }
+
/* IF ip pim drpriority */
if (pim_ifp->pim_dr_priority != PIM_DEFAULT_DR_PRIORITY) {
vty_out(vty, " " PIM_AF_NAME " pim drpriority %u\n",