From 35c4790aa7f2e9273fd223783554a1aedd0c9097 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 12 Aug 2023 00:14:00 -0400 Subject: [PATCH] pimd: Allow more immediate null registers to be sent in the vxlan code When a pim vxlan S,G is created, the code attempts to send out a NULL register. This is used to build the S,G tree from the RP to the FHR. Upon initial startup it is not unusual for the pim vxlan state be fully ready to go but the RP is still not reachable. Let's add a bit of a pump prime that allows the vxlan code to re-attempt to send the null register for vxlan S,G's that the RP's outgoing interface changed from unknown to an actual interface. Signed-off-by: Donald Sharp --- pimd/pim_nht.c | 23 +++++++++++++++++++++++ pimd/pim_vxlan.c | 36 ++++++++++++++++++++++++++++++++++++ pimd/pim_vxlan.h | 3 +++ 3 files changed, 62 insertions(+) diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 5f0f2a5933..10d80312e2 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,6 +449,16 @@ 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( 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 */ -- 2.39.5