2 * node.c - vrrp packet handling node definitions
4 * Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
6 * SPDX-License-Identifier: Apache-2.0
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>
25 u8 addrs[256]; /* print up to 64 IPv4 or 16 IPv6 addresses */
28 /* packet trace format function */
30 format_vrrp_trace (u8 * s, va_list * args)
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 *);
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: ");
42 for (i = 0; i < t->vrrp.n_addrs; i++)
45 s = format (s, "%U ", format_ip6_address,
46 (ip6_address_t *) (t->addrs + i * 16));
48 s = format (s, "%U ", format_ip4_address,
49 (ip4_address_t *) (t->addrs + i * 4));
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;
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")
71 #define _(sym,str) VRRP_ERROR_##sym,
77 static char *vrrp_error_strings[] = {
78 #define _(sym,string) string,
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
95 vrrp_vr_addr_cmp (vrrp_vr_t *vr, ip46_address_t *peer_addr)
97 vrrp_vr_config_t *vrc = &vr->config;
98 void *peer_addr_bytes, *local_addr;
102 clib_memset (&addr, 0, sizeof (addr));
104 if (vrrp_vr_is_ipv6 (vr))
106 peer_addr_bytes = &peer_addr->ip6;
107 local_addr = &addr.ip6;
109 ip6_address_copy (local_addr,
110 ip6_get_link_local_address (vrc->sw_if_index));
114 peer_addr_bytes = &peer_addr->ip4;
115 local_addr = &addr.ip4;
117 fib_sas4_get (vrc->sw_if_index, NULL, local_addr);
120 return memcmp (local_addr, peer_addr_bytes, addr_size);
124 vrrp_input_process_master (vrrp_vr_t *vr, vrrp_input_process_args_t *args)
126 /* received priority 0, another VR is shutting down. send an adv and
127 * remain in the master state
129 if (args->priority == 0)
131 clib_warning ("Received shutdown message from a peer on VR %U",
132 format_vrrp_vr_key, vr);
133 vrrp_incr_stat_counter (VRRP_STAT_COUNTER_PRIO0_RCVD, vr->stat_index);
134 vrrp_adv_send (vr, 0);
135 vrrp_vr_timer_set (vr, VRRP_VR_TIMER_ADV);
140 * - received priority > adjusted priority, or
141 * - received priority == adjusted priority and peer addr > local addr
142 * allow the local VR to be preempted by the peer
144 if ((args->priority > vrrp_vr_priority (vr)) ||
145 ((args->priority == vrrp_vr_priority (vr)) &&
146 (vrrp_vr_addr_cmp (vr, &args->src_addr) < 0)))
148 vrrp_vr_transition (vr, VRRP_VR_STATE_BACKUP, args);
153 /* if we made it this far, eiher received prority < adjusted priority or
154 * received == adjusted and local addr > peer addr. Ignore.
159 /* RFC 5798 section 6.4.2 */
161 vrrp_input_process_backup (vrrp_vr_t *vr, vrrp_input_process_args_t *args)
163 vrrp_vr_config_t *vrc = &vr->config;
164 vrrp_vr_runtime_t *vrt = &vr->runtime;
166 /* master shutting down, ready for election */
167 if (args->priority == 0)
169 clib_warning ("Master for VR %U is shutting down", format_vrrp_vr_key,
171 vrrp_incr_stat_counter (VRRP_STAT_COUNTER_PRIO0_RCVD, vr->stat_index);
172 vrt->master_down_int = vrt->skew;
173 vrrp_vr_timer_set (vr, VRRP_VR_TIMER_MASTER_DOWN);
177 /* no preempt set or adv from a higher priority router, update timers */
178 if (!(vrc->flags & VRRP_VR_PREEMPT) ||
179 (args->priority >= vrrp_vr_priority (vr)))
181 vrt->master_adv_int = args->max_adv_int;
183 vrrp_vr_skew_compute (vr);
184 vrrp_vr_master_down_compute (vr);
185 vrrp_vr_timer_set (vr, VRRP_VR_TIMER_MASTER_DOWN);
189 /* preempt set or our priority > received, continue to wait on master down */
194 vrrp_input_process (vrrp_input_process_args_t * args)
198 vr = vrrp_vr_lookup_index (args->vr_index);
202 clib_warning ("Error retrieving VR with index %u", args->vr_index);
206 vrrp_incr_stat_counter (VRRP_STAT_COUNTER_ADV_RCVD, vr->stat_index);
208 switch (vr->runtime.state)
210 case VRRP_VR_STATE_INIT:
212 case VRRP_VR_STATE_BACKUP:
213 /* this is usually the only state an advertisement should be received */
214 vrrp_input_process_backup (vr, args);
216 case VRRP_VR_STATE_MASTER:
217 /* might be getting preempted. or have a misbehaving peer */
218 clib_warning ("Received advertisement for master VR %U",
219 format_vrrp_vr_key, vr);
220 vrrp_input_process_master (vr, args);
223 clib_warning ("Received advertisement for VR %U in unknown state %d",
224 format_vrrp_vr_key, vr, vr->runtime.state);
237 } vrrp_arp_nd_trace_t;
241 format_vrrp_arp_nd_input_trace (u8 * s, va_list * va)
243 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
244 CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
245 vrrp_arp_nd_trace_t *t = va_arg (*va, vrrp_arp_nd_trace_t *);
247 s = format (s, "address %U",
248 (t->is_ipv6) ? format_ip6_address : format_ip4_address,
249 (t->is_ipv6) ? (void *) &t->ip.ip6 : (void *) &t->ip.ip4);
251 if (t->vr_index != ~0)
252 s = format (s, ": vr_index %u vr_id %u", t->vr_index, t->vr_id);
259 VRRP_ARP_INPUT_NEXT_DROP,
260 VRRP_ARP_INPUT_NEXT_REPLY_TX,
266 VRRP_ND_INPUT_NEXT_DROP,
267 VRRP_ND_INPUT_NEXT_REPLY_TX,
271 static_always_inline void
272 vrrp_arp_nd_next (vlib_buffer_t * b, u32 * next_index, u32 * vr_index,
275 vnet_main_t *vnm = vnet_get_main ();
276 vlib_main_t *vm = vlib_get_main ();
277 ethernet_header_t *eth, *eth_new;
278 void *lookup_addr = 0;
281 vnet_link_t link_type;
282 u8 *rewrite, rewrite_len;
285 ip6_header_t *ip6 = 0;
286 icmp6_neighbor_solicitation_or_advertisement_header_t *sol_adv = 0;
287 icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *lladdr = 0;
289 ethernet_arp_header_t *arp;
290 ip4_address_t ip4_addr;
294 ip6 = vlib_buffer_get_current (b);
296 /* we only care about about ICMP6 neighbor solicitiations */
297 if (ip6->protocol != IP_PROTOCOL_ICMP6)
300 sol_adv = ip6_next_header (ip6);
301 lladdr = (void *) (sol_adv + 1);
303 /* skip anything other than neighbor solicitations */
304 if (sol_adv->icmp.type != ICMP6_neighbor_solicitation)
307 lookup_addr = &sol_adv->target_address;
308 link_type = VNET_LINK_IP6;
312 arp = vlib_buffer_get_current (b);
314 /* skip non-request packets */
315 if (arp->opcode != clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_request))
318 lookup_addr = &arp->ip4_over_ethernet[1].ip4;
319 link_type = VNET_LINK_ARP;
322 sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
324 /* Don't bother with a hash lookup if no VRs configured on this interface */
325 if (!vrrp_intf_num_vrs (sw_if_index, is_ipv6))
328 /* skip requests that are not for VRRP addresses */
329 *vr_index = vrrp_vr_lookup_address (sw_if_index, is_ipv6, lookup_addr);
333 vr = vrrp_vr_lookup_index (*vr_index);
334 if (!vr || vr->runtime.state != VRRP_VR_STATE_MASTER)
336 /* RFC 5798 - section 6.4.2 - Backup "MUST NOT respond" to ARP/ND.
337 * So we must drop the request rather than allowing it to continue
338 * on the feature arc.
340 *next_index = VRRP_ARP_INPUT_NEXT_DROP;
344 /* RFC 5798 section 6.4.3: Master "MUST respond" to ARP/ND. */
345 eth = ethernet_buffer_get_header (b);
346 rewrite = ethernet_build_rewrite (vnm, sw_if_index, link_type,
348 rewrite_len = vec_len (rewrite);
349 if (rewrite_len == 0)
352 /* send the reply out the incoming interface */
353 *next_index = VRRP_ARP_INPUT_NEXT_REPLY_TX;
354 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
356 /* the outbound ethernet & vlan headers may have a different length than
357 * the received header, so get a pointer to the new start of the packet
358 * and write the header there.
360 vlib_buffer_advance (b, -rewrite_len);
361 eth_new = vlib_buffer_get_current (b);
362 clib_memcpy_fast (eth_new, rewrite, rewrite_len);
367 if (ip6_address_is_unspecified (&ip6->src_address))
368 ip6_set_reserved_multicast_address (&ip6->dst_address,
369 IP6_MULTICAST_SCOPE_link_local,
370 IP6_MULTICAST_GROUP_ID_all_hosts);
372 ip6->dst_address = ip6->src_address;
374 ip6->src_address = sol_adv->target_address;
375 ip6->hop_limit = 255;
376 sol_adv->icmp.type = ICMP6_neighbor_advertisement;
377 sol_adv->icmp.checksum = 0;
378 sol_adv->advertisement_flags =
379 clib_host_to_net_u32 (ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER
380 | ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED
381 | ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE);
383 clib_memcpy (lladdr->ethernet_address, vr->runtime.mac.bytes,
384 sizeof (mac_address_t));
385 lladdr->header.type =
386 ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
388 sol_adv->icmp.checksum =
389 ip6_tcp_udp_icmp_compute_checksum (vm, b, ip6, &bogus_length);
394 ip4_addr = arp->ip4_over_ethernet[1].ip4;
396 arp->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
397 arp->ip4_over_ethernet[1] = arp->ip4_over_ethernet[0];
399 arp->ip4_over_ethernet[0].mac = vr->runtime.mac;
400 arp->ip4_over_ethernet[0].ip4 = ip4_addr;
404 static_always_inline uword
405 vrrp_arp_nd_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
406 vlib_frame_t * frame, u8 is_ipv6)
408 u32 n_left_from, *from, next_index, *to_next;
410 from = vlib_frame_vector_args (frame);
411 n_left_from = frame->n_vectors;
412 next_index = node->cached_next_index;
414 while (n_left_from > 0)
418 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
420 while (n_left_from > 0 && n_left_to_next > 0)
435 b0 = vlib_get_buffer (vm, bi0);
437 vnet_feature_next (&next0, b0);
438 vrrp_arp_nd_next (b0, &next0, &vr_index, is_ipv6);
440 if (b0->flags & VLIB_BUFFER_IS_TRACED)
442 vrrp_arp_nd_trace_t *t =
443 vlib_add_trace (vm, node, b0, sizeof (*t));
449 icmp6_neighbor_solicitation_or_advertisement_header_t
452 ip0 = vlib_buffer_get_current (b0);
453 sol_adv0 = ip6_next_header (ip0);
454 t->ip.ip6 = sol_adv0->target_address;
458 ethernet_arp_header_t *arp0;
460 arp0 = vlib_buffer_get_current (b0);
461 t->ip.ip4 = arp0->ip4_over_ethernet[0].ip4;
464 vr = vrrp_vr_lookup_index (vr_index);
466 t->vr_id = vr->config.vr_id;
468 t->vr_index = vr_index;
469 t->is_ipv6 = is_ipv6;
472 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
473 n_left_to_next, bi0, next0);
476 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
479 return frame->n_vectors;
482 VLIB_NODE_FN (vrrp4_arp_input_node) (vlib_main_t * vm,
483 vlib_node_runtime_t * node,
484 vlib_frame_t * frame)
486 return vrrp_arp_nd_input_inline (vm, node, frame, 0 /* is_ipv6 */ );
490 VLIB_REGISTER_NODE (vrrp4_arp_input_node) =
492 .name = "vrrp4-arp-input",
493 .vector_size = sizeof (u32),
494 .format_trace = format_vrrp_arp_nd_input_trace,
495 .type = VLIB_NODE_TYPE_INTERNAL,
497 .n_errors = ARRAY_LEN(vrrp_error_strings),
498 .error_strings = vrrp_error_strings,
500 .n_next_nodes = VRRP_ARP_N_NEXT,
503 [VRRP_ARP_INPUT_NEXT_DROP] = "error-drop",
504 [VRRP_ARP_INPUT_NEXT_REPLY_TX] = "interface-output",
508 VNET_FEATURE_INIT (vrrp4_arp_feat_node, static) =
511 .node_name = "vrrp4-arp-input",
512 .runs_before = VNET_FEATURES ("arp-reply"),
515 VLIB_NODE_FN (vrrp6_nd_input_node) (vlib_main_t * vm,
516 vlib_node_runtime_t * node,
517 vlib_frame_t * frame)
519 return vrrp_arp_nd_input_inline (vm, node, frame, 1 /* is_ipv6 */);
523 VLIB_REGISTER_NODE (vrrp6_nd_input_node) =
525 .name = "vrrp6-nd-input",
526 .vector_size = sizeof (u32),
527 .format_trace = format_vrrp_arp_nd_input_trace,
528 .type = VLIB_NODE_TYPE_INTERNAL,
530 .n_errors = ARRAY_LEN(vrrp_error_strings),
531 .error_strings = vrrp_error_strings,
533 .n_next_nodes = VRRP_ND_N_NEXT,
536 [VRRP_ND_INPUT_NEXT_DROP] = "error-drop",
537 [VRRP_ND_INPUT_NEXT_REPLY_TX] = "interface-output",
541 VNET_FEATURE_INIT (vrrp6_nd_feat_node, static) =
543 .arc_name = "ip6-local",
544 .node_name = "vrrp6-nd-input",
545 .runs_before = VNET_FEATURES ("ip6-local-end-of-arc"),
548 static_always_inline uword
549 vrrp_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
550 vlib_frame_t * frame, u8 is_ipv6)
552 u32 n_left_from, *from;
553 vrrp_main_t *vmp = &vrrp_main;
555 from = vlib_frame_vector_args (frame);
556 n_left_from = frame->n_vectors;
558 while (n_left_from > 0)
564 vrrp_header_t *vrrp0;
566 vrrp_input_process_args_t args0;
573 b0 = vlib_get_buffer (vm, bi0);
575 ip0 = vlib_buffer_get_current (b0);
579 ip6_header_t *ip6 = ip0;
581 vrrp0 = (vrrp_header_t *) (ip6 + 1);
582 ttl0 = &ip6->hop_limit;
584 payload_len0 = clib_net_to_host_u16 (ip6->payload_length);
585 vlib_buffer_advance (b0, sizeof (*ip6));
586 clib_memcpy_fast (&args0.src_addr.ip6, &ip6->src_address, addr_len);
590 ip4_header_t *ip4 = ip0;
592 vrrp0 = (vrrp_header_t *) (ip4 + 1);
595 payload_len0 = clib_net_to_host_u16 (ip4->length) - sizeof(*ip4);
596 vlib_buffer_advance (b0, sizeof (*ip4));
597 clib_memcpy_fast (&args0.src_addr.ip4, &ip4->src_address, addr_len);
600 next0 = VRRP_INPUT_NEXT_DROP;
602 error0 = VRRP_ERROR_RECEIVED;
604 /* Validation from RFC 5798 sec 7.1 */
606 /* checksum set to 0 for calculation, save original value */
607 rx_csum0 = vrrp0->checksum;
610 /* Mandatory - TTL/hop limit must be 255 */
613 error0 = VRRP_ERROR_BAD_TTL;
614 vrrp_incr_err_counter (VRRP_ERR_COUNTER_TTL);
618 /* Mandatory - VRRP version must be 3 */
619 if ((vrrp0->vrrp_version_and_type >> 4) != 3)
621 error0 = VRRP_ERROR_NOT_VERSION_3;
622 vrrp_incr_err_counter (VRRP_ERR_COUNTER_VERSION);
626 /* Mandatory - packet must be complete */
627 if (b0->current_length < sizeof (*vrrp0) +
628 ((u32) vrrp0->n_addrs) * addr_len)
630 error0 = VRRP_ERROR_INCOMPLETE_PKT;
631 vrrp_incr_err_counter (VRRP_ERR_COUNTER_PKT_LEN);
635 /* Mandatory - checksum must be correct */
636 if (rx_csum0 != vrrp_adv_csum (ip0, vrrp0, is_ipv6, payload_len0))
638 error0 = VRRP_ERROR_BAD_CHECKSUM;
639 vrrp_incr_err_counter (VRRP_ERR_COUNTER_CHKSUM);
643 /* Mandatory - VR must be configured on the interface adv received on */
645 vrrp_vr_lookup (vnet_buffer(b0)->sw_if_index[VLIB_RX],
646 vrrp0->vr_id, is_ipv6)))
648 error0 = VRRP_ERROR_UNKNOWN_VR;
649 vrrp_incr_err_counter (VRRP_ERR_COUNTER_VRID);
653 /* Optional - count of addresses should match configuration */
654 /* Could also check that addresses match, but likely to be O(n^2) */
655 if (vrrp0->n_addrs != vec_len (vr0->config.vr_addrs))
657 error0 = VRRP_ERROR_ADDR_MISMATCH;
658 vrrp_incr_err_counter (VRRP_ERR_COUNTER_ADDR_LIST);
662 /* signal main thread to process contents of packet */
663 args0.vr_index = vr0 - vmp->vrs;
664 args0.priority = vrrp0->priority;
665 args0.max_adv_int = vrrp_adv_int_from_packet (vrrp0);
667 vl_api_rpc_call_main_thread (vrrp_input_process, (u8 *) &args0,
671 vrrp0->checksum = rx_csum0; /* restore csum for correct trace output */
672 b0->error = node->errors[error0];
674 if (b0->flags & VLIB_BUFFER_IS_TRACED)
676 vrrp_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
677 size_t addr_len = (is_ipv6 ? 16 : 4);
679 t->sw_if_index = vnet_buffer(b0)->sw_if_index[VLIB_RX];
680 t->is_ipv6 = is_ipv6;
681 clib_memcpy_fast (&t->vrrp, vrrp0, sizeof (*vrrp0));
682 clib_memcpy_fast (t->addrs, (void *) (vrrp0 + 1),
683 (size_t) vrrp0->n_addrs * addr_len);
686 /* always drop, never forward or reply here */
687 vlib_set_next_frame_buffer (vm, node, next0, bi0);
693 return frame->n_vectors;
696 VLIB_NODE_FN (vrrp4_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
697 vlib_frame_t * frame)
699 return vrrp_input_inline (vm, node, frame, 0);
703 VLIB_REGISTER_NODE (vrrp4_input_node) =
705 .name = "vrrp4-input",
706 .vector_size = sizeof (u32),
707 .format_trace = format_vrrp_trace,
708 .type = VLIB_NODE_TYPE_INTERNAL,
710 .n_errors = ARRAY_LEN(vrrp_error_strings),
711 .error_strings = vrrp_error_strings,
713 .n_next_nodes = VRRP_INPUT_N_NEXT,
716 [VRRP_INPUT_NEXT_DROP] = "error-drop",
720 VLIB_NODE_FN (vrrp6_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
721 vlib_frame_t * frame)
723 return vrrp_input_inline (vm, node, frame, 1);
726 VLIB_REGISTER_NODE (vrrp6_input_node) =
728 .name = "vrrp6-input",
729 .vector_size = sizeof (u32),
730 .format_trace = format_vrrp_trace,
731 .type = VLIB_NODE_TYPE_INTERNAL,
733 .n_errors = ARRAY_LEN(vrrp_error_strings),
734 .error_strings = vrrp_error_strings,
736 .n_next_nodes = VRRP_INPUT_N_NEXT,
739 [VRRP_INPUT_NEXT_DROP] = "error-drop",
747 ip46_address_t src, dst;
748 } vrrp_accept_owner_trace_t;
750 /* packet trace format function */
752 format_vrrp_accept_owner_trace (u8 * s, va_list * args)
754 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
755 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
756 vrrp_accept_owner_trace_t *t = va_arg (*args, vrrp_accept_owner_trace_t *);
757 int ip_ver = 4, ip_type = IP46_TYPE_IP4;
762 ip_type = IP46_TYPE_IP6;
765 s = format (s, "IPv%d sw_if_index %d %U -> %U",
766 ip_ver, t->sw_if_index,
767 format_ip46_address, &t->src, ip_type,
768 format_ip46_address, &t->dst, ip_type);
773 #define foreach_vrrp_accept_owner_error \
774 _(RECEIVED, "VRRP owner accept packets received") \
775 _(PROCESSED, "VRRP owner accept advertisements processed")
779 #define _(sym,str) VRRP_ACCEPT_OWNER_ERROR_##sym,
780 foreach_vrrp_accept_owner_error
782 VRRP_ACCEPT_OWNER_N_ERROR,
783 } vrrp_accept_owner_error_t;
785 static char *vrrp_accept_owner_error_strings[] = {
786 #define _(sym,string) string,
787 foreach_vrrp_accept_owner_error
793 VRRP_ACCEPT_OWNER_NEXT_PROCESS,
794 VRRP_ACCEPT_OWNER_N_NEXT,
795 } vrrp_accept_owner_next_t;
797 static_always_inline void
798 vrrp_accept_owner_next_node (u32 sw_if_index, u8 vr_id, u8 is_ipv6,
799 u32 *next_index, u32 *error)
801 vrrp_vr_t *vr = vrrp_vr_lookup (sw_if_index, vr_id, is_ipv6);
803 if (vr && (vr->runtime.state == VRRP_VR_STATE_MASTER) &&
804 (vr->config.flags & VRRP_VR_ACCEPT))
806 *next_index = VRRP_ACCEPT_OWNER_NEXT_PROCESS;
807 *error = VRRP_ACCEPT_OWNER_ERROR_PROCESSED;
811 static_always_inline uword
812 vrrp_accept_owner_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
813 vlib_frame_t * frame, u8 is_ipv6)
815 u32 n_left_from, *from, *to_next;
816 u32 next_index = node->cached_next_index;
818 from = vlib_frame_vector_args (frame);
819 n_left_from = frame->n_vectors;
821 while (n_left_from > 0)
825 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
827 while (n_left_from >= 2 && n_left_to_next >= 2)
830 vlib_buffer_t *b0, *b1;
833 vrrp_header_t *vrrp0, *vrrp1;
834 ip4_header_t *ip40, *ip41;
835 ip6_header_t *ip60, *ip61;
836 u32 sw_if_index0, sw_if_index1;
844 b0 = vlib_get_buffer (vm, bi0);
845 b1 = vlib_get_buffer (vm, bi1);
847 /* most packets will follow feature arc */
848 vnet_feature_next (&next0, b0);
849 vnet_feature_next (&next1, b1);
851 error0 = error1 = VRRP_ACCEPT_OWNER_ERROR_RECEIVED;
853 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
854 sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
856 /* find VRRP advertisements which should be sent to VRRP node */
859 ip60 = vlib_buffer_get_current (b0);
860 ip61 = vlib_buffer_get_current (b1);
862 if (PREDICT_FALSE (ip60->protocol == IP_PROTOCOL_VRRP))
864 vrrp0 = (vrrp_header_t *) (ip60 + 1);
865 vrrp_accept_owner_next_node (sw_if_index0, vrrp0->vr_id,
866 is_ipv6, &next0, &error0);
868 if (PREDICT_FALSE (ip61->protocol == IP_PROTOCOL_VRRP))
870 vrrp1 = (vrrp_header_t *) (ip61 + 1);
871 vrrp_accept_owner_next_node (sw_if_index1, vrrp1->vr_id,
872 is_ipv6, &next1, &error1);
877 ip40 = vlib_buffer_get_current (b0);
878 ip41 = vlib_buffer_get_current (b1);
880 if (PREDICT_FALSE (ip40->protocol == IP_PROTOCOL_VRRP))
882 vrrp0 = (vrrp_header_t *) (ip40 + 1);
883 vrrp_accept_owner_next_node (sw_if_index0, vrrp0->vr_id,
884 is_ipv6, &next0, &error0);
886 if (PREDICT_FALSE (ip41->protocol == IP_PROTOCOL_VRRP))
888 vrrp1 = (vrrp_header_t *) (ip41 + 1);
889 vrrp_accept_owner_next_node (sw_if_index1, vrrp1->vr_id,
890 is_ipv6, &next1, &error1);
894 b0->error = node->errors[error0];
895 b1->error = node->errors[error1];
897 if (b0->flags & VLIB_BUFFER_IS_TRACED)
899 vrrp_accept_owner_trace_t *t =
900 vlib_add_trace (vm, node, b0, sizeof (*t));
902 t->sw_if_index = sw_if_index0;
903 t->is_ipv6 = is_ipv6;
906 ip6_address_copy (&t->src.ip6, &ip60->src_address);
907 ip6_address_copy (&t->dst.ip6, &ip60->dst_address);
911 t->src.ip4.as_u32 = ip40->src_address.as_u32;
912 t->dst.ip4.as_u32 = ip40->dst_address.as_u32;
916 if (b1->flags & VLIB_BUFFER_IS_TRACED)
918 vrrp_accept_owner_trace_t *t =
919 vlib_add_trace (vm, node, b1, sizeof (*t));
921 t->sw_if_index = sw_if_index1;
922 t->is_ipv6 = is_ipv6;
925 ip6_address_copy (&t->src.ip6, &ip61->src_address);
926 ip6_address_copy (&t->dst.ip6, &ip61->dst_address);
930 t->src.ip4.as_u32 = ip41->src_address.as_u32;
931 t->dst.ip4.as_u32 = ip41->dst_address.as_u32;
940 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
941 to_next, n_left_to_next,
942 bi0, bi1, next0, next1);
945 while (n_left_from > 0 && n_left_to_next > 0)
951 vrrp_header_t *vrrp0;
959 b0 = vlib_get_buffer (vm, bi0);
961 /* most packets will follow feature arc */
962 vnet_feature_next (&next0, b0);
964 error0 = VRRP_ACCEPT_OWNER_ERROR_RECEIVED;
966 sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
968 /* find VRRP advertisements which should be sent to VRRP node */
971 ip6 = vlib_buffer_get_current (b0);
973 if (PREDICT_FALSE (ip6->protocol == IP_PROTOCOL_VRRP))
975 vrrp0 = (vrrp_header_t *) (ip6 + 1);
976 vrrp_accept_owner_next_node (sw_if_index0, vrrp0->vr_id,
977 is_ipv6, &next0, &error0);
982 ip4 = vlib_buffer_get_current (b0);
984 if (PREDICT_FALSE (ip4->protocol == IP_PROTOCOL_VRRP))
986 vrrp0 = (vrrp_header_t *) (ip4 + 1);
987 vrrp_accept_owner_next_node (sw_if_index0, vrrp0->vr_id,
988 is_ipv6, &next0, &error0);
992 b0->error = node->errors[error0];
994 if (b0->flags & VLIB_BUFFER_IS_TRACED)
996 vrrp_accept_owner_trace_t *t =
997 vlib_add_trace (vm, node, b0, sizeof (*t));
999 t->sw_if_index = sw_if_index0;
1000 t->is_ipv6 = is_ipv6;
1003 ip6_address_copy (&t->src.ip6, &ip6->src_address);
1004 ip6_address_copy (&t->dst.ip6, &ip6->dst_address);
1008 t->src.ip4.as_u32 = ip4->src_address.as_u32;
1009 t->dst.ip4.as_u32 = ip4->dst_address.as_u32;
1016 n_left_to_next -= 1;
1018 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1019 to_next, n_left_to_next,
1023 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1026 return frame->n_vectors;
1029 VLIB_NODE_FN (vrrp4_accept_owner_input_node) (vlib_main_t * vm,
1030 vlib_node_runtime_t * node,
1031 vlib_frame_t * frame)
1033 return vrrp_accept_owner_input_inline (vm, node, frame, 0);
1036 VLIB_REGISTER_NODE (vrrp4_accept_owner_input_node) =
1038 .name = "vrrp4-accept-owner-input",
1039 .vector_size = sizeof (u32),
1040 .format_trace = format_vrrp_accept_owner_trace,
1041 .type = VLIB_NODE_TYPE_INTERNAL,
1043 .n_errors = ARRAY_LEN(vrrp_accept_owner_error_strings),
1044 .error_strings = vrrp_accept_owner_error_strings,
1046 .n_next_nodes = VRRP_ACCEPT_OWNER_N_NEXT,
1049 [VRRP_ACCEPT_OWNER_NEXT_PROCESS] = "vrrp4-input",
1053 VNET_FEATURE_INIT (vrrp4_accept_owner_mc, static) =
1055 .arc_name = "ip4-multicast",
1056 .node_name = "vrrp4-accept-owner-input",
1057 .runs_before = VNET_FEATURES ("ip4-mfib-forward-lookup"),
1060 VLIB_NODE_FN (vrrp6_accept_owner_input_node) (vlib_main_t * vm,
1061 vlib_node_runtime_t * node,
1062 vlib_frame_t * frame)
1064 return vrrp_accept_owner_input_inline (vm, node, frame, 1);
1067 VLIB_REGISTER_NODE (vrrp6_accept_owner_input_node) =
1069 .name = "vrrp6-accept-owner-input",
1070 .vector_size = sizeof (u32),
1071 .format_trace = format_vrrp_accept_owner_trace,
1072 .type = VLIB_NODE_TYPE_INTERNAL,
1074 .n_errors = ARRAY_LEN(vrrp_accept_owner_error_strings),
1075 .error_strings = vrrp_accept_owner_error_strings,
1077 .n_next_nodes = VRRP_ACCEPT_OWNER_N_NEXT,
1080 [VRRP_ACCEPT_OWNER_NEXT_PROCESS] = "vrrp6-input",
1084 VNET_FEATURE_INIT (vrrp6_accept_owner_mc, static) =
1086 .arc_name = "ip6-multicast",
1087 .node_name = "vrrp6-accept-owner-input",
1088 .runs_before = VNET_FEATURES ("ip6-mfib-forward-lookup"),
1091 static clib_error_t *
1092 vrrp_input_init (vlib_main_t *vm)
1094 clib_error_t *error;
1096 if ((error = vlib_call_init_function (vm, vrrp_init)))
1099 ip4_register_protocol (IP_PROTOCOL_VRRP, vrrp4_input_node.index);
1100 ip6_register_protocol (IP_PROTOCOL_VRRP, vrrp6_input_node.index);
1105 VLIB_INIT_FUNCTION (vrrp_input_init);
1110 * fd.io coding-style-patch-verification: ON
1113 * eval: (c-set-style "gnu")