vrrp: add stats support and update API
[vpp.git] / src / plugins / vrrp / node.c
1 /*
2  * node.c - vrrp packet handling node definitions
3  *
4  * Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  *
8  */
9 #include <vlib/vlib.h>
10 #include <vlibmemory/api.h>
11 #include <vnet/vnet.h>
12 #include <vnet/ip/ip4_packet.h>
13 #include <vnet/ip/ip6_link.h>
14 #include <vnet/ethernet/arp_packet.h>
15 #include <vnet/fib/fib_sas.h>
16 #include <vppinfra/error.h>
17 #include <vrrp/vrrp.h>
18 #include <vrrp/vrrp_packet.h>
19
20 typedef struct
21 {
22   u32 sw_if_index;
23   u8 is_ipv6;
24   vrrp_header_t vrrp;
25   u8 addrs[256];                /* print up to 64 IPv4 or 16 IPv6 addresses */
26 } vrrp_trace_t;
27
28 /* packet trace format function */
29 static u8 *
30 format_vrrp_trace (u8 * s, va_list * args)
31 {
32   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
33   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
34   vrrp_trace_t *t = va_arg (*args, vrrp_trace_t *);
35   int i;
36
37   s = format (s, "VRRP: sw_if_index %d IPv%d\n",
38               t->sw_if_index, (t->is_ipv6) ? 6 : 4);
39   s = format (s, "    %U\n", format_vrrp_packet_hdr, &t->vrrp);
40   s = format (s, "    addresses: ");
41
42   for (i = 0; i < t->vrrp.n_addrs; i++)
43     {
44       if (t->is_ipv6)
45         s = format (s, "%U ", format_ip6_address,
46                     (ip6_address_t *) (t->addrs + i * 16));
47       else
48         s = format (s, "%U ", format_ip4_address,
49                     (ip4_address_t *) (t->addrs + i * 4));
50     }
51
52   return s;
53 }
54
55 extern vlib_node_registration_t vrrp4_input_node;
56 extern vlib_node_registration_t vrrp6_input_node;
57 extern vlib_node_registration_t vrrp4_arp_input_node;
58 extern vlib_node_registration_t vrrp6_nd_input_node;
59
60 #define foreach_vrrp_error                                        \
61 _(RECEIVED, "VRRP packets processed")                             \
62 _(BAD_TTL, "VRRP advertisement TTL is not 255")                   \
63 _(NOT_VERSION_3, "VRRP version is not 3")                         \
64 _(INCOMPLETE_PKT, "VRRP packet has wrong size")                   \
65 _(BAD_CHECKSUM, "VRRP checksum is invalid")                       \
66 _(UNKNOWN_VR, "VRRP message does not match known VRs")            \
67 _(ADDR_MISMATCH, "VR addrs do not match configuration")
68
69 typedef enum
70 {
71 #define _(sym,str) VRRP_ERROR_##sym,
72   foreach_vrrp_error
73 #undef _
74     VRRP_N_ERROR,
75 } vrrp_error_t;
76
77 static char *vrrp_error_strings[] = {
78 #define _(sym,string) string,
79   foreach_vrrp_error
80 #undef _
81 };
82
83 typedef enum
84 {
85   VRRP_INPUT_NEXT_DROP,
86   VRRP_INPUT_N_NEXT,
87 } vrrp_next_t;
88
89 /* Given a VR and a pointer to the VRRP header of an incoming packet,
90  * compare the local src address to the peers. Return < 0 if the local
91  * address < the peer address, 0 if they're equal, > 0 if
92  * the local address > the peer address
93  */
94 static int
95 vrrp_vr_addr_cmp (vrrp_vr_t *vr, ip46_address_t *peer_addr)
96 {
97   vrrp_vr_config_t *vrc = &vr->config;
98   void *peer_addr_bytes, *local_addr;
99   ip46_address_t addr;
100   int addr_size;
101
102   clib_memset (&addr, 0, sizeof (addr));
103
104   if (vrrp_vr_is_ipv6 (vr))
105     {
106       peer_addr_bytes = &peer_addr->ip6;
107       local_addr = &addr.ip6;
108       addr_size = 16;
109       ip6_address_copy (local_addr,
110                         ip6_get_link_local_address (vrc->sw_if_index));
111     }
112   else
113     {
114       peer_addr_bytes = &peer_addr->ip4;
115       local_addr = &addr.ip4;
116       addr_size = 4;
117       fib_sas4_get (vrc->sw_if_index, NULL, local_addr);
118     }
119
120   return memcmp (local_addr, peer_addr_bytes, addr_size);
121 }
122
123 static void
124 vrrp_input_process_master (vrrp_vr_t *vr, vrrp_input_process_args_t *args)
125 {
126   /* received priority 0, another VR is shutting down. send an adv and
127    * remain in the master state
128    */
129   if (args->priority == 0)
130     {
131       clib_warning ("Received shutdown message from a peer on VR %U",
132                     format_vrrp_vr_key, vr);
133       vrrp_incr_stat_counter (VRRP_STAT_COUNTER_PRIO0_RCVD, vr->stat_index);
134       vrrp_adv_send (vr, 0);
135       vrrp_vr_timer_set (vr, VRRP_VR_TIMER_ADV);
136       return;
137     }
138
139   /* if either:
140    * - received priority > adjusted priority, or
141    * - received priority == adjusted priority and peer addr > local addr
142    * allow the local VR to be preempted by the peer
143    */
144   if ((args->priority > vrrp_vr_priority (vr)) ||
145       ((args->priority == vrrp_vr_priority (vr)) &&
146        (vrrp_vr_addr_cmp (vr, &args->src_addr) < 0)))
147     {
148       vrrp_vr_transition (vr, VRRP_VR_STATE_BACKUP, args);
149
150       return;
151     }
152
153   /* if we made it this far, eiher received prority < adjusted priority or
154    * received == adjusted and local addr > peer addr. Ignore.
155    */
156   return;
157 }
158
159 /* RFC 5798 section 6.4.2 */
160 static void
161 vrrp_input_process_backup (vrrp_vr_t *vr, vrrp_input_process_args_t *args)
162 {
163   vrrp_vr_config_t *vrc = &vr->config;
164   vrrp_vr_runtime_t *vrt = &vr->runtime;
165
166   /* master shutting down, ready for election */
167   if (args->priority == 0)
168     {
169       clib_warning ("Master for VR %U is shutting down", format_vrrp_vr_key,
170                     vr);
171       vrrp_incr_stat_counter (VRRP_STAT_COUNTER_PRIO0_RCVD, vr->stat_index);
172       vrt->master_down_int = vrt->skew;
173       vrrp_vr_timer_set (vr, VRRP_VR_TIMER_MASTER_DOWN);
174       return;
175     }
176
177   /* no preempt set or adv from a higher priority router, update timers */
178   if (!(vrc->flags & VRRP_VR_PREEMPT) ||
179       (args->priority >= vrrp_vr_priority (vr)))
180     {
181       vrt->master_adv_int = args->max_adv_int;
182
183       vrrp_vr_skew_compute (vr);
184       vrrp_vr_master_down_compute (vr);
185       vrrp_vr_timer_set (vr, VRRP_VR_TIMER_MASTER_DOWN);
186       return;
187     }
188
189   /* preempt set or our priority > received, continue to wait on master down */
190   return;
191 }
192
193 always_inline void
194 vrrp_input_process (vrrp_input_process_args_t * args)
195 {
196   vrrp_vr_t *vr;
197
198   vr = vrrp_vr_lookup_index (args->vr_index);
199
200   if (!vr)
201     {
202       clib_warning ("Error retrieving VR with index %u", args->vr_index);
203       return;
204     }
205
206   vrrp_incr_stat_counter (VRRP_STAT_COUNTER_ADV_RCVD, vr->stat_index);
207
208   switch (vr->runtime.state)
209     {
210     case VRRP_VR_STATE_INIT:
211       return;
212     case VRRP_VR_STATE_BACKUP:
213       /* this is usually the only state an advertisement should be received */
214       vrrp_input_process_backup (vr, args);
215       break;
216     case VRRP_VR_STATE_MASTER:
217       /* might be getting preempted. or have a misbehaving peer */
218       clib_warning ("Received advertisement for master VR %U",
219                     format_vrrp_vr_key, vr);
220       vrrp_input_process_master (vr, args);
221       break;
222     default:
223       clib_warning ("Received advertisement for VR %U in unknown state %d",
224                     format_vrrp_vr_key, vr, vr->runtime.state);
225       break;
226     }
227
228   return;
229 }
230
231 typedef struct
232 {
233   ip46_address_t ip;
234   u32 vr_index;
235   u8 vr_id;
236   u8 is_ipv6;
237 } vrrp_arp_nd_trace_t;
238
239
240 static u8 *
241 format_vrrp_arp_nd_input_trace (u8 * s, va_list * va)
242 {
243   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
244   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
245   vrrp_arp_nd_trace_t *t = va_arg (*va, vrrp_arp_nd_trace_t *);
246
247   s = format (s, "address %U",
248               (t->is_ipv6) ? format_ip6_address : format_ip4_address,
249               (t->is_ipv6) ? (void *) &t->ip.ip6 : (void *) &t->ip.ip4);
250
251   if (t->vr_index != ~0)
252     s = format (s, ": vr_index %u vr_id %u", t->vr_index, t->vr_id);
253
254   return s;
255 }
256
257 typedef enum
258 {
259   VRRP_ARP_INPUT_NEXT_DROP,
260   VRRP_ARP_INPUT_NEXT_REPLY_TX,
261   VRRP_ARP_N_NEXT,
262 } vrrp_arp_next_t;
263
264 typedef enum
265 {
266   VRRP_ND_INPUT_NEXT_DROP,
267   VRRP_ND_INPUT_NEXT_REPLY_TX,
268   VRRP_ND_N_NEXT,
269 } vrrp_nd_next_t;
270
271 static_always_inline void
272 vrrp_arp_nd_next (vlib_buffer_t * b, u32 * next_index, u32 * vr_index,
273                   u8 is_ipv6)
274 {
275   vnet_main_t *vnm = vnet_get_main ();
276   vlib_main_t *vm = vlib_get_main ();
277   ethernet_header_t *eth, *eth_new;
278   void *lookup_addr = 0;
279   vrrp_vr_t *vr;
280   u32 sw_if_index;
281   vnet_link_t link_type;
282   u8 *rewrite, rewrite_len;
283   int bogus_length;
284   /* ND vars */
285   ip6_header_t *ip6 = 0;
286   icmp6_neighbor_solicitation_or_advertisement_header_t *sol_adv = 0;
287   icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *lladdr = 0;
288   /* ARP vars */
289   ethernet_arp_header_t *arp;
290   ip4_address_t ip4_addr;
291
292   if (is_ipv6)
293     {
294       ip6 = vlib_buffer_get_current (b);
295
296       /* we only care about about ICMP6 neighbor solicitiations */
297       if (ip6->protocol != IP_PROTOCOL_ICMP6)
298         return;
299
300       sol_adv = ip6_next_header (ip6);
301       lladdr = (void *) (sol_adv + 1);
302
303       /* skip anything other than neighbor solicitations */
304       if (sol_adv->icmp.type != ICMP6_neighbor_solicitation)
305         return;
306
307       lookup_addr = &sol_adv->target_address;
308       link_type = VNET_LINK_IP6;
309     }
310   else
311     {
312       arp = vlib_buffer_get_current (b);
313
314       /* skip non-request packets */
315       if (arp->opcode != clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request))
316         return;
317
318       lookup_addr = &arp->ip4_over_ethernet[1].ip4;
319       link_type = VNET_LINK_ARP;
320     }
321
322   sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
323
324   /* Don't bother with a hash lookup if no VRs configured on this interface */
325   if (!vrrp_intf_num_vrs (sw_if_index, is_ipv6))
326     return;
327
328   /* skip requests that are not for VRRP addresses */
329   *vr_index = vrrp_vr_lookup_address (sw_if_index, is_ipv6, lookup_addr);
330   if (*vr_index == ~0)
331     return;
332
333   vr = vrrp_vr_lookup_index (*vr_index);
334   if (!vr || vr->runtime.state != VRRP_VR_STATE_MASTER)
335     {
336       /* RFC 5798 - section 6.4.2 - Backup "MUST NOT respond" to ARP/ND.
337        * So we must drop the request rather than allowing it to continue
338        * on the feature arc.
339        */
340       *next_index = VRRP_ARP_INPUT_NEXT_DROP;
341       return;
342     }
343
344   /* RFC 5798 section 6.4.3: Master "MUST respond" to ARP/ND. */
345   eth = ethernet_buffer_get_header (b);
346   rewrite = ethernet_build_rewrite (vnm, sw_if_index, link_type,
347                                     eth->src_address);
348   rewrite_len = vec_len (rewrite);
349   if (rewrite_len == 0)
350     return;
351
352   /* send the reply out the incoming interface */
353   *next_index = VRRP_ARP_INPUT_NEXT_REPLY_TX;
354   vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
355
356   /* the outbound ethernet & vlan headers may have a different length than
357    * the received header, so get a pointer to the new start of the packet
358    * and write the header there.
359    */
360   vlib_buffer_advance (b, -rewrite_len);
361   eth_new = vlib_buffer_get_current (b);
362   clib_memcpy_fast (eth_new, rewrite, rewrite_len);
363   vec_free (rewrite);
364
365   if (is_ipv6)
366     {
367       if (ip6_address_is_unspecified (&ip6->src_address))
368         ip6_set_reserved_multicast_address (&ip6->dst_address,
369                                             IP6_MULTICAST_SCOPE_link_local,
370                                             IP6_MULTICAST_GROUP_ID_all_hosts);
371       else
372         ip6->dst_address = ip6->src_address;
373
374       ip6->src_address = sol_adv->target_address;
375       ip6->hop_limit = 255;
376       sol_adv->icmp.type = ICMP6_neighbor_advertisement;
377       sol_adv->icmp.checksum = 0;
378       sol_adv->advertisement_flags =
379         clib_host_to_net_u32 (ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER
380                               | ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED
381                               | ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE);
382
383       clib_memcpy (lladdr->ethernet_address, vr->runtime.mac.bytes,
384                    sizeof (mac_address_t));
385       lladdr->header.type =
386         ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
387
388       sol_adv->icmp.checksum =
389         ip6_tcp_udp_icmp_compute_checksum (vm, b, ip6, &bogus_length);
390
391     }
392   else
393     {
394       ip4_addr = arp->ip4_over_ethernet[1].ip4;
395
396       arp->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
397       arp->ip4_over_ethernet[1] = arp->ip4_over_ethernet[0];
398
399       arp->ip4_over_ethernet[0].mac = vr->runtime.mac;
400       arp->ip4_over_ethernet[0].ip4 = ip4_addr;
401     }
402 }
403
404 static_always_inline uword
405 vrrp_arp_nd_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
406                           vlib_frame_t * frame, u8 is_ipv6)
407 {
408   u32 n_left_from, *from, next_index, *to_next;
409
410   from = vlib_frame_vector_args (frame);
411   n_left_from = frame->n_vectors;
412   next_index = node->cached_next_index;
413
414   while (n_left_from > 0)
415     {
416       u32 n_left_to_next;
417
418       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
419
420       while (n_left_from > 0 && n_left_to_next > 0)
421         {
422
423           vlib_buffer_t *b0;
424           u32 bi0;
425           u32 next0;
426           u32 vr_index = ~0;
427
428           bi0 = from[0];
429           to_next[0] = bi0;
430           from += 1;
431           to_next += 1;
432           n_left_from -= 1;
433           n_left_to_next -= 1;
434
435           b0 = vlib_get_buffer (vm, bi0);
436
437           vnet_feature_next (&next0, b0);
438           vrrp_arp_nd_next (b0, &next0, &vr_index, is_ipv6);
439
440           if (b0->flags & VLIB_BUFFER_IS_TRACED)
441             {
442               vrrp_arp_nd_trace_t *t =
443                 vlib_add_trace (vm, node, b0, sizeof (*t));
444               vrrp_vr_t *vr;
445
446               if (is_ipv6)
447                 {
448                   ip6_header_t *ip0;
449                   icmp6_neighbor_solicitation_or_advertisement_header_t
450                     * sol_adv0;
451
452                   ip0 = vlib_buffer_get_current (b0);
453                   sol_adv0 = ip6_next_header (ip0);
454                   t->ip.ip6 = sol_adv0->target_address;
455                 }
456               else
457                 {
458                   ethernet_arp_header_t *arp0;
459
460                   arp0 = vlib_buffer_get_current (b0);
461                   t->ip.ip4 = arp0->ip4_over_ethernet[0].ip4;
462                 }
463
464               vr = vrrp_vr_lookup_index (vr_index);
465               if (vr)
466                 t->vr_id = vr->config.vr_id;
467
468               t->vr_index = vr_index;
469               t->is_ipv6 = is_ipv6;
470             }
471
472           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
473                                            n_left_to_next, bi0, next0);
474         }
475
476       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
477     }
478
479   return frame->n_vectors;
480 }
481
482 VLIB_NODE_FN (vrrp4_arp_input_node) (vlib_main_t * vm,
483                                      vlib_node_runtime_t * node,
484                                      vlib_frame_t * frame)
485 {
486   return vrrp_arp_nd_input_inline (vm, node, frame, 0 /* is_ipv6 */ );
487 }
488
489 /* *INDENT-OFF* */
490 VLIB_REGISTER_NODE (vrrp4_arp_input_node) =
491 {
492   .name = "vrrp4-arp-input",
493   .vector_size = sizeof (u32),
494   .format_trace = format_vrrp_arp_nd_input_trace,
495   .type = VLIB_NODE_TYPE_INTERNAL,
496
497   .n_errors = ARRAY_LEN(vrrp_error_strings),
498   .error_strings = vrrp_error_strings,
499
500   .n_next_nodes = VRRP_ARP_N_NEXT,
501
502   .next_nodes = {
503         [VRRP_ARP_INPUT_NEXT_DROP] = "error-drop",
504         [VRRP_ARP_INPUT_NEXT_REPLY_TX] = "interface-output",
505   },
506 };
507
508 VNET_FEATURE_INIT (vrrp4_arp_feat_node, static) =
509 {
510   .arc_name = "arp",
511   .node_name = "vrrp4-arp-input",
512   .runs_before = VNET_FEATURES ("arp-reply"),
513 };
514
515 VLIB_NODE_FN (vrrp6_nd_input_node) (vlib_main_t * vm,
516                                      vlib_node_runtime_t * node,
517                                      vlib_frame_t * frame)
518 {
519   return vrrp_arp_nd_input_inline (vm, node, frame, 1 /* is_ipv6 */);
520 }
521
522 /* *INDENT-OFF* */
523 VLIB_REGISTER_NODE (vrrp6_nd_input_node) =
524 {
525   .name = "vrrp6-nd-input",
526   .vector_size = sizeof (u32),
527   .format_trace = format_vrrp_arp_nd_input_trace,
528   .type = VLIB_NODE_TYPE_INTERNAL,
529
530   .n_errors = ARRAY_LEN(vrrp_error_strings),
531   .error_strings = vrrp_error_strings,
532
533   .n_next_nodes = VRRP_ND_N_NEXT,
534
535   .next_nodes = {
536         [VRRP_ND_INPUT_NEXT_DROP] = "error-drop",
537         [VRRP_ND_INPUT_NEXT_REPLY_TX] = "interface-output",
538   },
539 };
540
541 VNET_FEATURE_INIT (vrrp6_nd_feat_node, static) =
542 {
543   .arc_name = "ip6-local",
544   .node_name = "vrrp6-nd-input",
545   .runs_before = VNET_FEATURES ("ip6-local-end-of-arc"),
546 };
547
548 static_always_inline uword
549 vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
550                     vlib_frame_t * frame, u8 is_ipv6)
551 {
552   u32 n_left_from, *from;
553   vrrp_main_t *vmp = &vrrp_main;
554
555   from = vlib_frame_vector_args (frame);
556   n_left_from = frame->n_vectors;
557
558   while (n_left_from > 0)
559     {
560       u32 bi0;
561       vlib_buffer_t *b0;
562       u32 next0, error0;
563       void *ip0;
564       vrrp_header_t *vrrp0;
565       vrrp_vr_t *vr0;
566       vrrp_input_process_args_t args0;
567       u8 *ttl0;
568       u16 rx_csum0;
569       u16 payload_len0;
570       int addr_len;
571
572       bi0 = from[0];
573       b0 = vlib_get_buffer (vm, bi0);
574
575       ip0 = vlib_buffer_get_current (b0);
576
577       if (is_ipv6)
578         {
579           ip6_header_t *ip6 = ip0;
580
581           vrrp0 = (vrrp_header_t *) (ip6 + 1);
582           ttl0 = &ip6->hop_limit;
583           addr_len = 16;
584           payload_len0 = clib_net_to_host_u16 (ip6->payload_length);
585           vlib_buffer_advance (b0, sizeof (*ip6));
586           clib_memcpy_fast (&args0.src_addr.ip6, &ip6->src_address, addr_len);
587         }
588       else
589         {
590           ip4_header_t *ip4 = ip0;
591
592           vrrp0 = (vrrp_header_t *) (ip4 + 1);
593           ttl0 = &ip4->ttl;
594           addr_len = 4;
595           payload_len0 = clib_net_to_host_u16 (ip4->length) - sizeof(*ip4);
596           vlib_buffer_advance (b0, sizeof (*ip4));
597           clib_memcpy_fast (&args0.src_addr.ip4, &ip4->src_address, addr_len);
598         }
599
600       next0 = VRRP_INPUT_NEXT_DROP;
601
602       error0 = VRRP_ERROR_RECEIVED;
603
604       /* Validation from RFC 5798 sec 7.1 */
605
606       /* checksum set to 0 for calculation, save original value */
607       rx_csum0 = vrrp0->checksum;
608       vrrp0->checksum = 0;
609
610       /* Mandatory - TTL/hop limit must be 255 */
611       if (*ttl0 != 255)
612         {
613           error0 = VRRP_ERROR_BAD_TTL;
614           vrrp_incr_err_counter (VRRP_ERR_COUNTER_TTL);
615           goto trace;
616         }
617
618       /* Mandatory - VRRP version must be 3 */
619       if ((vrrp0->vrrp_version_and_type >> 4) != 3)
620         {
621           error0 = VRRP_ERROR_NOT_VERSION_3;
622           vrrp_incr_err_counter (VRRP_ERR_COUNTER_VERSION);
623           goto trace;
624         }
625
626       /* Mandatory - packet must be complete */
627       if (b0->current_length < sizeof (*vrrp0) +
628           ((u32) vrrp0->n_addrs) * addr_len)
629         {
630           error0 = VRRP_ERROR_INCOMPLETE_PKT;
631           vrrp_incr_err_counter (VRRP_ERR_COUNTER_PKT_LEN);
632           goto trace;
633         }
634
635       /* Mandatory - checksum must be correct */
636       if (rx_csum0 != vrrp_adv_csum (ip0, vrrp0, is_ipv6, payload_len0))
637         {
638           error0 = VRRP_ERROR_BAD_CHECKSUM;
639           vrrp_incr_err_counter (VRRP_ERR_COUNTER_CHKSUM);
640           goto trace;
641         }
642
643       /* Mandatory - VR must be configured on the interface adv received on */
644       if (!(vr0 =
645               vrrp_vr_lookup (vnet_buffer(b0)->sw_if_index[VLIB_RX],
646                               vrrp0->vr_id, is_ipv6)))
647         {
648           error0 = VRRP_ERROR_UNKNOWN_VR;
649           vrrp_incr_err_counter (VRRP_ERR_COUNTER_VRID);
650           goto trace;
651         }
652
653       /* Optional - count of addresses should match configuration */
654       /* Could also check that addresses match, but likely to be O(n^2) */
655       if (vrrp0->n_addrs != vec_len (vr0->config.vr_addrs))
656         {
657           error0 = VRRP_ERROR_ADDR_MISMATCH;
658           vrrp_incr_err_counter (VRRP_ERR_COUNTER_ADDR_LIST);
659           goto trace;
660         }
661
662       /* signal main thread to process contents of packet */
663       args0.vr_index = vr0 - vmp->vrs;
664       args0.priority = vrrp0->priority;
665       args0.max_adv_int = vrrp_adv_int_from_packet (vrrp0);
666
667       vl_api_rpc_call_main_thread (vrrp_input_process, (u8 *) &args0,
668                                    sizeof (args0));
669
670     trace:
671       vrrp0->checksum = rx_csum0; /* restore csum for correct trace output */
672       b0->error = node->errors[error0];
673
674       if (b0->flags & VLIB_BUFFER_IS_TRACED)
675         {
676           vrrp_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
677           size_t addr_len = (is_ipv6 ? 16 : 4);
678
679           t->sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX];
680           t->is_ipv6 = is_ipv6;
681           clib_memcpy_fast (&t->vrrp, vrrp0, sizeof (*vrrp0));
682           clib_memcpy_fast (t->addrs, (void *) (vrrp0 + 1),
683                             (size_t) vrrp0->n_addrs * addr_len);
684         }
685
686       /* always drop, never forward or reply here */
687       vlib_set_next_frame_buffer (vm, node, next0, bi0);
688
689       from += 1;
690       n_left_from -= 1;
691     }
692
693   return frame->n_vectors;
694 }
695
696 VLIB_NODE_FN (vrrp4_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
697                                 vlib_frame_t * frame)
698 {
699   return vrrp_input_inline (vm, node, frame, 0);
700 }
701
702 /* *INDENT-OFF* */
703 VLIB_REGISTER_NODE (vrrp4_input_node) =
704 {
705   .name = "vrrp4-input",
706   .vector_size = sizeof (u32),
707   .format_trace = format_vrrp_trace,
708   .type = VLIB_NODE_TYPE_INTERNAL,
709
710   .n_errors = ARRAY_LEN(vrrp_error_strings),
711   .error_strings = vrrp_error_strings,
712
713   .n_next_nodes = VRRP_INPUT_N_NEXT,
714
715   .next_nodes = {
716         [VRRP_INPUT_NEXT_DROP] = "error-drop",
717   },
718 };
719
720 VLIB_NODE_FN (vrrp6_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
721                                 vlib_frame_t * frame)
722 {
723   return vrrp_input_inline (vm, node, frame, 1);
724 }
725
726 VLIB_REGISTER_NODE (vrrp6_input_node) =
727 {
728   .name = "vrrp6-input",
729   .vector_size = sizeof (u32),
730   .format_trace = format_vrrp_trace,
731   .type = VLIB_NODE_TYPE_INTERNAL,
732
733   .n_errors = ARRAY_LEN(vrrp_error_strings),
734   .error_strings = vrrp_error_strings,
735
736   .n_next_nodes = VRRP_INPUT_N_NEXT,
737
738   .next_nodes = {
739         [VRRP_INPUT_NEXT_DROP] = "error-drop",
740   },
741 };
742
743 typedef struct
744 {
745   u32 sw_if_index;
746   u8 is_ipv6;
747   ip46_address_t src, dst;
748 } vrrp_accept_owner_trace_t;
749
750 /* packet trace format function */
751 static u8 *
752 format_vrrp_accept_owner_trace (u8 * s, va_list * args)
753 {
754   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
755   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
756   vrrp_accept_owner_trace_t *t = va_arg (*args, vrrp_accept_owner_trace_t *);
757   int ip_ver = 4, ip_type = IP46_TYPE_IP4;
758
759   if (t->is_ipv6)
760     {
761       ip_ver = 6;
762       ip_type = IP46_TYPE_IP6;
763     }
764
765   s = format (s, "IPv%d sw_if_index %d %U -> %U",
766               ip_ver, t->sw_if_index,
767               format_ip46_address, &t->src, ip_type,
768               format_ip46_address, &t->dst, ip_type);
769
770   return s;
771 }
772
773 #define foreach_vrrp_accept_owner_error                           \
774 _(RECEIVED, "VRRP owner accept packets received")                 \
775 _(PROCESSED, "VRRP owner accept advertisements processed")
776
777 typedef enum
778 {
779 #define _(sym,str) VRRP_ACCEPT_OWNER_ERROR_##sym,
780   foreach_vrrp_accept_owner_error
781 #undef _
782     VRRP_ACCEPT_OWNER_N_ERROR,
783 } vrrp_accept_owner_error_t;
784
785 static char *vrrp_accept_owner_error_strings[] = {
786 #define _(sym,string) string,
787   foreach_vrrp_accept_owner_error
788 #undef _
789 };
790
791 typedef enum
792 {
793   VRRP_ACCEPT_OWNER_NEXT_PROCESS,
794   VRRP_ACCEPT_OWNER_N_NEXT,
795 } vrrp_accept_owner_next_t;
796
797 static_always_inline void
798 vrrp_accept_owner_next_node (u32 sw_if_index, u8 vr_id, u8 is_ipv6,
799                              u32 *next_index, u32 *error)
800 {
801   vrrp_vr_t *vr = vrrp_vr_lookup (sw_if_index, vr_id, is_ipv6);
802
803   if (vr && (vr->runtime.state == VRRP_VR_STATE_MASTER) &&
804       (vr->config.flags & VRRP_VR_ACCEPT))
805     {
806       *next_index = VRRP_ACCEPT_OWNER_NEXT_PROCESS;
807       *error = VRRP_ACCEPT_OWNER_ERROR_PROCESSED;
808     }
809 }
810
811 static_always_inline uword
812 vrrp_accept_owner_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
813                                 vlib_frame_t * frame, u8 is_ipv6)
814 {
815   u32 n_left_from, *from, *to_next;
816   u32 next_index = node->cached_next_index;
817
818   from = vlib_frame_vector_args (frame);
819   n_left_from = frame->n_vectors;
820
821   while (n_left_from > 0)
822     {
823       u32 n_left_to_next;
824
825       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
826
827       while (n_left_from >= 2 && n_left_to_next >= 2)
828         {
829           u32 bi0, bi1;
830           vlib_buffer_t *b0, *b1;
831           u32 next0, next1;
832           u32 error0, error1;
833           vrrp_header_t *vrrp0, *vrrp1;
834           ip4_header_t *ip40, *ip41;
835           ip6_header_t *ip60, *ip61;
836           u32 sw_if_index0, sw_if_index1;
837
838           bi0 = from[0];
839           bi1 = from[1];
840
841           to_next[0] = bi0;
842           to_next[1] = bi1;
843
844           b0 = vlib_get_buffer (vm, bi0);
845           b1 = vlib_get_buffer (vm, bi1);
846
847           /* most packets will follow feature arc */
848           vnet_feature_next (&next0, b0);
849           vnet_feature_next (&next1, b1);
850
851           error0 = error1 = VRRP_ACCEPT_OWNER_ERROR_RECEIVED;
852
853           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
854           sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
855
856           /* find VRRP advertisements which should be sent to VRRP node */
857           if (is_ipv6)
858             {
859               ip60 = vlib_buffer_get_current (b0);
860               ip61 = vlib_buffer_get_current (b1);
861
862               if (PREDICT_FALSE (ip60->protocol == IP_PROTOCOL_VRRP))
863                 {
864                   vrrp0 = (vrrp_header_t *) (ip60 + 1);
865                   vrrp_accept_owner_next_node (sw_if_index0, vrrp0->vr_id,
866                                                is_ipv6, &next0, &error0);
867                 }
868               if (PREDICT_FALSE (ip61->protocol == IP_PROTOCOL_VRRP))
869                 {
870                   vrrp1 = (vrrp_header_t *) (ip61 + 1);
871                   vrrp_accept_owner_next_node (sw_if_index1, vrrp1->vr_id,
872                                                is_ipv6, &next1, &error1);
873                 }
874             }
875           else
876             {
877               ip40 = vlib_buffer_get_current (b0);
878               ip41 = vlib_buffer_get_current (b1);
879
880               if (PREDICT_FALSE (ip40->protocol == IP_PROTOCOL_VRRP))
881                 {
882                   vrrp0 = (vrrp_header_t *) (ip40 + 1);
883                   vrrp_accept_owner_next_node (sw_if_index0, vrrp0->vr_id,
884                                                is_ipv6, &next0, &error0);
885                 }
886               if (PREDICT_FALSE (ip41->protocol == IP_PROTOCOL_VRRP))
887                 {
888                   vrrp1 = (vrrp_header_t *) (ip41 + 1);
889                   vrrp_accept_owner_next_node (sw_if_index1, vrrp1->vr_id,
890                                                is_ipv6, &next1, &error1);
891                 }
892             }
893
894           b0->error = node->errors[error0];
895           b1->error = node->errors[error1];
896
897           if (b0->flags & VLIB_BUFFER_IS_TRACED)
898             {
899               vrrp_accept_owner_trace_t *t =
900                 vlib_add_trace (vm, node, b0, sizeof (*t));
901
902               t->sw_if_index = sw_if_index0;
903               t->is_ipv6 = is_ipv6;
904               if (is_ipv6)
905                 {
906                   ip6_address_copy (&t->src.ip6, &ip60->src_address);
907                   ip6_address_copy (&t->dst.ip6, &ip60->dst_address);
908                 }
909               else
910                 {
911                   t->src.ip4.as_u32 = ip40->src_address.as_u32;
912                   t->dst.ip4.as_u32 = ip40->dst_address.as_u32;
913                 }
914             }
915
916           if (b1->flags & VLIB_BUFFER_IS_TRACED)
917             {
918               vrrp_accept_owner_trace_t *t =
919                 vlib_add_trace (vm, node, b1, sizeof (*t));
920
921               t->sw_if_index = sw_if_index1;
922               t->is_ipv6 = is_ipv6;
923               if (is_ipv6)
924                 {
925                   ip6_address_copy (&t->src.ip6, &ip61->src_address);
926                   ip6_address_copy (&t->dst.ip6, &ip61->dst_address);
927                 }
928               else
929                 {
930                   t->src.ip4.as_u32 = ip41->src_address.as_u32;
931                   t->dst.ip4.as_u32 = ip41->dst_address.as_u32;
932                 }
933             }
934
935           from += 2;
936           n_left_from -= 2;
937           to_next += 2;
938           n_left_to_next -= 2;
939
940           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
941                                            to_next, n_left_to_next,
942                                            bi0, bi1, next0, next1);
943         }
944
945       while (n_left_from > 0 && n_left_to_next > 0)
946         {
947           u32 bi0;
948           vlib_buffer_t *b0;
949           u32 next0;
950           u32 error0;
951           vrrp_header_t *vrrp0;
952           ip4_header_t *ip4;
953           ip6_header_t *ip6;
954           u32 sw_if_index0;
955
956           bi0 = from[0];
957           to_next[0] = bi0;
958
959           b0 = vlib_get_buffer (vm, bi0);
960
961           /* most packets will follow feature arc */
962           vnet_feature_next (&next0, b0);
963
964           error0 = VRRP_ACCEPT_OWNER_ERROR_RECEIVED;
965
966           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
967
968           /* find VRRP advertisements which should be sent to VRRP node */
969           if (is_ipv6)
970             {
971               ip6 = vlib_buffer_get_current (b0);
972
973               if (PREDICT_FALSE (ip6->protocol == IP_PROTOCOL_VRRP))
974                 {
975                   vrrp0 = (vrrp_header_t *) (ip6 + 1);
976                   vrrp_accept_owner_next_node (sw_if_index0, vrrp0->vr_id,
977                                                is_ipv6, &next0, &error0);
978                 }
979             }
980           else
981             {
982               ip4 = vlib_buffer_get_current (b0);
983
984               if (PREDICT_FALSE (ip4->protocol == IP_PROTOCOL_VRRP))
985                 {
986                   vrrp0 = (vrrp_header_t *) (ip4 + 1);
987                   vrrp_accept_owner_next_node (sw_if_index0, vrrp0->vr_id,
988                                                is_ipv6, &next0, &error0);
989                 }
990             }
991
992           b0->error = node->errors[error0];
993
994           if (b0->flags & VLIB_BUFFER_IS_TRACED)
995             {
996               vrrp_accept_owner_trace_t *t =
997                 vlib_add_trace (vm, node, b0, sizeof (*t));
998
999               t->sw_if_index = sw_if_index0;
1000               t->is_ipv6 = is_ipv6;
1001               if (is_ipv6)
1002                 {
1003                   ip6_address_copy (&t->src.ip6, &ip6->src_address);
1004                   ip6_address_copy (&t->dst.ip6, &ip6->dst_address);
1005                 }
1006               else
1007                 {
1008                   t->src.ip4.as_u32 = ip4->src_address.as_u32;
1009                   t->dst.ip4.as_u32 = ip4->dst_address.as_u32;
1010                 }
1011             }
1012
1013           from += 1;
1014           n_left_from -= 1;
1015           to_next += 1;
1016           n_left_to_next -= 1;
1017
1018           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1019                                            to_next, n_left_to_next,
1020                                            bi0, next0);
1021         }
1022
1023       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1024     }
1025
1026   return frame->n_vectors;
1027 }
1028
1029 VLIB_NODE_FN (vrrp4_accept_owner_input_node) (vlib_main_t * vm,
1030                                               vlib_node_runtime_t * node,
1031                                               vlib_frame_t * frame)
1032 {
1033   return vrrp_accept_owner_input_inline (vm, node, frame, 0);
1034 }
1035
1036 VLIB_REGISTER_NODE (vrrp4_accept_owner_input_node) =
1037 {
1038   .name = "vrrp4-accept-owner-input",
1039   .vector_size = sizeof (u32),
1040   .format_trace = format_vrrp_accept_owner_trace,
1041   .type = VLIB_NODE_TYPE_INTERNAL,
1042
1043   .n_errors = ARRAY_LEN(vrrp_accept_owner_error_strings),
1044   .error_strings = vrrp_accept_owner_error_strings,
1045
1046   .n_next_nodes = VRRP_ACCEPT_OWNER_N_NEXT,
1047
1048   .next_nodes = {
1049         [VRRP_ACCEPT_OWNER_NEXT_PROCESS] = "vrrp4-input",
1050   },
1051 };
1052
1053 VNET_FEATURE_INIT (vrrp4_accept_owner_mc, static) =
1054 {
1055   .arc_name = "ip4-multicast",
1056   .node_name = "vrrp4-accept-owner-input",
1057   .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
1058 };
1059
1060 VLIB_NODE_FN (vrrp6_accept_owner_input_node) (vlib_main_t * vm,
1061                                            vlib_node_runtime_t * node,
1062                                            vlib_frame_t * frame)
1063 {
1064   return vrrp_accept_owner_input_inline (vm, node, frame, 1);
1065 }
1066
1067 VLIB_REGISTER_NODE (vrrp6_accept_owner_input_node) =
1068 {
1069   .name = "vrrp6-accept-owner-input",
1070   .vector_size = sizeof (u32),
1071   .format_trace = format_vrrp_accept_owner_trace,
1072   .type = VLIB_NODE_TYPE_INTERNAL,
1073
1074   .n_errors = ARRAY_LEN(vrrp_accept_owner_error_strings),
1075   .error_strings = vrrp_accept_owner_error_strings,
1076
1077   .n_next_nodes = VRRP_ACCEPT_OWNER_N_NEXT,
1078
1079   .next_nodes = {
1080         [VRRP_ACCEPT_OWNER_NEXT_PROCESS] = "vrrp6-input",
1081   },
1082 };
1083
1084 VNET_FEATURE_INIT (vrrp6_accept_owner_mc, static) =
1085 {
1086   .arc_name = "ip6-multicast",
1087   .node_name = "vrrp6-accept-owner-input",
1088   .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
1089 };
1090
1091 static clib_error_t *
1092 vrrp_input_init (vlib_main_t *vm)
1093 {
1094   clib_error_t *error;
1095
1096   if ((error = vlib_call_init_function (vm, vrrp_init)))
1097     return error;
1098
1099   ip4_register_protocol (IP_PROTOCOL_VRRP, vrrp4_input_node.index);
1100   ip6_register_protocol (IP_PROTOCOL_VRRP, vrrp6_input_node.index);
1101
1102   return 0;
1103 }
1104
1105 VLIB_INIT_FUNCTION (vrrp_input_init);
1106
1107 /* *INDENT-ON* */
1108
1109 /*
1110  * fd.io coding-style-patch-verification: ON
1111  *
1112  * Local Variables:
1113  * eval: (c-set-style "gnu")
1114  * End:
1115  */