]> git.puffer.fish Git - mirror/frr.git/commitdiff
vrrpd: delay sending adverts/garp/una for iface up
authorQuentin Young <qlyoung@cumulusnetworks.com>
Mon, 4 Mar 2019 18:46:08 +0000 (18:46 +0000)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Fri, 17 May 2019 00:27:08 +0000 (00:27 +0000)
When transitioning to Master from Backup, wait until Zebra sets the
macvlan device to protodown off before transmitting advertisements,
gratuitous ARPs, or Unsolicited Neighbor Advertisements.

Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
vrrpd/vrrp.c
vrrpd/vrrp.h

index fc0a57b71c1a1b647e91292ddafcfe004bdbeaaf..070bb9cc792875501d29d888da5e9792a891146d 100644 (file)
@@ -553,10 +553,12 @@ static void vrrp_router_destroy(struct vrrp_router *r)
        if (r->is_active)
                vrrp_event(r, VRRP_EVENT_SHUTDOWN);
 
-       if (r->sock_rx >= 0)
+       if (r->sock_rx >= 0) {
                close(r->sock_rx);
-       if (r->sock_tx >= 0)
+       }
+       if (r->sock_tx >= 0) {
                close(r->sock_tx);
+       }
 
        /* FIXME: also delete list elements */
        list_delete(&r->addrs);
@@ -1276,6 +1278,11 @@ static void vrrp_change_state_backup(struct vrrp_router *r)
        /* Disable Adver_Timer */
        THREAD_OFF(r->t_adver_timer);
 
+       /* This should not be necessary, but just in case */
+       r->advert_pending = false;
+       r->garp_pending = false;
+       r->ndisc_pending = false;
+
        vrrp_zclient_send_interface_protodown(r->mvl_ifp, true);
 }
 
@@ -1294,6 +1301,11 @@ static void vrrp_change_state_initialize(struct vrrp_router *r)
        r->master_adver_interval = 0;
        vrrp_recalculate_timers(r);
 
+       /* This should not be necessary, but just in case */
+       r->advert_pending = false;
+       r->garp_pending = false;
+       r->ndisc_pending = false;
+
        /* Disable ND Router Advertisements */
        if (r->family == AF_INET6)
                vrrp_zebra_radv_set(r, false);
@@ -1367,16 +1379,23 @@ static int vrrp_master_down_timer_expire(struct thread *thread)
        zlog_info(VRRP_LOGPFX VRRP_LOGPFX_VRID "Master_Down_Timer expired",
                  r->vr->vrid);
 
-       vrrp_send_advertisement(r);
-       if (r->family == AF_INET)
-               vrrp_garp_send_all(r);
-       if (r->family == AF_INET6)
-               vrrp_ndisc_una_send_all(r);
        thread_add_timer_msec(master, vrrp_adver_timer_expire, r,
                              r->vr->advertisement_interval * 10,
                              &r->t_adver_timer);
        vrrp_change_state(r, VRRP_STATE_MASTER);
 
+       /*
+        * Since this implemention uses protodown to implement backup status,
+        * we have to wait for the interface to come up before we can send our
+        * initial advert and garp/ndisc packets. This will be handled in
+        * vrrp_if_up().
+        */
+       r->advert_pending = true;
+       if (r->family == AF_INET)
+               r->garp_pending = true;
+       if (r->family == AF_INET6)
+               r->ndisc_pending = true;
+
        return 0;
 }
 
@@ -1512,6 +1531,10 @@ static int vrrp_shutdown(struct vrrp_router *r)
                r->sock_tx = -1;
        }
 
+       r->advert_pending = false;
+       r->garp_pending = false;
+       r->ndisc_pending = false;
+
        vrrp_change_state(r, VRRP_STATE_INITIALIZE);
 
        r->is_active = false;
@@ -1942,9 +1965,52 @@ void vrrp_if_up(struct interface *ifp)
 
        vrs = vrrp_lookup_by_if_any(ifp);
 
-       for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr))
+       for (ALL_LIST_ELEMENTS_RO(vrs, ln, vr)) {
                vrrp_check_start(vr);
 
+               /*
+                * Handle the situation in which we performed a state
+                * transition on this VRRP router but needed to wait for the
+                * macvlan interface to come up to perform some actions
+                */
+               if (ifp == vr->v4->mvl_ifp) {
+                       if (vr->v4->advert_pending) {
+                               DEBUGD(&vrrp_dbg_proto,
+                                      VRRP_LOGPFX VRRP_LOGPFX_VRID
+                                      "Interface up; sending pending advertisement",
+                                      vr->vrid);
+                               vrrp_send_advertisement(vr->v4);
+                               vr->v4->advert_pending = false;
+                       }
+                       if (vr->v4->garp_pending) {
+                               DEBUGD(&vrrp_dbg_proto,
+                                      VRRP_LOGPFX VRRP_LOGPFX_VRID
+                                      "Interface up; sending pending gratuitous ARP",
+                                      vr->vrid);
+                               vrrp_garp_send_all(vr->v4);
+                               vr->v4->garp_pending = false;
+                       }
+               }
+               if (ifp == vr->v6->mvl_ifp) {
+                       if (vr->v6->advert_pending) {
+                               DEBUGD(&vrrp_dbg_proto,
+                                      VRRP_LOGPFX VRRP_LOGPFX_VRID
+                                      "Interface up; sending pending advertisement",
+                                      vr->vrid);
+                               vrrp_send_advertisement(vr->v6);
+                               vr->v6->advert_pending = false;
+                       }
+                       if (vr->v6->ndisc_pending) {
+                               DEBUGD(&vrrp_dbg_proto,
+                                      VRRP_LOGPFX VRRP_LOGPFX_VRID
+                                      "Interface up; sending pending Unsolicited Neighbor Advertisement",
+                                      vr->vrid);
+                               vrrp_ndisc_una_send_all(vr->v6);
+                               vr->v6->ndisc_pending = false;
+                       }
+               }
+       }
+
        list_delete(&vrs);
 
        vrrp_autoconfig_if_up(ifp);
index 4ea1a3737769a1cff7e498d6605598d2e2889be3..99cebd5c8aa27f1b0893bcf41db3fedc7a4f1b69 100644 (file)
@@ -120,6 +120,27 @@ struct vrrp_router {
         */
        struct list *addrs;
 
+       /*
+        * This flag says whether we are waiting on an interface up
+        * notification from Zebra before we send an ADVERTISEMENT.
+        */
+       bool advert_pending;
+
+       /*
+        * If this is an IPv4 VRRP router, this flag says whether we are
+        * waiting on an interface up notification from Zebra before we send
+        * gratuitous ARP packets for all our addresses. Should never be true
+        * if family == AF_INET6.
+        */
+       bool garp_pending;
+       /*
+        * If this is an IPv6 VRRP router, this flag says whether we are
+        * waiting on an interface up notification from Zebra before we send
+        * Unsolicited Neighbor Advertisement packets for all our addresses.
+        * Should never be true if family == AF_INET.
+        */
+       bool ndisc_pending;
+
        /*
         * Effective priority
         *    => vr->priority if we are Backup