]> git.puffer.fish Git - mirror/frr.git/commitdiff
pimd: register local VTEP-IP for each BUM MDT via NULL registers
authorAnuradha Karuppiah <anuradhak@cumulusnetworks.com>
Fri, 22 Mar 2019 20:38:50 +0000 (13:38 -0700)
committerAnuradha Karuppiah <anuradhak@cumulusnetworks.com>
Sat, 20 Apr 2019 15:33:22 +0000 (08:33 -0700)
For multicast vxlan tunnels we register the local VTEP-IP independent
of the prescence of BUM traffic i.e. we prime the pump. This
is acheived via NULL registers.

VxLAN orig entries with upstream in a PIM_REG_JOIN state are linked to
a work list for periodic NULL register transmission. Once the SPT setup
is complete the upstream-entry moves to a PIM_REG_PRUNE state and is
remved from the VxLAN work list.

Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
pimd/pim_register.c
pimd/pim_upstream.c
pimd/pim_vxlan.c
pimd/pim_vxlan.h

index e2f38aab8b189e196e0acb9a69f10a13df910445..372b7ba9954d3463d96166b47c0e76bd788fae51 100644 (file)
@@ -43,6 +43,7 @@
 #include "pim_join.h"
 #include "pim_util.h"
 #include "pim_ssm.h"
+#include "pim_vxlan.h"
 
 struct thread *send_test_packet_timer = NULL;
 
@@ -60,6 +61,7 @@ void pim_register_join(struct pim_upstream *up)
        pim_channel_add_oif(up->channel_oil, pim->regiface,
                            PIM_OIF_FLAG_PROTO_PIM);
        up->reg_state = PIM_REG_JOIN;
+       pim_vxlan_update_sg_reg_state(pim, up, TRUE /*reg_join*/);
 }
 
 void pim_register_stop_send(struct interface *ifp, struct prefix_sg *sg,
@@ -145,6 +147,8 @@ int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size)
                pim_channel_del_oif(upstream->channel_oil, pim->regiface,
                                    PIM_OIF_FLAG_PROTO_PIM);
                pim_upstream_start_register_stop_timer(upstream, 0);
+               pim_vxlan_update_sg_reg_state(pim, upstream,
+                       FALSE /*reg_join*/);
                break;
        case PIM_REG_JOIN_PENDING:
                upstream->reg_state = PIM_REG_PRUNE;
index dc37815bba001bbb556b52fddaa7d897203a2f79..7de2092a53cca3616c465f0bd0156067f34d6f05 100644 (file)
@@ -51,6 +51,7 @@
 #include "pim_jp_agg.h"
 #include "pim_nht.h"
 #include "pim_ssm.h"
+#include "pim_vxlan.h"
 
 static void join_timer_stop(struct pim_upstream *up);
 static void
@@ -1432,6 +1433,7 @@ static int pim_upstream_register_stop_timer(struct thread *t)
                up->reg_state = PIM_REG_JOIN;
                pim_channel_add_oif(up->channel_oil, pim->regiface,
                                    PIM_OIF_FLAG_PROTO_PIM);
+               pim_vxlan_update_sg_reg_state(pim, up, TRUE /*reg_join*/);
                break;
        case PIM_REG_JOIN:
                break;
index 24b71bf3d838b1155b656b528db9c083d54444aa..d6d6eaec1ba253d4aad9d2bb1be9e9381db24a4b 100644 (file)
 /* pim-vxlan global info */
 struct pim_vxlan vxlan_info, *pim_vxlan_p = &vxlan_info;
 
