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