From 15a5dafe44ea3f64351858496c042e4037c3e750 Mon Sep 17 00:00:00 2001 From: anuradhak Date: Fri, 17 Mar 2017 11:51:13 -0700 Subject: [PATCH] pimd: Allow SSM groups to co-exist with ASM groups. SSM groups (232/8 or user configured SSM range) can exist in the same multicast network as ASM groups. For such groups all RPT related state machine operations have to be skipped as defined by section 4.8 of RFC4601 - 1. Source registration is skipped for SSM groups. For SSM groups mroute is setup on the FHR when a new multicast flow is rxed; however source registration (i.e. pimreg join) is skipped. This will let the ASIC black hole the traffic till a valid OIL is added to the mroute. 2. (*,G) IGMP registrations are ignored for SSM groups. Sample output: ============= fhr# sh ip pim group-type SSM group range : 232.0.0.0/8 fhr# sh ip pim group-type 232.1.1.1 Group type: SSM fhr# sh ip pim group-type 239.1.1.1 Group type: ASM fhr# Sample config: ============= fhr(config)# ip pim ssm prefix-list ssm-ranges fhr(config)# Signed-off-by: Anuradha Karuppiah Reviewed-by: Donald Sharp Ticket: CM-15344 Testing Done: 1. SSM/ASM source-registration/igmp-joins. 2. On the fly multicast group type changes. 3. pim-smoke. --- pimd/Makefile.am | 4 +- pimd/pim_cmd.c | 153 ++++++++++++++++++++++++++++++++++++++++++ pimd/pim_ifchannel.c | 13 ++++ pimd/pim_main.c | 5 +- pimd/pim_memory.c | 1 + pimd/pim_memory.h | 1 + pimd/pim_mroute.c | 22 ++++-- pimd/pim_register.c | 15 +++++ pimd/pim_register.h | 1 + pimd/pim_ssm.c | 156 +++++++++++++++++++++++++++++++++++++++++++ pimd/pim_ssm.h | 44 ++++++++++++ pimd/pim_upstream.c | 55 +++++++++++++-- pimd/pim_upstream.h | 1 + pimd/pim_vty.c | 8 +++ pimd/pim_zebra.c | 79 ++++++++++++++++++++++ pimd/pim_zebra.h | 1 + pimd/pimd.c | 14 ++++ pimd/pimd.h | 5 ++ 18 files changed, 560 insertions(+), 18 deletions(-) create mode 100644 pimd/pim_ssm.c create mode 100644 pimd/pim_ssm.h diff --git a/pimd/Makefile.am b/pimd/Makefile.am index 7e1b451eab..77eb5c7568 100644 --- a/pimd/Makefile.am +++ b/pimd/Makefile.am @@ -53,7 +53,7 @@ libpim_a_SOURCES = \ pim_ssmpingd.c pim_int.c pim_rp.c \ pim_static.c pim_br.c pim_register.c pim_routemap.c \ pim_msdp.c pim_msdp_socket.c pim_msdp_packet.c \ - pim_jp_agg.c pim_nht.c + pim_jp_agg.c pim_nht.c pim_ssm.c noinst_HEADERS = \ pim_memory.h \ @@ -66,7 +66,7 @@ noinst_HEADERS = \ pim_igmp_join.h pim_ssmpingd.h pim_int.h pim_rp.h \ pim_static.h pim_br.h pim_register.h \ pim_msdp.h pim_msdp_socket.h pim_msdp_packet.h pim_nht.h \ - pim_jp_agg.h + pim_jp_agg.h pim_ssm.h pimd_SOURCES = \ pim_main.c $(libpim_a_SOURCES) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index cf101b3e24..fc836aee3c 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -54,6 +54,7 @@ #include "pim_rp.h" #include "pim_zlookup.h" #include "pim_msdp.h" +#include "pim_ssm.h" static struct cmd_node pim_global_node = { PIM_NODE, @@ -3598,6 +3599,153 @@ DEFUN (no_ip_pim_rp_prefix_list, return pim_no_rp_cmd_worker (vty, argv[4]->arg, NULL, argv[6]->arg); } +static int +pim_ssm_cmd_worker (struct vty *vty, const char *plist) +{ + int result = pim_ssm_range_set (VRF_DEFAULT, plist); + + if (result == PIM_SSM_ERR_NONE) + return CMD_SUCCESS; + + switch (result) + { + case PIM_SSM_ERR_NO_VRF: + vty_out (vty, "%% VRF doesn't exist%s", VTY_NEWLINE); + break; + case PIM_SSM_ERR_DUP: + vty_out (vty, "%% duplicate config%s", VTY_NEWLINE); + break; + default: + vty_out (vty, "%% ssm range config failed%s", VTY_NEWLINE); + } + + return CMD_WARNING; +} + +DEFUN (ip_pim_ssm_prefix_list, + ip_pim_ssm_prefix_list_cmd, + "ip pim ssm prefix-list WORD", + IP_STR + "pim multicast routing\n" + "Source Specific Multicast\n" + "group range prefix-list filter\n" + "Name of a prefix-list\n") +{ + return pim_ssm_cmd_worker (vty, argv[0]->arg); +} + +DEFUN (no_ip_pim_ssm_prefix_list, + no_ip_pim_ssm_prefix_list_cmd, + "no ip pim ssm prefix-list", + NO_STR + IP_STR + "pim multicast routing\n" + "Source Specific Multicast\n" + "group range prefix-list filter\n") +{ + return pim_ssm_cmd_worker (vty, NULL); +} + +DEFUN (no_ip_pim_ssm_prefix_list_name, + no_ip_pim_ssm_prefix_list_name_cmd, + "no ip pim ssm prefix-list WORD", + NO_STR + IP_STR + "pim multicast routing\n" + "Source Specific Multicast\n" + "group range prefix-list filter\n" + "Name of a prefix-list\n") +{ + struct pim_ssm *ssm = pimg->ssm_info; + + if (ssm->plist_name && !strcmp(ssm->plist_name, argv[0]->arg)) + return pim_ssm_cmd_worker (vty, NULL); + + vty_out (vty, "%% pim ssm prefix-list %s doesn't exist%s", + argv[0]->arg, VTY_NEWLINE); + + return CMD_WARNING; +} + +static void +ip_pim_ssm_show_group_range(struct vty *vty, u_char uj) +{ + struct pim_ssm *ssm = pimg->ssm_info; + const char *range_str = ssm->plist_name?ssm->plist_name:PIM_SSM_STANDARD_RANGE; + + if (uj) + { + json_object *json; + json = json_object_new_object(); + json_object_string_add(json, "ssmGroups", range_str); + vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE); + json_object_free(json); + } + else + vty_out(vty, "SSM group range : %s%s", range_str, VTY_NEWLINE); +} + +DEFUN (show_ip_pim_ssm_range, + show_ip_pim_ssm_range_cmd, + "show ip pim group-type [json]", + SHOW_STR + IP_STR + PIM_STR + "PIM group type\n" + "JavaScript Object Notation\n") +{ + u_char uj = use_json(argc, argv); + ip_pim_ssm_show_group_range(vty, uj); + + return CMD_SUCCESS; +} + +static void +ip_pim_ssm_show_group_type(struct vty *vty, u_char uj, const char *group) +{ + struct in_addr group_addr; + const char *type_str; + int result; + + result = inet_pton(AF_INET, group, &group_addr); + if (result <= 0) + type_str = "invalid"; + else + { + if (pim_is_group_224_4 (group_addr)) + type_str = pim_is_grp_ssm (group_addr)?"SSM":"ASM"; + else + type_str = "not-multicast"; + } + + if (uj) + { + json_object *json; + json = json_object_new_object(); + json_object_string_add(json, "groupType", type_str); + vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE); + json_object_free(json); + } + else + vty_out(vty, "Group type : %s%s", type_str, VTY_NEWLINE); +} + +DEFUN (show_ip_pim_group_type, + show_ip_pim_group_type_cmd, + "show ip pim group-type A.B.C.D [json]", + SHOW_STR + IP_STR + PIM_STR + "multicast group type\n" + "group address\n" + "JavaScript Object Notation\n") +{ + u_char uj = use_json(argc, argv); + ip_pim_ssm_show_group_type(vty, uj, argv[0]->arg); + + return CMD_SUCCESS; +} + DEFUN_HIDDEN (ip_multicast_routing, ip_multicast_routing_cmd, "ip multicast-routing", @@ -6029,6 +6177,9 @@ void pim_cmd_init() install_element (CONFIG_NODE, &no_ip_pim_rp_cmd); install_element (CONFIG_NODE, &ip_pim_rp_prefix_list_cmd); install_element (CONFIG_NODE, &no_ip_pim_rp_prefix_list_cmd); + install_element (CONFIG_NODE, &no_ip_pim_ssm_prefix_list_cmd); + install_element (CONFIG_NODE, &no_ip_pim_ssm_prefix_list_name_cmd); + install_element (CONFIG_NODE, &ip_pim_ssm_prefix_list_cmd); install_element (CONFIG_NODE, &ip_pim_register_suppress_cmd); install_element (CONFIG_NODE, &no_ip_pim_register_suppress_cmd); install_element (CONFIG_NODE, &ip_pim_joinprune_time_cmd); @@ -6186,6 +6337,8 @@ void pim_cmd_init() install_element (VIEW_NODE, &show_ip_msdp_sa_detail_cmd); install_element (VIEW_NODE, &show_ip_msdp_sa_sg_cmd); install_element (VIEW_NODE, &show_ip_msdp_mesh_group_cmd); + install_element (VIEW_NODE, &show_ip_pim_ssm_range_cmd); + install_element (VIEW_NODE, &show_ip_pim_group_type_cmd); install_element (INTERFACE_NODE, &interface_pim_use_source_cmd); install_element (INTERFACE_NODE, &interface_no_pim_use_source_cmd); } diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index 6dc1fba375..e0e00ae67d 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -41,6 +41,7 @@ #include "pim_macro.h" #include "pim_oil.h" #include "pim_upstream.h" +#include "pim_ssm.h" int pim_ifchannel_compare (struct pim_ifchannel *ch1, struct pim_ifchannel *ch2) @@ -966,6 +967,18 @@ pim_ifchannel_local_membership_add(struct interface *ifp, if (!PIM_IF_TEST_PIM(pim_ifp->options)) return 0; + /* skip (*,G) ch creation if G is of type SSM */ + if (sg->src.s_addr == INADDR_ANY) + { + if (pim_is_grp_ssm (sg->grp)) + { + if (PIM_DEBUG_PIM_EVENTS) + zlog_debug("%s: local membership (S,G)=%s ignored as group is SSM", + __PRETTY_FUNCTION__, pim_str_sg_dump (sg)); + return 1; + } + } + ch = pim_ifchannel_add(ifp, sg, PIM_UPSTREAM_FLAG_MASK_SRC_IGMP); if (!ch) { return 0; diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 07f2812725..d814af6b2c 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -46,7 +46,6 @@ #include "pim_zebra.h" #include "pim_msdp.h" #include "pim_iface.h" -#include "pim_rp.h" extern struct host host; @@ -120,8 +119,8 @@ int main(int argc, char** argv, char** envp) { pim_vrf_init (); access_list_init(); prefix_list_init (); - prefix_list_add_hook (pim_rp_prefix_list_update); - prefix_list_delete_hook (pim_rp_prefix_list_update); + prefix_list_add_hook (pim_prefix_list_update); + prefix_list_delete_hook (pim_prefix_list_update); pim_route_map_init (); pim_init(); diff --git a/pimd/pim_memory.c b/pimd/pim_memory.c index f46cf193bb..2acca6f49b 100644 --- a/pimd/pim_memory.c +++ b/pimd/pim_memory.c @@ -51,3 +51,4 @@ DEFINE_MTYPE(PIMD, PIM_JP_AGG_GROUP, "PIM JP AGG Group") DEFINE_MTYPE(PIMD, PIM_JP_AGG_SOURCE, "PIM JP AGG Source") DEFINE_MTYPE(PIMD, PIM_PIM_INSTANCE, "PIM global state") DEFINE_MTYPE(PIMD, PIM_NEXTHOP_CACHE, "PIM nexthop cache state") +DEFINE_MTYPE(PIMD, PIM_SSM_INFO, "PIM SSM configuration") diff --git a/pimd/pim_memory.h b/pimd/pim_memory.h index bd9e12f2fc..02446de46a 100644 --- a/pimd/pim_memory.h +++ b/pimd/pim_memory.h @@ -50,5 +50,6 @@ DECLARE_MTYPE(PIM_JP_AGG_GROUP) DECLARE_MTYPE(PIM_JP_AGG_SOURCE) DECLARE_MTYPE(PIM_PIM_INSTANCE) DECLARE_MTYPE(PIM_NEXTHOP_CACHE) +DECLARE_MTYPE(PIM_SSM_INFO) #endif /* _QUAGGA_PIM_MEMORY_H */ diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 04b6a4c697..56f9f62ef9 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -39,6 +39,7 @@ #include "pim_register.h" #include "pim_ifchannel.h" #include "pim_zlookup.h" +#include "pim_ssm.h" /* GLOBAL VARS */ static struct thread *qpim_mroute_socket_reader = NULL; @@ -178,8 +179,7 @@ pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg up->channel_oil->cc.pktcnt++; PIM_UPSTREAM_FLAG_SET_FHR(up->flags); - pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM); - up->reg_state = PIM_REG_JOIN; + pim_register_join (up); return 0; } @@ -226,9 +226,18 @@ pim_mroute_msg_wholepkt (int fd, struct interface *ifp, const char *buf) * If we've received a register suppress */ if (!up->t_rs_timer) - pim_register_send((uint8_t *)buf + sizeof(struct ip), - ntohs (ip_hdr->ip_len) - sizeof (struct ip), - pim_ifp->primary_address, rpg, 0, up); + { + if (pim_is_grp_ssm (sg.grp)) + { + if (PIM_DEBUG_PIM_REG) + zlog_debug ("%s register forward skipped as group is SSM", + pim_str_sg_dump (&sg)); + return 0; + } + pim_register_send((uint8_t *)buf + sizeof(struct ip), + ntohs (ip_hdr->ip_len) - sizeof (struct ip), + pim_ifp->primary_address, rpg, 0, up); + } return 0; } @@ -442,8 +451,7 @@ pim_mroute_msg_wrvifwhole (int fd, struct interface *ifp, const char *buf) pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time); up->channel_oil = oil; up->channel_oil->cc.pktcnt++; - pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM); - up->reg_state = PIM_REG_JOIN; + pim_register_join (up); pim_upstream_inherited_olist (up); // Send the packet to the RP diff --git a/pimd/pim_register.c b/pimd/pim_register.c index cb9d7e3744..effc212722 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -43,9 +43,24 @@ #include "pim_zebra.h" #include "pim_join.h" #include "pim_util.h" +#include "pim_ssm.h" struct thread *send_test_packet_timer = NULL; +void +pim_register_join (struct pim_upstream *up) +{ + if (pim_is_grp_ssm (up->sg.grp)) + { + if (PIM_DEBUG_PIM_EVENTS) + zlog_debug ("%s register setup skipped as group is SSM", up->sg_str); + return; + } + + pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM); + up->reg_state = PIM_REG_JOIN; +} + void pim_register_stop_send (struct interface *ifp, struct prefix_sg *sg, struct in_addr src, struct in_addr originator) diff --git a/pimd/pim_register.h b/pimd/pim_register.h index 42a908b225..210a904ae9 100644 --- a/pimd/pim_register.h +++ b/pimd/pim_register.h @@ -40,5 +40,6 @@ int pim_register_recv (struct interface *ifp, void pim_register_send (const uint8_t *buf, int buf_size, struct in_addr src, struct pim_rpf *rpg, int null_register, struct pim_upstream *up); void pim_register_stop_send (struct interface *ifp, struct prefix_sg *sg, struct in_addr src, struct in_addr originator); +void pim_register_join (struct pim_upstream *up); #endif diff --git a/pimd/pim_ssm.c b/pimd/pim_ssm.c new file mode 100644 index 0000000000..49e4bdf023 --- /dev/null +++ b/pimd/pim_ssm.c @@ -0,0 +1,156 @@ +/* + * IP SSM ranges for FRR + * Copyright (C) 2017 Cumulus Networks, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include "pimd.h" +#include "pim_ssm.h" +#include "pim_zebra.h" + +static void +pim_ssm_range_reevaluate (void) +{ + /* 1. Setup register state for (S,G) entries if G has changed from SSM to + * ASM. + * 2. check existing (*,G) IGMP registrations to see if they are + * still ASM. if they are now SSM delete them. + * 3. Allow channel setup for IGMP (*,G) members if G is now ASM + * 4. I could tear down all (*,G), (S,G,rpt) states. But that is an + * unnecessary sladge hammer and may not be particularly useful as it is + * likely the SPT switchover has already happened for flows along such RPTs. + * As for the RPT states it seems that the best thing to do is let them age + * out gracefully. As long as the FHR and LHR do the right thing RPTs will + * disappear in time for SSM groups. + */ + pim_upstream_register_reevaluate (); + igmp_source_forward_reevaluate_all (); +} + +void +pim_ssm_prefix_list_update (struct prefix_list *plist) +{ + struct pim_ssm *ssm = pimg->ssm_info; + + if (!ssm->plist_name || strcmp (ssm->plist_name, prefix_list_name (plist))) + { + /* not ours */ + return; + } + + pim_ssm_range_reevaluate (); +} + +static int +pim_is_grp_standard_ssm (struct prefix *group) +{ + static int first = 1; + static struct prefix group_ssm; + + if (first) + { + str2prefix (PIM_SSM_STANDARD_RANGE, &group_ssm); + first = 0; + } + + return prefix_match (&group_ssm, group); +} + +int +pim_is_grp_ssm (struct in_addr group_addr) +{ + struct pim_ssm *ssm; + struct prefix group; + struct prefix_list *plist; + + memset (&group, 0, sizeof (group)); + group.family = AF_INET; + group.u.prefix4 = group_addr; + group.prefixlen = 32; + + ssm = pimg->ssm_info; + if (!ssm->plist_name) + { + return pim_is_grp_standard_ssm (&group); + } + + plist = prefix_list_lookup (AFI_IP, ssm->plist_name); + if (!plist) + return 0; + + return (prefix_list_apply (plist, &group) == PREFIX_PERMIT); +} + +int +pim_ssm_range_set (vrf_id_t vrf_id, const char *plist_name) +{ + struct pim_ssm *ssm; + int change = 0; + + if (vrf_id != VRF_DEFAULT) + return PIM_SSM_ERR_NO_VRF; + + ssm = pimg->ssm_info; + if (plist_name) + { + if (ssm->plist_name) + { + if (!strcmp (ssm->plist_name, plist_name)) + return PIM_SSM_ERR_DUP; + XFREE (MTYPE_PIM_FILTER_NAME, ssm->plist_name); + } + ssm->plist_name = XSTRDUP (MTYPE_PIM_FILTER_NAME, plist_name); + change = 1; + } + else + { + if (ssm->plist_name) + { + change = 1; + XFREE (MTYPE_PIM_FILTER_NAME, ssm->plist_name); + } + } + + if (change) + pim_ssm_range_reevaluate (); + + return PIM_SSM_ERR_NONE; +} + +void * +pim_ssm_init (vrf_id_t vrf_id) +{ + struct pim_ssm *ssm; + + ssm = XCALLOC (MTYPE_PIM_SSM_INFO, sizeof (*ssm)); + ssm->vrf_id = vrf_id; + + return ssm; +} + +void +pim_ssm_terminate (struct pim_ssm *ssm) +{ + if (ssm && ssm->plist_name) + XFREE (MTYPE_PIM_FILTER_NAME, ssm->plist_name); +} diff --git a/pimd/pim_ssm.h b/pimd/pim_ssm.h new file mode 100644 index 0000000000..ca82d334f1 --- /dev/null +++ b/pimd/pim_ssm.h @@ -0,0 +1,44 @@ +/* + * IP SSM ranges for FRR + * Copyright (C) 2017 Cumulus Networks, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +#ifndef PIM_SSM_H +#define PIM_SSM_H + +#define PIM_SSM_STANDARD_RANGE "232.0.0.0/8" + +/* SSM error codes */ +enum pim_ssm_err +{ + PIM_SSM_ERR_NONE = 0, + PIM_SSM_ERR_NO_VRF = -1, + PIM_SSM_ERR_DUP = -2, +}; + +struct pim_ssm +{ + vrf_id_t vrf_id; + char *plist_name; /* prefix list of group ranges */ +}; + +void pim_ssm_prefix_list_update (struct prefix_list *plist); +int pim_is_grp_ssm (struct in_addr group_addr); +int pim_ssm_range_set (vrf_id_t vrf_id, const char *plist_name); +void *pim_ssm_init (vrf_id_t vrf_id); +void pim_ssm_terminate (struct pim_ssm *ssm); +#endif diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 327e4f07d7..8d0a2dee25 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -53,6 +53,7 @@ #include "pim_msdp.h" #include "pim_jp_agg.h" #include "pim_nht.h" +#include "pim_ssm.h" struct hash *pim_upstream_hash = NULL; struct list *pim_upstream_list = NULL; @@ -476,6 +477,51 @@ pim_upstream_could_register (struct pim_upstream *up) return 0; } +/* Source registration is supressed for SSM groups. When the SSM range changes + * we re-revaluate register setup for existing upstream entries */ +void +pim_upstream_register_reevaluate (void) +{ + struct listnode *upnode; + struct pim_upstream *up; + + for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, upnode, up)) + { + /* If FHR is set CouldRegister is True. Also check if the flow + * is actually active; if it is not kat setup will trigger source + * registration whenever the flow becomes active. */ + if (!PIM_UPSTREAM_FLAG_TEST_FHR (up->flags) || !up->t_ka_timer) + continue; + + if (pim_is_grp_ssm (up->sg.grp)) + { + /* clear the register state for SSM groups */ + if (up->reg_state != PIM_REG_NOINFO) + { + if (PIM_DEBUG_PIM_EVENTS) + zlog_debug ("Clear register for %s as G is now SSM", + up->sg_str); + /* remove regiface from the OIL if it is there*/ + pim_channel_del_oif (up->channel_oil, pim_regiface, + PIM_OIF_FLAG_PROTO_PIM); + up->reg_state = PIM_REG_NOINFO; + } + } + else + { + /* register ASM sources with the RP */ + if (up->reg_state == PIM_REG_NOINFO) + { + if (PIM_DEBUG_PIM_EVENTS) + zlog_debug ("Register %s as G is now ASM", up->sg_str); + pim_channel_add_oif (up->channel_oil, pim_regiface, + PIM_OIF_FLAG_PROTO_PIM); + up->reg_state = PIM_REG_JOIN; + } + } + } +} + void pim_upstream_switch(struct pim_upstream *up, enum pim_upstream_state new_state) @@ -507,9 +553,8 @@ pim_upstream_switch(struct pim_upstream *up, PIM_UPSTREAM_FLAG_SET_FHR(up->flags); if (!old_fhr && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags)) { - up->reg_state = PIM_REG_JOIN; pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time); - pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM); + pim_register_join (up); } } else @@ -1008,10 +1053,8 @@ static void pim_upstream_fhr_kat_start(struct pim_upstream *up) zlog_debug ("kat started on %s; set fhr reg state to joined", up->sg_str); PIM_UPSTREAM_FLAG_SET_FHR(up->flags); - if (up->reg_state == PIM_REG_NOINFO) { - pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM); - up->reg_state = PIM_REG_JOIN; - } + if (up->reg_state == PIM_REG_NOINFO) + pim_register_join (up); } } diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index 126824e988..8e045ff010 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -188,4 +188,5 @@ void pim_upstream_terminate (void); void join_timer_start (struct pim_upstream *up); int pim_upstream_compare (void *arg1, void *arg2); +void pim_upstream_register_reevaluate (void); #endif /* PIM_UPSTREAM_H */ diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 5b6a79b95a..e6a9d1b9e3 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -38,6 +38,7 @@ #include "pim_static.h" #include "pim_rp.h" #include "pim_msdp.h" +#include "pim_ssm.h" int pim_debug_config_write (struct vty *vty) @@ -145,6 +146,7 @@ pim_debug_config_write (struct vty *vty) int pim_global_config_write(struct vty *vty) { int writes = 0; + struct pim_ssm *ssm = pimg->ssm_info; writes += pim_msdp_config_write (vty); @@ -174,6 +176,12 @@ int pim_global_config_write(struct vty *vty) qpim_packet_process, VTY_NEWLINE); ++writes; } + if (ssm->plist_name) + { + vty_out (vty, "ip pim ssm prefix-list %s%s", + ssm->plist_name, VTY_NEWLINE); + ++writes; + } if (qpim_ssmpingd_list) { struct listnode *node; diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index bf2c838abb..ccb184fcf2 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -46,6 +46,7 @@ #include "pim_igmpv3.h" #include "pim_jp_agg.h" #include "pim_nht.h" +#include "pim_ssm.h" #undef PIM_DEBUG_IFADDR_DUMP #define PIM_DEBUG_IFADDR_DUMP @@ -896,6 +897,84 @@ static int del_oif(struct channel_oil *channel_oil, return 0; } +static void +igmp_source_forward_reevaluate_one(struct igmp_source *source) +{ + struct prefix_sg sg; + struct igmp_group *group = source->source_group; + struct pim_ifchannel *ch; + + if ((source->source_addr.s_addr != INADDR_ANY) || + !IGMP_SOURCE_TEST_FORWARDING (source->source_flags)) + return; + + memset (&sg, 0, sizeof (struct prefix_sg)); + sg.src = source->source_addr; + sg.grp = group->group_addr; + + ch = pim_ifchannel_find (group->group_igmp_sock->interface, &sg); + if (pim_is_grp_ssm (group->group_addr)) + { + /* If SSM group withdraw local membership */ + if (ch && (ch->local_ifmembership == PIM_IFMEMBERSHIP_INCLUDE)) + { + if (PIM_DEBUG_PIM_EVENTS) + zlog_debug ("local membership del for %s as G is now SSM", + pim_str_sg_dump (&sg)); + pim_ifchannel_local_membership_del (group->group_igmp_sock->interface, &sg); + } + } + else + { + /* If ASM group add local membership */ + if (!ch || (ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO)) + { + if (PIM_DEBUG_PIM_EVENTS) + zlog_debug ("local membership add for %s as G is now ASM", + pim_str_sg_dump (&sg)); + pim_ifchannel_local_membership_add (group->group_igmp_sock->interface, &sg); + } + } +} + +void +igmp_source_forward_reevaluate_all(void) +{ + struct listnode *ifnode; + struct interface *ifp; + + for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT), ifnode, ifp)) + { + struct pim_interface *pim_ifp = ifp->info; + struct listnode *sock_node; + struct igmp_sock *igmp; + + if (!pim_ifp) + continue; + + /* scan igmp sockets */ + for (ALL_LIST_ELEMENTS_RO (pim_ifp->igmp_socket_list, sock_node, igmp)) + { + struct listnode *grpnode; + struct igmp_group *grp; + + /* scan igmp groups */ + for (ALL_LIST_ELEMENTS_RO (igmp->igmp_group_list, grpnode, grp)) + { + struct listnode *srcnode; + struct igmp_source *src; + + /* scan group sources */ + for (ALL_LIST_ELEMENTS_RO (grp->group_source_list, + srcnode, src)) + { + igmp_source_forward_reevaluate_one (src); + } /* scan group sources */ + } /* scan igmp groups */ + } /* scan igmp sockets */ + } /* scan interfaces */ +} + void igmp_source_forward_start(struct igmp_source *source) { struct igmp_group *group; diff --git a/pimd/pim_zebra.h b/pimd/pim_zebra.h index 5dc06a4a19..2ed463efaa 100644 --- a/pimd/pim_zebra.h +++ b/pimd/pim_zebra.h @@ -38,6 +38,7 @@ void igmp_anysource_forward_stop(struct igmp_group *group); void igmp_source_forward_start(struct igmp_source *source); void igmp_source_forward_stop(struct igmp_source *source); +void igmp_source_forward_reevaluate_all(void); void pim_forward_start(struct pim_ifchannel *ch); void pim_forward_stop(struct pim_ifchannel *ch); diff --git a/pimd/pimd.c b/pimd/pimd.c index b67544b28e..72fe0e7046 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -41,6 +41,7 @@ #include "pim_ssmpingd.h" #include "pim_static.h" #include "pim_rp.h" +#include "pim_ssm.h" #include "pim_zlookup.h" #include "pim_nht.h" @@ -182,6 +183,13 @@ pim_rp_list_hash_clean (void *data) list_delete_all_node (pnc->upstream_list); } +void +pim_prefix_list_update (struct prefix_list *plist) +{ + pim_rp_prefix_list_update (plist); + pim_ssm_prefix_list_update (plist); +} + static void pim_instance_terminate (void) { @@ -191,6 +199,7 @@ pim_instance_terminate (void) hash_clean (pimg->rpf_hash, (void *) pim_rp_list_hash_clean); hash_free (pimg->rpf_hash); } + pim_ssm_terminate (pimg->ssm_info); XFREE (MTYPE_PIM_PIM_INSTANCE, pimg); } @@ -233,6 +242,11 @@ pim_instance_init (vrf_id_t vrf_id, afi_t afi) if (PIM_DEBUG_ZEBRA) zlog_debug ("%s: NHT rpf hash init ", __PRETTY_FUNCTION__); + pim->ssm_info = pim_ssm_init (vrf_id); + if (!pim->ssm_info) { + pim_instance_terminate (); + return NULL; + } return pim; } diff --git a/pimd/pimd.h b/pimd/pimd.h index b3bdd9e243..69aee28f8f 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -24,6 +24,9 @@ #include #include "zebra.h" #include "libfrr.h" +#include "prefix.h" +#include "vty.h" +#include "plist.h" #include "pim_str.h" #include "pim_memory.h" @@ -240,6 +243,7 @@ struct pim_instance afi_t afi; vrf_id_t vrf_id; struct hash *rpf_hash; + void *ssm_info; /* per-vrf SSM configuration */ }; extern struct pim_instance *pimg; //Pim Global Instance @@ -250,5 +254,6 @@ void pim_terminate(void); extern void pim_route_map_init (void); extern void pim_route_map_terminate(void); void pim_vrf_init (void); +void pim_prefix_list_update (struct prefix_list *plist); #endif /* PIMD_H */ -- 2.39.5