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