f1ab1b27185d723d69e1e190fb549e59db3f2bc1
[vpp.git] / src / plugins / vrrp / vrrp.c
1 /*
2  * vrrp.c - vrrp plugin action functions
3  *
4  * Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  *
8  */
9
10 #include <vnet/vnet.h>
11 #include <vnet/plugin/plugin.h>
12 #include <vnet/mfib/mfib_entry.h>
13 #include <vnet/mfib/mfib_table.h>
14 #include <vnet/adj/adj.h>
15 #include <vnet/adj/adj_mcast.h>
16 #include <vnet/fib/fib_table.h>
17 #include <vnet/ip/igmp_packet.h>
18 #include <vnet/ip/ip6_link.h>
19
20 #include <vrrp/vrrp.h>
21 #include <vrrp/vrrp_packet.h>
22
23 #include <vpp/app/version.h>
24
25 vrrp_main_t vrrp_main;
26
27 static const mac_address_t ipv4_vmac = {
28   .bytes = {0x00, 0x00, 0x5e, 0x00, 0x01, 0x00}
29 };
30
31 static const mac_address_t ipv6_vmac = {
32   .bytes = {0x00, 0x00, 0x5e, 0x00, 0x02, 0x00}
33 };
34
35 vlib_simple_counter_main_t vrrp_errs[] = {
36   /* Total number of VRRP packets received with invalid checksum */
37   {
38     .name = "CHKSUM_ERRS",
39     .stat_segment_name = "/net/vrrp/chksum-errs",
40   },
41   /* Total number of VRRP packets received with unknown or unsupported version
42    */
43   {
44     .name = "VERSION_ERRS",
45     .stat_segment_name = "/net/vrrp/version-errs",
46   },
47   /* Total number of VRRP packets received with invalid VRID */
48   {
49     .name = "VRID_ERRS",
50     .stat_segment_name = "/net/vrrp/vrid-errs",
51   },
52   /* Total number of VRRP packets received with TTL/Hop limit != 255 */
53   {
54     .name = "TTL_ERRS",
55     .stat_segment_name = "/net/vrrp/ttl-errs",
56   },
57   /* Number of packets received with an address list not matching the locally
58      configured one */
59   {
60     .name = "ADDR_LIST_ERRS",
61     .stat_segment_name = "/net/vrrp/addr-list-errs",
62   },
63   /* Number of packets received with a length less than the VRRP header */
64   {
65     .name = "PACKET_LEN_ERRS",
66     .stat_segment_name = "/net/vrrp/packet-len-errs",
67   },
68 };
69
70 void
71 vrrp_incr_err_counter (vrrp_err_counter_t err_type)
72 {
73   if (err_type >= VRRP_ERR_COUNTER_MAX)
74     {
75       clib_warning ("Attempt to increse error counter of unknown type %u",
76                     err_type);
77       return;
78     }
79   vlib_increment_simple_counter (&vrrp_errs[err_type],
80                                  vlib_get_main ()->thread_index, 0, 1);
81 }
82
83 // per-VRRP statistics
84
85 /* Number of times a VRRP instance has transitioned to master */
86 vlib_simple_counter_main_t vrrp_stats[] = {
87   {
88     .name = "MASTER_TRANS",
89     .stat_segment_name = "/net/vrrp/master-trans",
90   },
91   /* Number of VRRP advertisements sent by a VRRP instance */
92   {
93     .name = "ADV_SENT",
94     .stat_segment_name = "/net/vrrp/adv-sent",
95   },
96   /* Number of VRRP advertisements received by a VRRP instance */
97   {
98     .name = "ADV_RCVD",
99     .stat_segment_name = "/net/vrrp/adv-rcvd",
100   },
101   /* Number of VRRP priority-0 packets sent by a VRRP instance */
102   {
103     .name = "PRIO0_SENT",
104     .stat_segment_name = "/net/vrrp/prio0-sent",
105   },
106   /* Number of VRRP priority-0 packets received by a VRRP instance */
107   {
108     .name = "PRIO0_RCVD",
109     .stat_segment_name = "/net/vrrp/prio0-rcvd",
110   },
111 };
112
113 void
114 vrrp_incr_stat_counter (vrrp_stat_counter_t stat_type, u32 stat_index)
115 {
116   if (stat_type >= VRRP_STAT_COUNTER_MAX)
117     {
118       clib_warning ("Attempt to increse stat counter of unknown type %u",
119                     stat_type);
120       return;
121     }
122   vlib_increment_simple_counter (
123     &vrrp_stats[stat_type], vlib_get_main ()->thread_index, stat_index, 1);
124 }
125
126 typedef struct
127 {
128   vrrp_vr_key_t key;
129   u32 count;
130 } vrrp_hwif_vr_count_t;
131
132 typedef enum
133 {
134   VRRP_IF_UPDATE_IP,
135   VRRP_IF_UPDATE_HW_LINK,
136   VRRP_IF_UPDATE_SW_ADMIN,
137 } vrrp_intf_update_type_t;
138
139 typedef struct
140 {
141   vrrp_intf_update_type_t type;
142   u32 sw_if_index;
143   u32 hw_if_index;
144   int intf_up;
145 } vrrp_intf_update_t;
146
147 static int vrrp_intf_is_up (u32 sw_if_index, u8 is_ipv6,
148                             vrrp_intf_update_t * pending);
149
150 static walk_rc_t
151 vrrp_hwif_master_count_walk (vnet_main_t * vnm, u32 sw_if_index, void *arg)
152 {
153   vrrp_hwif_vr_count_t *vr_count = arg;
154   vrrp_vr_t *vr;
155
156   vr = vrrp_vr_lookup (sw_if_index, vr_count->key.vr_id,
157                        vr_count->key.is_ipv6);
158
159   if (vr && (vr->runtime.state == VRRP_VR_STATE_MASTER))
160     vr_count->count++;
161
162   return WALK_CONTINUE;
163 }
164
165 /*
166  * Get a count of VRs in master state on a given hardware interface with
167  * the provided VR ID and AF.
168  */
169 static u32
170 vrrp_vr_hwif_master_vrs_by_vrid (u32 hw_if_index, u8 vr_id, u8 is_ipv6)
171 {
172   vnet_main_t *vnm = vnet_get_main ();
173   vrrp_hwif_vr_count_t vr_count;
174
175   clib_memset (&vr_count, 0, sizeof (vr_count));
176
177   vr_count.key.vr_id = vr_id;
178   vr_count.key.is_ipv6 = is_ipv6;
179
180   vnet_hw_interface_walk_sw (vnm, hw_if_index,
181                              vrrp_hwif_master_count_walk, &vr_count);
182
183   return vr_count.count;
184 }
185
186 /*
187  * Add or delete the VR virtual MAC address on the hardware interface
188  * when a VR enters or leaves the master state.
189  *
190  * Multiple subinterfaces may host the same VR ID. We should only add or
191  * delete the virtual MAC if this is the first VR being enabled on the
192  * hardware interface or the last one being disabled, respectively.
193  */
194 void
195 vrrp_vr_transition_vmac (vrrp_vr_t * vr, vrrp_vr_state_t new_state)
196 {
197   vnet_main_t *vnm = vnet_get_main ();
198   clib_error_t *error = 0;
199   vnet_hw_interface_t *hw;
200   u8 enable = (new_state == VRRP_VR_STATE_MASTER);
201   u32 n_master_vrs;
202
203   hw = vnet_get_sup_hw_interface (vnm, vr->config.sw_if_index);
204   n_master_vrs =
205     vrrp_vr_hwif_master_vrs_by_vrid (hw->hw_if_index, vr->config.vr_id,
206                                      vrrp_vr_is_ipv6 (vr));
207
208   /* enable only if current master vrs is 0, disable only if 0 or 1 */
209   if ((enable && !n_master_vrs) || (!enable && (n_master_vrs < 2)))
210     {
211       clib_warning ("%s virtual MAC address %U on hardware interface %u",
212                     (enable) ? "Adding" : "Deleting",
213                     format_ethernet_address, vr->runtime.mac.bytes,
214                     hw->hw_if_index);
215
216       error = vnet_hw_interface_add_del_mac_address
217         (vnm, hw->hw_if_index, vr->runtime.mac.bytes, enable);
218     }
219
220   if (error)
221     clib_error_report (error);
222 }
223
224 /*
225  * Manage VR interface data on transition to/from master:
226  *  - enable or disable ARP/ND input feature if appropriate
227  *  - update count of VRs in master state
228  */
229 static void
230 vrrp_vr_transition_intf (vrrp_vr_t * vr, vrrp_vr_state_t new_state)
231 {
232   vrrp_intf_t *intf;
233   const char *arc_name = 0, *node_name = 0;
234   const char *mc_arc_name = 0, *mc_node_name = 0;
235   u8 is_ipv6 = vrrp_vr_is_ipv6 (vr);
236   u32 *vr_index;
237   int n_master_accept = 0;
238   int n_started = 0;
239
240   if (is_ipv6)
241     {
242       arc_name = "ip6-local";
243       node_name = "vrrp6-nd-input";
244       mc_arc_name = "ip6-multicast";
245       mc_node_name = "vrrp6-accept-owner-input";
246     }
247   else
248     {
249       arc_name = "arp";
250       node_name = "vrrp4-arp-input";
251       mc_arc_name = "ip4-multicast";
252       mc_node_name = "vrrp4-accept-owner-input";
253     }
254
255   intf = vrrp_intf_get (vr->config.sw_if_index);
256
257   /* Check other VRs on this intf to see if features need to be toggled */
258   vec_foreach (vr_index, intf->vr_indices[is_ipv6])
259   {
260     vrrp_vr_t *intf_vr = vrrp_vr_lookup_index (*vr_index);
261
262     if (intf_vr == vr)
263       continue;
264
265     if (intf_vr->runtime.state == VRRP_VR_STATE_INIT)
266       continue;
267
268     n_started++;
269
270     if ((intf_vr->runtime.state == VRRP_VR_STATE_MASTER) &&
271         vrrp_vr_accept_mode_enabled (intf_vr))
272       n_master_accept++;
273   }
274
275   /* If entering/leaving init state, start/stop ARP or ND feature if no other
276    * VRs are active on the interface.
277    */
278   if (((vr->runtime.state == VRRP_VR_STATE_INIT) ||
279        (new_state == VRRP_VR_STATE_INIT)) && (n_started == 0))
280     vnet_feature_enable_disable (arc_name, node_name,
281                                  vr->config.sw_if_index,
282                                  (new_state != VRRP_VR_STATE_INIT), NULL, 0);
283
284   /* Special housekeeping when entering/leaving master mode */
285   if ((vr->runtime.state == VRRP_VR_STATE_MASTER) ||
286       (new_state == VRRP_VR_STATE_MASTER))
287     {
288       /* Maintain count of master state VRs on interface */
289       if (new_state == VRRP_VR_STATE_MASTER)
290         intf->n_master_vrs[is_ipv6]++;
291       else if (intf->n_master_vrs[is_ipv6] > 0)
292         intf->n_master_vrs[is_ipv6]--;
293
294       /* If accept mode is enabled and no other master on intf has accept
295        * mode enabled, enable/disable feature node to avoid spurious drops by
296        * spoofing check.
297        */
298       if (vrrp_vr_accept_mode_enabled (vr) && !n_master_accept)
299         vnet_feature_enable_disable (mc_arc_name, mc_node_name,
300                                      vr->config.sw_if_index,
301                                      (new_state == VRRP_VR_STATE_MASTER),
302                                      NULL, 0);
303     }
304 }
305
306 /* If accept mode enabled, add/remove VR addresses from interface */
307 static void
308 vrrp_vr_transition_addrs (vrrp_vr_t * vr, vrrp_vr_state_t new_state)
309 {
310   vlib_main_t *vm = vlib_get_main ();
311   u8 is_del;
312   ip46_address_t *vr_addr;
313
314   if (!vrrp_vr_accept_mode_enabled (vr))
315     return;
316
317   /* owner always has VR addresses configured, should never remove them */
318   if (vrrp_vr_is_owner (vr))
319     return;
320
321   /* only need to do something if entering or leaving master state */
322   if ((vr->runtime.state != VRRP_VR_STATE_MASTER) &&
323       (new_state != VRRP_VR_STATE_MASTER))
324     return;
325
326   is_del = (new_state != VRRP_VR_STATE_MASTER);
327
328   clib_warning ("%s VR addresses on sw_if_index %u",
329                 (is_del) ? "Deleting" : "Adding", vr->config.sw_if_index);
330
331   vec_foreach (vr_addr, vr->config.vr_addrs)
332   {
333     ip_interface_address_t *ia = NULL;
334
335     /* We need to know the address length to use, find it from another
336      * address on the interface. Or use a default (/24, /64).
337      */
338     if (!vrrp_vr_is_ipv6 (vr))
339       {
340         ip4_main_t *im = &ip4_main;
341         ip4_address_t *intf4;
342
343         intf4 =
344           ip4_interface_address_matching_destination
345           (im, &vr_addr->ip4, vr->config.sw_if_index, &ia);
346
347         ip4_add_del_interface_address (vm, vr->config.sw_if_index,
348                                        &vr_addr->ip4,
349                                        (intf4 ? ia->address_length : 24),
350                                        is_del);
351       }
352     else
353       {
354         ip6_main_t *im = &ip6_main;
355         ip6_address_t *intf6;
356
357         intf6 =
358           ip6_interface_address_matching_destination
359           (im, &vr_addr->ip6, vr->config.sw_if_index, &ia);
360
361         ip6_add_del_interface_address (vm, vr->config.sw_if_index,
362                                        &vr_addr->ip6,
363                                        (intf6 ? ia->address_length : 64),
364                                        is_del);
365       }
366   }
367 }
368
369 void
370 vrrp_vr_transition (vrrp_vr_t * vr, vrrp_vr_state_t new_state, void *data)
371 {
372
373   clib_warning ("VR %U transitioning to %U", format_vrrp_vr_key, vr,
374                 format_vrrp_vr_state, new_state);
375
376   /* Don't do anything if transitioning to the state VR is already in.
377    * This should never happen, just covering our bases.
378    */
379   if (new_state == vr->runtime.state)
380     return;
381
382   if (new_state == VRRP_VR_STATE_MASTER)
383     {
384       vrrp_incr_stat_counter (VRRP_STAT_COUNTER_MASTER_TRANS, vr->stat_index);
385       /* RFC 5798 sec 6.4.1 (105) - startup event for VR with priority 255
386        *          sec 6.4.2 (365) - master down timer fires on backup VR
387        */
388
389       vrrp_vr_multicast_group_join (vr);
390       vrrp_adv_send (vr, 0);
391       vrrp_garp_or_na_send (vr);
392
393       vrrp_vr_timer_set (vr, VRRP_VR_TIMER_ADV);
394     }
395   else if (new_state == VRRP_VR_STATE_BACKUP)
396     {
397       /* RFC 5798 sec 6.4.1 (150) - startup event for VR with priority < 255
398        *          sec 6.4.3 (735) - master preempted by higher priority VR
399        */
400
401       vrrp_vr_multicast_group_join (vr);
402
403       if (vr->runtime.state == VRRP_VR_STATE_MASTER)
404         {
405           vrrp_input_process_args_t *args = data;
406
407           if (args)
408             vr->runtime.master_adv_int = args->max_adv_int;
409         }
410       else                      /* INIT, INTF_DOWN */
411         vr->runtime.master_adv_int = vr->config.adv_interval;
412
413       vrrp_vr_skew_compute (vr);
414       vrrp_vr_master_down_compute (vr);
415       vrrp_vr_timer_set (vr, VRRP_VR_TIMER_MASTER_DOWN);
416
417     }
418   else if (new_state == VRRP_VR_STATE_INIT)
419     {
420       /* RFC 5798 sec 6.4.2 (345) - shutdown event for backup VR
421        *          sec 6.4.3 (655) - shutdown event for master VR
422        */
423
424       vrrp_vr_timer_cancel (vr);
425       if (vr->runtime.state == VRRP_VR_STATE_MASTER)
426         vrrp_adv_send (vr, 1);
427     }
428   else if (new_state == VRRP_VR_STATE_INTF_DOWN)
429     /* State is not specified by RFC. This is to avoid attempting to
430      * send packets on an interface that's down and to avoid having a
431      * VR believe it is already the master when an interface is brought up
432      */
433     vrrp_vr_timer_cancel (vr);
434
435   /* add/delete virtual IP addrs if accept_mode is true */
436   vrrp_vr_transition_addrs (vr, new_state);
437
438   /* enable/disable input features if necessary */
439   vrrp_vr_transition_intf (vr, new_state);
440
441   /* add/delete virtual MAC address on NIC if necessary */
442   vrrp_vr_transition_vmac (vr, new_state);
443
444   vrrp_vr_event (vr, new_state);
445
446   vr->runtime.state = new_state;
447 }
448
449 #define VRRP4_MCAST_ADDR_AS_U8 { 224, 0, 0, 18 }
450 #define VRRP6_MCAST_ADDR_AS_U8 \
451 { 0xff, 0x2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x12 }
452
453 static const mfib_prefix_t all_vrrp4_routers = {
454   .fp_proto = FIB_PROTOCOL_IP4,
455   .fp_len = 32,
456   .fp_grp_addr = {
457                   .ip4 = {
458                           .as_u8 = VRRP4_MCAST_ADDR_AS_U8,
459                           },
460                   },
461 };
462
463 static const mfib_prefix_t all_vrrp6_routers = {
464   .fp_proto = FIB_PROTOCOL_IP6,
465   .fp_len = 128,
466   .fp_grp_addr = {
467                   .ip6 = {
468                           .as_u8 = VRRP6_MCAST_ADDR_AS_U8,
469                           },
470                   },
471 };
472
473 static int
474 vrrp_intf_enable_disable_mcast (u8 enable, u32 sw_if_index, u8 is_ipv6)
475 {
476   vrrp_main_t *vrm = &vrrp_main;
477   vrrp_intf_t *intf;
478   u32 fib_index, i;
479   u32 n_vrs_in_fib = 0;
480   const mfib_prefix_t *vrrp_prefix;
481   fib_protocol_t proto;
482   vnet_link_t link_type;
483   fib_route_path_t for_us = {
484     .frp_sw_if_index = 0xffffffff,
485     .frp_weight = 1,
486     .frp_flags = FIB_ROUTE_PATH_LOCAL,
487     .frp_mitf_flags = MFIB_ITF_FLAG_FORWARD,
488   };
489   fib_route_path_t via_itf = {
490     .frp_sw_if_index = sw_if_index,
491     .frp_weight = 1,
492     .frp_mitf_flags = MFIB_ITF_FLAG_ACCEPT,
493   };
494
495   intf = vrrp_intf_get (sw_if_index);
496
497   if (is_ipv6)
498     {
499       proto = FIB_PROTOCOL_IP6;
500       link_type = VNET_LINK_IP6;
501       vrrp_prefix = &all_vrrp6_routers;
502     }
503   else
504     {
505       proto = FIB_PROTOCOL_IP4;
506       link_type = VNET_LINK_IP4;
507       vrrp_prefix = &all_vrrp4_routers;
508     }
509
510   for_us.frp_proto = fib_proto_to_dpo (proto);
511   via_itf.frp_proto = fib_proto_to_dpo (proto);
512   fib_index = mfib_table_get_index_for_sw_if_index (proto, sw_if_index);
513
514   vec_foreach_index (i, vrm->vrrp_intfs)
515     {
516       if (mfib_table_get_index_for_sw_if_index (proto, i) != fib_index)
517         continue;
518
519       n_vrs_in_fib += vrrp_intf_num_vrs (i, is_ipv6);
520     }
521
522   if (enable)
523     {
524       /* ensure that the local mcast route exists */
525       mfib_table_entry_path_update (fib_index, vrrp_prefix, MFIB_SOURCE_API,
526                                     MFIB_ENTRY_FLAG_NONE, &for_us);
527
528       mfib_table_entry_path_update (fib_index, vrrp_prefix, MFIB_SOURCE_API,
529                                     MFIB_ENTRY_FLAG_NONE, &via_itf);
530       intf->mcast_adj_index[! !is_ipv6] =
531         adj_mcast_add_or_lock (proto, link_type, sw_if_index);
532     }
533   else
534     {
535       /* Remove mcast local routes if this is the last VR being deleted */
536       if (n_vrs_in_fib == 0)
537         mfib_table_entry_path_remove (fib_index, vrrp_prefix, MFIB_SOURCE_API,
538                                       &for_us);
539
540       mfib_table_entry_path_remove (fib_index, vrrp_prefix, MFIB_SOURCE_API,
541                                     &via_itf);
542     }
543
544   return 0;
545 }
546
547 static int
548 vrrp_intf_vr_add_del (u8 is_add, u32 sw_if_index, u32 vr_index, u8 is_ipv6)
549 {
550   vrrp_intf_t *vr_intf;
551
552   vr_intf = vrrp_intf_get (sw_if_index);
553   if (!vr_intf)
554     return -1;
555
556   if (is_add)
557     {
558       if (!vec_len (vr_intf->vr_indices[is_ipv6]))
559         vrrp_intf_enable_disable_mcast (1, sw_if_index, is_ipv6);
560
561       vec_add1 (vr_intf->vr_indices[is_ipv6], vr_index);
562     }
563   else
564     {
565       u32 per_intf_index =
566         vec_search (vr_intf->vr_indices[is_ipv6], vr_index);
567
568       if (per_intf_index != ~0)
569         vec_del1 (vr_intf->vr_indices[is_ipv6], per_intf_index);
570
571       /* no more VRs on this interface, disable multicast */
572       if (!vec_len (vr_intf->vr_indices[is_ipv6]))
573         vrrp_intf_enable_disable_mcast (0, sw_if_index, is_ipv6);
574     }
575
576   return 0;
577 }
578
579 /* RFC 5798 section 8.3.2 says to take care not to configure more than
580  * one VRRP router as the "IPvX address owner" of a VRID. Make sure that
581  * all of the addresses configured for this VR are configured on the
582  * interface.
583  */
584 static int
585 vrrp_vr_valid_addrs_owner (vrrp_vr_config_t * vr_conf)
586 {
587   ip46_address_t *addr;
588   u8 is_ipv6 = (vr_conf->flags & VRRP_VR_IPV6) != 0;
589
590   vec_foreach (addr, vr_conf->vr_addrs)
591   {
592     if (!ip_interface_has_address (vr_conf->sw_if_index, addr, !is_ipv6))
593       return VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
594   }
595
596   return 0;
597 }
598
599 static int
600 vrrp_vr_valid_addrs_unused (vrrp_vr_config_t *vr_conf, index_t vrrp_index)
601 {
602   ip46_address_t *vr_addr;
603   u8 is_ipv6 = (vr_conf->flags & VRRP_VR_IPV6) != 0;
604
605   vec_foreach (vr_addr, vr_conf->vr_addrs)
606   {
607     u32 vr_index;
608     void *addr;
609
610     addr = (is_ipv6) ? (void *) &vr_addr->ip6 : (void *) &vr_addr->ip4;
611     vr_index = vrrp_vr_lookup_address (vr_conf->sw_if_index, is_ipv6, addr);
612     if (vr_index != ~0 && vrrp_index != vr_index)
613       return VNET_API_ERROR_ADDRESS_IN_USE;
614   }
615
616   return 0;
617 }
618
619 static int
620 vrrp_vr_valid_addrs (vrrp_vr_config_t *vr_conf, index_t vrrp_index)
621 {
622   int ret = 0;
623
624   /* If the VR owns the addresses, make sure they are configured */
625   if (vr_conf->priority == 255 &&
626       (ret = vrrp_vr_valid_addrs_owner (vr_conf)) < 0)
627     return ret;
628
629   /* make sure no other VR has already configured any of the VR addresses */
630   ret = vrrp_vr_valid_addrs_unused (vr_conf, vrrp_index);
631
632   return ret;
633 }
634
635 int
636 vrrp_vr_addr_add_del (vrrp_vr_t * vr, u8 is_add, ip46_address_t * vr_addr)
637 {
638   vrrp_main_t *vmp = &vrrp_main;
639   u32 vr_index;
640   vrrp4_arp_key_t key4;
641   vrrp6_nd_key_t key6;
642   ip46_address_t *addr;
643
644   if (!vr || !vr_addr)
645     return VNET_API_ERROR_INVALID_ARGUMENT;
646
647   vr_index = vr - vmp->vrs;
648
649   if (vrrp_vr_is_ipv6 (vr))
650     {
651       key6.sw_if_index = vr->config.sw_if_index;
652       key6.addr = vr_addr->ip6;
653       if (is_add)
654         {
655           hash_set_mem_alloc (&vmp->vrrp6_nd_lookup, &key6, vr_index);
656           vec_add1 (vr->config.vr_addrs, vr_addr[0]);
657         }
658       else
659         {
660           hash_unset_mem_free (&vmp->vrrp6_nd_lookup, &key6);
661           vec_foreach (addr, vr->config.vr_addrs)
662           {
663             if (!ip46_address_cmp (addr, vr_addr))
664               {
665                 vec_del1 (vr->config.vr_addrs, vr->config.vr_addrs - addr);
666                 break;
667               }
668           }
669         }
670     }
671   else
672     {
673       key4.sw_if_index = vr->config.sw_if_index;
674       key4.addr = vr_addr->ip4;
675       if (is_add)
676         {
677           hash_set (vmp->vrrp4_arp_lookup, key4.as_u64, vr_index);
678           vec_add1 (vr->config.vr_addrs, vr_addr[0]);
679         }
680       else
681         {
682           hash_unset (vmp->vrrp4_arp_lookup, key4.as_u64);
683           vec_foreach (addr, vr->config.vr_addrs)
684           {
685             if (!ip46_address_cmp (addr, vr_addr))
686               {
687                 vec_del1 (vr->config.vr_addrs, vr->config.vr_addrs - addr);
688                 break;
689               }
690           }
691         }
692     }
693
694   return 0;
695 }
696
697 static void
698 vrrp_vr_addrs_add_del (vrrp_vr_t * vr, u8 is_add, ip46_address_t * vr_addrs)
699 {
700   ip46_address_t *vr_addr;
701
702   vec_foreach (vr_addr, vr_addrs)
703   {
704     vrrp_vr_addr_add_del (vr, is_add, vr_addr);
705   }
706 }
707
708 int
709 vrrp_vr_update (index_t *vrrp_index, vrrp_vr_config_t *vr_conf)
710 {
711   index_t index = *vrrp_index;
712   vrrp_main_t *vrm = &vrrp_main;
713   vrrp_vr_t *vr = NULL;
714   vrrp_vr_key_t key = { 0 };
715   uint8_t must_restart = 0;
716   int ret = 0;
717
718   /* no valid index -> create and return allocated index */
719   if (index == INDEX_INVALID)
720     {
721       return vrrp_vr_add_del (1, vr_conf, vrrp_index);
722     }
723   /* update: lookup vrrp instance */
724   if (pool_is_free_index (vrm->vrs, index))
725     return (VNET_API_ERROR_NO_SUCH_ENTRY);
726
727   /* fetch existing VR */
728   vr = pool_elt_at_index (vrm->vrs, index);
729
730   /* populate key */
731   key.vr_id = vr->config.vr_id;
732   key.is_ipv6 = !!(vr->config.flags & VRRP_VR_IPV6);
733   ;
734   key.sw_if_index = vr->config.sw_if_index;
735
736   /* Do not allow changes to the keys of the VRRP instance */
737   if (vr_conf->vr_id != key.vr_id || vr_conf->sw_if_index != key.sw_if_index ||
738       !!(vr_conf->flags & VRRP_VR_IPV6) != key.is_ipv6)
739     {
740       clib_warning ("Attempt to change VR ID, IP version or interface index "
741                     "for VRRP instance with index %u",
742                     index);
743       return VNET_API_ERROR_INVALID_ARGUMENT;
744     }
745
746   /* were IPvX addresses included ? */
747   if (!vec_len (vr_conf->vr_addrs))
748     {
749       clib_warning ("Conf of VR %u for IPv%d on sw_if_index %u "
750                     " does not contain IP addresses",
751                     key.vr_id, key.is_ipv6 ? 6 : 4, key.sw_if_index);
752       return VNET_API_ERROR_INVALID_SRC_ADDRESS;
753     }
754
755   /* Make sure the addresses are ok to use */
756   if ((ret = vrrp_vr_valid_addrs (vr_conf, index)) < 0)
757     return ret;
758
759   /* stop it if needed */
760   must_restart = (vr->runtime.state != VRRP_VR_STATE_INIT);
761   if (must_restart)
762     vrrp_vr_start_stop (0, &key);
763
764   /* overwrite new config */
765   vr->config.priority = vr_conf->priority;
766   vr->config.adv_interval = vr_conf->adv_interval;
767   vr->config.flags = vr_conf->flags;
768
769   /* check if any address has changed */
770   ip46_address_t *vr_addr, *conf_addr;
771   uint8_t found;
772   vec_foreach (vr_addr, vr->config.vr_addrs)
773     {
774       found = 0;
775       vec_foreach (conf_addr, vr_conf->vr_addrs)
776         {
777           if (ip46_address_is_equal (vr_addr, conf_addr))
778             {
779               found = 1;
780               break;
781             }
782         }
783       if (!found)
784         {
785           vrrp_vr_addr_add_del (vr, 0, vr_addr);
786         }
787     }
788   vec_foreach (conf_addr, vr_conf->vr_addrs)
789     {
790       found = 0;
791       vec_foreach (vr_addr, vr->config.vr_addrs)
792         {
793           if (ip46_address_is_equal (vr_addr, conf_addr))
794             {
795               found = 1;
796               break;
797             }
798         }
799       if (!found)
800         {
801           vrrp_vr_addr_add_del (vr, 1, conf_addr);
802         }
803     }
804
805   /* restart it if needed */
806   if (must_restart)
807     vrrp_vr_start_stop (1, &key);
808
809   return 0;
810 }
811
812 static void
813 vrrp_vr_del_common (vrrp_vr_t *vr, vrrp_vr_key_t *key)
814 {
815   vrrp_main_t *vrm = &vrrp_main;
816   ip46_address_t *vr_addrs_del_copy;
817
818   vrrp_vr_tracking_ifs_add_del (vr, vr->tracking.interfaces, 0);
819   vr_addrs_del_copy = vec_dup (vr->config.vr_addrs);
820   vrrp_vr_addrs_add_del (vr, 0, vr_addrs_del_copy);
821   mhash_unset (&vrm->vr_index_by_key, key, 0);
822   vec_free (vr_addrs_del_copy);
823   vec_free (vr->config.peer_addrs);
824   vec_free (vr->config.vr_addrs);
825   vec_free (vr->tracking.interfaces);
826   pool_put (vrm->vrs, vr);
827 }
828
829 int
830 vrrp_vr_del (index_t vrrp_index)
831 {
832   vrrp_main_t *vrm = &vrrp_main;
833   vrrp_vr_key_t key;
834   vrrp_vr_t *vr = 0;
835
836   if (pool_is_free_index (vrm->vrs, vrrp_index))
837     {
838       return (VNET_API_ERROR_NO_SUCH_ENTRY);
839     }
840   else
841     {
842       vr = pool_elt_at_index (vrm->vrs, vrrp_index);
843       key.sw_if_index = vr->config.sw_if_index;
844       key.vr_id = vr->config.vr_id;
845       key.is_ipv6 = vrrp_vr_is_ipv6 (vr);
846       vrrp_vr_del_common (vr, &key);
847       return 0;
848     }
849 }
850
851 /* Action function shared between message handler and debug CLI */
852 int
853 vrrp_vr_add_del (u8 is_add, vrrp_vr_config_t *vr_conf, index_t *ret_index)
854 {
855   vrrp_main_t *vrm = &vrrp_main;
856   vnet_main_t *vnm = vnet_get_main ();
857   vrrp_vr_key_t key;
858   uword *p;
859   u32 vr_index;
860   vrrp_vr_t *vr = 0;
861   int ret;
862
863   if (vr_conf->sw_if_index == ~0 ||
864       !vnet_sw_interface_is_valid (vnm, vr_conf->sw_if_index))
865     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
866
867   clib_memset (&key, 0, sizeof (key));
868
869   key.sw_if_index = vr_conf->sw_if_index;
870   key.vr_id = vr_conf->vr_id;
871   key.is_ipv6 = ((vr_conf->flags & VRRP_VR_IPV6) != 0);
872
873   p = mhash_get (&vrm->vr_index_by_key, &key);
874
875   if (is_add)
876     {
877       /* does a VR matching this key already exist ? */
878       if (p)
879         {
880           clib_warning ("VR %u for IPv%d already exists on sw_if_index %u",
881                         key.vr_id, (key.is_ipv6) ? 6 : 4, key.sw_if_index);
882           return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
883         }
884
885       /* were IPvX addresses included ? */
886       if (!vec_len (vr_conf->vr_addrs))
887         {
888           clib_warning ("Conf of VR %u for IPv%d on sw_if_index %u "
889                         " does not contain IP addresses",
890                         key.vr_id, (key.is_ipv6) ? 6 : 4, key.sw_if_index);
891           return VNET_API_ERROR_INVALID_SRC_ADDRESS;
892         }
893
894       /* Make sure the addresses are ok to use */
895       if ((ret = vrrp_vr_valid_addrs (vr_conf, INDEX_INVALID)) < 0)
896         return ret;
897
898       pool_get_zero (vrm->vrs, vr);
899       vr_index = vr - vrm->vrs;
900
901       clib_memcpy (&vr->config, vr_conf, sizeof (vrrp_vr_config_t));
902
903       vr->config.vr_addrs = 0;  /* allocate our own memory */
904       vrrp_vr_addrs_add_del (vr, is_add, vr_conf->vr_addrs);
905
906       vr->runtime.state = VRRP_VR_STATE_INIT;
907       vr->runtime.timer_index = ~0;
908
909       /* set virtual MAC based on IP version and VR ID */
910       vr->runtime.mac = (key.is_ipv6) ? ipv6_vmac : ipv4_vmac;
911       vr->runtime.mac.bytes[5] = vr_conf->vr_id;
912
913       /* recall pool index for stats */
914       vr->stat_index = vr_index;
915       /* and return it if we were asked to */
916       if (ret_index != NULL)
917         {
918           *ret_index = vr_index;
919         }
920       /* allocate & reset stats */
921       for (int i = 0; i < VRRP_STAT_COUNTER_MAX; i++)
922         {
923           vlib_validate_simple_counter (&vrrp_stats[i], vr_index);
924           vlib_zero_simple_counter (&vrrp_stats[i], vr_index);
925         }
926
927       mhash_set (&vrm->vr_index_by_key, &key, vr_index, 0);
928     }
929   else
930     {
931       if (!p)
932         {
933           clib_warning ("No VR %u for IPv%d exists on sw_if_index %u",
934                         key.vr_id, (key.is_ipv6) ? 6 : 4, key.sw_if_index);
935           return VNET_API_ERROR_NO_SUCH_ENTRY;
936         }
937
938       vr_index = p[0];
939       vr = pool_elt_at_index (vrm->vrs, vr_index);
940       vrrp_vr_del_common (vr, &key);
941     }
942
943   vrrp_intf_vr_add_del (is_add, vr_conf->sw_if_index, vr_index, key.is_ipv6);
944
945   return 0;
946 }
947
948 int
949 vrrp_vr_start_stop (u8 is_start, vrrp_vr_key_t * vr_key)
950 {
951   vrrp_main_t *vmp = &vrrp_main;
952   uword *p;
953   vrrp_vr_t *vr = 0;
954
955   p = mhash_get (&vmp->vr_index_by_key, vr_key);
956   if (!p)
957     return VNET_API_ERROR_NO_SUCH_ENTRY;
958
959   vr = pool_elt_at_index (vmp->vrs, p[0]);
960
961   /* return success if already in the desired state */
962   switch (vr->runtime.state)
963     {
964     case VRRP_VR_STATE_INIT:
965       if (!is_start)
966         {
967           clib_warning ("Attempting to stop already stopped VR (%U)",
968                         format_vrrp_vr_key, vr);
969           return 0;
970         }
971       break;
972     default:
973       if (is_start)
974         {
975           clib_warning ("Attempting to start already started VR (%U)",
976                         format_vrrp_vr_key, vr);
977           return 0;
978         }
979       break;
980     }
981
982   if (is_start)
983     {
984       if (vrrp_vr_is_unicast (vr) && vec_len (vr->config.peer_addrs) == 0)
985         {
986           clib_warning ("Cannot start unicast VR without peers");
987           return VNET_API_ERROR_INIT_FAILED;
988         }
989
990       vmp->n_vrs_started++;
991
992       if (!vrrp_intf_is_up (vr->config.sw_if_index, vrrp_vr_is_ipv6 (vr),
993                             NULL))
994         {
995           clib_warning ("VRRP VR started on down interface (%U)",
996                         format_vrrp_vr_key, vr);
997           vrrp_vr_transition (vr, VRRP_VR_STATE_INTF_DOWN, NULL);
998         }
999       else if (vrrp_vr_is_owner (vr))
1000         vrrp_vr_transition (vr, VRRP_VR_STATE_MASTER, NULL);
1001       else
1002         vrrp_vr_transition (vr, VRRP_VR_STATE_BACKUP, NULL);
1003     }
1004   else
1005     {
1006       vmp->n_vrs_started--;
1007
1008       vrrp_vr_transition (vr, VRRP_VR_STATE_INIT, NULL);
1009     }
1010
1011   clib_warning ("%d VRs configured, %d VRs running",
1012                 pool_elts (vmp->vrs), vmp->n_vrs_started);
1013
1014   return 0;
1015 }
1016
1017 static int
1018 vrrp_vr_set_peers_validate (vrrp_vr_t * vr, ip46_address_t * peers)
1019 {
1020   if (!vrrp_vr_is_unicast (vr))
1021     {
1022       clib_warning ("Peers can only be set on a unicast VR");
1023       return VNET_API_ERROR_INVALID_ARGUMENT;
1024     }
1025
1026   if (vr->runtime.state != VRRP_VR_STATE_INIT)
1027     {
1028       clib_warning ("Cannot set peers on a running VR");
1029       return VNET_API_ERROR_RSRC_IN_USE;
1030     }
1031
1032   if (vec_len (peers) == 0)
1033     {
1034       clib_warning ("No peer addresses provided");
1035       return VNET_API_ERROR_INVALID_DST_ADDRESS;
1036     }
1037
1038   return 0;
1039 }
1040
1041 int
1042 vrrp_vr_set_peers (vrrp_vr_key_t * vr_key, ip46_address_t * peers)
1043 {
1044   vrrp_main_t *vmp = &vrrp_main;
1045   uword *p;
1046   vrrp_vr_t *vr = 0;
1047   int ret = 0;
1048
1049   p = mhash_get (&vmp->vr_index_by_key, vr_key);
1050   if (!p)
1051     return VNET_API_ERROR_NO_SUCH_ENTRY;
1052
1053   vr = pool_elt_at_index (vmp->vrs, p[0]);
1054
1055   ret = vrrp_vr_set_peers_validate (vr, peers);
1056   if (ret < 0)
1057     return ret;
1058
1059   if (vr->config.peer_addrs)
1060     vec_free (vr->config.peer_addrs);
1061
1062   vr->config.peer_addrs = vec_dup (peers);
1063
1064   return 0;
1065 }
1066
1067 /* Manage reference on the interface to the VRs which track that interface */
1068 static void
1069 vrrp_intf_tracking_vr_add_del (u32 sw_if_index, vrrp_vr_t * vr, u8 is_add)
1070 {
1071   vrrp_intf_t *intf;
1072   u32 vr_index;
1073   u8 is_ipv6 = vrrp_vr_is_ipv6 (vr);
1074   int i;
1075
1076   intf = vrrp_intf_get (sw_if_index);
1077   vr_index = vrrp_vr_index (vr);
1078
1079   /* Try to find the VR index in the list of tracking VRs */
1080   vec_foreach_index (i, intf->tracking_vrs[is_ipv6])
1081   {
1082     if (vec_elt (intf->tracking_vrs[is_ipv6], i) != vr_index)
1083       continue;
1084
1085     /* Current index matches VR index */
1086     if (!is_add)
1087       vec_delete (intf->tracking_vrs[is_ipv6], 1, i);
1088
1089     /* If deleting, the job is done. If adding, it's already here */
1090     return;
1091   }
1092
1093   /* vr index was not found. */
1094   if (is_add)
1095     vec_add1 (intf->tracking_vrs[is_ipv6], vr_index);
1096 }
1097
1098 /* Check if sw intf admin state is up or in the process of coming up */
1099 static int
1100 vrrp_intf_sw_admin_up (u32 sw_if_index, vrrp_intf_update_t * pending)
1101 {
1102   vnet_main_t *vnm = vnet_get_main ();
1103   int admin_up;
1104
1105   if (pending && (pending->type == VRRP_IF_UPDATE_SW_ADMIN))
1106     admin_up = pending->intf_up;
1107   else
1108     admin_up = vnet_sw_interface_is_admin_up (vnm, sw_if_index);
1109
1110   return admin_up;
1111 }
1112
1113 /* Check if hw intf link state is up or int the process of coming up */
1114 static int
1115 vrrp_intf_hw_link_up (u32 sw_if_index, vrrp_intf_update_t * pending)
1116 {
1117   vnet_main_t *vnm = vnet_get_main ();
1118   vnet_sw_interface_t *sup_sw;
1119   int link_up;
1120
1121   sup_sw = vnet_get_sup_sw_interface (vnm, sw_if_index);
1122
1123   if (pending && (pending->type == VRRP_IF_UPDATE_HW_LINK) &&
1124       (pending->hw_if_index == sup_sw->hw_if_index))
1125     link_up = pending->intf_up;
1126   else
1127     link_up = vnet_hw_interface_is_link_up (vnm, sup_sw->hw_if_index);
1128
1129   return link_up;
1130 }
1131
1132 /* Check if interface has ability to send IP packets. */
1133 static int
1134 vrrp_intf_ip_up (u32 sw_if_index, u8 is_ipv6, vrrp_intf_update_t * pending)
1135 {
1136   int ip_up;
1137
1138   if (pending && pending->type == VRRP_IF_UPDATE_IP)
1139     ip_up = pending->intf_up;
1140   else
1141     /* Either a unicast address has to be explicitly assigned, or
1142      * for IPv6 only, a link local assigned and multicast/ND enabled
1143      */
1144     ip_up =
1145       ((ip_interface_get_first_ip (sw_if_index, !is_ipv6) != 0) ||
1146        (is_ipv6 && ip6_link_is_enabled (sw_if_index)));
1147
1148   return ip_up;
1149 }
1150
1151 static int
1152 vrrp_intf_is_up (u32 sw_if_index, u8 is_ipv6, vrrp_intf_update_t * pending)
1153 {
1154   int admin_up, link_up, ip_up;
1155
1156   admin_up = vrrp_intf_sw_admin_up (sw_if_index, pending);
1157   link_up = vrrp_intf_hw_link_up (sw_if_index, pending);
1158   ip_up = vrrp_intf_ip_up (sw_if_index, is_ipv6, pending);
1159
1160   return (admin_up && link_up && ip_up);
1161 }
1162
1163 /* Examine the state of interfaces tracked by a VR and compute the priority
1164  * adjustment that should be applied to the VR. If this is being called
1165  * by the hw_link_up_down callback, the pending new flags on the sup hw
1166  * interface have not been updated yet, so accept those as an optional
1167  * argument.
1168  */
1169 void
1170 vrrp_vr_tracking_ifs_compute (vrrp_vr_t * vr, vrrp_intf_update_t * pending)
1171 {
1172   vrrp_vr_tracking_if_t *intf;
1173   u32 total_priority = 0;
1174
1175   vec_foreach (intf, vr->tracking.interfaces)
1176   {
1177     if (vrrp_intf_is_up (intf->sw_if_index, vrrp_vr_is_ipv6 (vr), pending))
1178       continue;
1179
1180     total_priority += intf->priority;
1181   }
1182
1183   if (total_priority != vr->tracking.interfaces_dec)
1184     {
1185       clib_warning ("VR %U interface track adjustment change from %u to %u",
1186                     format_vrrp_vr_key, vr, vr->tracking.interfaces_dec,
1187                     total_priority);
1188       vr->tracking.interfaces_dec = total_priority;
1189     }
1190 }
1191
1192 /* Manage tracked interfaces on a VR */
1193 int
1194 vrrp_vr_tracking_if_add_del (vrrp_vr_t * vr, u32 sw_if_index, u8 prio,
1195                              u8 is_add)
1196 {
1197   vnet_main_t *vnm = vnet_get_main ();
1198   vrrp_vr_tracking_if_t *track_intf;
1199
1200   /* VR can't track non-existent interface */
1201   if (!vnet_sw_interface_is_valid (vnm, sw_if_index))
1202     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
1203
1204   /* VR can't track it's own interface */
1205   if (sw_if_index == vr->config.sw_if_index)
1206     return VNET_API_ERROR_INVALID_SW_IF_INDEX_2;
1207
1208   /* update intf vector of tracking VRs */
1209   vrrp_intf_tracking_vr_add_del (sw_if_index, vr, is_add);
1210
1211   /* update VR vector of tracked interfaces */
1212   vec_foreach (track_intf, vr->tracking.interfaces)
1213   {
1214     if (track_intf->sw_if_index != sw_if_index)
1215       continue;
1216
1217     /* found it */
1218     if (!is_add)
1219       vec_delete
1220         (vr->tracking.interfaces, 1, track_intf - vr->tracking.interfaces);
1221
1222     return 0;
1223   }
1224
1225   if (is_add)
1226     {
1227       vec_add2 (vr->tracking.interfaces, track_intf, 1);
1228
1229       track_intf->sw_if_index = sw_if_index;
1230       track_intf->priority = prio;
1231     }
1232
1233   return 0;
1234 }
1235
1236 int
1237 vrrp_vr_tracking_ifs_add_del (vrrp_vr_t * vr,
1238                               vrrp_vr_tracking_if_t * track_ifs, u8 is_add)
1239 {
1240   vrrp_vr_tracking_if_t *track_if, *ifs_copy;
1241   int rv = 0;
1242
1243   /* if deleting & track_ifs points to the VR list of tracked intfs, the
1244    * vector could be modified as we iterate it. make a copy instead */
1245   ifs_copy = vec_dup (track_ifs);
1246
1247   /* add each tracked interface in the vector */
1248   vec_foreach (track_if, ifs_copy)
1249   {
1250     rv = vrrp_vr_tracking_if_add_del (vr, track_if->sw_if_index,
1251                                       track_if->priority, (is_add != 0));
1252
1253     /* if operation failed, undo the previous changes */
1254     if (rv)
1255       {
1256         vrrp_vr_tracking_if_t *rb_if;
1257
1258         for (rb_if = track_if - 1; rb_if >= track_ifs; rb_if -= 1)
1259           vrrp_vr_tracking_if_add_del (vr, rb_if->sw_if_index,
1260                                        rb_if->priority, !(is_add != 0));
1261         break;
1262       }
1263   }
1264
1265   vec_free (ifs_copy);
1266
1267   vrrp_vr_tracking_ifs_compute (vr, 0);
1268
1269   return rv;
1270 }
1271
1272 /* Compute priority to advertise on all VRs which track the given interface
1273  * and address family. The flags on an HW interface are not updated until
1274  * after link up/down callbacks are invoked, so if this function is called
1275  * by the link up/down callback, the flags about to be set will be passed
1276  * via the 'pending' argument. Otherwise, pending will be NULL.
1277  */
1278 static void
1279 vrrp_intf_tracking_vrs_compute (u32 sw_if_index,
1280                                 vrrp_intf_update_t * pending, u8 is_ipv6)
1281 {
1282   u32 *vr_index;
1283   vrrp_vr_t *vr;
1284   vrrp_intf_t *intf = vrrp_intf_get (sw_if_index);
1285
1286   vec_foreach (vr_index, intf->tracking_vrs[is_ipv6])
1287   {
1288     vr = vrrp_vr_lookup_index (*vr_index);
1289     if (vr)
1290       vrrp_vr_tracking_ifs_compute (vr, pending);
1291   }
1292 }
1293
1294 /* Interface being brought up/down is a quasi-{startup/shutdown} event.
1295  * Execute an appropriate state transition for all VRs on the interface.
1296  * This function may be invoked by:
1297  *    sw interface admin up/down event
1298  *    hw interface link up/down event
1299  */
1300 clib_error_t *
1301 vrrp_sw_interface_up_down (vrrp_intf_update_t * pending)
1302 {
1303   vrrp_intf_t *intf;
1304   int i;
1305   u32 *vr_index;
1306   vrrp_vr_t *vr;
1307
1308   intf = vrrp_intf_get (pending->sw_if_index);
1309   if (!intf)
1310     return 0;
1311
1312   /* adjust state of VR's configured on this interface */
1313   for (i = 0; i < 2; i++)
1314     {
1315       int is_up;
1316
1317       if (!intf->vr_indices[i])
1318         continue;
1319
1320       is_up = vrrp_intf_is_up (pending->sw_if_index, i, pending);
1321
1322       vec_foreach (vr_index, intf->vr_indices[i])
1323       {
1324         vrrp_vr_state_t vr_state;
1325
1326         vr = vrrp_vr_lookup_index (*vr_index);
1327         if (!vr)
1328           continue;
1329
1330         if (vr->runtime.state == VRRP_VR_STATE_INIT)
1331           continue;             /* VR not started yet, no transition */
1332
1333         if (!is_up)
1334           vr_state = VRRP_VR_STATE_INTF_DOWN;
1335         else
1336           {
1337             if (vr->runtime.state != VRRP_VR_STATE_INTF_DOWN)
1338               continue;         /* shouldn't happen */
1339
1340             vr_state = (vrrp_vr_is_owner (vr)) ?
1341               VRRP_VR_STATE_MASTER : VRRP_VR_STATE_BACKUP;
1342           }
1343
1344         vrrp_vr_transition (vr, vr_state, NULL);
1345       }
1346     }
1347
1348   /* compute adjustments on any VR's tracking this interface */
1349   vrrp_intf_tracking_vrs_compute (pending->sw_if_index, pending,
1350                                   0 /* is_ipv6 */ );
1351   vrrp_intf_tracking_vrs_compute (pending->sw_if_index, pending,
1352                                   1 /* is_ipv6 */ );
1353
1354   return 0;
1355 }
1356
1357 /* Process change in admin status on an interface */
1358 clib_error_t *
1359 vrrp_sw_interface_admin_up_down (vnet_main_t * vnm, u32 sw_if_index,
1360                                  u32 flags)
1361 {
1362   vrrp_intf_update_t pending = {
1363     .type = VRRP_IF_UPDATE_SW_ADMIN,
1364     .sw_if_index = sw_if_index,
1365     .intf_up = ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0),
1366   };
1367
1368   return vrrp_sw_interface_up_down (&pending);
1369 }
1370
1371 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (vrrp_sw_interface_admin_up_down);
1372
1373 static walk_rc_t
1374 vrrp_hw_interface_link_up_down_walk (vnet_main_t * vnm,
1375                                      u32 sw_if_index, void *arg)
1376 {
1377   vrrp_intf_update_t *pending = arg;
1378
1379   pending->sw_if_index = sw_if_index;
1380   vrrp_sw_interface_up_down (pending);
1381
1382   return WALK_CONTINUE;
1383 }
1384
1385 static clib_error_t *
1386 vrrp_hw_interface_link_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
1387 {
1388   vrrp_intf_update_t pending = {
1389     .type = VRRP_IF_UPDATE_HW_LINK,
1390     .hw_if_index = hw_if_index,
1391     .intf_up = ((flags & VNET_HW_INTERFACE_FLAG_LINK_UP) != 0),
1392   };
1393
1394   /* walk the sw interface and sub interfaces to adjust interface tracking */
1395   vnet_hw_interface_walk_sw (vnm, hw_if_index,
1396                              vrrp_hw_interface_link_up_down_walk, &pending);
1397
1398   return 0;
1399 }
1400
1401 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (vrrp_hw_interface_link_up_down);
1402
1403 static void
1404 vrrp_ip4_add_del_interface_addr (ip4_main_t * im,
1405                                  uword opaque,
1406                                  u32 sw_if_index,
1407                                  ip4_address_t * address,
1408                                  u32 address_length,
1409                                  u32 if_address_index, u32 is_del)
1410 {
1411   vrrp_intf_tracking_vrs_compute (sw_if_index, NULL, 0 /* is_ipv6 */ );
1412 }
1413
1414 static ip6_link_delegate_id_t vrrp_ip6_delegate_id;
1415
1416 static u8 *
1417 format_vrrp_ip6_link (u8 * s, va_list * args)
1418 {
1419   index_t indi = va_arg (*args, index_t);
1420   u32 indent = va_arg (*args, u32);
1421   vrrp_intf_t *intf;
1422   u32 *vr_index;
1423
1424   intf = vrrp_intf_get ((u32) indi);
1425
1426   s = format (s, "%UVRRP VRs monitoring this link:\n",
1427               format_white_space, indent);
1428
1429   vec_foreach (vr_index, intf->tracking_vrs[1])
1430   {
1431     vrrp_vr_t *vr = vrrp_vr_lookup_index (*vr_index);
1432
1433     s = format (s, "%U%U\n", format_white_space, indent + 2,
1434                 format_vrrp_vr_key, vr);
1435   }
1436
1437   return s;
1438 }
1439
1440 static void
1441 vrrp_intf_ip6_enable_disable (u32 sw_if_index, int enable)
1442 {
1443   vrrp_intf_update_t pending = {
1444     .type = VRRP_IF_UPDATE_IP,
1445     .sw_if_index = sw_if_index,
1446     .intf_up = enable,
1447   };
1448
1449   vrrp_intf_tracking_vrs_compute (sw_if_index, &pending, 1 /* is_ipv6 */ );
1450 }
1451
1452 static void
1453 vrrp_intf_ip6_enable (u32 sw_if_index)
1454 {
1455   vrrp_intf_ip6_enable_disable (sw_if_index, 1 /* enable */ );
1456   ip6_link_delegate_update (sw_if_index, vrrp_ip6_delegate_id, sw_if_index);
1457 }
1458
1459 static void
1460 vrrp_intf_ip6_disable (index_t indi)
1461 {
1462   vrrp_intf_ip6_enable_disable (indi, 0 /* enable */ );
1463 }
1464
1465 const static ip6_link_delegate_vft_t vrrp_ip6_delegate_vft = {
1466   .ildv_enable = vrrp_intf_ip6_enable,
1467   .ildv_disable = vrrp_intf_ip6_disable,
1468   .ildv_format = format_vrrp_ip6_link,
1469 };
1470
1471 static clib_error_t *
1472 vrrp_init (vlib_main_t * vm)
1473 {
1474   vrrp_main_t *vmp = &vrrp_main;
1475   clib_error_t *error = 0;
1476   ip4_main_t *im4 = &ip4_main;
1477   ip4_add_del_interface_address_callback_t cb4;
1478   vlib_node_t *intf_output_node;
1479
1480   clib_memset (vmp, 0, sizeof (*vmp));
1481
1482   if ((error = vlib_call_init_function (vm, ip4_lookup_init)) ||
1483       (error = vlib_call_init_function (vm, ip6_lookup_init)))
1484     return error;
1485
1486   vmp->vlib_main = vm;
1487   vmp->vnet_main = vnet_get_main ();
1488
1489   intf_output_node = vlib_get_node_by_name (vm, (u8 *) "interface-output");
1490   vmp->intf_output_node_idx = intf_output_node->index;
1491
1492   error = vrrp_plugin_api_hookup (vm);
1493
1494   if (error)
1495     return error;
1496
1497   mhash_init (&vmp->vr_index_by_key, sizeof (u32), sizeof (vrrp_vr_key_t));
1498   vmp->vrrp4_arp_lookup = hash_create (0, sizeof (uword));
1499   vmp->vrrp6_nd_lookup = hash_create_mem (0, sizeof (vrrp6_nd_key_t),
1500                                           sizeof (uword));
1501
1502   cb4.function = vrrp_ip4_add_del_interface_addr;
1503   cb4.function_opaque = 0;
1504   vec_add1 (im4->add_del_interface_address_callbacks, cb4);
1505
1506   vrrp_ip6_delegate_id = ip6_link_delegate_register (&vrrp_ip6_delegate_vft);
1507
1508   /* allocate & reset error counters */
1509   for (int i = 0; i < VRRP_ERR_COUNTER_MAX; i++)
1510     {
1511       vlib_validate_simple_counter (&vrrp_errs[i], 0);
1512       vlib_zero_simple_counter (&vrrp_errs[i], 0);
1513     }
1514
1515   return error;
1516 }
1517
1518 VLIB_INIT_FUNCTION (vrrp_init);
1519
1520
1521 /* *INDENT-OFF* */
1522 VLIB_PLUGIN_REGISTER () =
1523 {
1524   .version = VPP_BUILD_VER,
1525   .description = "VRRP v3 (RFC 5798)",
1526 };
1527 /* *INDENT-ON* */
1528
1529 /*
1530  * fd.io coding-style-patch-verification: ON
1531  *
1532  * Local Variables:
1533  * eval: (c-set-style "gnu")
1534  * End:
1535  */