@@ -176,6 +176,28 @@ static struct {
176176/* FAULT */ { {NULL }, {NULL }, {vrrp_sync_master }, {NULL } }
177177};
178178
179+ static void
180+ vrrp_state_set_backup (vrrp_t * vrrp )
181+ {
182+ log_message (LOG_INFO , "(%s) VRRP moving state to backup" , vrrp -> iname );
183+ vrrp -> state = VRRP_STATE_BACK ;
184+ }
185+
186+ static void
187+ vrrp_fault_exit_timer_thread (thread_ref_t thread )
188+ {
189+ vrrp_t * vrrp = THREAD_ARG (thread );
190+
191+ log_message (LOG_INFO , "(%s) VRRP fault_init_exit_delay of %g seconds complete." ,
192+ vrrp -> iname , vrrp -> fault_init_exit_delay /TIMER_HZ_DOUBLE );
193+
194+ if (vrrp -> fault_exit_timer_cb )
195+ vrrp -> fault_exit_timer_cb (vrrp );
196+ vrrp -> fault_exit_timer_thread = NULL ;
197+ vrrp -> fault_exit_timer_cb = NULL ;
198+ vrrp -> fault_exit_time .tv_sec = 0 ;
199+ }
200+
179201/*
180202 * Initialize state handling
181203 * --rfc2338.6.4.1
@@ -274,8 +296,15 @@ vrrp_init_state(list_head_t *l)
274296 !vrrp -> num_script_init &&
275297 (!vrrp -> sync || !vrrp -> sync -> num_member_init )) {
276298 if (vrrp -> state != VRRP_STATE_BACK ) {
277- log_message (LOG_INFO , "(%s) Entering BACKUP STATE (init)" , vrrp -> iname );
278- vrrp -> state = VRRP_STATE_BACK ;
299+ if (vrrp -> state == VRRP_STATE_FAULT && timercmp (& time_now , & vrrp -> fault_exit_time , < )) {
300+ log_message (LOG_INFO , "(%s) Entering FAULT STATE due to exit delay time" , vrrp -> iname );
301+ vrrp -> fault_exit_timer_cb = vrrp_state_set_backup ;
302+ vrrp -> fault_exit_timer_thread = thread_add_timer_sands (master ,
303+ vrrp_fault_exit_timer_thread , vrrp , & vrrp -> fault_exit_time );
304+ } else {
305+ log_message (LOG_INFO , "(%s) Entering BACKUP STATE (init)" , vrrp -> iname );
306+ vrrp -> state = VRRP_STATE_BACK ;
307+ }
279308 }
280309 } else {
281310 /* Note: if we have alpha mode scripts, we enter fault state, but don't want
@@ -324,8 +353,12 @@ vrrp_init_instance_sands(vrrp_t *vrrp)
324353 else
325354 vrrp -> sands = timer_add_long (time_now , vrrp -> ms_down_timer );
326355 }
327- else if (vrrp -> state == VRRP_STATE_FAULT || vrrp -> state == VRRP_STATE_INIT )
328- vrrp -> sands .tv_sec = TIMER_DISABLED ;
356+ else if (vrrp -> state == VRRP_STATE_FAULT || vrrp -> state == VRRP_STATE_INIT ) {
357+ if (timercmp (& time_now , & vrrp -> fault_exit_time , < )) {
358+ vrrp -> sands = vrrp -> fault_exit_time ;
359+ } else
360+ vrrp -> sands .tv_sec = TIMER_DISABLED ;
361+ }
329362
330363 rb_move_cached (& vrrp -> rb_sands , & vrrp -> sockets -> rb_sands , vrrp_timer_less );
331364}
@@ -688,11 +721,59 @@ vrrp_gratuitous_arp_vmac_update_thread(thread_ref_t thread)
688721#endif
689722
690723void
691- try_up_instance (vrrp_t * vrrp , bool leaving_init )
724+ up_instance (vrrp_t * vrrp )
692725{
693726 int wantstate ;
694727 ip_address_t ip_addr = {0 };
695728
729+ /* If the sync group can't go to master, we must go to backup state */
730+ wantstate = vrrp -> wantstate ;
731+ if (vrrp -> sync && vrrp -> wantstate == VRRP_STATE_MAST && !vrrp_sync_can_goto_master (vrrp ))
732+ vrrp -> wantstate = VRRP_STATE_BACK ;
733+
734+ /* We can come up */
735+ vrrp_state_leave_fault (vrrp );
736+
737+ /* If we are using unicast, the master may have lost us from its ARP cache.
738+ * We want to renew the ARP cache on the master, so that it can send adverts
739+ * to us straight away, without a delay before it sends an ARP request message
740+ * and we respond. If we don't do this, we can time out and transition to master
741+ * before the master renews its ARP entry, since the master cannot send us adverts
742+ * until it has done so. */
743+ if (__test_bit (VRRP_FLAG_UNICAST , & vrrp -> flags ) &&
744+ vrrp -> ifp &&
745+ vrrp -> saddr .ss_family != AF_UNSPEC ) {
746+ if (__test_bit (LOG_DETAIL_BIT , & debug ))
747+ log_message (LOG_INFO , "%s: sending gratuitous %s for %s" , vrrp -> iname , vrrp -> family == AF_INET ? "ARP" : "NA" , inet_sockaddrtos (& vrrp -> saddr ));
748+
749+ ip_addr .ifp = IF_BASE_IFP (vrrp -> ifp );
750+
751+ if (vrrp -> saddr .ss_family == AF_INET ) {
752+ ip_addr .u .sin .sin_addr .s_addr = PTR_CAST (struct sockaddr_in , & vrrp -> saddr )-> sin_addr .s_addr ;
753+ send_gratuitous_arp_immediate (ip_addr .ifp , & ip_addr );
754+ } else {
755+ /* IPv6 */
756+ ip_addr .u .sin6_addr = PTR_CAST (struct sockaddr_in6 , & vrrp -> saddr )-> sin6_addr ;
757+ ndisc_send_unsolicited_na_immediate (ip_addr .ifp , & ip_addr );
758+ }
759+ }
760+
761+ vrrp_init_instance_sands (vrrp );
762+ vrrp_thread_requeue_read (vrrp );
763+
764+ vrrp -> wantstate = wantstate ;
765+
766+ if (vrrp -> sync ) {
767+ if (vrrp -> state == VRRP_STATE_MAST )
768+ vrrp_sync_master (vrrp );
769+ else
770+ vrrp_sync_backup (vrrp );
771+ }
772+ }
773+
774+ void
775+ try_up_instance (vrrp_t * vrrp , bool leaving_init )
776+ {
696777 if (leaving_init ) {
697778 if (vrrp -> num_script_if_fault )
698779 return ;
@@ -735,49 +816,16 @@ try_up_instance(vrrp_t *vrrp, bool leaving_init)
735816 return ;
736817 }
737818
738- /* If the sync group can't go to master, we must go to backup state */
739- wantstate = vrrp -> wantstate ;
740- if (vrrp -> sync && vrrp -> wantstate == VRRP_STATE_MAST && !vrrp_sync_can_goto_master (vrrp ))
741- vrrp -> wantstate = VRRP_STATE_BACK ;
742-
743- /* We can come up */
744- vrrp_state_leave_fault (vrrp );
745-
746- /* If we are using unicast, the master may have lost us from its ARP cache.
747- * We want to renew the ARP cache on the master, so that it can send adverts
748- * to us straight away, without a delay before it sends an ARP request message
749- * and we respond. If we don't do this, we can time out and transition to master
750- * before the master renews its ARP entry, since the master cannot send us adverts
751- * until it has done so. */
752- if (__test_bit (VRRP_FLAG_UNICAST , & vrrp -> flags ) &&
753- vrrp -> ifp &&
754- vrrp -> saddr .ss_family != AF_UNSPEC ) {
755- if (__test_bit (LOG_DETAIL_BIT , & debug ))
756- log_message (LOG_INFO , "%s: sending gratuitous %s for %s" , vrrp -> iname , vrrp -> family == AF_INET ? "ARP" : "NA" , inet_sockaddrtos (& vrrp -> saddr ));
757-
758- ip_addr .ifp = IF_BASE_IFP (vrrp -> ifp );
759-
760- if (vrrp -> saddr .ss_family == AF_INET ) {
761- ip_addr .u .sin .sin_addr .s_addr = PTR_CAST (struct sockaddr_in , & vrrp -> saddr )-> sin_addr .s_addr ;
762- send_gratuitous_arp_immediate (ip_addr .ifp , & ip_addr );
763- } else {
764- /* IPv6 */
765- ip_addr .u .sin6_addr = PTR_CAST (struct sockaddr_in6 , & vrrp -> saddr )-> sin6_addr ;
766- ndisc_send_unsolicited_na_immediate (ip_addr .ifp , & ip_addr );
767- }
819+ if (vrrp -> fault_init_exit_delay ) {
820+ vrrp -> fault_exit_time = timer_add_long (time_now , vrrp -> fault_init_exit_delay );
821+ vrrp -> fault_exit_timer_thread =
822+ thread_add_timer_sands (master , vrrp_fault_exit_timer_thread ,
823+ vrrp , & vrrp -> fault_exit_time );
824+ vrrp -> fault_exit_timer_cb = up_instance ;
825+ return ;
768826 }
769827
770- vrrp_init_instance_sands (vrrp );
771- vrrp_thread_requeue_read (vrrp );
772-
773- vrrp -> wantstate = wantstate ;
774-
775- if (vrrp -> sync ) {
776- if (vrrp -> state == VRRP_STATE_MAST )
777- vrrp_sync_master (vrrp );
778- else
779- vrrp_sync_backup (vrrp );
780- }
828+ up_instance (vrrp );
781829}
782830
783831#ifdef _WITH_BFD_
0 commit comments