summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pimd/pim_cmd.c41
-rw-r--r--pimd/pim_ifchannel.c2
-rw-r--r--pimd/pim_mroute.c24
-rw-r--r--pimd/pim_upstream.c113
-rw-r--r--pimd/pim_upstream.h8
-rw-r--r--pimd/pim_vty.c6
-rw-r--r--pimd/pimd.c1
-rw-r--r--pimd/pimd.h8
8 files changed, 173 insertions, 30 deletions
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 3c5a16ec68..de2b7cbba6 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -1040,6 +1040,7 @@ static void pim_show_interfaces(struct vty *vty, u_char uj)
struct pim_upstream *up;
int fhr = 0;
int pim_nbrs = 0;
+ int pim_ifchannels = 0;
json_object *json = NULL;
json_object *json_row = NULL;
json_object *json_tmp;
@@ -1056,6 +1057,7 @@ static void pim_show_interfaces(struct vty *vty, u_char uj)
continue;
pim_nbrs = pim_ifp->pim_neighbor_list->count;
+ pim_ifchannels = pim_ifp->pim_ifchannel_list->count;
fhr = 0;
for (ALL_LIST_ELEMENTS_RO(pim_upstream_list, upnode, up))
@@ -1066,6 +1068,7 @@ static void pim_show_interfaces(struct vty *vty, u_char uj)
json_row = json_object_new_object();
json_object_pim_ifp_add(json_row, ifp);
json_object_int_add(json_row, "pimNeighbors", pim_nbrs);
+ json_object_int_add(json_row, "pimIfChannels", pim_ifchannels);
json_object_int_add(json_row, "firstHopRouter", fhr);
json_object_string_add(json_row, "pimDesignatedRouter", inet_ntoa(pim_ifp->pim_dr_addr));
@@ -1078,7 +1081,7 @@ static void pim_show_interfaces(struct vty *vty, u_char uj)
if (uj) {
vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE);
} else {
- vty_out(vty, "Interface State Address PIM Nbrs PIM DR FHR%s", VTY_NEWLINE);
+ vty_out(vty, "Interface State Address PIM Nbrs PIM DR FHR IfChannels%s", VTY_NEWLINE);
json_object_object_foreach(json, key, val) {
vty_out(vty, "%-9s ", key);
@@ -1100,7 +1103,10 @@ static void pim_show_interfaces(struct vty *vty, u_char uj)
}
json_object_object_get_ex(val, "firstHopRouter", &json_tmp);
- vty_out(vty, "%3d%s", json_object_get_int(json_tmp), VTY_NEWLINE);
+ vty_out(vty, "%3d ", json_object_get_int(json_tmp));
+
+ json_object_object_get_ex(val, "pimIfChannels", &json_tmp);
+ vty_out(vty, "%9d%s", json_object_get_int(json_tmp), VTY_NEWLINE);
}
}
@@ -3410,6 +3416,35 @@ pim_rp_cmd_worker (struct vty *vty, const char *rp, const char *group, const cha
return CMD_SUCCESS;
}
+DEFUN (ip_pim_spt_switchover_infinity,
+ ip_pim_spt_switchover_infinity_cmd,
+ "ip pim spt-switchover infinity-and-beyond",
+ IP_STR
+ PIM_STR
+ "SPT-Switchover\n"
+ "Never switch to SPT Tree\n")
+{
+ pimg->spt_switchover = PIM_SPT_INFINITY;
+
+ pim_upstream_remove_lhr_star_pimreg();
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_pim_spt_switchover_infinity,
+ no_ip_pim_spt_switchover_infinity_cmd,
+ "no ip pim spt-switchover infinity-and-beyond",
+ NO_STR
+ IP_STR
+ PIM_STR
+ "SPT_Switchover\n"
+ "Never switch to SPT Tree\n")
+{
+ pimg->spt_switchover = PIM_SPT_IMMEDIATE;
+
+ pim_upstream_add_lhr_star_pimreg();
+ return CMD_SUCCESS;
+}
+
DEFUN (ip_pim_joinprune_time,
ip_pim_joinprune_time_cmd,
"ip pim join-prune-interval <60-600>",
@@ -6181,6 +6216,8 @@ void pim_cmd_init()
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_spt_switchover_infinity_cmd);
+ install_element (CONFIG_NODE, &no_ip_pim_spt_switchover_infinity_cmd);
install_element (CONFIG_NODE, &ip_pim_joinprune_time_cmd);
install_element (CONFIG_NODE, &no_ip_pim_joinprune_time_cmd);
install_element (CONFIG_NODE, &ip_pim_keep_alive_cmd);
diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c
index e6b4ba92a9..ebd36f8782 100644
--- a/pimd/pim_ifchannel.c
+++ b/pimd/pim_ifchannel.c
@@ -1006,6 +1006,8 @@ pim_ifchannel_local_membership_add(struct interface *ifp,
pim_upstream_switch (child, PIM_UPSTREAM_JOINED);
}
}
+ if (pimg->spt_switchover != PIM_SPT_INFINITY)
+ pim_channel_add_oif(up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP);
}
return 1;
diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c
index 2fb243b9bd..1df4c033bc 100644
--- a/pimd/pim_mroute.c
+++ b/pimd/pim_mroute.c
@@ -200,6 +200,30 @@ pim_mroute_msg_wholepkt (int fd, struct interface *ifp, const char *buf)
up = pim_upstream_find(&sg);
if (!up) {
+ struct prefix_sg star = sg;
+ star.src.s_addr = INADDR_ANY;
+
+ up = pim_upstream_find(&star);
+
+ if (up && PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags))
+ {
+ up = pim_upstream_add (&sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_LHR, __PRETTY_FUNCTION__);
+ if (!up)
+ {
+ if (PIM_DEBUG_MROUTE)
+ zlog_debug ("%s: Unable to create upstream information for %s",
+ __PRETTY_FUNCTION__, pim_str_sg_dump (&sg));
+ return 0;
+ }
+ pim_upstream_keep_alive_timer_start (up, qpim_keep_alive_time);
+ pim_upstream_inherited_olist (up);
+ pim_upstream_switch(up, PIM_UPSTREAM_JOINED);
+
+ if (PIM_DEBUG_MROUTE)
+ zlog_debug ("%s: Creating %s upstream on LHR",
+ __PRETTY_FUNCTION__, up->sg_str);
+ return 0;
+ }
if (PIM_DEBUG_MROUTE_DETAIL) {
zlog_debug("%s: Unable to find upstream channel WHOLEPKT%s",
__PRETTY_FUNCTION__, pim_str_sg_dump (&sg));
diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c
index 172d0d21c9..5743dac654 100644
--- a/pimd/pim_upstream.c
+++ b/pimd/pim_upstream.c
@@ -198,7 +198,20 @@ pim_upstream_del(struct pim_upstream *up, const char *name)
upstream_channel_oil_detach(up);
if (up->sources)
- list_delete (up->sources);
+ {
+ struct listnode *node, *nnode;
+ struct pim_upstream *child;
+ for (ALL_LIST_ELEMENTS (up->sources, node, nnode, child))
+ {
+ if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(child->flags))
+ {
+ PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(child->flags);
+ pim_upstream_del(child, __PRETTY_FUNCTION__);
+ }
+ }
+
+ list_delete (up->sources);
+ }
up->sources = NULL;
/*
@@ -1083,26 +1096,31 @@ pim_upstream_keep_alive_timer (struct thread *t)
up->t_ka_timer = NULL;
if (I_am_RP (up->sg.grp))
- {
- pim_br_clear_pmbr (&up->sg);
- /*
- * We need to do more here :)
- * But this is the start.
- */
- }
+ {
+ pim_br_clear_pmbr (&up->sg);
+ /*
+ * We need to do more here :)
+ * But this is the start.
+ */
+ }
/* source is no longer active - pull the SA from MSDP's cache */
pim_msdp_sa_local_del(&up->sg);
/* if entry was created because of activity we need to deref it */
if (PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
- {
- pim_upstream_fhr_kat_expiry(up);
- if (PIM_DEBUG_TRACE)
- zlog_debug ("kat expired on %s; remove stream reference", up->sg_str);
- PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
- pim_upstream_del(up, __PRETTY_FUNCTION__);
- }
+ {
+ pim_upstream_fhr_kat_expiry(up);
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("kat expired on %s; remove stream reference", up->sg_str);
+ PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(up->flags);
+ pim_upstream_del(up, __PRETTY_FUNCTION__);
+ }
+ else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags))
+ {
+ PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(up->flags);
+ pim_upstream_del(up, __PRETTY_FUNCTION__);
+ }
return 0;
}
@@ -1633,29 +1651,68 @@ pim_upstream_sg_running (void *arg)
return;
}
- if (pim_upstream_kat_start_ok(up)) {
- /* Add a source reference to the stream if
- * one doesn't already exist */
- if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
+ if (pim_upstream_kat_start_ok(up))
{
- if (PIM_DEBUG_TRACE)
- zlog_debug ("source reference created on kat restart %s", up->sg_str);
+ /* Add a source reference to the stream if
+ * one doesn't already exist */
+ if (!PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(up->flags))
+ {
+ if (PIM_DEBUG_TRACE)
+ zlog_debug ("source reference created on kat restart %s", up->sg_str);
- pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM);
- PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
- pim_upstream_fhr_kat_start(up);
+ pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM);
+ PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
+ pim_upstream_fhr_kat_start(up);
+ }
+ pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time);
}
+ else if (PIM_UPSTREAM_FLAG_TEST_SRC_LHR(up->flags))
pim_upstream_keep_alive_timer_start(up, qpim_keep_alive_time);
- }
if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE)
- {
- pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
- }
+ {
+ pim_upstream_set_sptbit(up, up->rpf.source_nexthop.interface);
+ }
return;
}
void
+pim_upstream_add_lhr_star_pimreg (void)
+{
+ struct pim_upstream *up;
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, node, up))
+ {
+ if (up->sg.src.s_addr != INADDR_ANY)
+ continue;
+
+ if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags))
+ continue;
+
+ pim_channel_add_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP);
+ }
+}
+
+void
+pim_upstream_remove_lhr_star_pimreg (void)
+{
+ struct pim_upstream *up;
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO (pim_upstream_list, node, up))
+ {
+ if (up->sg.src.s_addr != INADDR_ANY)
+ continue;
+
+ if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP (up->flags))
+ continue;
+
+ pim_channel_del_oif (up->channel_oil, pim_regiface, PIM_OIF_FLAG_PROTO_IGMP);
+ }
+}
+
+void
pim_upstream_init (void)
{
pim_upstream_sg_wheel = wheel_init (master, 31000, 100,
diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h
index 6f7556f323..a1af4483ac 100644
--- a/pimd/pim_upstream.h
+++ b/pimd/pim_upstream.h
@@ -34,6 +34,8 @@
#define PIM_UPSTREAM_FLAG_MASK_SRC_STREAM (1 << 5)
#define PIM_UPSTREAM_FLAG_MASK_SRC_MSDP (1 << 6)
#define PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE (1 << 7)
+#define PIM_UPSTREAM_FLAG_MASK_SRC_LHR (1 << 8)
+#define PIM_UPSTREAM_FLAG_ALL 0xFFFFFFFF
#define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
#define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
@@ -43,6 +45,7 @@
#define PIM_UPSTREAM_FLAG_TEST_SRC_STREAM(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
#define PIM_UPSTREAM_FLAG_TEST_SRC_MSDP(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
#define PIM_UPSTREAM_FLAG_TEST_SEND_SG_RPT_PRUNE(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE)
+#define PIM_UPSTREAM_FLAG_TEST_SRC_LHR(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_SRC_LHR)
#define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
#define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
@@ -52,6 +55,7 @@
#define PIM_UPSTREAM_FLAG_SET_SRC_STREAM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
#define PIM_UPSTREAM_FLAG_SET_SRC_MSDP(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
#define PIM_UPSTREAM_FLAG_SET_SEND_SG_RPT_PRUNE(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE)
+#define PIM_UPSTREAM_FLAG_SET_SRC_LHR(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_LHR)
#define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED)
#define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED)
@@ -61,6 +65,7 @@
#define PIM_UPSTREAM_FLAG_UNSET_SRC_STREAM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_STREAM)
#define PIM_UPSTREAM_FLAG_UNSET_SRC_MSDP(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_MSDP)
#define PIM_UPSTREAM_FLAG_UNSET_SEND_SG_RPT_PRUNE(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SEND_SG_RPT_PRUNE)
+#define PIM_UPSTREAM_FLAG_UNSET_SRC_LHR(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_LHR)
enum pim_upstream_state {
PIM_UPSTREAM_NOTJOINED,
@@ -193,4 +198,7 @@ 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);
+
+void pim_upstream_add_lhr_star_pimreg (void);
+void pim_upstream_remove_lhr_star_pimreg (void);
#endif /* PIM_UPSTREAM_H */
diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c
index f4bfcc5ce0..3d52dc9c41 100644
--- a/pimd/pim_vty.c
+++ b/pimd/pim_vty.c
@@ -182,6 +182,12 @@ int pim_global_config_write(struct vty *vty)
ssm->plist_name, VTY_NEWLINE);
++writes;
}
+ if (pimg->spt_switchover == PIM_SPT_INFINITY)
+ {
+ vty_out (vty, "ip pim spt-switchover infinity-and-beyond%s",
+ VTY_NEWLINE);
+ ++writes;
+ }
if (qpim_ssmpingd_list) {
struct listnode *node;
diff --git a/pimd/pimd.c b/pimd/pimd.c
index bdbd251e20..eaef4ff5c0 100644
--- a/pimd/pimd.c
+++ b/pimd/pimd.c
@@ -249,6 +249,7 @@ pim_instance_init (vrf_id_t vrf_id, afi_t afi)
pim->vrf_id = vrf_id;
pim->afi = afi;
+ pim->spt_switchover = PIM_SPT_IMMEDIATE;
pim->rpf_hash = hash_create_size (256, pim_rpf_hash_key, pim_rpf_equal);
if (PIM_DEBUG_ZEBRA)
diff --git a/pimd/pimd.h b/pimd/pimd.h
index 69aee28f8f..6c3dcfafca 100644
--- a/pimd/pimd.h
+++ b/pimd/pimd.h
@@ -237,11 +237,19 @@ extern int32_t qpim_register_probe_time;
#define PIM_DONT_DEBUG_MSDP_PACKETS (qpim_debugs &= ~PIM_MASK_MSDP_PACKETS)
#define PIM_DONT_DEBUG_MSDP_INTERNAL (qpim_debugs &= ~PIM_MASK_MSDP_INTERNAL)
+enum pim_spt_switchover {
+ PIM_SPT_IMMEDIATE,
+ PIM_SPT_INFINITY,
+};
+
/* Per VRF PIM DB */
struct pim_instance
{
afi_t afi;
vrf_id_t vrf_id;
+
+ enum pim_spt_switchover spt_switchover;
+
struct hash *rpf_hash;
void *ssm_info; /* per-vrf SSM configuration */
};