FD.io VPP  v20.09-64-g4f7b92f0a
Vector Packet Processing
node.c
Go to the documentation of this file.
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>
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 {
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 
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,
73 #undef _
75 } vrrp_error_t;
76 
77 static char *vrrp_error_strings[] = {
78 #define _(sym,string) string,
80 #undef _
81 };
82 
83 typedef enum
84 {
87 } vrrp_next_t;
88 
90 {
92  vrrp_header_t *pkt;
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,
117  }
118  else
119  {
120  peer_addr = &(((ip4_header_t *) pkt) - 1)->src_address;
121  local_addr = &addr.ip4;
122  addr_size = 4;
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);
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;
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 
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
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;
242 
243 
244 static u8 *
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",
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 {
267 
268 typedef enum
269 {
274 
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;
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 */
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  {
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
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 
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  {
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 
489 {
490  return vrrp_arp_nd_input_inline (vm, node, frame, 0 /* is_ipv6 */ );
491 }
492 
493 /* *INDENT-OFF* */
495 {
496  .name = "vrrp4-arp-input",
497  .vector_size = sizeof (u32),
498  .format_trace = format_vrrp_arp_nd_input_trace,
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 
522 {
523  return vrrp_arp_nd_input_inline (vm, node, frame, 1 /* is_ipv6 */);
524 }
525 
526 /* *INDENT-OFF* */
528 {
529  .name = "vrrp6-nd-input",
530  .vector_size = sizeof (u32),
531  .format_trace = format_vrrp_arp_nd_input_trace,
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 
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;
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 =
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 
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 
693 {
694  return vrrp_input_inline (vm, node, frame, 0);
695 }
696 
697 /* *INDENT-OFF* */
699 {
700  .name = "vrrp4-input",
701  .vector_size = sizeof (u32),
702  .format_trace = format_vrrp_trace,
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 
717 {
718  return vrrp_input_inline (vm, node, frame, 1);
719 }
720 
722 {
723  .name = "vrrp6-input",
724  .vector_size = sizeof (u32),
725  .format_trace = format_vrrp_trace,
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 {
742  ip46_address_t src, dst;
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 *);
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,
776 #undef _
779 
781 #define _(sym,string) string,
783 #undef _
784 };
785 
786 typedef enum
787 {
791 
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 
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  {
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  {
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  {
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 
1026  vlib_frame_t * frame)
1027 {
1028  return vrrp_accept_owner_input_inline (vm, node, frame, 0);
1029 }
1030 
1032 {
1033  .name = "vrrp4-accept-owner-input",
1034  .vector_size = sizeof (u32),
1035  .format_trace = format_vrrp_accept_owner_trace,
1037 
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 
1057  vlib_frame_t * frame)
1058 {
1059  return vrrp_accept_owner_input_inline (vm, node, frame, 1);
1060 }
1061 
1063 {
1064  .name = "vrrp6-accept-owner-input",
1065  .vector_size = sizeof (u32),
1066  .format_trace = format_vrrp_accept_owner_trace,
1068 
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 *
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 
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  */
#define ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:124
static void vrrp_input_process_master(vrrp_vr_t *vr, vrrp_header_t *pkt)
Definition: node.c:131
vrrp_error_t
Definition: node.c:69
static vlib_cli_command_t trace
(constructor) VLIB_CLI_COMMAND (trace)
Definition: vlib_api_cli.c:899
vlib_node_registration_t vrrp6_nd_input_node
(constructor) VLIB_REGISTER_NODE (vrrp6_nd_input_node)
Definition: node.c:527
#define CLIB_UNUSED(x)
Definition: clib.h:87
u32 sw_if_index
Definition: vrrp.h:71
vlib_node_registration_t vrrp4_arp_input_node
(constructor) VLIB_REGISTER_NODE (vrrp4_arp_input_node)
Definition: node.c:494
void ip6_register_protocol(u32 protocol, u32 node_index)
Definition: ip6_forward.c:1664
static clib_error_t * vrrp_init(vlib_main_t *vm)
Definition: vrrp.c:1219
ip4_address_t src_address
Definition: ip4_packet.h:125
static void vlib_set_next_frame_buffer(vlib_main_t *vm, vlib_node_runtime_t *node, u32 next_index, u32 buffer_index)
Definition: node_funcs.h:424
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
Definition: vrrp.h:106
vrrp_arp_next_t
Definition: node.c:261
#define clib_memcpy_fast(a, b, c)
Definition: string.h:81
#define ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
u8 src_address[6]
Definition: packet.h:56
vlib_node_registration_t vrrp6_accept_owner_input_node
(constructor) VLIB_REGISTER_NODE (vrrp6_accept_owner_input_node)
Definition: node.c:1062
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:113
u8 vr_id
Definition: vrrp.api:17
static int vrrp_vr_addr_cmp(vrrp_vr_t *vr, vrrp_header_t *pkt)
Definition: node.c:101
vrrp_vr_t * vrs
Definition: vrrp.h:151
ip_lookup_main_t lookup_main
Definition: ip4.h:108
vlib_main_t * vm
Definition: in2out_ed.c:1582
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
vrrp_vr_state_t state
Definition: vrrp.h:96
#define VLIB_NODE_FN(node)
Definition: node.h:202
struct vrrp_input_process_args vrrp_input_process_args_t
void ip4_register_protocol(u32 protocol, u32 node_index)
Definition: ip4_forward.c:1933
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:469
vhost_vring_addr_t addr
Definition: vhost_user.h:111
ip6_address_t src_address
Definition: ip6_packet.h:310
unsigned char u8
Definition: types.h:56
static vrrp_vr_t * vrrp_vr_lookup_index(u32 vr_index)
Definition: vrrp.h:250
vrrp_accept_owner_next_t
Definition: node.c:786
#define clib_memcpy(d, s, n)
Definition: string.h:180
static_always_inline uword vrrp_accept_owner_input_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, u8 is_ipv6)
Definition: node.c:807
format_function_t format_ip4_address
Definition: format.h:73
u16 master_adv_int
Definition: vrrp.h:97
#define static_always_inline
Definition: clib.h:108
ethernet_arp_ip4_over_ethernet_address_t ip4_over_ethernet[2]
Definition: arp_packet.h:142
vrrp_accept_owner_error_t
Definition: node.c:772
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
ip46_address_t src
Definition: node.c:742
vl_api_ip6_address_t ip6
Definition: one.api:424
#define ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE
ip4_address_t dst_address
Definition: ip4_packet.h:125
vrrp_vr_config_t config
Definition: vrrp.h:108
void vl_api_rpc_call_main_thread(void *fp, u8 *data, u32 data_length)
Definition: vlib_api.c:619
static void vrrp_input_process_backup(vrrp_vr_t *vr, vrrp_header_t *pkt)
Definition: node.c:167
vlib_node_registration_t vrrp4_accept_owner_input_node
(constructor) VLIB_REGISTER_NODE (vrrp4_accept_owner_input_node)
Definition: node.c:1031
unsigned int u32
Definition: types.h:88
u16 skew
Definition: vrrp.h:98
#define vlib_call_init_function(vm, x)
Definition: init.h:270
ip46_address_t ip
Definition: node.c:237
u16 master_down_int
Definition: vrrp.h:99
u16 vrrp_adv_csum(void *l3_hdr, void *payload, u8 is_ipv6, u16 len)
Definition: vrrp_packet.c:143
u8 is_ipv6
Definition: node.c:23
mac_address_t mac
Definition: vrrp.h:100
u8 * format_vrrp_packet_hdr(u8 *s, va_list *args)
Definition: vrrp_format.c:124
vl_api_fib_path_type_t type
Definition: fib_types.api:123
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
vlib_node_registration_t vrrp4_input_node
(constructor) VLIB_REGISTER_NODE (vrrp4_input_node)
Definition: node.c:698
static ethernet_header_t * ethernet_buffer_get_header(vlib_buffer_t *b)
Definition: ethernet.h:408
u8 * format_vrrp_vr_key(u8 *s, va_list *args)
Definition: vrrp_format.c:65
vrrp_vr_flags_t flags
Definition: vrrp.h:75
unsigned short u16
Definition: types.h:57
vrrp_header_t vrrp
Definition: node.c:24
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
u8 vr_id
Definition: vrrp.h:72
vrrp_nd_next_t
Definition: node.c:268
#define PREDICT_FALSE(x)
Definition: clib.h:120
#define always_inline
Definition: ipsec.h:28
vl_api_ip4_address_t ip4
Definition: one.api:376
vrrp_vr_runtime_t runtime
Definition: vrrp.h:109
static_always_inline uword vrrp_input_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, u8 is_ipv6)
Definition: node.c:553
static void vrrp_vr_master_down_compute(vrrp_vr_t *vr)
Definition: vrrp.h:222
vl_api_address_union_t src_address
Definition: ip_types.api:111
#define vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, next0, next1)
Finish enqueueing two buffers forward in the graph.
Definition: buffer_node.h:70
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:224
vl_api_address_t dst
Definition: gre.api:55
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:391
static char * vrrp_error_strings[]
Definition: node.c:77
static_always_inline void vrrp_accept_owner_next_node(u32 sw_if_index, u8 vr_id, u8 is_ipv6, u32 *next_index, u32 *error)
Definition: node.c:793
static u8 vrrp_vr_is_ipv6(vrrp_vr_t *vr)
Definition: vrrp.h:311
format_function_t format_ip46_address
Definition: ip46_address.h:50
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
u16 n_vectors
Definition: node.h:396
format_function_t format_ip6_address
Definition: format.h:91
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:380
static_always_inline void vnet_feature_next(u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:322
#define clib_warning(format, args...)
Definition: error.h:59
vlib_node_registration_t vrrp6_input_node
(constructor) VLIB_REGISTER_NODE (vrrp6_input_node)
Definition: node.c:721
#define foreach_vrrp_error
Definition: node.c:60
#define foreach_vrrp_accept_owner_error
Definition: node.c:768
#define ARRAY_LEN(x)
Definition: clib.h:67
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:483
static u8 vrrp_vr_priority(vrrp_vr_t *vr)
Definition: vrrp.h:355
static void * ip6_next_header(ip6_header_t *i)
Definition: ip6_packet.h:371
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1582
static void vrrp_input_process(vrrp_input_process_args_t *args)
Definition: node.c:200
vrrp_main_t vrrp_main
Definition: vrrp.c:25
u16 ip6_tcp_udp_icmp_compute_checksum(vlib_main_t *vm, vlib_buffer_t *p0, ip6_header_t *ip0, int *bogus_lengthp)
Definition: ip6_forward.c:1095
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:510
static u8 * format_vrrp_accept_owner_trace(u8 *s, va_list *args)
Definition: node.c:747
enum vnet_link_t_ vnet_link_t
Link Type: A description of the protocol of packets on the link.
int vrrp_adv_send(vrrp_vr_t *vr, int shutdown)
Definition: vrrp_packet.c:272
void vrrp_vr_timer_set(vrrp_vr_t *vr, vrrp_vr_timer_type_t type)
Definition: vrrp_periodic.c:89
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:248
#define VNET_FEATURES(...)
Definition: feature.h:470
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
u32 sw_if_index
Definition: node.c:22
struct _vlib_node_registration vlib_node_registration_t
Definition: defs.h:47
u16 payload_length
Definition: ip6_packet.h:301
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
static u8 * format_vrrp_trace(u8 *s, va_list *args)
Definition: node.c:30
static char * vrrp_accept_owner_error_strings[]
Definition: node.c:780
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1583
static u8 * format_vrrp_arp_nd_input_trace(u8 *s, va_list *va)
Definition: node.c:245
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:297
static int vrrp_intf_num_vrs(u32 sw_if_index, u8 is_ipv6)
Definition: vrrp.h:300
u8 * ethernet_build_rewrite(vnet_main_t *vnm, u32 sw_if_index, vnet_link_t link_type, const void *dst_address)
build a rewrite string to use for sending packets of type &#39;link_type&#39; to &#39;dst_address&#39; ...
Definition: interface.c:83
static vrrp_vr_t * vrrp_vr_lookup(u32 sw_if_index, u8 vr_id, u8 is_ipv6)
Definition: vrrp.h:230
static void ip6_address_copy(ip6_address_t *dst, const ip6_address_t *src)
Definition: ip6_packet.h:127
vrrp_header_t * pkt
Definition: node.c:92
static uword ip6_address_is_unspecified(const ip6_address_t *a)
Definition: ip6_packet.h:237
#define vnet_buffer(b)
Definition: buffer.h:417
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1144
static clib_error_t * vrrp_input_init(vlib_main_t *vm)
Definition: node.c:1087
ip46_address_t dst
Definition: node.c:742
static_always_inline uword vrrp_arp_nd_input_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, u8 is_ipv6)
Definition: node.c:409
ip46_address_t * vr_addrs
Definition: vrrp.h:76
void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace.c:577
bool is_ipv6
Definition: dhcp.api:202
static_always_inline void vrrp_arp_nd_next(vlib_buffer_t *b, u32 *next_index, u32 *vr_index, u8 is_ipv6)
Definition: node.c:276
static int ip4_src_address_for_packet(ip_lookup_main_t *lm, u32 sw_if_index, ip4_address_t *src)
Definition: ip4.h:217
static void vrrp_vr_skew_compute(vrrp_vr_t *vr)
Definition: vrrp.h:213
u8 addrs[256]
Definition: node.c:25
vrrp_next_t
Definition: node.c:83
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:33
Definition: defs.h:46
ip6_address_t dst_address
Definition: ip6_packet.h:310
static void ip6_set_reserved_multicast_address(ip6_address_t *a, ip6_multicast_address_scope_t scope, u16 id)
Definition: ip6_packet.h:134
VNET_FEATURE_INIT(lb_nat4_in2out_node_fn, static)
static u32 vrrp_vr_lookup_address(u32 sw_if_index, u8 is_ipv6, void *addr)
Definition: vrrp.h:261
void vrrp_vr_transition(vrrp_vr_t *vr, vrrp_vr_state_t new_state, void *data)
Definition: vrrp.c:282