Merge pull request #291 from AnuradhaKaruppiah/pim-ssm

Pim ssm
This commit is contained in:
Jafar Al-Gharaibeh 2017-03-31 00:15:23 -05:00 committed by GitHub
commit 2b5c7fa46d
19 changed files with 572 additions and 41 deletions

View File

@ -53,7 +53,7 @@ libpim_a_SOURCES = \
pim_ssmpingd.c pim_int.c pim_rp.c \ pim_ssmpingd.c pim_int.c pim_rp.c \
pim_static.c pim_br.c pim_register.c pim_routemap.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_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 = \ noinst_HEADERS = \
pim_memory.h \ pim_memory.h \
@ -66,7 +66,7 @@ noinst_HEADERS = \
pim_igmp_join.h pim_ssmpingd.h pim_int.h pim_rp.h \ pim_igmp_join.h pim_ssmpingd.h pim_int.h pim_rp.h \
pim_static.h pim_br.h pim_register.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_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 = \ pimd_SOURCES = \
pim_main.c $(libpim_a_SOURCES) pim_main.c $(libpim_a_SOURCES)

View File

@ -54,6 +54,7 @@
#include "pim_rp.h" #include "pim_rp.h"
#include "pim_zlookup.h" #include "pim_zlookup.h"
#include "pim_msdp.h" #include "pim_msdp.h"
#include "pim_ssm.h"
static struct cmd_node pim_global_node = { static struct cmd_node pim_global_node = {
PIM_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); 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, DEFUN_HIDDEN (ip_multicast_routing,
ip_multicast_routing_cmd, ip_multicast_routing_cmd,
"ip multicast-routing", "ip multicast-routing",
@ -4292,7 +4440,7 @@ DEFUN (interface_no_ip_pim_drprio,
} }
static int static int
pim_cmd_interface_add (struct interface *ifp, enum pim_interface_type itype) pim_cmd_interface_add (struct interface *ifp)
{ {
struct pim_interface *pim_ifp = ifp->info; struct pim_interface *pim_ifp = ifp->info;
@ -4306,14 +4454,12 @@ pim_cmd_interface_add (struct interface *ifp, enum pim_interface_type itype)
PIM_IF_DO_PIM(pim_ifp->options); PIM_IF_DO_PIM(pim_ifp->options);
} }
pim_ifp->itype = itype;
pim_if_addr_add_all(ifp); pim_if_addr_add_all(ifp);
pim_if_membership_refresh(ifp); pim_if_membership_refresh(ifp);
return 1; return 1;
} }
DEFUN_HIDDEN (interface_ip_pim_ssm,
DEFUN (interface_ip_pim_ssm,
interface_ip_pim_ssm_cmd, interface_ip_pim_ssm_cmd,
"ip pim ssm", "ip pim ssm",
IP_STR IP_STR
@ -4322,11 +4468,12 @@ DEFUN (interface_ip_pim_ssm,
{ {
VTY_DECLVAR_CONTEXT(interface, ifp); VTY_DECLVAR_CONTEXT(interface, ifp);
if (!pim_cmd_interface_add(ifp, PIM_INTERFACE_SSM)) { if (!pim_cmd_interface_add(ifp)) {
vty_out(vty, "Could not enable PIM SSM on interface%s", VTY_NEWLINE); vty_out(vty, "Could not enable PIM SM on interface%s", VTY_NEWLINE);
return CMD_WARNING; return CMD_WARNING;
} }
vty_out(vty, "WARN: Enabled PIM SM on interface; configure PIM SSM range if needed%s", VTY_NEWLINE);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -4338,7 +4485,7 @@ DEFUN (interface_ip_pim_sm,
IFACE_PIM_SM_STR) IFACE_PIM_SM_STR)
{ {
VTY_DECLVAR_CONTEXT(interface, ifp); VTY_DECLVAR_CONTEXT(interface, ifp);
if (!pim_cmd_interface_add(ifp, PIM_INTERFACE_SM)) { if (!pim_cmd_interface_add(ifp)) {
vty_out(vty, "Could not enable PIM SM on interface%s", VTY_NEWLINE); vty_out(vty, "Could not enable PIM SM on interface%s", VTY_NEWLINE);
return CMD_WARNING; return CMD_WARNING;
} }
@ -4374,7 +4521,7 @@ pim_cmd_interface_delete (struct interface *ifp)
return 1; return 1;
} }
DEFUN (interface_no_ip_pim_ssm, DEFUN_HIDDEN (interface_no_ip_pim_ssm,
interface_no_ip_pim_ssm_cmd, interface_no_ip_pim_ssm_cmd,
"no ip pim ssm", "no ip pim ssm",
NO_STR NO_STR
@ -6029,6 +6176,9 @@ void pim_cmd_init()
install_element (CONFIG_NODE, &no_ip_pim_rp_cmd); install_element (CONFIG_NODE, &no_ip_pim_rp_cmd);
install_element (CONFIG_NODE, &ip_pim_rp_prefix_list_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_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, &ip_pim_register_suppress_cmd);
install_element (CONFIG_NODE, &no_ip_pim_register_suppress_cmd); install_element (CONFIG_NODE, &no_ip_pim_register_suppress_cmd);
install_element (CONFIG_NODE, &ip_pim_joinprune_time_cmd); install_element (CONFIG_NODE, &ip_pim_joinprune_time_cmd);
@ -6186,6 +6336,8 @@ void pim_cmd_init()
install_element (VIEW_NODE, &show_ip_msdp_sa_detail_cmd); 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_sa_sg_cmd);
install_element (VIEW_NODE, &show_ip_msdp_mesh_group_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_pim_use_source_cmd);
install_element (INTERFACE_NODE, &interface_no_pim_use_source_cmd); install_element (INTERFACE_NODE, &interface_no_pim_use_source_cmd);
} }

View File

@ -58,11 +58,6 @@ struct pim_iface_upstream_switch {
struct list *us; struct list *us;
}; };
enum pim_interface_type {
PIM_INTERFACE_SSM,
PIM_INTERFACE_SM
};
enum pim_secondary_addr_flags { enum pim_secondary_addr_flags {
PIM_SEC_ADDRF_NONE = 0, PIM_SEC_ADDRF_NONE = 0,
PIM_SEC_ADDRF_STALE = (1 << 0) PIM_SEC_ADDRF_STALE = (1 << 0)
@ -74,7 +69,6 @@ struct pim_secondary_addr {
}; };
struct pim_interface { struct pim_interface {
enum pim_interface_type itype;
uint32_t options; /* bit vector */ uint32_t options; /* bit vector */
ifindex_t mroute_vif_index; ifindex_t mroute_vif_index;
struct in_addr primary_address; /* remember addr to detect change */ struct in_addr primary_address; /* remember addr to detect change */

View File

@ -41,6 +41,7 @@
#include "pim_macro.h" #include "pim_macro.h"
#include "pim_oil.h" #include "pim_oil.h"
#include "pim_upstream.h" #include "pim_upstream.h"
#include "pim_ssm.h"
int int
pim_ifchannel_compare (struct pim_ifchannel *ch1, struct pim_ifchannel *ch2) pim_ifchannel_compare (struct pim_ifchannel *ch1, struct pim_ifchannel *ch2)
@ -967,6 +968,18 @@ pim_ifchannel_local_membership_add(struct interface *ifp,
if (!PIM_IF_TEST_PIM(pim_ifp->options)) if (!PIM_IF_TEST_PIM(pim_ifp->options))
return 0; 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); ch = pim_ifchannel_add(ifp, sg, PIM_UPSTREAM_FLAG_MASK_SRC_IGMP);
if (!ch) { if (!ch) {
return 0; return 0;

View File

@ -46,7 +46,6 @@
#include "pim_zebra.h" #include "pim_zebra.h"
#include "pim_msdp.h" #include "pim_msdp.h"
#include "pim_iface.h" #include "pim_iface.h"
#include "pim_rp.h"
extern struct host host; extern struct host host;
@ -120,8 +119,8 @@ int main(int argc, char** argv, char** envp) {
pim_vrf_init (); pim_vrf_init ();
access_list_init(); access_list_init();
prefix_list_init (); prefix_list_init ();
prefix_list_add_hook (pim_rp_prefix_list_update); prefix_list_add_hook (pim_prefix_list_update);
prefix_list_delete_hook (pim_rp_prefix_list_update); prefix_list_delete_hook (pim_prefix_list_update);
pim_route_map_init (); pim_route_map_init ();
pim_init(); pim_init();

View File

@ -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_JP_AGG_SOURCE, "PIM JP AGG Source")
DEFINE_MTYPE(PIMD, PIM_PIM_INSTANCE, "PIM global state") DEFINE_MTYPE(PIMD, PIM_PIM_INSTANCE, "PIM global state")
DEFINE_MTYPE(PIMD, PIM_NEXTHOP_CACHE, "PIM nexthop cache state") DEFINE_MTYPE(PIMD, PIM_NEXTHOP_CACHE, "PIM nexthop cache state")
DEFINE_MTYPE(PIMD, PIM_SSM_INFO, "PIM SSM configuration")

View File

@ -50,5 +50,6 @@ DECLARE_MTYPE(PIM_JP_AGG_GROUP)
DECLARE_MTYPE(PIM_JP_AGG_SOURCE) DECLARE_MTYPE(PIM_JP_AGG_SOURCE)
DECLARE_MTYPE(PIM_PIM_INSTANCE) DECLARE_MTYPE(PIM_PIM_INSTANCE)
DECLARE_MTYPE(PIM_NEXTHOP_CACHE) DECLARE_MTYPE(PIM_NEXTHOP_CACHE)
DECLARE_MTYPE(PIM_SSM_INFO)
#endif /* _QUAGGA_PIM_MEMORY_H */ #endif /* _QUAGGA_PIM_MEMORY_H */

View File

@ -39,6 +39,7 @@
#include "pim_register.h" #include "pim_register.h"
#include "pim_ifchannel.h" #include "pim_ifchannel.h"
#include "pim_zlookup.h" #include "pim_zlookup.h"
#include "pim_ssm.h"
/* GLOBAL VARS */ /* GLOBAL VARS */
static struct thread *qpim_mroute_socket_reader = NULL; static struct thread *qpim_mroute_socket_reader = NULL;
@ -127,8 +128,7 @@ pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg
*/ */
if ((pim_rpf_addr_is_inaddr_none (rpg)) || if ((pim_rpf_addr_is_inaddr_none (rpg)) ||
(!pim_ifp) || (!pim_ifp) ||
(!(PIM_I_am_DR(pim_ifp))) || (!(PIM_I_am_DR(pim_ifp))))
(pim_ifp->itype == PIM_INTERFACE_SSM))
{ {
if (PIM_DEBUG_MROUTE_DETAIL) if (PIM_DEBUG_MROUTE_DETAIL)
zlog_debug ("%s: Interface is not configured correctly to handle incoming packet: Could be !DR, !pim_ifp, !SM, !RP", zlog_debug ("%s: Interface is not configured correctly to handle incoming packet: Could be !DR, !pim_ifp, !SM, !RP",
@ -178,8 +178,7 @@ pim_mroute_msg_nocache (int fd, struct interface *ifp, const struct igmpmsg *msg
up->channel_oil->cc.pktcnt++; up->channel_oil->cc.pktcnt++;
PIM_UPSTREAM_FLAG_SET_FHR(up->flags); PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM); pim_register_join (up);
up->reg_state = PIM_REG_JOIN;
return 0; return 0;
} }
@ -214,8 +213,7 @@ pim_mroute_msg_wholepkt (int fd, struct interface *ifp, const char *buf)
if ((pim_rpf_addr_is_inaddr_none (rpg)) || if ((pim_rpf_addr_is_inaddr_none (rpg)) ||
(!pim_ifp) || (!pim_ifp) ||
(!(PIM_I_am_DR(pim_ifp))) || (!(PIM_I_am_DR(pim_ifp)))) {
(pim_ifp->itype == PIM_INTERFACE_SSM)) {
if (PIM_DEBUG_MROUTE) { if (PIM_DEBUG_MROUTE) {
zlog_debug("%s: Failed Check send packet", __PRETTY_FUNCTION__); zlog_debug("%s: Failed Check send packet", __PRETTY_FUNCTION__);
} }
@ -226,9 +224,18 @@ pim_mroute_msg_wholepkt (int fd, struct interface *ifp, const char *buf)
* If we've received a register suppress * If we've received a register suppress
*/ */
if (!up->t_rs_timer) if (!up->t_rs_timer)
{
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), pim_register_send((uint8_t *)buf + sizeof(struct ip),
ntohs (ip_hdr->ip_len) - sizeof (struct ip), ntohs (ip_hdr->ip_len) - sizeof (struct ip),
pim_ifp->primary_address, rpg, 0, up); pim_ifp->primary_address, rpg, 0, up);
}
return 0; return 0;
} }
@ -442,8 +449,7 @@ pim_mroute_msg_wrvifwhole (int fd, struct interface *ifp, const char *buf)
pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time); pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
up->channel_oil = oil; up->channel_oil = oil;
up->channel_oil->cc.pktcnt++; up->channel_oil->cc.pktcnt++;
pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM); pim_register_join (up);
up->reg_state = PIM_REG_JOIN;
pim_upstream_inherited_olist (up); pim_upstream_inherited_olist (up);
// Send the packet to the RP // Send the packet to the RP

View File

@ -43,9 +43,24 @@
#include "pim_zebra.h" #include "pim_zebra.h"
#include "pim_join.h" #include "pim_join.h"
#include "pim_util.h" #include "pim_util.h"
#include "pim_ssm.h"
struct thread *send_test_packet_timer = NULL; 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 void
pim_register_stop_send (struct interface *ifp, struct prefix_sg *sg, pim_register_stop_send (struct interface *ifp, struct prefix_sg *sg,
struct in_addr src, struct in_addr originator) struct in_addr src, struct in_addr originator)

View File

@ -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_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_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 #endif

158
pimd/pim_ssm.c Normal file
View File

@ -0,0 +1,158 @@
/*
* 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 <zebra.h>
#include <lib/linklist.h>
#include <lib/prefix.h>
#include <lib/vty.h>
#include <lib/vrf.h>
#include <lib/plist.h>
#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);
}

44
pimd/pim_ssm.h Normal file
View File

@ -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

View File

@ -53,6 +53,7 @@
#include "pim_msdp.h" #include "pim_msdp.h"
#include "pim_jp_agg.h" #include "pim_jp_agg.h"
#include "pim_nht.h" #include "pim_nht.h"
#include "pim_ssm.h"
struct hash *pim_upstream_hash = NULL; struct hash *pim_upstream_hash = NULL;
struct list *pim_upstream_list = NULL; struct list *pim_upstream_list = NULL;
@ -476,6 +477,51 @@ pim_upstream_could_register (struct pim_upstream *up)
return 0; 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 void
pim_upstream_switch(struct pim_upstream *up, pim_upstream_switch(struct pim_upstream *up,
enum pim_upstream_state new_state) enum pim_upstream_state new_state)
@ -507,9 +553,8 @@ pim_upstream_switch(struct pim_upstream *up,
PIM_UPSTREAM_FLAG_SET_FHR(up->flags); PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
if (!old_fhr && PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(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_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 else
@ -1018,10 +1063,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); zlog_debug ("kat started on %s; set fhr reg state to joined", up->sg_str);
PIM_UPSTREAM_FLAG_SET_FHR(up->flags); PIM_UPSTREAM_FLAG_SET_FHR(up->flags);
if (up->reg_state == PIM_REG_NOINFO) { if (up->reg_state == PIM_REG_NOINFO)
pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_PIM); pim_register_join (up);
up->reg_state = PIM_REG_JOIN;
}
} }
} }

View File

@ -192,4 +192,5 @@ void pim_upstream_terminate (void);
void join_timer_start (struct pim_upstream *up); void join_timer_start (struct pim_upstream *up);
int pim_upstream_compare (void *arg1, void *arg2); int pim_upstream_compare (void *arg1, void *arg2);
void pim_upstream_register_reevaluate (void);
#endif /* PIM_UPSTREAM_H */ #endif /* PIM_UPSTREAM_H */

View File

@ -38,6 +38,7 @@
#include "pim_static.h" #include "pim_static.h"
#include "pim_rp.h" #include "pim_rp.h"
#include "pim_msdp.h" #include "pim_msdp.h"
#include "pim_ssm.h"
int int
pim_debug_config_write (struct vty *vty) 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 pim_global_config_write(struct vty *vty)
{ {
int writes = 0; int writes = 0;
struct pim_ssm *ssm = pimg->ssm_info;
writes += pim_msdp_config_write (vty); writes += pim_msdp_config_write (vty);
@ -174,6 +176,12 @@ int pim_global_config_write(struct vty *vty)
qpim_packet_process, VTY_NEWLINE); qpim_packet_process, VTY_NEWLINE);
++writes; ++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) { if (qpim_ssmpingd_list) {
struct listnode *node; struct listnode *node;
@ -206,11 +214,7 @@ int pim_interface_config_write(struct vty *vty)
if (ifp->info) { if (ifp->info) {
struct pim_interface *pim_ifp = ifp->info; struct pim_interface *pim_ifp = ifp->info;
/* IF ip pim ssm */
if (PIM_IF_TEST_PIM(pim_ifp->options)) { if (PIM_IF_TEST_PIM(pim_ifp->options)) {
if (pim_ifp->itype == PIM_INTERFACE_SSM)
vty_out(vty, " ip pim ssm%s", VTY_NEWLINE);
else
vty_out(vty, " ip pim sm%s", VTY_NEWLINE); vty_out(vty, " ip pim sm%s", VTY_NEWLINE);
++writes; ++writes;
} }

View File

@ -46,6 +46,7 @@
#include "pim_igmpv3.h" #include "pim_igmpv3.h"
#include "pim_jp_agg.h" #include "pim_jp_agg.h"
#include "pim_nht.h" #include "pim_nht.h"
#include "pim_ssm.h"
#undef PIM_DEBUG_IFADDR_DUMP #undef PIM_DEBUG_IFADDR_DUMP
#define PIM_DEBUG_IFADDR_DUMP #define PIM_DEBUG_IFADDR_DUMP
@ -760,6 +761,84 @@ static int fib_lookup_if_vif_index(struct in_addr addr)
return vif_index; return vif_index;
} }
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) void igmp_source_forward_start(struct igmp_source *source)
{ {
struct igmp_group *group; struct igmp_group *group;

View File

@ -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_start(struct igmp_source *source);
void igmp_source_forward_stop(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_start(struct pim_ifchannel *ch);
void pim_forward_stop(struct pim_ifchannel *ch); void pim_forward_stop(struct pim_ifchannel *ch);

View File

@ -41,6 +41,7 @@
#include "pim_ssmpingd.h" #include "pim_ssmpingd.h"
#include "pim_static.h" #include "pim_static.h"
#include "pim_rp.h" #include "pim_rp.h"
#include "pim_ssm.h"
#include "pim_zlookup.h" #include "pim_zlookup.h"
#include "pim_nht.h" #include "pim_nht.h"
@ -182,6 +183,13 @@ pim_rp_list_hash_clean (void *data)
list_delete_all_node (pnc->upstream_list); 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 static void
pim_instance_terminate (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_clean (pimg->rpf_hash, (void *) pim_rp_list_hash_clean);
hash_free (pimg->rpf_hash); hash_free (pimg->rpf_hash);
} }
pim_ssm_terminate (pimg->ssm_info);
XFREE (MTYPE_PIM_PIM_INSTANCE, pimg); 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) if (PIM_DEBUG_ZEBRA)
zlog_debug ("%s: NHT rpf hash init ", __PRETTY_FUNCTION__); 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; return pim;
} }

View File

@ -24,6 +24,9 @@
#include <stdint.h> #include <stdint.h>
#include "zebra.h" #include "zebra.h"
#include "libfrr.h" #include "libfrr.h"
#include "prefix.h"
#include "vty.h"
#include "plist.h"
#include "pim_str.h" #include "pim_str.h"
#include "pim_memory.h" #include "pim_memory.h"
@ -240,6 +243,7 @@ struct pim_instance
afi_t afi; afi_t afi;
vrf_id_t vrf_id; vrf_id_t vrf_id;
struct hash *rpf_hash; struct hash *rpf_hash;
void *ssm_info; /* per-vrf SSM configuration */
}; };
extern struct pim_instance *pimg; //Pim Global Instance 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_init (void);
extern void pim_route_map_terminate(void); extern void pim_route_map_terminate(void);
void pim_vrf_init (void); void pim_vrf_init (void);
void pim_prefix_list_update (struct prefix_list *plist);
#endif /* PIMD_H */ #endif /* PIMD_H */