+static void pim_vxlan_work_timer_setup(bool start);
+
+/*************************** 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.
+ *
+ * A max of 500 NULL registers are generated at one shot. If paused reg
+ * generation continues on the next second and so on till all register
+ * messages have been sent out. And the process is restarted every 60s.
+ *
+ * purpose of this null register generation is to setup the SPT and maintain
+ * independent of the presence of overlay BUM traffic.
+ ****************************************************************************/
+static void pim_vxlan_do_reg_work(void)
+{
+       struct listnode *listnode;
+       int work_cnt = 0;
+       struct pim_vxlan_sg *vxlan_sg;
+       static int sec_count;
+
+       ++sec_count;
+
+       if (sec_count > PIM_VXLAN_NULL_REG_INTERVAL) {
+               sec_count = 0;
+               listnode = vxlan_info.next_work ?
+                                       vxlan_info.next_work :
+                                       vxlan_info.work_list->head;
+               if (PIM_DEBUG_VXLAN && listnode)
+                       zlog_debug("vxlan SG work %s",
+                               vxlan_info.next_work ? "continues" : "starts");
+       } else {
+               listnode = vxlan_info.next_work;
+       }
+
+       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",
+                                               vxlan_sg->sg_str);
+                       pim_null_register_send(vxlan_sg->up);
+                       ++work_cnt;
+               }
+
+               if (work_cnt > vxlan_info.max_work_cnt) {
+                       vxlan_info.next_work = listnode->next;
+                       if (PIM_DEBUG_VXLAN)
+                               zlog_debug("vxlan SG %d work items proc and pause",
+                                       work_cnt);
+                       return;
+               }
+       }
+
+       if (work_cnt) {
+               if (PIM_DEBUG_VXLAN)
+                       zlog_debug("vxlan SG %d work items proc", work_cnt);
+       }
+       vxlan_info.next_work = NULL;
+}
+
+/* Staggered work related info is initialized when the first work comes
+ * along
+ */
+static void pim_vxlan_init_work(void)
+{
+       if (vxlan_info.flags & PIM_VXLANF_WORK_INITED)
+               return;
+
+       vxlan_info.max_work_cnt = PIM_VXLAN_WORK_MAX;
+       vxlan_info.flags |= PIM_VXLANF_WORK_INITED;
+       vxlan_info.work_list = list_new();
+       pim_vxlan_work_timer_setup(TRUE /* start */);
+}
+
+static void pim_vxlan_add_work(struct pim_vxlan_sg *vxlan_sg)
+{
+       if (vxlan_sg->flags & PIM_VXLAN_SGF_DEL_IN_PROG) {
+               if (PIM_DEBUG_VXLAN)
+                       zlog_debug("vxlan SG %s skip work list; del-in-prog",
+                                       vxlan_sg->sg_str);
+               return;
+       }
+
+       pim_vxlan_init_work();
+
+       /* already a part of the work list */
+       if (vxlan_sg->work_node)
+               return;
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s work list add",
+                               vxlan_sg->sg_str);
+       vxlan_sg->work_node = listnode_add(vxlan_info.work_list, vxlan_sg);
+       /* XXX: adjust max_work_cnt if needed */
+}
+
+static void pim_vxlan_del_work(struct pim_vxlan_sg *vxlan_sg)
+{
+       if (!vxlan_sg->work_node)
+               return;
+
+       if (PIM_DEBUG_VXLAN)
+               zlog_debug("vxlan SG %s work list del",
+                               vxlan_sg->sg_str);
+
+       if (vxlan_sg->work_node == vxlan_info.next_work)
+               vxlan_info.next_work = vxlan_sg->work_node->next;
+
+       list_delete_node(vxlan_info.work_list, vxlan_sg->work_node);
+       vxlan_sg->work_node = NULL;
+}
+
+void pim_vxlan_update_sg_reg_state(struct pim_instance *pim,
+               struct pim_upstream *up, bool reg_join)
+{
+       struct pim_vxlan_sg *vxlan_sg;
+
+       vxlan_sg = pim_vxlan_sg_find(pim, &up->sg);
+       if (!vxlan_sg)
+               return;
+
+       /* add the vxlan sg entry to a work list for periodic reg joins.
+        * the entry will stay in the list as long as the register state is
+        * PIM_REG_JOIN
+        */
+       if (reg_join)
+               pim_vxlan_add_work(vxlan_sg);
+       else
+               pim_vxlan_del_work(vxlan_sg);
+}
+
+static int pim_vxlan_work_timer_cb(struct thread *t)
+{
+       pim_vxlan_do_reg_work();
+       pim_vxlan_work_timer_setup(true /* start */);
+       return 0;
+}
+
+/* global 1second timer used for periodic processing */
+static void pim_vxlan_work_timer_setup(bool start)
+{
+       THREAD_OFF(vxlan_info.work_timer);
+       if (start)
+               thread_add_timer(router->master, pim_vxlan_work_timer_cb, NULL,
+                       PIM_VXLAN_WORK_TIME, &vxlan_info.work_timer);
+}
+
 /**************************** vxlan origination mroutes ***********************
  * For every (local-vtep-ip, bum-mcast-grp) registered by evpn an origination
  * mroute is setup by pimd. The purpose of this mroute is to forward vxlan
@@ -394,6 +541,8 @@ void pim_vxlan_sg_del(struct pim_instance *pim, struct prefix_sg *sg)
 
        vxlan_sg->flags |= PIM_VXLAN_SGF_DEL_IN_PROG;
 
+       pim_vxlan_del_work(vxlan_sg);
+
        if (pim_vxlan_is_orig_mroute(vxlan_sg))
                pim_vxlan_orig_mr_del(vxlan_sg);
 
index 0f729b4fff72d38ab467112740841b501b844ed9..5b810c3071b697b98ac6dc8e8a1e9a1870fa73a2 100644 (file)
@@ -120,5 +120,7 @@ extern struct pim_vxlan_sg *pim_vxlan_sg_find(struct pim_instance *pim,
 extern struct pim_vxlan_sg *pim_vxlan_sg_add(struct pim_instance *pim,
                                           struct prefix_sg *sg);
 extern void pim_vxlan_sg_del(struct pim_instance *pim, struct prefix_sg *sg);
+extern void pim_vxlan_update_sg_reg_state(struct pim_instance *pim,
+               struct pim_upstream *up, bool reg_join);
 
 #endif /* PIM_VXLAN_H */