summaryrefslogtreecommitdiff
path: root/pimd
diff options
context:
space:
mode:
authormobash-rasool <mrasool@vmware.com>2023-08-15 22:26:21 +0530
committerGitHub <noreply@github.com>2023-08-15 22:26:21 +0530
commit2b4e03871166265ee82003b89d5e82a378478a97 (patch)
treeff8a601398e8df2a6954ae834e57f2a2fa591f7f /pimd
parent77014daf3a88f4a4e2874db93e4b3915937f20ee (diff)
parent538520239951422ac88791a8516a293fd1d3504c (diff)
Merge pull request #14193 from donaldsharp/pim_vxlan_weirdness
Do not look into pim's eyes, pim gets mad
Diffstat (limited to 'pimd')
-rw-r--r--pimd/pim_msg.c27
-rw-r--r--pimd/pim_nht.c41
-rw-r--r--pimd/pim_upstream.c1
-rw-r--r--pimd/pim_vxlan.c36
-rw-r--r--pimd/pim_vxlan.h3
5 files changed, 98 insertions, 10 deletions
diff --git a/pimd/pim_msg.c b/pimd/pim_msg.c
index 5d1f08314b..6814798bf5 100644
--- a/pimd/pim_msg.c
+++ b/pimd/pim_msg.c
@@ -196,7 +196,32 @@ size_t pim_msg_get_jp_group_size(struct list *sources)
__func__, up->sg_str);
for (ALL_LIST_ELEMENTS_RO(up->sources, up_node, child)) {
- if (!PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags)) {
+ /*
+ * PIM VXLAN is weird
+ * It auto creates the S,G and populates a bunch
+ * of flags that make it look like a SPT prune should
+ * be sent. But this regularly scheduled join
+ * for the *,G in the VXLAN setup can happen at
+ * scheduled times *before* the null register
+ * is received by the RP to cause it to initiate
+ * the S,G joins toward the source. Let's just
+ * assume that if this is a SRC VXLAN ORIG route
+ * and no actual ifchannels( joins ) have been
+ * created then do not send the embedded prune
+ * Why you may ask? Well if the prune is S,G
+ * RPT Prune is received *before* the join
+ * from the RP( if it flows to this routers
+ * upstream interface ) then we'll just wisely
+ * create a mroute with an empty oil on
+ * the upstream intermediate router preventing
+ * packets from flowing to the RP
+ */
+ if (PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(child->flags) &&
+ listcount(child->ifchannels) == 0) {
+ if (PIM_DEBUG_PIM_PACKETS)
+ zlog_debug("%s: %s Vxlan originated S,G route with no ifchannels, not adding prune to compound message",
+ __func__, child->sg_str);
+ } else if (!PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags)) {
/* If we are using SPT and the SPT and RPT IIFs
* are different we can prune the source off
* of the RPT.
diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c
index 5f0f2a5933..4e8e5f0df7 100644
--- a/pimd/pim_nht.c
+++ b/pimd/pim_nht.c
@@ -31,6 +31,8 @@
#include "pim_zlookup.h"
#include "pim_rp.h"
#include "pim_addr.h"
+#include "pim_register.h"
+#include "pim_vxlan.h"
/**
* pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
@@ -399,17 +401,28 @@ static void pim_update_rp_nh(struct pim_instance *pim,
{
struct listnode *node = NULL;
struct rp_info *rp_info = NULL;
+ struct interface *ifp;
/*Traverse RP list and update each RP Nexthop info */
for (ALL_LIST_ELEMENTS_RO(pnc->rp_list, node, rp_info)) {
if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
continue;
+ ifp = rp_info->rp.source_nexthop.interface;
// Compute PIM RPF using cached nexthop
if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
rp_info->rp.rpf_addr,
&rp_info->group, 1))
pim_rp_nexthop_del(rp_info);
+
+ /*
+ * If we transition from no path to a path
+ * we need to search through all the vxlan's
+ * that use this rp and send NULL registers
+ * for all the vxlan S,G streams
+ */
+ if (!ifp && rp_info->rp.source_nexthop.interface)
+ pim_vxlan_rp_info_is_alive(pim, &rp_info->rp);
}
}
@@ -436,17 +449,27 @@ static int pim_update_upstream_nh_helper(struct hash_bucket *bucket, void *arg)
(rpf_result == PIM_RPF_FAILURE && old.source_nexthop.interface))
pim_zebra_upstream_rpf_changed(pim, up, &old);
+ /*
+ * If we are a VXLAN source and we are transitioning from not
+ * having an outgoing interface to having an outgoing interface
+ * let's immediately send the null pim register
+ */
+ if (!old.source_nexthop.interface && up->rpf.source_nexthop.interface &&
+ PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(up->flags) &&
+ (up->reg_state == PIM_REG_NOINFO || up->reg_state == PIM_REG_JOIN)) {
+ pim_null_register_send(up);
+ }
if (PIM_DEBUG_PIM_NHT) {
- zlog_debug(
- "%s: NHT upstream %s(%s) old ifp %s new ifp %s",
- __func__, up->sg_str, pim->vrf->name,
- old.source_nexthop.interface ? old.source_nexthop
- .interface->name
- : "Unknown",
- up->rpf.source_nexthop.interface ? up->rpf.source_nexthop
- .interface->name
- : "Unknown");
+ zlog_debug("%s: NHT upstream %s(%s) old ifp %s new ifp %s rpf_result: %d",
+ __func__, up->sg_str, pim->vrf->name,
+ old.source_nexthop.interface ? old.source_nexthop
+ .interface->name
+ : "Unknown",
+ up->rpf.source_nexthop.interface ? up->rpf.source_nexthop
+ .interface->name
+ : "Unknown",
+ rpf_result);
}
return HASHWALK_CONTINUE;
diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c
index a8d087bf49..fd99e77761 100644
--- a/pimd/pim_upstream.c
+++ b/pimd/pim_upstream.c
@@ -912,6 +912,7 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
false /*update_mroute*/);
rpf_result = pim_rpf_update(pim, up, NULL, __func__);
if (rpf_result == PIM_RPF_FAILURE) {
+ up->channel_oil->oil_inherited_rescan = 1;
if (PIM_DEBUG_PIM_TRACE)
zlog_debug(
"%s: Attempting to create upstream(%s), Unable to RPF for source",
diff --git a/pimd/pim_vxlan.c b/pimd/pim_vxlan.c
index 8df3c90f00..9650da89a8 100644
--- a/pimd/pim_vxlan.c
+++ b/pimd/pim_vxlan.c
@@ -32,6 +32,41 @@ static void pim_vxlan_work_timer_setup(bool start);
static void pim_vxlan_set_peerlink_rif(struct pim_instance *pim,
struct interface *ifp);
+/*
+ * The rp info has gone from no path to having a
+ * path. Let's immediately send out the null pim register
+ * as that else we will be sitting for up to 60 seconds waiting
+ * for it too pop. Which is not cool.
+ */
+void pim_vxlan_rp_info_is_alive(struct pim_instance *pim,
+ struct pim_rpf *rpg_changed)
+{
+ struct listnode *listnode;
+ struct pim_vxlan_sg *vxlan_sg;
+ struct pim_rpf *rpg;
+
+ /*
+ * No vxlan here, move along, nothing to see
+ */
+ if (!vxlan_info.work_list)
+ return;
+
+ for (listnode = vxlan_info.work_list->head; listnode;
+ listnode = listnode->next) {
+ vxlan_sg = listgetdata(listnode);
+
+ rpg = RP(pim, vxlan_sg->up->sg.grp);
+
+ /*
+ * If the rp is the same we should send
+ */
+ if (rpg == rpg_changed) {
+ zlog_debug("VXLAN RP INFO is alive sending");
+ pim_null_register_send(vxlan_sg->up);
+ }
+ }
+}
+
/*************************** vxlan work list **********************************
* A work list is maintained for staggered generation of pim null register
* messages for vxlan SG entries that are in a reg_join state.
@@ -66,6 +101,7 @@ static void pim_vxlan_do_reg_work(void)
for (; listnode; listnode = listnode->next) {
vxlan_sg = (struct pim_vxlan_sg *)listnode->data;
+
if (vxlan_sg->up && (vxlan_sg->up->reg_state == PIM_REG_JOIN)) {
if (PIM_DEBUG_VXLAN)
zlog_debug("vxlan SG %s periodic NULL register",
diff --git a/pimd/pim_vxlan.h b/pimd/pim_vxlan.h
index 9a135ca6b8..5039bf6540 100644
--- a/pimd/pim_vxlan.h
+++ b/pimd/pim_vxlan.h
@@ -135,6 +135,9 @@ extern bool pim_vxlan_do_mlag_reg(void);
extern void pim_vxlan_inherit_mlag_flags(struct pim_instance *pim,
struct pim_upstream *up, bool inherit);
+extern void pim_vxlan_rp_info_is_alive(struct pim_instance *pim,
+ struct pim_rpf *rpg_changed);
+
/* Shutdown of PIM stop the thread */
extern void pim_vxlan_terminate(void);
#endif /* PIM_VXLAN_H */