]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: add support for DF delay timer 7634/head
authorAnuradha Karuppiah <anuradhak@cumulusnetworks.com>
Sun, 14 Jun 2020 19:13:23 +0000 (12:13 -0700)
committerAnuradha Karuppiah <anuradhak@nvidia.com>
Tue, 15 Dec 2020 18:03:50 +0000 (10:03 -0800)
When a new ES is created it is held in a non-DF state for 3 seconds
as specified by RFC7432. This allows the switch time to import
the Type-4 routes from the peers. And the peers time to rx the new
Type-4 route.

root@torm-11:mgmt:~# vtysh -c "show evpn es 03:44:38:39:ff:ff:01:00:00:01"|grep DF
 DF status: non-df
 DF delay: 00:00:01
 DF preference: 50000
root@torm-11:mgmt:~# vtysh -c "show evpn es 03:44:38:39:ff:ff:01:00:00:01"|grep DF
 DF status: df
 DF preference: 50000
root@torm-11:mgmt:~#

Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
zebra/zebra_evpn_mh.c
zebra/zebra_evpn_mh.h

index 2d7552aa41cfe12054067c4e434e33c4ce83ec57..3a0df1c0152773f9968516bddccec51dd5fece91 100644 (file)
@@ -1470,16 +1470,16 @@ static bool zebra_evpn_es_br_port_dplane_update(struct zebra_evpn_es *es,
 
 /* returns TRUE if dplane entry was updated */
 static bool zebra_evpn_es_df_change(struct zebra_evpn_es *es, bool new_non_df,
-                                   const char *caller)
+                                   const char *caller, const char *reason)
 {
        bool old_non_df;
 
        old_non_df = !!(es->flags & ZEBRA_EVPNES_NON_DF);
 
        if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
-               zlog_debug("df-change(%s) es %s old %s new %s", caller,
-                          es->esi_str, old_non_df ? "non-df" : "df",
-                          new_non_df ? "non-df" : "df");
+               zlog_debug("df-change es %s %s to %s; %s: %s", es->esi_str,
+                          old_non_df ? "non-df" : "df",
+                          new_non_df ? "non-df" : "df", caller, reason);
 
        if (old_non_df == new_non_df)
                return false;
@@ -1507,7 +1507,8 @@ static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
         */
        if (!(es->flags & ZEBRA_EVPNES_LOCAL)
            || !zmh_info->es_originator_ip.s_addr)
-               return zebra_evpn_es_df_change(es, new_non_df, caller);
+               return zebra_evpn_es_df_change(es, new_non_df, caller,
+                                              "not-ready");
 
        /* if oper-state is down DF filtering must be on. when the link comes
         * up again dataplane should block BUM till FRR has had the chance
@@ -1515,7 +1516,18 @@ static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
         */
        if (!(es->flags & ZEBRA_EVPNES_OPER_UP)) {
                new_non_df = true;
-               return zebra_evpn_es_df_change(es, new_non_df, caller);
+               return zebra_evpn_es_df_change(es, new_non_df, caller,
+                                              "oper-down");
+       }
+
+       /* ES was just created; we need to wait for the peers to rx the
+        * our Type-4 routes and for the switch to import the peers' Type-4
+        * routes
+        */
+       if (es->df_delay_timer) {
+               new_non_df = true;
+               return zebra_evpn_es_df_change(es, new_non_df, caller,
+                                              "df-delay");
        }
 
        for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
@@ -1547,7 +1559,7 @@ static bool zebra_evpn_es_run_df_election(struct zebra_evpn_es *es,
                }
        }
 
-       return zebra_evpn_es_df_change(es, new_non_df, caller);
+       return zebra_evpn_es_df_change(es, new_non_df, caller, "elected");
 }
 
 static void zebra_evpn_es_vtep_add(struct zebra_evpn_es *es,
@@ -1932,6 +1944,20 @@ static void zebra_evpn_mh_dup_addr_detect_off(void)
        }
 }
 
