]> git.proxmox.com Git - mirror_frr.git/commitdiff
pimd: Allow SSM groups to co-exist with ASM groups.
authoranuradhak <anuradhak@cumulusnetworks.com>
Fri, 17 Mar 2017 18:51:13 +0000 (11:51 -0700)
committeranuradhak <anuradhak@cumulusnetworks.com>
Thu, 23 Mar 2017 16:47:53 +0000 (09:47 -0700)
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 <anuradhak@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Ticket: CM-15344
Testing Done:
1. SSM/ASM source-registration/igmp-joins.
2. On the fly multicast group type changes.
3. pim-smoke.

18 files changed:
pimd/Makefile.am
pimd/pim_cmd.c
pimd/pim_ifchannel.c
pimd/pim_main.c
pimd/pim_memory.c
pimd/pim_memory.h
pimd/pim_mroute.c
pimd/pim_register.c
pimd/pim_register.h
pimd/pim_ssm.c [new file with mode: 0644]
pimd/pim_ssm.h [new file with mode: 0644]
pimd/pim_upstream.c
pimd/pim_upstream.h
pimd/pim_vty.c
pimd/pim_zebra.c
pimd/pim_zebra.h
pimd/pimd.c
pimd/pimd.h

index 7e1b451eab266c9ec822146ee2078f78585a8f93..77eb5c7568f628905fe8ac9af5f9719f1635b490 100644 (file)
@@ -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)
index cf101b3e245a19e48995d05c9a87acc5c3593d11..fc836aee3cf147b3003782c8dffff2344656c6ee 100644 (file)
@@ -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);
 }
index 6dc1fba3755ece6fed7d0a51f114139fbadf9b2d..e0e00ae67d808d0f4c298dd89611bb0e8565a62d 100644 (file)
@@ -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;
index 07f2812725a9fd2ddba04261cda4cfe11b17c04d..d814af6b2c1ba9b2750f5488f800a8790ad8b750 100644 (file)
@@ -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();
index f46cf193bb16944ab59181e1214b2aa7cd184b83..2acca6f49be879483ee3cdc56db6fa8c4eaac0d0 100644 (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_PIM_INSTANCE,      "PIM global state")
 DEFINE_MTYPE(PIMD, PIM_NEXTHOP_CACHE,     "PIM nexthop cache state")
+DEFINE_MTYPE(PIMD, PIM_SSM_INFO,          "PIM SSM configuration")
index bd9e12f2fc4de6b4984a27e4bd641487e3a10d25..02446de46a65f93d48c725d129490a15ba10cb86 100644 (file)
@@ -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 */
index 04b6a4c697af147e70a8487738f4e6bcbc932da5..56f9f62ef9125412cc53631ef06e039352e0b0e5 100644 (file)
@@ -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
index cb9d7e3744d4439ccc283960b05b4d47182d5490..effc212722b46e1c46e1cd3f4b14d00e8368c971 100644 (file)
 #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)
index 42a908b225af702efff0b0afdbbfb3f31098b691..210a904ae9488af0133458b5de04076b90efb229 100644 (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_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 (file)
index 0000000..49e4bdf
--- /dev/null
@@ -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 <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);
+}
diff --git a/pimd/pim_ssm.h b/pimd/pim_ssm.h
new file mode 100644 (file)
index 0000000..ca82d33
--- /dev/null
@@ -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
index 327e4f07d7fff5207d400c8ab5bb9bd65982d8c4..8d0a2dee2548439dbd343f90f79ea2c1503e9fa1 100644 (file)
@@ -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);
   }
 }
 
index 126824e9888fb5e2f45e36b66dcbfc50124596cb..8e045ff0105d9e60a0031924cddcdd8e67641431 100644 (file)
@@ -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 */
index 5b6a79b95a0a22daaeee7d07dd546c626a41a1ea..e6a9d1b9e3c6c01a7cdb60771d6af97023ac56f1 100644 (file)
@@ -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;
index bf2c838abb21b167b9ac136342593738a99e4d62..ccb184fcf2292e7dc4fb0dd1da34dfbcf3f069e3 100644 (file)
@@ -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;
index 5dc06a4a19d7916113a0efc63cf6ae5976fc05ed..2ed463efaad14c842997efedd4e2303b03dbe8a4 100644 (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_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);
index b67544b28efed659b163c09a19e164ebfd96940b..72fe0e7046cff0d79e2a875334162bdfc15fec4f 100644 (file)
@@ -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;
 }
index b3bdd9e243ce72c1f30a78e1f0d8567b7cac5366..69aee28f8f86cbca70ee5edd902978e9e1d53fca 100644 (file)
@@ -24,6 +24,9 @@
 #include <stdint.h>
 #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 */