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