+static int zebra_evpn_es_df_delay_exp_cb(struct thread *t)
+{
+       struct zebra_evpn_es *es;
+
+       es = THREAD_ARG(t);
+
+       if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
+               zlog_debug("es %s df-delay expired", es->esi_str);
+
+       zebra_evpn_es_run_df_election(es, __func__);
+
+       return 0;
+}
+
 static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
                struct zebra_if *zif)
 {
@@ -1971,6 +1997,12 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es,
                zebra_evpn_es_re_eval_send_to_client(es,
                        false /* es_evi_re_reval */);
 
+       /* Start the DF delay timer on the local ES */
+       if (!es->df_delay_timer)
+               thread_add_timer(zrouter.master, zebra_evpn_es_df_delay_exp_cb,
+                                es, ZEBRA_EVPN_MH_DF_DELAY_TIME,
+                                &es->df_delay_timer);
+
        /* See if the local VTEP can function as DF on the ES */
        if (!zebra_evpn_es_run_df_election(es, __func__)) {
                /* check if the dplane entry needs to be re-programmed as a
@@ -2007,6 +2039,8 @@ static void zebra_evpn_es_local_info_clear(struct zebra_evpn_es **esp)
 
        es->flags &= ~(ZEBRA_EVPNES_LOCAL | ZEBRA_EVPNES_READY_FOR_BGP);
 
+       THREAD_OFF(es->df_delay_timer);
+
        /* remove the DF filter */
        dplane_updated = zebra_evpn_es_run_df_election(es, __func__);
 
@@ -2696,6 +2730,7 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty,
        char alg_buf[EVPN_DF_ALG_STR_LEN];
        struct zebra_evpn_es_vtep *es_vtep;
        struct listnode *node;
+       char thread_buf[THREAD_TIMER_STRLEN];
 
        if (json) {
                json_object *json_vteps;
@@ -2732,6 +2767,12 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty,
                                    listcount(es->es_evi_list));
                json_object_int_add(json, "macCount", listcount(es->mac_list));
                json_object_int_add(json, "dfPreference", es->df_pref);
+               if (es->df_delay_timer)
+                       json_object_string_add(
+                               json, "dfDelayTimer",
+                               thread_timer_to_hhmmss(thread_buf,
+                                                      sizeof(thread_buf),
+                                                      es->df_delay_timer));
                json_object_int_add(json, "nexthopGroup", es->nhg_id);
                if (listcount(es->es_vtep_list)) {
                        json_vteps = json_object_new_array();
@@ -2766,12 +2807,16 @@ static void zebra_evpn_es_show_entry_detail(struct vty *vty,
                                "yes" : "no");
                vty_out(vty, " VNI Count: %d\n", listcount(es->es_evi_list));
                vty_out(vty, " MAC Count: %d\n", listcount(es->mac_list));
-               vty_out(vty, " DF: status: %s preference: %u\n",
-                       !(es->flags & ZEBRA_EVPNES_LOCAL)
-                               ? "-"
-                               : ((es->flags & ZEBRA_EVPNES_NON_DF) ? "non-df"
-                                                                    : "df"),
-                       es->df_pref);
+               if (es->flags & ZEBRA_EVPNES_LOCAL)
+                       vty_out(vty, " DF status: %s \n",
+                               (es->flags & ZEBRA_EVPNES_NON_DF) ? "non-df"
+                                                                 : "df");
+               if (es->df_delay_timer)
+                       vty_out(vty, " DF delay: %s\n",
+                               thread_timer_to_hhmmss(thread_buf,
+                                                      sizeof(thread_buf),
+                                                      es->df_delay_timer));
+               vty_out(vty, " DF preference: %u\n", es->df_pref);
                vty_out(vty, " Nexthop group: %u\n", es->nhg_id);
                vty_out(vty, " VTEPs:\n");
                for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
@@ -3479,8 +3524,7 @@ static void zebra_evpn_mh_startup_delay_timer_start(const char *rc)
        if (zmh_info->startup_delay_timer) {
                if (IS_ZEBRA_DEBUG_EVPN_MH_ES)
                        zlog_debug("startup-delay timer cancelled");
-               thread_cancel(&zmh_info->startup_delay_timer);
-               zmh_info->startup_delay_timer = NULL;
+               THREAD_OFF(zmh_info->startup_delay_timer);
        }
 
        if (zmh_info->startup_delay_time) {
index dc2c299cf23fddf0983b217c1847c5cd477df2b0..14b29875740a83acd6aca31d862a77d630921247 100644 (file)
@@ -88,6 +88,13 @@ struct zebra_evpn_es {
         * advertised via the ESR
         */
        uint16_t df_pref;
+
+       /* When a new ES is configured it is held in a non-DF state
+        * for 3 seconds. This allows the peer Type-4 routes to be
+        * imported before running the DF election.
+        */
+#define ZEBRA_EVPN_MH_DF_DELAY_TIME 3 /* seconds */
+       struct thread *df_delay_timer;
 };
 RB_HEAD(zebra_es_rb_head, zebra_evpn_es);
 RB_PROTOTYPE(zebra_es_rb_head, zebra_evpn_es, rb_node, zebra_es_rb_cmp);