FD.io VPP  v19.01.3-6-g70449b9b9
Vector Packet Processing
ip6_neighbor.c
Go to the documentation of this file.
1 /*
2  * ip/ip6_neighbor.c: IP6 neighbor handling
3  *
4  * Copyright (c) 2010 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <vnet/ip/ip.h>
19 #include <vnet/ip/ip6_neighbor.h>
20 #include <vnet/ethernet/ethernet.h>
21 #include <vppinfra/mhash.h>
22 #include <vnet/adj/adj.h>
23 #include <vnet/adj/adj_mcast.h>
24 #include <vnet/fib/fib_table.h>
25 #include <vnet/fib/ip6_fib.h>
26 #include <vnet/mfib/ip6_mfib.h>
27 #include <vnet/ip/ip6_ll_table.h>
28 #include <vnet/l2/l2_input.h>
29 
30 /**
31  * @file
32  * @brief IPv6 Neighbor Adjacency and Neighbor Discovery.
33  *
34  * The files contains the API and CLI code for managing IPv6 neighbor
35  * adjacency tables and neighbor discovery logic.
36  */
37 
38 /* can't use sizeof link_layer_address, that's 8 */
39 #define ETHER_MAC_ADDR_LEN 6
40 
41 /* advertised prefix option */
42 typedef struct
43 {
44  /* basic advertised information */
51 
52  /* advertised values are computed from these times if decrementing */
55 
56  /* local information */
57  int enabled;
60 
61 #define MIN_ADV_VALID_LIFETIME 7203 /* seconds */
62 #define DEF_ADV_VALID_LIFETIME 2592000
63 #define DEF_ADV_PREF_LIFETIME 604800
64 
65  /* extensions are added here, mobile, DNS etc.. */
67 
68 
69 typedef struct
70 {
71  /* group information */
77 
78 /* configured router advertisement information per ipv6 interface */
79 typedef struct
80 {
81 
82  /* advertised config information, zero means unspecified */
89 
90  /* mtu option */
92 
93  /* source link layer option */
94  u8 link_layer_address[8];
96 
97  /* prefix option */
99 
100  /* Hash table mapping address to index in interface advertised prefix pool. */
102 
103  /* MLDP group information */
105 
106  /* Hash table mapping address to index in mldp address pool. */
108 
109  /* local information */
111  int send_radv; /* radv on/off on this interface - set by config */
112  int cease_radv; /* we are ceasing to send - set byf config */
122 
123  /* timing information */
124 #define DEF_MAX_RADV_INTERVAL 200
125 #define DEF_MIN_RADV_INTERVAL .75 * DEF_MAX_RADV_INTERVAL
126 #define DEF_CURR_HOP_LIMIT 64
127 #define DEF_DEF_RTR_LIFETIME 3 * DEF_MAX_RADV_INTERVAL
128 #define MAX_DEF_RTR_LIFETIME 9000
129 
130 #define MAX_INITIAL_RTR_ADVERT_INTERVAL 16 /* seconds */
131 #define MAX_INITIAL_RTR_ADVERTISEMENTS 3 /*transmissions */
132 #define MIN_DELAY_BETWEEN_RAS 3 /* seconds */
133 #define MAX_DELAY_BETWEEN_RAS 1800 /* seconds */
134 #define MAX_RA_DELAY_TIME .5 /* seconds */
135 
141 
145 
146 
150 
151  /* stats */
155 
156  /* Link local address to use (defaults to underlying physical for logical interfaces */
158 
159  /* router solicitations sending state */
160  u8 keep_sending_rs; /* when true then next fields are valid */
167 } ip6_radv_t;
168 
169 typedef struct
170 {
171  u32 next_index;
172  uword node_index;
173  uword type_opaque;
174  uword data;
175  /* Used for nd event notification only */
176  void *data_callback;
177  u32 pid;
179 
180 
181 typedef struct
182 {
183  /* Hash tables mapping name to opcode. */
185 
186  /* lite beer "glean" adjacency handling */
189 
190  /* Mac address change notification */
193 
195 
197 
199 
201 
203 
204  /* Neighbor attack mitigation */
207 
208  /* Wildcard nd report publisher */
211 
212  /* Router advertisement report publisher */
216 
217 /* ipv6 neighbor discovery - timer/event types */
218 typedef enum
219 {
222 
223 typedef union
224 {
226  struct
227  {
230  } up_down_event;
232 
235 static ip6_address_t ip6a_zero; /* ip6 address 0 */
236 
237 static void wc_nd_signal_report (wc_nd_report_t * r);
238 static void ra_signal_report (ra_report_t * r);
239 
242 {
243  static ip6_address_t empty_address = { {0} };
245  ip6_radv_t *radv_info;
246  u32 ri = ~0;
247 
248  if (vec_len (nm->if_radv_pool_index_by_sw_if_index) > sw_if_index)
250  if (ri == ~0)
251  {
252  clib_warning ("IPv6 is not enabled for sw_if_index %d", sw_if_index);
253  return empty_address;
254  }
255  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
256  if (radv_info == NULL)
257  {
258  clib_warning ("Internal error");
259  return empty_address;
260  }
261  return radv_info->link_local_address;
262 }
263 
264 /**
265  * @brief publish wildcard arp event
266  * @param sw_if_index The interface on which the ARP entires are acted
267  */
268 static int
270 {
271  wc_nd_report_t r = {
273  .ip6 = *ip6,
274  };
275  memcpy (r.mac, mac, sizeof r.mac);
276 
277  void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
279  return 0;
280 }
281 
282 static void
284 {
288  uword et = nm->wc_ip6_nd_publisher_et;
289 
290  if (ni == (uword) ~ 0)
291  return;
292  wc_nd_report_t *q =
293  vlib_process_signal_event_data (vm, ni, et, 1, sizeof *q);
294 
295  *q = *r;
296 }
297 
298 void
299 wc_nd_set_publisher_node (uword node_index, uword event_type)
300 {
302  nm->wc_ip6_nd_publisher_node = node_index;
303  nm->wc_ip6_nd_publisher_et = event_type;
304 }
305 
306 static int
308 {
309  void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
310  vl_api_rpc_call_main_thread (ra_signal_report, (u8 *) r, sizeof *r);
311  return 0;
312 }
313 
314 static void
316 {
319  uword ni = nm->ip6_ra_publisher_node;
320  uword et = nm->ip6_ra_publisher_et;
321 
322  if (ni == (uword) ~ 0)
323  return;
324  ra_report_t *q = vlib_process_signal_event_data (vm, ni, et, 1, sizeof *q);
325 
326  *q = *r;
327 }
328 
329 void
330 ra_set_publisher_node (uword node_index, uword event_type)
331 {
333  nm->ip6_ra_publisher_node = node_index;
334  nm->ip6_ra_publisher_et = event_type;
335 }
336 
337 static u8 *
339 {
340  vlib_main_t *vm = va_arg (*va, vlib_main_t *);
341  ip6_neighbor_t *n = va_arg (*va, ip6_neighbor_t *);
342  vnet_main_t *vnm = vnet_get_main ();
344  u8 *flags = 0;
345 
346  if (!n)
347  return format (s, "%=12s%=45s%=6s%=20s%=40s", "Time", "Address", "Flags",
348  "Link layer", "Interface");
349 
351  flags = format (flags, "D");
352 
354  flags = format (flags, "S");
355 
357  flags = format (flags, "N");
358 
359  si = vnet_get_sw_interface (vnm, n->key.sw_if_index);
360  s = format (s, "%=12U%=45U%=6s%=20U%=40U",
363  flags ? (char *) flags : "",
366 
367  vec_free (flags);
368  return s;
369 }
370 
371 static void
373 {
375  {
377  {
378  ip6_ll_prefix_t pfx = {
379  .ilp_addr = n->key.ip6_address,
380  .ilp_sw_if_index = n->key.sw_if_index,
381  };
383  }
384  else
385  {
386  fib_prefix_t pfx = {
387  .fp_len = 128,
388  .fp_proto = FIB_PROTOCOL_IP6,
389  .fp_addr.ip6 = n->key.ip6_address,
390  };
391  fib_table_entry_path_remove (fib_index,
392  &pfx,
395  &pfx.fp_addr,
396  n->key.sw_if_index, ~0,
398  }
399  }
400 }
401 
402 typedef struct
403 {
407  u8 link_layer_address[6];
411 
414 
415 static void set_unset_ip6_neighbor_rpc
418  const ip6_address_t * a,
419  const u8 * link_layer_address,
420  int is_add, int is_static, int is_no_fib_entry)
421 {
423  void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
424 
425  args.sw_if_index = sw_if_index;
426  args.is_add = is_add;
427  args.is_static = is_static;
428  args.is_no_fib_entry = is_no_fib_entry;
429  clib_memcpy (&args.addr, a, sizeof (*a));
430  if (NULL != link_layer_address)
431  clib_memcpy (args.link_layer_address, link_layer_address, 6);
432 
434  (u8 *) & args, sizeof (args));
435 }
436 
437 static void
439 {
440  icmp6_neighbor_solicitation_header_t *h;
441  vnet_main_t *vnm = vnet_get_main ();
442  ip6_main_t *im = &ip6_main;
444  ip6_address_t *dst, *src;
447  vlib_buffer_t *b;
448  int bogus_length;
449  vlib_main_t *vm;
450  u32 bi = 0;
451 
452  vm = vlib_get_main ();
453 
454  si = vnet_get_sw_interface (vnm, adj->rewrite_header.sw_if_index);
455  dst = &adj->sub_type.nbr.next_hop.ip6;
456 
458  {
459  return;
460  }
462  adj->rewrite_header.
463  sw_if_index, &ia);
464  if (!src)
465  {
466  return;
467  }
468 
471  &bi);
472  if (!h)
473  return;
474 
475  hi = vnet_get_sup_hw_interface (vnm, adj->rewrite_header.sw_if_index);
476 
477  h->ip.dst_address.as_u8[13] = dst->as_u8[13];
478  h->ip.dst_address.as_u8[14] = dst->as_u8[14];
479  h->ip.dst_address.as_u8[15] = dst->as_u8[15];
480  h->ip.src_address = src[0];
481  h->neighbor.target_address = dst[0];
482 
483  clib_memcpy (h->link_layer_option.ethernet_address,
484  hi->hw_address, vec_len (hi->hw_address));
485 
486  h->neighbor.icmp.checksum =
487  ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
488  ASSERT (bogus_length == 0);
489 
490  b = vlib_get_buffer (vm, bi);
491  vnet_buffer (b)->sw_if_index[VLIB_RX] =
492  vnet_buffer (b)->sw_if_index[VLIB_TX] = adj->rewrite_header.sw_if_index;
493 
494  /* Add encapsulation string for software interface (e.g. ethernet header). */
495  vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
496  vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
497 
498  {
500  u32 *to_next = vlib_frame_vector_args (f);
501  to_next[0] = bi;
502  f->n_vectors = 1;
504  }
505 }
506 
507 static void
509 {
512  nbr->key.sw_if_index,
513  adj_get_link_type (ai),
514  nbr->link_layer_address));
515 }
516 
517 static void
519 {
520  ip_adjacency_t *adj = adj_get (ai);
521 
525  adj->rewrite_header.
526  sw_if_index,
527  adj_get_link_type (ai),
529 }
530 
531 #define IP6_NBR_MK_KEY(k, sw_if_index, addr) \
532 { \
533  k.sw_if_index = sw_if_index; \
534  k.ip6_address = *addr; \
535  k.pad = 0; \
536 }
537 
538 static ip6_neighbor_t *
539 ip6_nd_find (u32 sw_if_index, const ip6_address_t * addr)
540 {
542  ip6_neighbor_t *n = NULL;
544  uword *p;
545 
546  IP6_NBR_MK_KEY (k, sw_if_index, addr);
547 
548  p = mhash_get (&nm->neighbor_index_by_key, &k);
549  if (p)
550  {
551  n = pool_elt_at_index (nm->neighbor_pool, p[0]);
552  }
553 
554  return (n);
555 }
556 
557 static adj_walk_rc_t
559 {
560  ip6_neighbor_t *nbr = ctx;
561 
562  ip6_nd_mk_complete (ai, nbr);
563 
564  return (ADJ_WALK_RC_CONTINUE);
565 }
566 
567 static adj_walk_rc_t
569 {
571 
572  return (ADJ_WALK_RC_CONTINUE);
573 }
574 
575 static clib_error_t *
577  u32 sw_if_index, u32 flags)
578 {
580  ip6_neighbor_t *n;
581  u32 i, *to_delete = 0;
582 
583  /* *INDENT-OFF* */
584  pool_foreach (n, nm->neighbor_pool,
585  ({
586  if (n->key.sw_if_index == sw_if_index)
587  vec_add1 (to_delete, n - nm->neighbor_pool);
588  }));
589  /* *INDENT-ON* */
590 
592  {
593  for (i = 0; i < vec_len (to_delete); i++)
594  {
595  n = pool_elt_at_index (nm->neighbor_pool, to_delete[i]);
598  }
599  }
600  else
601  {
602  for (i = 0; i < vec_len (to_delete); i++)
603  {
604  n = pool_elt_at_index (nm->neighbor_pool, to_delete[i]);
608  continue;
611  (n->key.sw_if_index));
612  mhash_unset (&nm->neighbor_index_by_key, &n->key, 0);
613  pool_put (nm->neighbor_pool, n);
614  }
615  }
616 
617  vec_free (to_delete);
618  return 0;
619 }
620 
622 
623 void
625 {
626  ip6_neighbor_t *nbr;
627  ip_adjacency_t *adj;
628 
629  adj = adj_get (ai);
630 
631  nbr = ip6_nd_find (sw_if_index, &adj->sub_type.nbr.next_hop.ip6);
632 
633  switch (adj->lookup_next_index)
634  {
637  break;
638  case IP_LOOKUP_NEXT_ARP:
639  if (NULL != nbr)
640  {
641  adj_nbr_walk_nh6 (sw_if_index, &nbr->key.ip6_address,
643  }
644  else
645  {
646  /*
647  * no matching ND entry.
648  * construct the rewrite required to for an ND packet, and stick
649  * that in the adj's pipe to smoke.
650  */
654  sw_if_index,
657 
658  /*
659  * since the FIB has added this adj for a route, it makes sense it may
660  * want to forward traffic sometime soon. Let's send a speculative ND.
661  * just one. If we were to do periodically that wouldn't be bad either,
662  * but that's more code than i'm prepared to write at this time for
663  * relatively little reward.
664  */
665  ip6_nbr_probe (adj);
666  }
667  break;
672  sw_if_index,
675  break;
677  {
678  /*
679  * Construct a partial rewrite from the known ethernet mcast dest MAC
680  */
681  u8 *rewrite;
682  u8 offset;
683 
684  rewrite = ethernet_build_rewrite (vnm,
685  sw_if_index,
686  adj->ia_link,
688 
689  /*
690  * Complete the remaining fields of the adj's rewrite to direct the
691  * complete of the rewrite at switch time by copying in the IP
692  * dst address's bytes.
693  * Ofset is 2 bytes into the desintation address.
694  */
695  offset = vec_len (rewrite) - 2;
696  adj_mcast_update_rewrite (ai, rewrite, offset);
697 
698  break;
699  }
700  case IP_LOOKUP_NEXT_DROP:
701  case IP_LOOKUP_NEXT_PUNT:
707  case IP_LOOKUP_N_NEXT:
708  ASSERT (0);
709  break;
710  }
711 }
712 
713 
714 static void
716 {
718  {
719  ip6_ll_prefix_t pfx = {
720  .ilp_addr = n->key.ip6_address,
721  .ilp_sw_if_index = n->key.sw_if_index,
722  };
723  n->fib_entry_index =
725  }
726  else
727  {
728  fib_prefix_t pfx = {
729  .fp_len = 128,
730  .fp_proto = FIB_PROTOCOL_IP6,
731  .fp_addr.ip6 = n->key.ip6_address,
732  };
733 
734  n->fib_entry_index =
735  fib_table_entry_path_add (fib_index, &pfx, FIB_SOURCE_ADJ,
737  DPO_PROTO_IP6, &pfx.fp_addr,
738  n->key.sw_if_index, ~0, 1, NULL,
740  }
741 }
742 
743 static ip6_neighbor_t *
745 {
746  ip6_neighbor_t *n;
748  u32 count = 0;
750  if (index == ~0) /* Try again from elt 0 */
751  index = pool_next_index (nm->neighbor_pool, index);
752 
753  /* Find a non-static random entry to free up for reuse */
754  do
755  {
756  if ((count++ == 100) || (index == ~0))
757  return NULL; /* give up after 100 entries */
758  n = pool_elt_at_index (nm->neighbor_pool, index);
759  nm->neighbor_delete_rotor = index;
760  index = pool_next_index (nm->neighbor_pool, index);
761  }
762  while (n->flags & IP6_NEIGHBOR_FLAG_STATIC);
763 
764  /* Remove ARP entry from its interface and update fib */
769  mhash_unset (&nm->neighbor_index_by_key, &n->key, 0);
770 
771  return n;
772 }
773 
774 int
776  u32 sw_if_index,
777  const ip6_address_t * a,
778  const u8 * link_layer_address,
779  uword n_bytes_link_layer_address,
780  int is_static, int is_no_fib_entry)
781 {
784  ip6_neighbor_t *n = 0;
785  int make_new_nd_cache_entry = 1;
786  uword *p;
787  u32 next_index;
788  pending_resolution_t *pr, *mc;
789 
790  if (vlib_get_thread_index ())
791  {
792  set_unset_ip6_neighbor_rpc (vm, sw_if_index, a, link_layer_address,
793  1 /* set new neighbor */ , is_static,
794  is_no_fib_entry);
795  return 0;
796  }
797 
799  k.ip6_address = a[0];
800  k.pad = 0;
801 
802  p = mhash_get (&nm->neighbor_index_by_key, &k);
803  if (p)
804  {
805  n = pool_elt_at_index (nm->neighbor_pool, p[0]);
806  /* Refuse to over-write static neighbor entry. */
807  if (!is_static && (n->flags & IP6_NEIGHBOR_FLAG_STATIC))
808  {
809  /* if MAC address match, still check to send event */
810  if (0 == memcmp (n->link_layer_address,
811  link_layer_address, n_bytes_link_layer_address))
812  goto check_customers;
813  return -2;
814  }
815  make_new_nd_cache_entry = 0;
816  }
817 
818  if (make_new_nd_cache_entry)
819  {
820  if (nm->limit_neighbor_cache_size &&
822  {
824  if (NULL == n)
825  return -2;
826  }
827  else
828  pool_get (nm->neighbor_pool, n);
829 
830  mhash_set (&nm->neighbor_index_by_key, &k, n - nm->neighbor_pool,
831  /* old value */ 0);
832  n->key = k;
834 
836  link_layer_address, n_bytes_link_layer_address);
837 
838  /*
839  * create the adj-fib. the entry in the FIB table for and to the peer.
840  */
841  if (!is_no_fib_entry)
842  {
845  }
846  else
847  {
849  }
850  }
851  else
852  {
853  /*
854  * prevent a DoS attack from the data-plane that
855  * spams us with no-op updates to the MAC address
856  */
857  if (0 == memcmp (n->link_layer_address,
858  link_layer_address, n_bytes_link_layer_address))
859  {
861  goto check_customers;
862  }
863 
865  link_layer_address, n_bytes_link_layer_address);
866  }
867 
868  /* Update time stamp and flags. */
870  if (is_static)
871  {
874  }
875  else
876  {
879  }
880 
881  adj_nbr_walk_nh6 (sw_if_index,
883 
884 check_customers:
885  /* Customer(s) waiting for this address to be resolved? */
887  if (p)
888  {
889  next_index = p[0];
890 
891  while (next_index != (u32) ~ 0)
892  {
893  pr = pool_elt_at_index (nm->pending_resolutions, next_index);
895  pr->type_opaque, pr->data);
896  next_index = pr->next_index;
897  pool_put (nm->pending_resolutions, pr);
898  }
899 
900  mhash_unset (&nm->pending_resolutions_by_address, (void *) a, 0);
901  }
902 
903  /* Customer(s) requesting ND event for this address? */
904  p = mhash_get (&nm->mac_changes_by_address, a);
905  if (p)
906  {
907  next_index = p[0];
908 
909  while (next_index != (u32) ~ 0)
910  {
911  int (*fp) (u32, u8 *, u32, ip6_address_t *);
912  int rv = 1;
913  mc = pool_elt_at_index (nm->mac_changes, next_index);
914  fp = mc->data_callback;
915 
916  /* Call the user's data callback, return 1 to suppress dup events */
917  if (fp)
918  rv =
919  (*fp) (mc->data, (u8 *) link_layer_address, sw_if_index,
920  &ip6a_zero);
921  /*
922  * Signal the resolver process, as long as the user
923  * says they want to be notified
924  */
925  if (rv == 0)
927  mc->type_opaque, mc->data);
928  next_index = mc->next_index;
929  }
930  }
931 
932  return 0;
933 }
934 
935 int
937  u32 sw_if_index, const ip6_address_t * a)
938 {
941  ip6_neighbor_t *n;
942  uword *p;
943  int rv = 0;
944 
945  if (vlib_get_thread_index ())
946  {
947  set_unset_ip6_neighbor_rpc (vm, sw_if_index, a, NULL,
948  0 /* unset */ , 0, 0);
949  return 0;
950  }
951 
953  k.ip6_address = a[0];
954  k.pad = 0;
955 
956  p = mhash_get (&nm->neighbor_index_by_key, &k);
957  if (p == 0)
958  {
959  rv = -1;
960  goto out;
961  }
962 
963  n = pool_elt_at_index (nm->neighbor_pool, p[0]);
964 
965  adj_nbr_walk_nh6 (sw_if_index,
968  (n, ip6_fib_table_get_index_for_sw_if_index (sw_if_index));
969 
970  mhash_unset (&nm->neighbor_index_by_key, &n->key, 0);
971  pool_put (nm->neighbor_pool, n);
972 
973 out:
974  return rv;
975 }
976 
979 {
980  vlib_main_t *vm = vlib_get_main ();
981  if (a->is_add)
983  a->link_layer_address, 6, a->is_static,
984  a->is_no_fib_entry);
985  else
987 }
988 
989 static int
990 ip6_neighbor_sort (void *a1, void *a2)
991 {
992  vnet_main_t *vnm = vnet_get_main ();
993  ip6_neighbor_t *n1 = a1, *n2 = a2;
994  int cmp;
995  cmp = vnet_sw_interface_compare (vnm, n1->key.sw_if_index,
996  n2->key.sw_if_index);
997  if (!cmp)
998  cmp = ip6_address_compare (&n1->key.ip6_address, &n2->key.ip6_address);
999  return cmp;
1000 }
1001 
1004 {
1006  return nm->neighbor_pool;
1007 }
1008 
1011 {
1013  ip6_neighbor_t *n, *ns = 0;
1014 
1015  /* *INDENT-OFF* */
1016  pool_foreach (n, nm->neighbor_pool,
1017  ({
1018  if (sw_if_index != ~0 && n->key.sw_if_index != sw_if_index)
1019  continue;
1020  vec_add1 (ns, n[0]);
1021  }));
1022  /* *INDENT-ON* */
1023 
1024  if (ns)
1026  return ns;
1027 }
1028 
1029 static clib_error_t *
1031  unformat_input_t * input, vlib_cli_command_t * cmd)
1032 {
1033  vnet_main_t *vnm = vnet_get_main ();
1034  ip6_neighbor_t *n, *ns;
1035  clib_error_t *error = 0;
1036  u32 sw_if_index;
1037 
1038  /* Filter entries by interface if given. */
1039  sw_if_index = ~0;
1040  (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index);
1041 
1042  ns = ip6_neighbors_entries (sw_if_index);
1043  if (ns)
1044  {
1046  vec_foreach (n, ns)
1047  {
1049  }
1050  vec_free (ns);
1051  }
1052 
1053  return error;
1054 }
1055 
1056 /*?
1057  * This command is used to display the adjacent IPv6 hosts found via
1058  * neighbor discovery. Optionally, limit the output to the specified
1059  * interface.
1060  *
1061  * @cliexpar
1062  * Example of how to display the IPv6 neighbor adjacency table:
1063  * @cliexstart{show ip6 neighbors}
1064  * Time Address Flags Link layer Interface
1065  * 34.0910 ::a:1:1:0:7 02:fe:6a:07:39:6f GigabitEthernet2/0/0
1066  * 173.2916 ::b:5:1:c:2 02:fe:50:62:3a:94 GigabitEthernet2/0/0
1067  * 886.6654 ::1:1:c:0:9 S 02:fe:e4:45:27:5b GigabitEthernet3/0/0
1068  * @cliexend
1069  * Example of how to display the IPv6 neighbor adjacency table for given interface:
1070  * @cliexstart{show ip6 neighbors GigabitEthernet2/0/0}
1071  * Time Address Flags Link layer Interface
1072  * 34.0910 ::a:1:1:0:7 02:fe:6a:07:39:6f GigabitEthernet2/0/0
1073  * 173.2916 ::b:5:1:c:2 02:fe:50:62:3a:94 GigabitEthernet2/0/0
1074  * @cliexend
1075 ?*/
1076 /* *INDENT-OFF* */
1078  .path = "show ip6 neighbors",
1079  .function = show_ip6_neighbors,
1080  .short_help = "show ip6 neighbors [<interface>]",
1081 };
1082 /* *INDENT-ON* */
1083 
1084 static clib_error_t *
1086  unformat_input_t * input, vlib_cli_command_t * cmd)
1087 {
1088  vnet_main_t *vnm = vnet_get_main ();
1090  u8 mac_address[6];
1091  int addr_valid = 0;
1092  int is_del = 0;
1093  int is_static = 0;
1094  int is_no_fib_entry = 0;
1095  u32 sw_if_index;
1096 
1097  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1098  {
1099  /* intfc, ip6-address, mac-address */
1100  if (unformat (input, "%U %U %U",
1101  unformat_vnet_sw_interface, vnm, &sw_if_index,
1102  unformat_ip6_address, &addr,
1103  unformat_ethernet_address, mac_address))
1104  addr_valid = 1;
1105 
1106  else if (unformat (input, "delete") || unformat (input, "del"))
1107  is_del = 1;
1108  else if (unformat (input, "static"))
1109  is_static = 1;
1110  else if (unformat (input, "no-fib-entry"))
1111  is_no_fib_entry = 1;
1112  else
1113  break;
1114  }
1115 
1116  if (!addr_valid)
1117  return clib_error_return (0, "Missing interface, ip6 or hw address");
1118 
1119  if (!is_del)
1120  vnet_set_ip6_ethernet_neighbor (vm, sw_if_index, &addr,
1121  mac_address, sizeof (mac_address),
1122  is_static, is_no_fib_entry);
1123  else
1124  vnet_unset_ip6_ethernet_neighbor (vm, sw_if_index, &addr);
1125  return 0;
1126 }
1127 
1128 /*?
1129  * This command is used to manually add an entry to the IPv6 neighbor
1130  * adjacency table. Optionally, the entry can be added as static. It is
1131  * also used to remove an entry from the table. Use the '<em>show ip6
1132  * neighbors</em>' command to display all learned and manually entered entries.
1133  *
1134  * @cliexpar
1135  * Example of how to add a static entry to the IPv6 neighbor adjacency table:
1136  * @cliexcmd{set ip6 neighbor GigabitEthernet2/0/0 ::1:1:c:0:9 02:fe:e4:45:27:5b static}
1137  * Example of how to delete an entry from the IPv6 neighbor adjacency table:
1138  * @cliexcmd{set ip6 neighbor del GigabitEthernet2/0/0 ::1:1:c:0:9 02:fe:e4:45:27:5b}
1139 ?*/
1140 /* *INDENT-OFF* */
1142 {
1143  .path = "set ip6 neighbor",
1144  .function = set_ip6_neighbor,
1145  .short_help = "set ip6 neighbor [del] <interface> <ip6-address> <mac-address> [static]",
1146 };
1147 /* *INDENT-ON* */
1148 
1149 typedef enum
1150 {
1155 
1158  vlib_node_runtime_t * node,
1159  vlib_frame_t * frame,
1160  uword is_solicitation)
1161 {
1162  vnet_main_t *vnm = vnet_get_main ();
1163  ip6_main_t *im = &ip6_main;
1164  uword n_packets = frame->n_vectors;
1165  u32 *from, *to_next;
1166  u32 n_left_from, n_left_to_next, next_index, n_advertisements_sent;
1168  vlib_node_runtime_t *error_node =
1170  int bogus_length;
1171 
1172  from = vlib_frame_vector_args (frame);
1173  n_left_from = n_packets;
1174  next_index = node->cached_next_index;
1175 
1176  if (node->flags & VLIB_NODE_FLAG_TRACE)
1177  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
1178  /* stride */ 1,
1179  sizeof (icmp6_input_trace_t));
1180 
1181  option_type =
1182  (is_solicitation
1183  ? ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address
1184  : ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address);
1185  n_advertisements_sent = 0;
1186 
1187  while (n_left_from > 0)
1188  {
1189  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1190 
1191  while (n_left_from > 0 && n_left_to_next > 0)
1192  {
1193  vlib_buffer_t *p0;
1194  ip6_header_t *ip0;
1195  icmp6_neighbor_solicitation_or_advertisement_header_t *h0;
1196  icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *o0;
1197  u32 bi0, options_len0, sw_if_index0, next0, error0;
1198  u32 ip6_sadd_link_local, ip6_sadd_unspecified;
1199  int is_rewrite0;
1200  u32 ni0;
1201 
1202  bi0 = to_next[0] = from[0];
1203 
1204  from += 1;
1205  to_next += 1;
1206  n_left_from -= 1;
1207  n_left_to_next -= 1;
1208 
1209  p0 = vlib_get_buffer (vm, bi0);
1210  ip0 = vlib_buffer_get_current (p0);
1211  h0 = ip6_next_header (ip0);
1212  options_len0 =
1213  clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
1214 
1215  error0 = ICMP6_ERROR_NONE;
1216  sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1217  ip6_sadd_link_local =
1219  ip6_sadd_unspecified =
1221 
1222  /* Check that source address is unspecified, link-local or else on-link. */
1223  if (!ip6_sadd_unspecified && !ip6_sadd_link_local)
1224  {
1225  u32 src_adj_index0 = ip6_src_lookup_for_packet (im, p0, ip0);
1226 
1227  if (ADJ_INDEX_INVALID != src_adj_index0)
1228  {
1229  ip_adjacency_t *adj0 = adj_get (src_adj_index0);
1230 
1231  /* Allow all realistic-looking rewrite adjacencies to pass */
1232  ni0 = adj0->lookup_next_index;
1233  is_rewrite0 = (ni0 >= IP_LOOKUP_NEXT_ARP) &&
1234  (ni0 < IP6_LOOKUP_N_NEXT);
1235 
1236  error0 = ((adj0->rewrite_header.sw_if_index != sw_if_index0
1237  || !is_rewrite0)
1238  ?
1239  ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_NOT_ON_LINK
1240  : error0);
1241  }
1242  else
1243  {
1244  error0 =
1245  ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_NOT_ON_LINK;
1246  }
1247  }
1248 
1249  o0 = (void *) (h0 + 1);
1250  o0 = ((options_len0 == 8 && o0->header.type == option_type
1251  && o0->header.n_data_u64s == 1) ? o0 : 0);
1252 
1253  /* If src address unspecified or link local, donot learn neighbor MAC */
1254  if (PREDICT_TRUE (error0 == ICMP6_ERROR_NONE && o0 != 0 &&
1255  !ip6_sadd_unspecified))
1256  {
1257  vnet_set_ip6_ethernet_neighbor (vm, sw_if_index0,
1258  is_solicitation ?
1259  &ip0->src_address :
1260  &h0->target_address,
1261  o0->ethernet_address,
1262  sizeof (o0->ethernet_address),
1263  0, 0);
1264  }
1265 
1266  if (is_solicitation && error0 == ICMP6_ERROR_NONE)
1267  {
1268  /* Check that target address is local to this router. */
1269  fib_node_index_t fei;
1270  u32 fib_index;
1271 
1272  fib_index =
1274 
1275  if (~0 == fib_index)
1276  {
1277  error0 = ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_UNKNOWN;
1278  }
1279  else
1280  {
1281  if (ip6_address_is_link_local_unicast (&h0->target_address))
1282  {
1284  (ip6_ll_fib_get (sw_if_index0),
1285  &h0->target_address, 128);
1286  }
1287  else
1288  {
1289  fei = ip6_fib_table_lookup_exact_match (fib_index,
1290  &h0->target_address,
1291  128);
1292  }
1293 
1294  if (FIB_NODE_INDEX_INVALID == fei)
1295  {
1296  /* The target address is not in the FIB */
1297  error0 =
1298  ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_UNKNOWN;
1299  }
1300  else
1301  {
1302  if (FIB_ENTRY_FLAG_LOCAL &
1305  {
1306  /* It's an address that belongs to one of our interfaces
1307  * that's good. */
1308  }
1309  else
1311  (fei, FIB_SOURCE_IP6_ND_PROXY) ||
1313  {
1314  /* The address was added by IPv6 Proxy ND config.
1315  * We should only respond to these if the NS arrived on
1316  * the link that has a matching covering prefix */
1317  }
1318  else
1319  {
1320  error0 =
1321  ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_UNKNOWN;
1322  }
1323  }
1324  }
1325  }
1326 
1327  if (is_solicitation)
1328  next0 = (error0 != ICMP6_ERROR_NONE
1331  else
1332  {
1333  next0 = 0;
1334  error0 = error0 == ICMP6_ERROR_NONE ?
1335  ICMP6_ERROR_NEIGHBOR_ADVERTISEMENTS_RX : error0;
1336  }
1337 
1338  if (is_solicitation && error0 == ICMP6_ERROR_NONE)
1339  {
1340  vnet_sw_interface_t *sw_if0;
1341  ethernet_interface_t *eth_if0;
1342  ethernet_header_t *eth0;
1343 
1344  /* dst address is either source address or the all-nodes mcast addr */
1345  if (!ip6_sadd_unspecified)
1346  ip0->dst_address = ip0->src_address;
1347  else
1349  IP6_MULTICAST_SCOPE_link_local,
1350  IP6_MULTICAST_GROUP_ID_all_hosts);
1351 
1352  ip0->src_address = h0->target_address;
1353  ip0->hop_limit = 255;
1354  h0->icmp.type = ICMP6_neighbor_advertisement;
1355 
1356  sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
1358  eth_if0 =
1360  if (eth_if0 && o0)
1361  {
1362  clib_memcpy (o0->ethernet_address, eth_if0->address, 6);
1363  o0->header.type =
1364  ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
1365  }
1366 
1367  h0->advertisement_flags = clib_host_to_net_u32
1370 
1371  h0->icmp.checksum = 0;
1372  h0->icmp.checksum =
1373  ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0,
1374  &bogus_length);
1375  ASSERT (bogus_length == 0);
1376 
1377  /* Reuse current MAC header, copy SMAC to DMAC and
1378  * interface MAC to SMAC */
1380  eth0 = vlib_buffer_get_current (p0);
1381  clib_memcpy (eth0->dst_address, eth0->src_address, 6);
1382  if (eth_if0)
1383  clib_memcpy (eth0->src_address, eth_if0->address, 6);
1384 
1385  /* Setup input and output sw_if_index for packet */
1386  ASSERT (vnet_buffer (p0)->sw_if_index[VLIB_RX] == sw_if_index0);
1387  vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1388  vnet_buffer (p0)->sw_if_index[VLIB_RX] =
1390 
1391  n_advertisements_sent++;
1392  }
1393 
1394  p0->error = error_node->errors[error0];
1395 
1396  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1397  to_next, n_left_to_next,
1398  bi0, next0);
1399  }
1400 
1401  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1402  }
1403 
1404  /* Account for advertisements sent. */
1405  vlib_error_count (vm, error_node->node_index,
1406  ICMP6_ERROR_NEIGHBOR_ADVERTISEMENTS_TX,
1407  n_advertisements_sent);
1408 
1409  return frame->n_vectors;
1410 }
1411 
1412 /* for "syslogging" - use elog for now */
1413 #define foreach_log_level \
1414  _ (DEBUG, "DEBUG") \
1415  _ (INFO, "INFORMATION") \
1416  _ (NOTICE, "NOTICE") \
1417  _ (WARNING, "WARNING") \
1418  _ (ERR, "ERROR") \
1419  _ (CRIT, "CRITICAL") \
1420  _ (ALERT, "ALERT") \
1421  _ (EMERG, "EMERGENCY")
1422 
1423 typedef enum
1424 {
1425 #define _(f,s) LOG_##f,
1427 #undef _
1428 } log_level_t;
1429 
1430 static char *log_level_strings[] = {
1431 #define _(f,s) s,
1433 #undef _
1434 };
1435 
1436 static int logmask = 1 << LOG_DEBUG;
1437 
1438 static void
1439 ip6_neighbor_syslog (vlib_main_t * vm, int priority, char *fmt, ...)
1440 {
1441  /* just use elog for now */
1442  u8 *what;
1443  va_list va;
1444 
1445  if ((priority > LOG_EMERG) || !(logmask & (1 << priority)))
1446  return;
1447 
1448  va_start (va, fmt);
1449  if (fmt)
1450  {
1451  what = va_format (0, fmt, &va);
1452 
1453  ELOG_TYPE_DECLARE (e) =
1454  {
1455  .format = "ip6 nd: (%s): %s",.format_args = "T4T4",};
1456  struct
1457  {
1458  u32 s[2];
1459  } *ed;
1460  ed = ELOG_DATA (&vm->elog_main, e);
1461  ed->s[0] = elog_string (&vm->elog_main, log_level_strings[priority]);
1462  ed->s[1] = elog_string (&vm->elog_main, (char *) what);
1463  }
1464  va_end (va);
1465  return;
1466 }
1467 
1468 clib_error_t *
1470  _vnet_ip6_neighbor_function_list_elt_t * elt)
1471 {
1472  clib_error_t *error = 0;
1473 
1474  while (elt)
1475  {
1476  error = elt->fp (data);
1477  if (error)
1478  return error;
1479  elt = elt->next_ip6_neighbor_function;
1480  }
1481 
1482  return error;
1483 }
1484 
1485 /* ipv6 neighbor discovery - router advertisements */
1486 typedef enum
1487 {
1493 
1496  vlib_node_runtime_t * node, vlib_frame_t * frame)
1497 {
1498  vnet_main_t *vnm = vnet_get_main ();
1499  ip6_main_t *im = &ip6_main;
1501  uword n_packets = frame->n_vectors;
1502  u32 *from, *to_next;
1503  u32 n_left_from, n_left_to_next, next_index;
1504  u32 n_advertisements_sent = 0;
1505  int bogus_length;
1506 
1508 
1509  vlib_node_runtime_t *error_node =
1511 
1512  from = vlib_frame_vector_args (frame);
1513  n_left_from = n_packets;
1514  next_index = node->cached_next_index;
1515 
1516  if (node->flags & VLIB_NODE_FLAG_TRACE)
1517  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
1518  /* stride */ 1,
1519  sizeof (icmp6_input_trace_t));
1520 
1521  /* source may append his LL address */
1522  option_type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
1523 
1524  while (n_left_from > 0)
1525  {
1526  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1527 
1528  while (n_left_from > 0 && n_left_to_next > 0)
1529  {
1530  vlib_buffer_t *p0;
1531  ip6_header_t *ip0;
1532  ip6_radv_t *radv_info = 0;
1533 
1534  icmp6_neighbor_discovery_header_t *h0;
1535  icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *o0;
1536 
1537  u32 bi0, options_len0, sw_if_index0, next0, error0;
1538  u32 is_solicitation = 1, is_dropped = 0;
1539  u32 is_unspecified, is_link_local;
1540 
1541  bi0 = to_next[0] = from[0];
1542 
1543  from += 1;
1544  to_next += 1;
1545  n_left_from -= 1;
1546  n_left_to_next -= 1;
1547 
1548  p0 = vlib_get_buffer (vm, bi0);
1549  ip0 = vlib_buffer_get_current (p0);
1550  h0 = ip6_next_header (ip0);
1551  options_len0 =
1552  clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
1553  is_unspecified = ip6_address_is_unspecified (&ip0->src_address);
1554  is_link_local =
1556 
1557  error0 = ICMP6_ERROR_NONE;
1558  sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1559 
1560  /* check if solicitation (not from nd_timer node) */
1562  is_solicitation = 0;
1563 
1564  /* Check that source address is unspecified, link-local or else on-link. */
1565  if (!is_unspecified && !is_link_local)
1566  {
1567  u32 src_adj_index0 = ip6_src_lookup_for_packet (im, p0, ip0);
1568 
1569  if (ADJ_INDEX_INVALID != src_adj_index0)
1570  {
1571  ip_adjacency_t *adj0 = adj_get (src_adj_index0);
1572 
1573  error0 = (adj0->rewrite_header.sw_if_index != sw_if_index0
1574  ?
1575  ICMP6_ERROR_ROUTER_SOLICITATION_SOURCE_NOT_ON_LINK
1576  : error0);
1577  }
1578  else
1579  {
1580  error0 = ICMP6_ERROR_ROUTER_SOLICITATION_SOURCE_NOT_ON_LINK;
1581  }
1582  }
1583 
1584  /* check for source LL option and process */
1585  o0 = (void *) (h0 + 1);
1586  o0 = ((options_len0 == 8
1587  && o0->header.type == option_type
1588  && o0->header.n_data_u64s == 1) ? o0 : 0);
1589 
1590  /* if src address unspecified IGNORE any options */
1591  if (PREDICT_TRUE (error0 == ICMP6_ERROR_NONE && o0 != 0 &&
1592  !is_unspecified && !is_link_local))
1593  {
1594  vnet_set_ip6_ethernet_neighbor (vm, sw_if_index0,
1595  &ip0->src_address,
1596  o0->ethernet_address,
1597  sizeof (o0->ethernet_address),
1598  0, 0);
1599  }
1600 
1601  /* default is to drop */
1603 
1604  if (error0 == ICMP6_ERROR_NONE)
1605  {
1606  vnet_sw_interface_t *sw_if0;
1607  ethernet_interface_t *eth_if0;
1608  u32 adj_index0;
1609 
1610  sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
1612  eth_if0 =
1614 
1615  /* only support ethernet interface type for now */
1616  error0 =
1617  (!eth_if0) ? ICMP6_ERROR_ROUTER_SOLICITATION_UNSUPPORTED_INTF
1618  : error0;
1619 
1620  if (error0 == ICMP6_ERROR_NONE)
1621  {
1622  u32 ri;
1623 
1624  /* adjust the sizeof the buffer to just include the ipv6 header */
1625  p0->current_length -=
1626  (options_len0 +
1627  sizeof (icmp6_neighbor_discovery_header_t));
1628 
1629  /* look up the radv_t information for this interface */
1631  sw_if_index0)
1632  {
1633  ri =
1634  nm->if_radv_pool_index_by_sw_if_index[sw_if_index0];
1635 
1636  if (ri != ~0)
1637  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
1638  }
1639 
1640  error0 =
1641  ((!radv_info) ?
1642  ICMP6_ERROR_ROUTER_SOLICITATION_RADV_NOT_CONFIG :
1643  error0);
1644 
1645  if (error0 == ICMP6_ERROR_NONE)
1646  {
1647  f64 now = vlib_time_now (vm);
1648 
1649  /* for solicited adverts - need to rate limit */
1650  if (is_solicitation)
1651  {
1652  if (0 != radv_info->last_radv_time &&
1653  (now - radv_info->last_radv_time) <
1655  is_dropped = 1;
1656  else
1657  radv_info->last_radv_time = now;
1658  }
1659 
1660  /* send now */
1661  icmp6_router_advertisement_header_t rh;
1662 
1663  rh.icmp.type = ICMP6_router_advertisement;
1664  rh.icmp.code = 0;
1665  rh.icmp.checksum = 0;
1666 
1667  rh.current_hop_limit = radv_info->curr_hop_limit;
1668  rh.router_lifetime_in_sec =
1669  clib_host_to_net_u16
1670  (radv_info->adv_router_lifetime_in_sec);
1671  rh.
1672  time_in_msec_between_retransmitted_neighbor_solicitations
1673  =
1674  clib_host_to_net_u32 (radv_info->
1675  adv_time_in_msec_between_retransmitted_neighbor_solicitations);
1676  rh.neighbor_reachable_time_in_msec =
1677  clib_host_to_net_u32 (radv_info->
1678  adv_neighbor_reachable_time_in_msec);
1679 
1680  rh.flags =
1681  (radv_info->adv_managed_flag) ?
1683  0;
1684  rh.flags |=
1685  ((radv_info->adv_other_flag) ?
1687  0);
1688 
1689 
1690  u16 payload_length =
1691  sizeof (icmp6_router_advertisement_header_t);
1692 
1695  (p0), &bi0, (void *) &rh,
1696  sizeof (icmp6_router_advertisement_header_t)))
1697  {
1698  /* buffer allocation failed, drop the pkt */
1699  error0 = ICMP6_ERROR_ALLOC_FAILURE;
1700  goto drop0;
1701  }
1702 
1703  if (radv_info->adv_link_layer_address)
1704  {
1705  icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
1706  h;
1707 
1708  h.header.type =
1709  ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
1710  h.header.n_data_u64s = 1;
1711 
1712  /* copy ll address */
1713  clib_memcpy (&h.ethernet_address[0],
1714  eth_if0->address, 6);
1715 
1718  (p0), &bi0, (void *) &h,
1719  sizeof
1720  (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t)))
1721  {
1722  error0 = ICMP6_ERROR_ALLOC_FAILURE;
1723  goto drop0;
1724  }
1725 
1726  payload_length +=
1727  sizeof
1728  (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t);
1729  }
1730 
1731  /* add MTU option */
1732  if (radv_info->adv_link_mtu)
1733  {
1734  icmp6_neighbor_discovery_mtu_option_t h;
1735 
1736  h.unused = 0;
1737  h.mtu =
1738  clib_host_to_net_u32 (radv_info->adv_link_mtu);
1739  h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_mtu;
1740  h.header.n_data_u64s = 1;
1741 
1742  payload_length +=
1743  sizeof (icmp6_neighbor_discovery_mtu_option_t);
1744 
1747  (p0), &bi0, (void *) &h,
1748  sizeof
1749  (icmp6_neighbor_discovery_mtu_option_t)))
1750  {
1751  error0 = ICMP6_ERROR_ALLOC_FAILURE;
1752  goto drop0;
1753  }
1754  }
1755 
1756  /* add advertised prefix options */
1757  ip6_radv_prefix_t *pr_info;
1758 
1759  /* *INDENT-OFF* */
1760  pool_foreach (pr_info, radv_info->adv_prefixes_pool,
1761  ({
1762  if(pr_info->enabled &&
1763  (!pr_info->decrement_lifetime_flag
1764  || (pr_info->pref_lifetime_expires >0)))
1765  {
1766  /* advertise this prefix */
1767  icmp6_neighbor_discovery_prefix_information_option_t h;
1768 
1769  h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_prefix_information;
1770  h.header.n_data_u64s = (sizeof(icmp6_neighbor_discovery_prefix_information_option_t) >> 3);
1771 
1772  h.dst_address_length = pr_info->prefix_len;
1773 
1774  h.flags = (pr_info->adv_on_link_flag) ? ICMP6_NEIGHBOR_DISCOVERY_PREFIX_INFORMATION_FLAG_ON_LINK : 0;
1775  h.flags |= (pr_info->adv_autonomous_flag) ? ICMP6_NEIGHBOR_DISCOVERY_PREFIX_INFORMATION_AUTO : 0;
1776 
1777  if(radv_info->cease_radv && pr_info->deprecated_prefix_flag)
1778  {
1779  h.valid_time = clib_host_to_net_u32(MIN_ADV_VALID_LIFETIME);
1780  h.preferred_time = 0;
1781  }
1782  else
1783  {
1784  if(pr_info->decrement_lifetime_flag)
1785  {
1786  pr_info->adv_valid_lifetime_in_secs = ((pr_info->valid_lifetime_expires > now)) ?
1787  (pr_info->valid_lifetime_expires - now) : 0;
1788 
1789  pr_info->adv_pref_lifetime_in_secs = ((pr_info->pref_lifetime_expires > now)) ?
1790  (pr_info->pref_lifetime_expires - now) : 0;
1791  }
1792 
1793  h.valid_time = clib_host_to_net_u32(pr_info->adv_valid_lifetime_in_secs);
1794  h.preferred_time = clib_host_to_net_u32(pr_info->adv_pref_lifetime_in_secs) ;
1795  }
1796  h.unused = 0;
1797 
1798  clib_memcpy(&h.dst_address, &pr_info->prefix, sizeof(ip6_address_t));
1799 
1800  payload_length += sizeof( icmp6_neighbor_discovery_prefix_information_option_t);
1801 
1802  if (vlib_buffer_add_data
1803  (vm, vlib_buffer_get_free_list_index (p0),
1804  &bi0,
1805  (void *)&h,
1806  sizeof(icmp6_neighbor_discovery_prefix_information_option_t)))
1807  {
1808  error0 = ICMP6_ERROR_ALLOC_FAILURE;
1809  goto drop0;
1810  }
1811 
1812  }
1813  }));
1814  /* *INDENT-ON* */
1815 
1816  /* add additional options before here */
1817 
1818  /* finish building the router advertisement... */
1819  if (!is_unspecified && radv_info->send_unicast)
1820  {
1821  ip0->dst_address = ip0->src_address;
1822  }
1823  else
1824  {
1825  /* target address is all-nodes mcast addr */
1827  (&ip0->dst_address,
1828  IP6_MULTICAST_SCOPE_link_local,
1829  IP6_MULTICAST_GROUP_ID_all_hosts);
1830  }
1831 
1832  /* source address MUST be the link-local address */
1833  ip0->src_address = radv_info->link_local_address;
1834 
1835  ip0->hop_limit = 255;
1836  ip0->payload_length =
1837  clib_host_to_net_u16 (payload_length);
1838 
1839  icmp6_router_advertisement_header_t *rh0 =
1840  (icmp6_router_advertisement_header_t *) (ip0 + 1);
1841  rh0->icmp.checksum =
1842  ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0,
1843  &bogus_length);
1844  ASSERT (bogus_length == 0);
1845 
1846  /* setup output if and adjacency */
1847  vnet_buffer (p0)->sw_if_index[VLIB_RX] =
1849 
1850  if (is_solicitation)
1851  {
1852  ethernet_header_t *eth0;
1853  /* Reuse current MAC header, copy SMAC to DMAC and
1854  * interface MAC to SMAC */
1855  vlib_buffer_reset (p0);
1856  eth0 = vlib_buffer_get_current (p0);
1857  clib_memcpy (eth0->dst_address, eth0->src_address,
1858  6);
1859  clib_memcpy (eth0->src_address, eth_if0->address,
1860  6);
1861  next0 =
1862  is_dropped ? next0 :
1864  vnet_buffer (p0)->sw_if_index[VLIB_TX] =
1865  sw_if_index0;
1866  }
1867  else
1868  {
1869  adj_index0 = radv_info->mcast_adj_index;
1870  if (adj_index0 == 0)
1871  error0 = ICMP6_ERROR_DST_LOOKUP_MISS;
1872  else
1873  {
1874  next0 =
1875  is_dropped ? next0 :
1877  vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
1878  adj_index0;
1879  }
1880  }
1881  p0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
1882 
1883  radv_info->n_solicitations_dropped += is_dropped;
1884  radv_info->n_solicitations_rcvd += is_solicitation;
1885 
1886  if ((error0 == ICMP6_ERROR_NONE) && !is_dropped)
1887  {
1888  radv_info->n_advertisements_sent++;
1889  n_advertisements_sent++;
1890  }
1891  }
1892  }
1893  }
1894 
1895  drop0:
1896  p0->error = error_node->errors[error0];
1897 
1898  if (error0 != ICMP6_ERROR_NONE)
1899  vlib_error_count (vm, error_node->node_index, error0, 1);
1900 
1901  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1902  to_next, n_left_to_next,
1903  bi0, next0);
1904 
1905  }
1906 
1907  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1908  }
1909 
1910  /* Account for router advertisements sent. */
1911  vlib_error_count (vm, error_node->node_index,
1912  ICMP6_ERROR_ROUTER_ADVERTISEMENTS_TX,
1913  n_advertisements_sent);
1914 
1915  return frame->n_vectors;
1916 }
1917 
1918  /* validate advertised info for consistancy (see RFC-4861 section 6.2.7) - log any inconsistencies, packet will always be dropped */
1921  vlib_node_runtime_t * node, vlib_frame_t * frame)
1922 {
1923  vnet_main_t *vnm = vnet_get_main ();
1925  uword n_packets = frame->n_vectors;
1926  u32 *from, *to_next;
1927  u32 n_left_from, n_left_to_next, next_index;
1928  u32 n_advertisements_rcvd = 0;
1929 
1930  vlib_node_runtime_t *error_node =
1932 
1933  from = vlib_frame_vector_args (frame);
1934  n_left_from = n_packets;
1935  next_index = node->cached_next_index;
1936 
1937  if (node->flags & VLIB_NODE_FLAG_TRACE)
1938  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
1939  /* stride */ 1,
1940  sizeof (icmp6_input_trace_t));
1941 
1942  while (n_left_from > 0)
1943  {
1944  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1945 
1946  while (n_left_from > 0 && n_left_to_next > 0)
1947  {
1948  vlib_buffer_t *p0;
1949  ip6_header_t *ip0;
1950  ip6_radv_t *radv_info = 0;
1951  icmp6_router_advertisement_header_t *h0;
1952  u32 bi0, options_len0, sw_if_index0, next0, error0;
1953 
1954  bi0 = to_next[0] = from[0];
1955 
1956  from += 1;
1957  to_next += 1;
1958  n_left_from -= 1;
1959  n_left_to_next -= 1;
1960 
1961  p0 = vlib_get_buffer (vm, bi0);
1962  ip0 = vlib_buffer_get_current (p0);
1963  h0 = ip6_next_header (ip0);
1964  options_len0 =
1965  clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
1966 
1967  error0 = ICMP6_ERROR_NONE;
1968  sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1969 
1970  /* Check that source address is link-local */
1971  error0 = (!ip6_address_is_link_local_unicast (&ip0->src_address)) ?
1972  ICMP6_ERROR_ROUTER_ADVERTISEMENT_SOURCE_NOT_LINK_LOCAL : error0;
1973 
1974  /* default is to drop */
1976 
1977  n_advertisements_rcvd++;
1978 
1979  if (error0 == ICMP6_ERROR_NONE)
1980  {
1981  vnet_sw_interface_t *sw_if0;
1982  ethernet_interface_t *eth_if0;
1983 
1984  sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
1986  eth_if0 =
1988 
1989  /* only support ethernet interface type for now */
1990  error0 =
1991  (!eth_if0) ? ICMP6_ERROR_ROUTER_SOLICITATION_UNSUPPORTED_INTF
1992  : error0;
1993 
1994  if (error0 == ICMP6_ERROR_NONE)
1995  {
1996  u32 ri;
1997 
1998  /* look up the radv_t information for this interface */
2000  sw_if_index0)
2001  {
2002  ri =
2003  nm->if_radv_pool_index_by_sw_if_index[sw_if_index0];
2004 
2005  if (ri != ~0)
2006  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
2007  }
2008 
2009  error0 =
2010  ((!radv_info) ?
2011  ICMP6_ERROR_ROUTER_SOLICITATION_RADV_NOT_CONFIG :
2012  error0);
2013 
2014  if (error0 == ICMP6_ERROR_NONE)
2015  {
2016  radv_info->keep_sending_rs = 0;
2017 
2018  ra_report_t r;
2019 
2020  r.sw_if_index = sw_if_index0;
2021  memcpy (r.router_address, &ip0->src_address, 16);
2022  r.current_hop_limit = h0->current_hop_limit;
2023  r.flags = h0->flags;
2025  clib_net_to_host_u16 (h0->router_lifetime_in_sec);
2027  clib_net_to_host_u32
2028  (h0->neighbor_reachable_time_in_msec);
2029  r.time_in_msec_between_retransmitted_neighbor_solicitations = clib_net_to_host_u32 (h0->time_in_msec_between_retransmitted_neighbor_solicitations);
2030  r.prefixes = 0;
2031 
2032  /* validate advertised information */
2033  if ((h0->current_hop_limit && radv_info->curr_hop_limit)
2034  && (h0->current_hop_limit !=
2035  radv_info->curr_hop_limit))
2036  {
2037  ip6_neighbor_syslog (vm, LOG_WARNING,
2038  "our AdvCurHopLimit on %U doesn't agree with %U",
2040  vnm, sw_if_index0,
2042  &ip0->src_address);
2043  }
2044 
2045  if ((h0->flags &
2047  != radv_info->adv_managed_flag)
2048  {
2049  ip6_neighbor_syslog (vm, LOG_WARNING,
2050  "our AdvManagedFlag on %U doesn't agree with %U",
2052  vnm, sw_if_index0,
2054  &ip0->src_address);
2055  }
2056 
2057  if ((h0->flags &
2059  != radv_info->adv_other_flag)
2060  {
2061  ip6_neighbor_syslog (vm, LOG_WARNING,
2062  "our AdvOtherConfigFlag on %U doesn't agree with %U",
2064  vnm, sw_if_index0,
2066  &ip0->src_address);
2067  }
2068 
2069  if ((h0->
2070  time_in_msec_between_retransmitted_neighbor_solicitations
2071  && radv_info->
2072  adv_time_in_msec_between_retransmitted_neighbor_solicitations)
2073  && (h0->
2074  time_in_msec_between_retransmitted_neighbor_solicitations
2075  !=
2076  clib_host_to_net_u32 (radv_info->
2077  adv_time_in_msec_between_retransmitted_neighbor_solicitations)))
2078  {
2079  ip6_neighbor_syslog (vm, LOG_WARNING,
2080  "our AdvRetransTimer on %U doesn't agree with %U",
2082  vnm, sw_if_index0,
2084  &ip0->src_address);
2085  }
2086 
2087  if ((h0->neighbor_reachable_time_in_msec &&
2089  (h0->neighbor_reachable_time_in_msec !=
2090  clib_host_to_net_u32
2092  {
2093  ip6_neighbor_syslog (vm, LOG_WARNING,
2094  "our AdvReachableTime on %U doesn't agree with %U",
2096  vnm, sw_if_index0,
2098  &ip0->src_address);
2099  }
2100 
2101  /* check for MTU or prefix options or .. */
2102  u8 *opt_hdr = (u8 *) (h0 + 1);
2103  while (options_len0 > 0)
2104  {
2105  icmp6_neighbor_discovery_option_header_t *o0 =
2106  (icmp6_neighbor_discovery_option_header_t *)
2107  opt_hdr;
2108  int opt_len = o0->n_data_u64s << 3;
2110  o0->type;
2111 
2112  if (options_len0 < 2)
2113  {
2114  ip6_neighbor_syslog (vm, LOG_ERR,
2115  "malformed RA packet on %U from %U",
2117  vnm, sw_if_index0,
2119  &ip0->src_address);
2120  break;
2121  }
2122 
2123  if (opt_len == 0)
2124  {
2125  ip6_neighbor_syslog (vm, LOG_ERR,
2126  " zero length option in RA on %U from %U",
2128  vnm, sw_if_index0,
2130  &ip0->src_address);
2131  break;
2132  }
2133  else if (opt_len > options_len0)
2134  {
2135  ip6_neighbor_syslog (vm, LOG_ERR,
2136  "option length in RA packet greater than total length on %U from %U",
2138  vnm, sw_if_index0,
2140  &ip0->src_address);
2141  break;
2142  }
2143 
2144  options_len0 -= opt_len;
2145  opt_hdr += opt_len;
2146 
2147  switch (option_type)
2148  {
2149  case ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address:
2150  {
2151  icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
2152  * h =
2153  (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
2154  *) (o0);
2155 
2156  if (opt_len < sizeof (*h))
2157  break;
2158 
2159  memcpy (r.slla, h->ethernet_address, 6);
2160  }
2161  break;
2162 
2163  case ICMP6_NEIGHBOR_DISCOVERY_OPTION_mtu:
2164  {
2165  icmp6_neighbor_discovery_mtu_option_t *h =
2166  (icmp6_neighbor_discovery_mtu_option_t
2167  *) (o0);
2168 
2169  if (opt_len < sizeof (*h))
2170  break;
2171 
2172  r.mtu = clib_net_to_host_u32 (h->mtu);
2173 
2174  if ((h->mtu && radv_info->adv_link_mtu) &&
2175  (h->mtu !=
2176  clib_host_to_net_u32
2177  (radv_info->adv_link_mtu)))
2178  {
2179  ip6_neighbor_syslog (vm, LOG_WARNING,
2180  "our AdvLinkMTU on %U doesn't agree with %U",
2182  vnm, sw_if_index0,
2184  &ip0->src_address);
2185  }
2186  }
2187  break;
2188 
2189  case ICMP6_NEIGHBOR_DISCOVERY_OPTION_prefix_information:
2190  {
2191  icmp6_neighbor_discovery_prefix_information_option_t
2192  * h =
2193  (icmp6_neighbor_discovery_prefix_information_option_t
2194  *) (o0);
2195 
2196  /* validate advertised prefix options */
2197  ip6_radv_prefix_t *pr_info;
2198  u32 preferred, valid;
2199 
2200  if (opt_len < sizeof (*h))
2201  break;
2202 
2204  vec_len (r.prefixes));
2207  vec_len (r.prefixes) - 1);
2208 
2209  preferred =
2210  clib_net_to_host_u32 (h->preferred_time);
2211  valid = clib_net_to_host_u32 (h->valid_time);
2212 
2213  prefix->preferred_time = preferred;
2214  prefix->valid_time = valid;
2215  prefix->flags = h->flags & 0xc0;
2216  prefix->dst_address_length =
2217  h->dst_address_length;
2218  prefix->dst_address = h->dst_address;
2219 
2220  /* look for matching prefix - if we our advertising it, it better be consistant */
2221  /* *INDENT-OFF* */
2222  pool_foreach (pr_info, radv_info->adv_prefixes_pool,
2223  ({
2224 
2225  ip6_address_t mask;
2226  ip6_address_mask_from_width(&mask, pr_info->prefix_len);
2227 
2228  if(pr_info->enabled &&
2229  (pr_info->prefix_len == h->dst_address_length) &&
2230  ip6_address_is_equal_masked (&pr_info->prefix, &h->dst_address, &mask))
2231  {
2232  /* found it */
2233  if(!pr_info->decrement_lifetime_flag &&
2234  valid != pr_info->adv_valid_lifetime_in_secs)
2235  {
2236  ip6_neighbor_syslog(vm, LOG_WARNING,
2237  "our ADV validlifetime on %U for %U does not agree with %U",
2238  format_vnet_sw_if_index_name, vnm, sw_if_index0,format_ip6_address, &pr_info->prefix,
2239  format_ip6_address, &h->dst_address);
2240  }
2241  if(!pr_info->decrement_lifetime_flag &&
2242  preferred != pr_info->adv_pref_lifetime_in_secs)
2243  {
2244  ip6_neighbor_syslog(vm, LOG_WARNING,
2245  "our ADV preferredlifetime on %U for %U does not agree with %U",
2246  format_vnet_sw_if_index_name, vnm, sw_if_index0,format_ip6_address, &pr_info->prefix,
2247  format_ip6_address, &h->dst_address);
2248  }
2249  }
2250  break;
2251  }));
2252  /* *INDENT-ON* */
2253  break;
2254  }
2255  default:
2256  /* skip this one */
2257  break;
2258  }
2259  }
2260  ra_publish (&r);
2261  }
2262  }
2263  }
2264 
2265  p0->error = error_node->errors[error0];
2266 
2267  if (error0 != ICMP6_ERROR_NONE)
2268  vlib_error_count (vm, error_node->node_index, error0, 1);
2269 
2270  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2271  to_next, n_left_to_next,
2272  bi0, next0);
2273  }
2274 
2275  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2276  }
2277 
2278  /* Account for router advertisements received. */
2279  vlib_error_count (vm, error_node->node_index,
2280  ICMP6_ERROR_ROUTER_ADVERTISEMENTS_RX,
2281  n_advertisements_rcvd);
2282 
2283  return frame->n_vectors;
2284 }
2285 
2286 static inline f64
2288 {
2289  static u32 seed = 0;
2290  static u8 seed_set = 0;
2291  if (!seed_set)
2292  {
2293  seed = random_default_seed ();
2294  seed_set = 1;
2295  }
2296  return random_f64 (&seed) * (to - from) + from;
2297 }
2298 
2299 static inline u8
2301 {
2302  vnet_main_t *vnm = vnet_get_main ();
2303  vnet_hw_interface_t *hw_if = vnet_get_sup_hw_interface (vnm, sw_if_index);
2304  if (!hw_if->hw_address)
2305  return 1;
2306  clib_memcpy (address, hw_if->hw_address, 6);
2307  return 0;
2308 }
2309 
2310 static inline vlib_buffer_t *
2312 {
2313  u32 bi0;
2314  vlib_buffer_t *p0;
2316  icmp6_router_solicitation_header_t *rh;
2317  u16 payload_length;
2318  int bogus_length;
2319  u32 sw_if_index;
2320 
2321  sw_if_index = radv_info->sw_if_index;
2322 
2323  if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
2324  {
2325  clib_warning ("buffer allocation failure");
2326  return 0;
2327  }
2328 
2329  p0 = vlib_get_buffer (vm, bi0);
2333  p0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
2334 
2335  vnet_buffer (p0)->sw_if_index[VLIB_RX] = sw_if_index;
2336  vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index;
2337 
2338  vnet_buffer (p0)->ip.adj_index[VLIB_TX] = radv_info->mcast_adj_index;
2339 
2340  rh = vlib_buffer_get_current (p0);
2341  p0->current_length = sizeof (*rh);
2342 
2343  rh->neighbor.icmp.type = ICMP6_router_solicitation;
2344  rh->neighbor.icmp.code = 0;
2345  rh->neighbor.icmp.checksum = 0;
2346  rh->neighbor.reserved_must_be_zero = 0;
2347 
2348  rh->link_layer_option.header.type =
2349  ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
2350  if (0 != get_mac_address (sw_if_index,
2351  rh->link_layer_option.ethernet_address))
2352  {
2353  clib_warning ("interface with sw_if_index %u has no mac address",
2354  sw_if_index);
2355  vlib_buffer_free (vm, &bi0, 1);
2356  return 0;
2357  }
2358  rh->link_layer_option.header.n_data_u64s = 1;
2359 
2360  payload_length = sizeof (rh->neighbor) + sizeof (u64);
2361 
2362  rh->ip.ip_version_traffic_class_and_flow_label =
2363  clib_host_to_net_u32 (0x6 << 28);
2364  rh->ip.payload_length = clib_host_to_net_u16 (payload_length);
2365  rh->ip.protocol = IP_PROTOCOL_ICMP6;
2366  rh->ip.hop_limit = 255;
2367  rh->ip.src_address = radv_info->link_local_address;
2368  /* set address ff02::2 */
2369  rh->ip.dst_address.as_u64[0] = clib_host_to_net_u64 (0xff02ULL << 48);
2370  rh->ip.dst_address.as_u64[1] = clib_host_to_net_u64 (2);
2371 
2372  rh->neighbor.icmp.checksum = ip6_tcp_udp_icmp_compute_checksum (vm, p0,
2373  &rh->ip,
2374  &bogus_length);
2375 
2376  return p0;
2377 }
2378 
2379 static inline void
2381 {
2382  u32 bi0;
2383 
2384  ra->keep_sending_rs = 0;
2385  if (ra->buffer)
2386  {
2387  bi0 = vlib_get_buffer_index (vm, ra->buffer);
2388  vlib_buffer_free (vm, &bi0, 1);
2389  ra->buffer = 0;
2390  }
2391 }
2392 
2393 static inline bool
2394 check_send_rs (vlib_main_t * vm, ip6_radv_t * radv_info, f64 current_time,
2395  f64 * due_time)
2396 {
2397  vlib_buffer_t *p0;
2398  vlib_frame_t *f;
2399  u32 *to_next;
2400  u32 next_index;
2401  vlib_buffer_t *c0;
2402  u32 ci0;
2403 
2405 
2406  if (!radv_info->keep_sending_rs)
2407  return false;
2408 
2409  params = &radv_info->params;
2410 
2411  if (radv_info->due_time > current_time)
2412  {
2413  *due_time = radv_info->due_time;
2414  return true;
2415  }
2416 
2417  p0 = radv_info->buffer;
2418 
2419  next_index = ip6_rewrite_mcast_node.index;
2420 
2421  c0 = vlib_buffer_copy (vm, p0);
2422  ci0 = vlib_get_buffer_index (vm, c0);
2423 
2424  f = vlib_get_frame_to_node (vm, next_index);
2425  to_next = vlib_frame_vector_args (f);
2426  to_next[0] = ci0;
2427  f->n_vectors = 1;
2428  vlib_put_frame_to_node (vm, next_index, f);
2429 
2430  if (params->mrc != 0 && --radv_info->n_left == 0)
2431  stop_sending_rs (vm, radv_info);
2432  else
2433  {
2434  radv_info->sleep_interval =
2435  (2 + random_f64_from_to (-0.1, 0.1)) * radv_info->sleep_interval;
2436  if (radv_info->sleep_interval > params->mrt)
2437  radv_info->sleep_interval =
2438  (1 + random_f64_from_to (-0.1, 0.1)) * params->mrt;
2439 
2440  radv_info->due_time = current_time + radv_info->sleep_interval;
2441 
2442  if (params->mrd != 0
2443  && current_time > radv_info->start_time + params->mrd)
2444  stop_sending_rs (vm, radv_info);
2445  else
2446  *due_time = radv_info->due_time;
2447  }
2448 
2449  return radv_info->keep_sending_rs;
2450 }
2451 
2452 static uword
2454  vlib_frame_t * f0)
2455 {
2457  ip6_radv_t *radv_info;
2458  uword *event_data = 0;
2459  f64 sleep_time = 1e9;
2460  f64 current_time;
2461  f64 due_time;
2462  f64 dt = 0;
2463 
2464  while (true)
2465  {
2466  vlib_process_wait_for_event_or_clock (vm, sleep_time);
2467  vlib_process_get_events (vm, &event_data);
2468  vec_reset_length (event_data);
2469 
2470  current_time = vlib_time_now (vm);
2471  do
2472  {
2473  due_time = current_time + 1e9;
2474  /* *INDENT-OFF* */
2475  pool_foreach (radv_info, nm->if_radv_pool,
2476  ({
2477  if (check_send_rs (vm, radv_info, current_time, &dt)
2478  && (dt < due_time))
2479  due_time = dt;
2480  }));
2481  /* *INDENT-ON* */
2482  current_time = vlib_time_now (vm);
2483  }
2484  while (due_time < current_time);
2485 
2486  sleep_time = due_time - current_time;
2487  }
2488 
2489  return 0;
2490 }
2491 
2492 /* *INDENT-OFF* */
2494  .function = send_rs_process,
2495  .type = VLIB_NODE_TYPE_PROCESS,
2496  .name = "send-rs-process",
2497 };
2498 /* *INDENT-ON* */
2499 
2500 void
2503  params)
2504 {
2506  u32 rai;
2507  ip6_radv_t *ra = 0;
2508 
2509  ASSERT (~0 != sw_if_index);
2510 
2512  ra = pool_elt_at_index (nm->if_radv_pool, rai);
2513 
2514  stop_sending_rs (vm, ra);
2515 
2516  if (!stop)
2517  {
2518  ra->keep_sending_rs = 1;
2519  ra->params = *params;
2520  ra->n_left = params->mrc;
2521  ra->start_time = vlib_time_now (vm);
2522  ra->sleep_interval = (1 + random_f64_from_to (-0.1, 0.1)) * params->irt;
2523  ra->due_time = 0; /* send first packet ASAP */
2524  ra->buffer = create_buffer_for_rs (vm, ra);
2525  if (!ra->buffer)
2526  ra->keep_sending_rs = 0;
2527  else
2529  }
2530 }
2531 
2532 /**
2533  * @brief Add a multicast Address to the advertised MLD set
2534  */
2535 static void
2537 {
2538  ip6_mldp_group_t *mcast_group_info;
2539  uword *p;
2540 
2541  /* lookup mldp info for this interface */
2542  p = mhash_get (&radv_info->address_to_mldp_index, addr);
2543  mcast_group_info =
2544  p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
2545 
2546  /* add address */
2547  if (!mcast_group_info)
2548  {
2549  /* add */
2550  u32 mi;
2551  pool_get (radv_info->mldp_group_pool, mcast_group_info);
2552 
2553  mi = mcast_group_info - radv_info->mldp_group_pool;
2554  mhash_set (&radv_info->address_to_mldp_index, addr, mi, /* old_value */
2555  0);
2556 
2557  mcast_group_info->type = 4;
2558  mcast_group_info->mcast_source_address_pool = 0;
2559  mcast_group_info->num_sources = 0;
2560  clib_memcpy (&mcast_group_info->mcast_address, addr,
2561  sizeof (ip6_address_t));
2562  }
2563 }
2564 
2565 /**
2566  * @brief Delete a multicast Address from the advertised MLD set
2567  */
2568 static void
2570 {
2571  ip6_mldp_group_t *mcast_group_info;
2572  uword *p;
2573 
2574  p = mhash_get (&radv_info->address_to_mldp_index, &addr);
2575  mcast_group_info =
2576  p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
2577 
2578  if (mcast_group_info)
2579  {
2580  mhash_unset (&radv_info->address_to_mldp_index, &addr,
2581  /* old_value */ 0);
2582  pool_put (radv_info->mldp_group_pool, mcast_group_info);
2583  }
2584 }
2585 
2586 /**
2587  * @brief Add a multicast Address to the advertised MLD set
2588  */
2589 static void
2593 {
2595 
2596  ip6_set_reserved_multicast_address (&addr, scope, group);
2597 
2598  ip6_neighbor_add_mld_prefix (a, &addr);
2599 }
2600 
2601 /**
2602  * @brief create and initialize router advertisement parameters with default
2603  * values for this intfc
2604  */
2605 u32
2607  u32 sw_if_index, u32 is_add)
2608 {
2610  ip6_radv_t *a = 0;
2611  u32 ri = ~0;
2612  vnet_sw_interface_t *sw_if0;
2613  ethernet_interface_t *eth_if0 = 0;
2614 
2615  /* lookup radv container - ethernet interfaces only */
2616  sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
2617  if (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
2618  eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
2619 
2620  if (!eth_if0)
2621  return ri;
2622 
2624  ~0);
2626 
2627  if (ri != ~0)
2628  {
2629  a = pool_elt_at_index (nm->if_radv_pool, ri);
2630 
2631  if (!is_add)
2632  {
2633  ip6_radv_prefix_t *p;
2634  ip6_mldp_group_t *m;
2635 
2636  /* release the lock on the interface's mcast adj */
2638 
2639  /* clean up prefix and MDP pools */
2640  /* *INDENT-OFF* */
2642  ({
2643  mhash_unset (&a->address_to_prefix_index, &p->prefix, 0);
2644  }));
2645  pool_flush (m, a->mldp_group_pool,
2646  ({
2647  mhash_unset (&a->address_to_mldp_index, &m->mcast_address, 0);
2648  }));
2649  /* *INDENT-ON* */
2650 
2653 
2656 
2657  if (a->keep_sending_rs)
2658  a->keep_sending_rs = 0;
2659 
2660  pool_put (nm->if_radv_pool, a);
2662  ri = ~0;
2663  }
2664  }
2665  else
2666  {
2667  if (is_add)
2668  {
2669  pool_get (nm->if_radv_pool, a);
2670 
2671  ri = a - nm->if_radv_pool;
2673 
2674  /* initialize default values (most of which are zero) */
2675  clib_memset (a, 0, sizeof (a[0]));
2676 
2677  a->sw_if_index = sw_if_index;
2682 
2683  /* send ll address source address option */
2684  a->adv_link_layer_address = 1;
2685 
2689  a->seed = (u32) clib_cpu_time_now ();
2690  (void) random_u32 (&a->seed);
2691  a->randomizer = clib_cpu_time_now ();
2692  (void) random_u64 (&a->randomizer);
2693 
2697 
2698  /* deafult is to send */
2699  a->send_radv = 1;
2700 
2701  /* fill in radv_info for this interface that will be needed later */
2702  a->adv_link_mtu =
2703  vnet_sw_interface_get_mtu (vnm, sw_if_index, VNET_MTU_IP6);
2704 
2705  clib_memcpy (a->link_layer_address, eth_if0->address, 6);
2706 
2707  /* fill in default link-local address (this may be overridden) */
2709  (&a->link_local_address, eth_if0->address);
2710 
2711  mhash_init (&a->address_to_prefix_index, sizeof (uword),
2712  sizeof (ip6_address_t));
2713  mhash_init (&a->address_to_mldp_index, sizeof (uword),
2714  sizeof (ip6_address_t));
2715 
2717  VNET_LINK_IP6,
2718  sw_if_index);
2719 
2720  a->keep_sending_rs = 0;
2721 
2722  /* add multicast groups we will always be reporting */
2724  IP6_MULTICAST_SCOPE_link_local,
2725  IP6_MULTICAST_GROUP_ID_all_hosts);
2727  IP6_MULTICAST_SCOPE_link_local,
2728  IP6_MULTICAST_GROUP_ID_all_routers);
2730  IP6_MULTICAST_SCOPE_link_local,
2731  IP6_MULTICAST_GROUP_ID_mldv2_routers);
2732  }
2733  }
2734  return ri;
2735 }
2736 
2737 /* send an mldpv2 report */
2738 static void
2740 {
2741  vnet_main_t *vnm = vnet_get_main ();
2742  vlib_main_t *vm = vnm->vlib_main;
2744  vnet_sw_interface_t *sw_if0;
2745  ethernet_interface_t *eth_if0;
2746  u32 ri;
2747  int bogus_length;
2748 
2749  ip6_radv_t *radv_info;
2750  u16 payload_length;
2751  vlib_buffer_t *b0;
2752  ip6_header_t *ip0;
2753  u32 *to_next;
2754  vlib_frame_t *f;
2755  u32 bo0;
2756  u32 n_to_alloc = 1;
2757  u32 n_allocated;
2758 
2759  icmp6_multicast_listener_report_header_t *rh0;
2760  icmp6_multicast_listener_report_packet_t *rp0;
2761 
2762  sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
2764  eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
2765 
2766  if (!eth_if0 || !vnet_sw_interface_is_admin_up (vnm, sw_if_index))
2767  return;
2768 
2769  /* look up the radv_t information for this interface */
2771  ~0);
2772 
2774 
2775  if (ri == ~0)
2776  return;
2777 
2778  /* send report now - build a mldpv2 report packet */
2779  n_allocated = vlib_buffer_alloc (vm, &bo0, n_to_alloc);
2780  if (PREDICT_FALSE (n_allocated == 0))
2781  {
2782  alloc_fail:
2783  clib_warning ("buffer allocation failure");
2784  return;
2785  }
2786 
2787  b0 = vlib_get_buffer (vm, bo0);
2788 
2789  /* adjust the sizeof the buffer to just include the ipv6 header */
2790  b0->current_length = sizeof (icmp6_multicast_listener_report_packet_t);
2791 
2792  payload_length = sizeof (icmp6_multicast_listener_report_header_t);
2793 
2794  b0->error = ICMP6_ERROR_NONE;
2795 
2796  rp0 = vlib_buffer_get_current (b0);
2797  ip0 = (ip6_header_t *) & rp0->ip;
2798  rh0 = (icmp6_multicast_listener_report_header_t *) & rp0->report_hdr;
2799 
2800  clib_memset (rp0, 0x0, sizeof (icmp6_multicast_listener_report_packet_t));
2801 
2803  clib_host_to_net_u32 (0x6 << 28);
2804 
2805  ip0->protocol = IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS;
2806  /* for DEBUG - vnet driver won't seem to emit router alerts */
2807  /* ip0->protocol = IP_PROTOCOL_ICMP6; */
2808  ip0->hop_limit = 1;
2809 
2810  rh0->icmp.type = ICMP6_multicast_listener_report_v2;
2811 
2812  /* source address MUST be the link-local address */
2813  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
2814  ip0->src_address = radv_info->link_local_address;
2815 
2816  /* destination is all mldpv2 routers */
2818  IP6_MULTICAST_SCOPE_link_local,
2819  IP6_MULTICAST_GROUP_ID_mldv2_routers);
2820 
2821  /* add reports here */
2822  ip6_mldp_group_t *m;
2823  int num_addr_records = 0;
2824  icmp6_multicast_address_record_t rr;
2825 
2826  /* fill in the hop-by-hop extension header (router alert) info */
2827  rh0->ext_hdr.next_hdr = IP_PROTOCOL_ICMP6;
2828  rh0->ext_hdr.n_data_u64s = 0;
2829 
2830  rh0->alert.type = IP6_MLDP_ALERT_TYPE;
2831  rh0->alert.len = 2;
2832  rh0->alert.value = 0;
2833 
2834  rh0->pad.type = 1;
2835  rh0->pad.len = 0;
2836 
2837  rh0->icmp.checksum = 0;
2838 
2839  /* *INDENT-OFF* */
2840  pool_foreach (m, radv_info->mldp_group_pool,
2841  ({
2842  rr.type = m->type;
2843  rr.aux_data_len_u32s = 0;
2844  rr.num_sources = clib_host_to_net_u16 (m->num_sources);
2845  clib_memcpy(&rr.mcast_addr, &m->mcast_address, sizeof(ip6_address_t));
2846 
2847  num_addr_records++;
2848 
2849  if(vlib_buffer_add_data
2850  (vm, vlib_buffer_get_free_list_index (b0), &bo0,
2851  (void *)&rr, sizeof(icmp6_multicast_address_record_t)))
2852  {
2853  vlib_buffer_free (vm, &bo0, 1);
2854  goto alloc_fail;
2855  }
2856 
2857  payload_length += sizeof( icmp6_multicast_address_record_t);
2858  }));
2859  /* *INDENT-ON* */
2860 
2861  rh0->rsvd = 0;
2862  rh0->num_addr_records = clib_host_to_net_u16 (num_addr_records);
2863 
2864  /* update lengths */
2865  ip0->payload_length = clib_host_to_net_u16 (payload_length);
2866 
2867  rh0->icmp.checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0,
2868  &bogus_length);
2869  ASSERT (bogus_length == 0);
2870 
2871  /*
2872  * OK to override w/ no regard for actual FIB, because
2873  * ip6-rewrite only looks at the adjacency.
2874  */
2875  vnet_buffer (b0)->sw_if_index[VLIB_RX] =
2877 
2878  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = radv_info->mcast_adj_index;
2879  b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
2880 
2881  vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "ip6-rewrite-mcast");
2882 
2883  f = vlib_get_frame_to_node (vm, node->index);
2884  to_next = vlib_frame_vector_args (f);
2885  to_next[0] = bo0;
2886  f->n_vectors = 1;
2887 
2888  vlib_put_frame_to_node (vm, node->index, f);
2889  return;
2890 }
2891 
2892 /* *INDENT-OFF* */
2894 {
2895  .function = icmp6_router_solicitation,
2896  .name = "icmp6-router-solicitation",
2897 
2898  .vector_size = sizeof (u32),
2899 
2900  .format_trace = format_icmp6_input_trace,
2901 
2902  .n_next_nodes = ICMP6_ROUTER_SOLICITATION_N_NEXT,
2903  .next_nodes = {
2904  [ICMP6_ROUTER_SOLICITATION_NEXT_DROP] = "ip6-drop",
2905  [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW] = "ip6-rewrite-mcast",
2906  [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX] = "interface-output",
2907  },
2908 };
2909 /* *INDENT-ON* */
2910 
2911 /* send a RA or update the timer info etc.. */
2912 static uword
2914  vlib_node_runtime_t * node,
2915  vlib_frame_t * frame)
2916 {
2917  vnet_main_t *vnm = vnet_get_main ();
2919  ip6_radv_t *radv_info;
2920  vlib_frame_t *f = 0;
2921  u32 n_this_frame = 0;
2922  u32 n_left_to_next = 0;
2923  u32 *to_next = 0;
2924  u32 bo0;
2925  icmp6_router_solicitation_header_t *h0;
2926  vlib_buffer_t *b0;
2927  f64 now = vlib_time_now (vm);
2928 
2929  /* Interface ip6 radv info list */
2930  /* *INDENT-OFF* */
2931  pool_foreach (radv_info, nm->if_radv_pool,
2932  ({
2933  if( !vnet_sw_interface_is_admin_up (vnm, radv_info->sw_if_index))
2934  {
2935  radv_info->initial_adverts_sent = radv_info->initial_adverts_count-1;
2936  radv_info->next_multicast_time = now;
2937  radv_info->last_multicast_time = now;
2938  radv_info->last_radv_time = 0;
2939  radv_info->all_routers_mcast = 0;
2940  continue;
2941  }
2942 
2943  /* Make sure that we've joined the all-routers multicast group */
2944  if(!radv_info->all_routers_mcast)
2945  {
2946  /* send MDLP_REPORT_EVENT message */
2947  ip6_neighbor_send_mldpv2_report(radv_info->sw_if_index);
2948  radv_info->all_routers_mcast = 1;
2949  }
2950 
2951  /* is it time to send a multicast RA on this interface? */
2952  if(radv_info->send_radv && (now >= radv_info->next_multicast_time))
2953  {
2954  u32 n_to_alloc = 1;
2955  u32 n_allocated;
2956 
2957  f64 rfn = (radv_info->max_radv_interval - radv_info->min_radv_interval) *
2958  random_f64 (&radv_info->seed) + radv_info->min_radv_interval;
2959 
2960  /* multicast send - compute next multicast send time */
2961  if( radv_info->initial_adverts_sent > 0)
2962  {
2963  radv_info->initial_adverts_sent--;
2964  if(rfn > radv_info-> initial_adverts_interval)
2965  rfn = radv_info-> initial_adverts_interval;
2966 
2967  /* check to see if we are ceasing to send */
2968  if( radv_info->initial_adverts_sent == 0)
2969  if(radv_info->cease_radv)
2970  radv_info->send_radv = 0;
2971  }
2972 
2973  radv_info->next_multicast_time = rfn + now;
2974  radv_info->last_multicast_time = now;
2975 
2976  /* send advert now - build a "solicted" router advert with unspecified source address */
2977  n_allocated = vlib_buffer_alloc (vm, &bo0, n_to_alloc);
2978 
2979  if (PREDICT_FALSE(n_allocated == 0))
2980  {
2981  clib_warning ("buffer allocation failure");
2982  continue;
2983  }
2984  b0 = vlib_get_buffer (vm, bo0);
2985  b0->current_length = sizeof( icmp6_router_solicitation_header_t);
2986  b0->error = ICMP6_ERROR_NONE;
2987  vnet_buffer (b0)->sw_if_index[VLIB_RX] = radv_info->sw_if_index;
2988 
2989  h0 = vlib_buffer_get_current (b0);
2990 
2991  clib_memset (h0, 0, sizeof (icmp6_router_solicitation_header_t));
2992 
2993  h0->ip.ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (0x6 << 28);
2994  h0->ip.payload_length = clib_host_to_net_u16 (sizeof (icmp6_router_solicitation_header_t)
2995  - STRUCT_OFFSET_OF (icmp6_router_solicitation_header_t, neighbor));
2996  h0->ip.protocol = IP_PROTOCOL_ICMP6;
2997  h0->ip.hop_limit = 255;
2998 
2999  /* set src/dst address as "unspecified" this marks this packet as internally generated rather than recieved */
3000  h0->ip.src_address.as_u64[0] = 0;
3001  h0->ip.src_address.as_u64[1] = 0;
3002 
3003  h0->ip.dst_address.as_u64[0] = 0;
3004  h0->ip.dst_address.as_u64[1] = 0;
3005 
3006  h0->neighbor.icmp.type = ICMP6_router_solicitation;
3007 
3008  if (PREDICT_FALSE(f == 0))
3009  {
3011  to_next = vlib_frame_vector_args (f);
3012  n_left_to_next = VLIB_FRAME_SIZE;
3013  n_this_frame = 0;
3014  }
3015 
3016  n_this_frame++;
3017  n_left_to_next--;
3018  to_next[0] = bo0;
3019  to_next += 1;
3020 
3021  if (PREDICT_FALSE(n_left_to_next == 0))
3022  {
3023  f->n_vectors = n_this_frame;
3025  f = 0;
3026  }
3027  }
3028  }));
3029  /* *INDENT-ON* */
3030 
3031  if (f)
3032  {
3033  ASSERT (n_this_frame);
3034  f->n_vectors = n_this_frame;
3036  }
3037  return 0;
3038 }
3039 
3040 static uword
3042  vlib_node_runtime_t * node,
3043  vlib_frame_t * frame)
3044 {
3045  uword event_type;
3047 
3048  /* init code here */
3049 
3050  while (1)
3051  {
3052  vlib_process_wait_for_event_or_clock (vm, 1. /* seconds */ );
3053 
3054  event_data = vlib_process_get_event_data (vm, &event_type);
3055 
3056  if (!event_data)
3057  {
3058  /* No events found: timer expired. */
3059  /* process interface list and send RAs as appropriate, update timer info */
3060  ip6_neighbor_process_timer_event (vm, node, frame);
3061  }
3062  else
3063  {
3064  switch (event_type)
3065  {
3066 
3067  case ICMP6_ND_EVENT_INIT:
3068  break;
3069 
3070  case ~0:
3071  break;
3072 
3073  default:
3074  ASSERT (0);
3075  }
3076 
3077  if (event_data)
3078  _vec_len (event_data) = 0;
3079  }
3080  }
3081  return frame->n_vectors;
3082 }
3083 
3084 /* *INDENT-OFF* */
3086 {
3087  .function = icmp6_router_advertisement,
3088  .name = "icmp6-router-advertisement",
3089 
3090  .vector_size = sizeof (u32),
3091 
3092  .format_trace = format_icmp6_input_trace,
3093 
3094  .n_next_nodes = 1,
3095  .next_nodes = {
3096  [0] = "ip6-drop",
3097  },
3098 };
3099 /* *INDENT-ON* */
3100 
3102 
3104  .name = "ip6-icmp-neighbor-discovery-event-process",
3105  .type = VLIB_NODE_TYPE_PROCESS,
3106 };
3107 
3108 static uword
3110  vlib_node_runtime_t * node, vlib_frame_t * frame)
3111 {
3112  return icmp6_neighbor_solicitation_or_advertisement (vm, node, frame,
3113  /* is_solicitation */
3114  1);
3115 }
3116 
3117 static uword
3119  vlib_node_runtime_t * node,
3120  vlib_frame_t * frame)
3121 {
3122  return icmp6_neighbor_solicitation_or_advertisement (vm, node, frame,
3123  /* is_solicitation */
3124  0);
3125 }
3126 
3127 /* *INDENT-OFF* */
3129 {
3130  .function = icmp6_neighbor_solicitation,
3131  .name = "icmp6-neighbor-solicitation",
3132 
3133  .vector_size = sizeof (u32),
3134 
3135  .format_trace = format_icmp6_input_trace,
3136 
3137  .n_next_nodes = ICMP6_NEIGHBOR_SOLICITATION_N_NEXT,
3138  .next_nodes = {
3140  [ICMP6_NEIGHBOR_SOLICITATION_NEXT_REPLY] = "interface-output",
3141  },
3142 };
3143 /* *INDENT-ON* */
3144 
3145 /* *INDENT-OFF* */
3147 {
3148  .function = icmp6_neighbor_advertisement,
3149  .name = "icmp6-neighbor-advertisement",
3150 
3151  .vector_size = sizeof (u32),
3152 
3153  .format_trace = format_icmp6_input_trace,
3154 
3155  .n_next_nodes = 1,
3156  .next_nodes = {
3157  [0] = "ip6-drop",
3158  },
3159 };
3160 /* *INDENT-ON* */
3161 
3162 typedef enum
3163 {
3168 
3169 typedef enum
3170 {
3175 
3176 static uword
3178  vlib_node_runtime_t * node,
3179  vlib_frame_t * frame, int is_glean)
3180 {
3181  vnet_main_t *vnm = vnet_get_main ();
3182  ip6_main_t *im = &ip6_main;
3183  ip_lookup_main_t *lm = &im->lookup_main;
3184  u32 *from, *to_next_drop;
3185  uword n_left_from, n_left_to_next_drop;
3186  u64 seed;
3187  u32 thread_index = vm->thread_index;
3188  int bogus_length;
3190 
3191  if (node->flags & VLIB_NODE_FLAG_TRACE)
3192  ip6_forward_next_trace (vm, node, frame, VLIB_TX);
3193 
3194  seed = throttle_seed (&im->nd_throttle, thread_index, vlib_time_now (vm));
3195 
3196  from = vlib_frame_vector_args (frame);
3197  n_left_from = frame->n_vectors;
3198 
3199  while (n_left_from > 0)
3200  {
3202  to_next_drop, n_left_to_next_drop);
3203 
3204  while (n_left_from > 0 && n_left_to_next_drop > 0)
3205  {
3206  u32 pi0, adj_index0, sw_if_index0, drop0, r0, next0;
3207  vnet_hw_interface_t *hw_if0;
3208  ip6_radv_t *radv_info;
3209  ip_adjacency_t *adj0;
3210  vlib_buffer_t *p0;
3211  ip6_header_t *ip0;
3212 
3213  pi0 = from[0];
3214 
3215  p0 = vlib_get_buffer (vm, pi0);
3216 
3217  adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
3218 
3219  ip0 = vlib_buffer_get_current (p0);
3220 
3221  adj0 = adj_get (adj_index0);
3222 
3223  if (!is_glean)
3224  {
3225  ip0->dst_address.as_u64[0] =
3226  adj0->sub_type.nbr.next_hop.ip6.as_u64[0];
3227  ip0->dst_address.as_u64[1] =
3228  adj0->sub_type.nbr.next_hop.ip6.as_u64[1];
3229  }
3230 
3231  sw_if_index0 = adj0->rewrite_header.sw_if_index;
3232  vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
3233 
3234  /* combine the address and interface for a hash */
3235  r0 = ip6_address_hash_to_u64 (&ip0->dst_address) ^ sw_if_index0;
3236 
3237  drop0 = throttle_check (&im->nd_throttle, thread_index, r0, seed);
3238 
3239  from += 1;
3240  n_left_from -= 1;
3241  to_next_drop[0] = pi0;
3242  to_next_drop += 1;
3243  n_left_to_next_drop -= 1;
3244 
3245  hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
3246 
3247  /* If the interface is link-down, drop the pkt */
3248  if (!(hw_if0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
3249  drop0 = 1;
3250 
3251  if (vec_len (nm->if_radv_pool_index_by_sw_if_index) > sw_if_index0)
3252  {
3253  u32 ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index0];
3254 
3255  if (ri != ~0)
3256  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3257  else
3258  drop0 = 1;
3259  }
3260  else
3261  drop0 = 1;
3262 
3263  /*
3264  * the adj has been updated to a rewrite but the node the DPO that got
3265  * us here hasn't - yet. no big deal. we'll drop while we wait.
3266  */
3268  drop0 = 1;
3269 
3270  p0->error =
3273 
3274  if (drop0)
3275  continue;
3276 
3277  {
3278  u32 bi0 = 0;
3279  icmp6_neighbor_solicitation_header_t *h0;
3280  vlib_buffer_t *b0;
3281 
3283  (vm, &im->discover_neighbor_packet_template, &bi0);
3284  if (!h0)
3285  continue;
3286 
3287  /* copy the persistent fields from the original */
3288  b0 = vlib_get_buffer (vm, bi0);
3289  clib_memcpy_fast (b0->opaque2, p0->opaque2, sizeof (p0->opaque2));
3290 
3291  /*
3292  * Build ethernet header.
3293  * Choose source address based on destination lookup
3294  * adjacency.
3295  */
3296  if (!ip6_src_address_for_packet (lm,
3297  sw_if_index0,
3298  &ip0->dst_address,
3299  &h0->ip.src_address))
3300  {
3301  /* There is no address on the interface */
3302  p0->error =
3304  vlib_buffer_free (vm, &bi0, 1);
3305  continue;
3306  }
3307 
3308  /*
3309  * Destination address is a solicited node multicast address.
3310  * We need to fill in
3311  * the low 24 bits with low 24 bits of target's address.
3312  */
3313  h0->ip.dst_address.as_u8[13] = ip0->dst_address.as_u8[13];
3314  h0->ip.dst_address.as_u8[14] = ip0->dst_address.as_u8[14];
3315  h0->ip.dst_address.as_u8[15] = ip0->dst_address.as_u8[15];
3316 
3317  h0->neighbor.target_address = ip0->dst_address;
3318 
3319  clib_memcpy (h0->link_layer_option.ethernet_address,
3320  hw_if0->hw_address, vec_len (hw_if0->hw_address));
3321 
3322  /* $$$$ appears we need this; why is the checksum non-zero? */
3323  h0->neighbor.icmp.checksum = 0;
3324  h0->neighbor.icmp.checksum =
3325  ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h0->ip,
3326  &bogus_length);
3327 
3328  ASSERT (bogus_length == 0);
3329 
3330  vlib_buffer_copy_trace_flag (vm, p0, bi0);
3331  vnet_buffer (b0)->sw_if_index[VLIB_TX]
3332  = vnet_buffer (p0)->sw_if_index[VLIB_TX];
3333 
3334  vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
3335  radv_info->mcast_adj_index;
3336 
3337  b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
3339 
3340  vlib_set_next_frame_buffer (vm, node, next0, bi0);
3341  }
3342  }
3343 
3345  n_left_to_next_drop);
3346  }
3347 
3348  return frame->n_vectors;
3349 }
3350 
3351 static uword
3353  vlib_node_runtime_t * node, vlib_frame_t * frame)
3354 {
3355  return (ip6_discover_neighbor_inline (vm, node, frame, 0));
3356 }
3357 
3358 static uword
3360 {
3361  return (ip6_discover_neighbor_inline (vm, node, frame, 1));
3362 }
3363 
3365  [IP6_DISCOVER_NEIGHBOR_ERROR_DROP] = "address overflow drops",
3366  [IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT] = "neighbor solicitations sent",
3368  = "no source address for ND solicitation",
3369 };
3370 
3371 /* *INDENT-OFF* */
3373 {
3374  .function = ip6_glean,
3375  .name = "ip6-glean",
3376  .vector_size = sizeof (u32),
3377  .format_trace = format_ip6_forward_next_trace,
3379  .error_strings = ip6_discover_neighbor_error_strings,
3380  .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
3381  .next_nodes =
3382  {
3383  [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "ip6-drop",
3384  [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "ip6-rewrite-mcast",
3385  },
3386 };
3388 {
3389  .function = ip6_discover_neighbor,
3390  .name = "ip6-discover-neighbor",
3391  .vector_size = sizeof (u32),
3392  .format_trace = format_ip6_forward_next_trace,
3394  .error_strings = ip6_discover_neighbor_error_strings,
3395  .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
3396  .next_nodes =
3397  {
3398  [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "ip6-drop",
3399  [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "ip6-rewrite-mcast",
3400  },
3401 };
3402 /* *INDENT-ON* */
3403 
3404 /* API support functions */
3405 int
3407  u8 suppress, u8 managed, u8 other,
3408  u8 ll_option, u8 send_unicast, u8 cease,
3409  u8 use_lifetime, u32 lifetime,
3410  u32 initial_count, u32 initial_interval,
3411  u32 max_interval, u32 min_interval, u8 is_no)
3412 {
3414  int error;
3415  u32 ri;
3416 
3417  /* look up the radv_t information for this interface */
3419  ~0);
3421  error = (ri != ~0) ? 0 : VNET_API_ERROR_INVALID_SW_IF_INDEX;
3422 
3423  if (!error)
3424  {
3425 
3426  ip6_radv_t *radv_info;
3427  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3428 
3429  if ((max_interval != 0) && (min_interval == 0))
3430  min_interval = .75 * max_interval;
3431 
3432  max_interval =
3433  (max_interval !=
3434  0) ? ((is_no) ? DEF_MAX_RADV_INTERVAL : max_interval) :
3435  radv_info->max_radv_interval;
3436  min_interval =
3437  (min_interval !=
3438  0) ? ((is_no) ? DEF_MIN_RADV_INTERVAL : min_interval) :
3439  radv_info->min_radv_interval;
3440  lifetime =
3441  (use_lifetime !=
3442  0) ? ((is_no) ? DEF_DEF_RTR_LIFETIME : lifetime) :
3443  radv_info->adv_router_lifetime_in_sec;
3444 
3445  if (lifetime)
3446  {
3447  if (lifetime > MAX_DEF_RTR_LIFETIME)
3448  lifetime = MAX_DEF_RTR_LIFETIME;
3449 
3450  if (lifetime <= max_interval)
3451  return VNET_API_ERROR_INVALID_VALUE;
3452  }
3453 
3454  if (min_interval != 0)
3455  {
3456  if ((min_interval > .75 * max_interval) || (min_interval < 3))
3457  return VNET_API_ERROR_INVALID_VALUE;
3458  }
3459 
3460  if ((initial_count > MAX_INITIAL_RTR_ADVERTISEMENTS) ||
3461  (initial_interval > MAX_INITIAL_RTR_ADVERT_INTERVAL))
3462  return VNET_API_ERROR_INVALID_VALUE;
3463 
3464  /*
3465  if "flag" is set and is_no is true then restore default value else set value corresponding to "flag"
3466  if "flag" is clear don't change corresponding value
3467  */
3468  radv_info->send_radv =
3469  (suppress != 0) ? ((is_no != 0) ? 1 : 0) : radv_info->send_radv;
3470  radv_info->adv_managed_flag =
3471  (managed != 0) ? ((is_no) ? 0 : 1) : radv_info->adv_managed_flag;
3472  radv_info->adv_other_flag =
3473  (other != 0) ? ((is_no) ? 0 : 1) : radv_info->adv_other_flag;
3474  radv_info->adv_link_layer_address =
3475  (ll_option !=
3476  0) ? ((is_no) ? 1 : 0) : radv_info->adv_link_layer_address;
3477  radv_info->send_unicast =
3478  (send_unicast != 0) ? ((is_no) ? 0 : 1) : radv_info->send_unicast;
3479  radv_info->cease_radv =
3480  (cease != 0) ? ((is_no) ? 0 : 1) : radv_info->cease_radv;
3481 
3482  radv_info->min_radv_interval = min_interval;
3483  radv_info->max_radv_interval = max_interval;
3484  radv_info->adv_router_lifetime_in_sec = lifetime;
3485 
3486  radv_info->initial_adverts_count =
3487  (initial_count !=
3488  0) ? ((is_no) ? MAX_INITIAL_RTR_ADVERTISEMENTS : initial_count) :
3489  radv_info->initial_adverts_count;
3490  radv_info->initial_adverts_interval =
3491  (initial_interval !=
3492  0) ? ((is_no) ? MAX_INITIAL_RTR_ADVERT_INTERVAL : initial_interval) :
3493  radv_info->initial_adverts_interval;
3494 
3495  /* restart */
3496  if ((cease != 0) && (is_no))
3497  radv_info->send_radv = 1;
3498 
3499  radv_info->initial_adverts_sent = radv_info->initial_adverts_count - 1;
3500  radv_info->next_multicast_time = vlib_time_now (vm);
3501  radv_info->last_multicast_time = vlib_time_now (vm);
3502  radv_info->last_radv_time = 0;
3503  }
3504  return (error);
3505 }
3506 
3507 int
3509  ip6_address_t * prefix_addr, u8 prefix_len,
3510  u8 use_default, u32 val_lifetime, u32 pref_lifetime,
3511  u8 no_advertise, u8 off_link, u8 no_autoconfig,
3512  u8 no_onlink, u8 is_no)
3513 {
3515  int error;
3516 
3517  u32 ri;
3518 
3519  /* look up the radv_t information for this interface */
3521  ~0);
3522 
3524 
3525  error = (ri != ~0) ? 0 : VNET_API_ERROR_INVALID_SW_IF_INDEX;
3526 
3527  if (!error)
3528  {
3529  f64 now = vlib_time_now (vm);
3530  ip6_radv_t *radv_info;
3531  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3532 
3533  /* prefix info add, delete or update */
3535 
3536  /* lookup prefix info for this address on this interface */
3537  uword *p = mhash_get (&radv_info->address_to_prefix_index, prefix_addr);
3538 
3539  prefix = p ? pool_elt_at_index (radv_info->adv_prefixes_pool, p[0]) : 0;
3540 
3541  if (is_no)
3542  {
3543  /* delete */
3544  if (!prefix)
3545  return VNET_API_ERROR_INVALID_VALUE; /* invalid prefix */
3546 
3547  if (prefix->prefix_len != prefix_len)
3548  return VNET_API_ERROR_INVALID_VALUE_2;
3549 
3550  /* FIXME - Should the DP do this or the CP ? */
3551  /* do specific delete processing here before returning */
3552  /* try to remove from routing table */
3553 
3554  mhash_unset (&radv_info->address_to_prefix_index, prefix_addr,
3555  /* old_value */ 0);
3556  pool_put (radv_info->adv_prefixes_pool, prefix);
3557 
3558  radv_info->initial_adverts_sent =
3559  radv_info->initial_adverts_count - 1;
3560  radv_info->next_multicast_time = vlib_time_now (vm);
3561  radv_info->last_multicast_time = vlib_time_now (vm);
3562  radv_info->last_radv_time = 0;
3563  return (error);
3564  }
3565 
3566  /* adding or changing */
3567  if (!prefix)
3568  {
3569  /* add */
3570  u32 pi;
3571  pool_get (radv_info->adv_prefixes_pool, prefix);
3572  pi = prefix - radv_info->adv_prefixes_pool;
3573  mhash_set (&radv_info->address_to_prefix_index, prefix_addr, pi,
3574  /* old_value */ 0);
3575 
3576  clib_memset (prefix, 0x0, sizeof (ip6_radv_prefix_t));
3577 
3578  prefix->prefix_len = prefix_len;
3579  clib_memcpy (&prefix->prefix, prefix_addr, sizeof (ip6_address_t));
3580 
3581  /* initialize default values */
3582  prefix->adv_on_link_flag = 1; /* L bit set */
3583  prefix->adv_autonomous_flag = 1; /* A bit set */
3586  prefix->enabled = 1;
3587  prefix->decrement_lifetime_flag = 1;
3588  prefix->deprecated_prefix_flag = 1;
3589 
3590  if (off_link == 0)
3591  {
3592  /* FIXME - Should the DP do this or the CP ? */
3593  /* insert prefix into routing table as a connected prefix */
3594  }
3595 
3596  if (use_default)
3597  goto restart;
3598  }
3599  else
3600  {
3601 
3602  if (prefix->prefix_len != prefix_len)
3603  return VNET_API_ERROR_INVALID_VALUE_2;
3604 
3605  if (off_link != 0)
3606  {
3607  /* FIXME - Should the DP do this or the CP ? */
3608  /* remove from routing table if already there */
3609  }
3610  }
3611 
3612  if ((val_lifetime == ~0) || (pref_lifetime == ~0))
3613  {
3614  prefix->adv_valid_lifetime_in_secs = ~0;
3615  prefix->adv_pref_lifetime_in_secs = ~0;
3616  prefix->decrement_lifetime_flag = 0;
3617  }
3618  else
3619  {
3620  prefix->adv_valid_lifetime_in_secs = val_lifetime;;
3621  prefix->adv_pref_lifetime_in_secs = pref_lifetime;
3622  }
3623 
3624  /* copy remaining */
3625  prefix->enabled = !(no_advertise != 0);
3626  prefix->adv_on_link_flag = !((off_link != 0) || (no_onlink != 0));
3627  prefix->adv_autonomous_flag = !(no_autoconfig != 0);
3628 
3629  restart:
3630  /* restart */
3631  /* fill in the expiration times */
3632  prefix->valid_lifetime_expires =
3633  now + prefix->adv_valid_lifetime_in_secs;
3634  prefix->pref_lifetime_expires = now + prefix->adv_pref_lifetime_in_secs;
3635 
3636  radv_info->initial_adverts_sent = radv_info->initial_adverts_count - 1;
3637  radv_info->next_multicast_time = vlib_time_now (vm);
3638  radv_info->last_multicast_time = vlib_time_now (vm);
3639  radv_info->last_radv_time = 0;
3640  }
3641  return (error);
3642 }
3643 
3644 clib_error_t *
3646  vlib_cli_command_t * cmd)
3647 {
3648  vnet_main_t *vnm = vnet_get_main ();
3650  clib_error_t *error = 0;
3651  u8 is_no = 0;
3652  u8 suppress = 0, managed = 0, other = 0;
3653  u8 suppress_ll_option = 0, send_unicast = 0, cease = 0;
3654  u8 use_lifetime = 0;
3655  u32 sw_if_index, ra_lifetime = 0, ra_initial_count =
3656  0, ra_initial_interval = 0;
3657  u32 ra_max_interval = 0, ra_min_interval = 0;
3658 
3659  unformat_input_t _line_input, *line_input = &_line_input;
3660  vnet_sw_interface_t *sw_if0;
3661 
3662  int add_radv_info = 1;
3663  __attribute__ ((unused)) ip6_radv_t *radv_info = 0;
3664  ip6_address_t ip6_addr;
3665  u32 addr_len;
3666 
3667 
3668  /* Get a line of input. */
3669  if (!unformat_user (main_input, unformat_line_input, line_input))
3670  return 0;
3671 
3672  /* get basic radv info for this interface */
3673  if (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3674  {
3675 
3676  if (unformat_user (line_input,
3677  unformat_vnet_sw_interface, vnm, &sw_if_index))
3678  {
3679  u32 ri;
3680  ethernet_interface_t *eth_if0 = 0;
3681 
3682  sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
3683  if (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
3684  eth_if0 =
3686 
3687  if (!eth_if0)
3688  {
3689  error =
3690  clib_error_return (0, "Interface must be of ethernet type");
3691  goto done;
3692  }
3693 
3694  /* look up the radv_t information for this interface */
3696  sw_if_index, ~0);
3697 
3699 
3700  if (ri != ~0)
3701  {
3702  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3703  }
3704  else
3705  {
3706  error = clib_error_return (0, "unknown interface %U'",
3707  format_unformat_error, line_input);
3708  goto done;
3709  }
3710  }
3711  else
3712  {
3713  error = clib_error_return (0, "invalid interface name %U'",
3714  format_unformat_error, line_input);
3715  goto done;
3716  }
3717  }
3718 
3719  /* get the rest of the command */
3720  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3721  {
3722  if (unformat (line_input, "no"))
3723  is_no = 1;
3724  else if (unformat (line_input, "prefix %U/%d",
3725  unformat_ip6_address, &ip6_addr, &addr_len))
3726  {
3727  add_radv_info = 0;
3728  break;
3729  }
3730  else if (unformat (line_input, "ra-managed-config-flag"))
3731  {
3732  managed = 1;
3733  break;
3734  }
3735  else if (unformat (line_input, "ra-other-config-flag"))
3736  {
3737  other = 1;
3738  break;
3739  }
3740  else if (unformat (line_input, "ra-suppress") ||
3741  unformat (line_input, "ra-surpress"))
3742  {
3743  suppress = 1;
3744  break;
3745  }
3746  else if (unformat (line_input, "ra-suppress-link-layer") ||
3747  unformat (line_input, "ra-surpress-link-layer"))
3748  {
3749  suppress_ll_option = 1;
3750  break;
3751  }
3752  else if (unformat (line_input, "ra-send-unicast"))
3753  {
3754  send_unicast = 1;
3755  break;
3756  }
3757  else if (unformat (line_input, "ra-lifetime"))
3758  {
3759  if (!unformat (line_input, "%d", &ra_lifetime))
3760  {
3761  error = unformat_parse_error (line_input);
3762  goto done;
3763  }
3764  use_lifetime = 1;
3765  break;
3766  }
3767  else if (unformat (line_input, "ra-initial"))
3768  {
3769  if (!unformat
3770  (line_input, "%d %d", &ra_initial_count, &ra_initial_interval))
3771  {
3772  error = unformat_parse_error (line_input);
3773  goto done;
3774  }
3775  break;
3776  }
3777  else if (unformat (line_input, "ra-interval"))
3778  {
3779  if (!unformat (line_input, "%d", &ra_max_interval))
3780  {
3781  error = unformat_parse_error (line_input);
3782  goto done;
3783  }
3784 
3785  if (!unformat (line_input, "%d", &ra_min_interval))
3786  ra_min_interval = 0;
3787  break;
3788  }
3789  else if (unformat (line_input, "ra-cease"))
3790  {
3791  cease = 1;
3792  break;
3793  }
3794  else
3795  {
3796  error = unformat_parse_error (line_input);
3797  goto done;
3798  }
3799  }
3800 
3801  if (add_radv_info)
3802  {
3803  ip6_neighbor_ra_config (vm, sw_if_index,
3804  suppress, managed, other,
3805  suppress_ll_option, send_unicast, cease,
3806  use_lifetime, ra_lifetime,
3807  ra_initial_count, ra_initial_interval,
3808  ra_max_interval, ra_min_interval, is_no);
3809  }
3810  else
3811  {
3812  u32 valid_lifetime_in_secs = 0;
3813  u32 pref_lifetime_in_secs = 0;
3814  u8 use_prefix_default_values = 0;
3815  u8 no_advertise = 0;
3816  u8 off_link = 0;
3817  u8 no_autoconfig = 0;
3818  u8 no_onlink = 0;
3819 
3820  /* get the rest of the command */
3821  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3822  {
3823  if (unformat (line_input, "default"))
3824  {
3825  use_prefix_default_values = 1;
3826  break;
3827  }
3828  else if (unformat (line_input, "infinite"))
3829  {
3830  valid_lifetime_in_secs = ~0;
3831  pref_lifetime_in_secs = ~0;
3832  break;
3833  }
3834  else if (unformat (line_input, "%d %d", &valid_lifetime_in_secs,
3835  &pref_lifetime_in_secs))
3836  break;
3837  else
3838  break;
3839  }
3840 
3841 
3842  /* get the rest of the command */
3843  while (!use_prefix_default_values &&
3845  {
3846  if (unformat (line_input, "no-advertise"))
3847  no_advertise = 1;
3848  else if (unformat (line_input, "off-link"))
3849  off_link = 1;
3850  else if (unformat (line_input, "no-autoconfig"))
3851  no_autoconfig = 1;
3852  else if (unformat (line_input, "no-onlink"))
3853  no_onlink = 1;
3854  else
3855  {
3856  error = unformat_parse_error (line_input);
3857  goto done;
3858  }
3859  }
3860 
3861  ip6_neighbor_ra_prefix (vm, sw_if_index,
3862  &ip6_addr, addr_len,
3863  use_prefix_default_values,
3864  valid_lifetime_in_secs,
3865  pref_lifetime_in_secs,
3866  no_advertise,
3867  off_link, no_autoconfig, no_onlink, is_no);
3868  }
3869 
3870 done:
3871  unformat_free (line_input);
3872 
3873  return error;
3874 }
3875 
3876 static void
3878 {
3880  u32 i;
3881 
3882  for (i = 0; i < vec_len (addrs); i++)
3883  {
3885  pool_elt_at_index (lm->if_address_pool, addrs[i]);
3887 
3888  vlib_cli_output (vm, "\t\t%U/%d",
3889  format_ip6_address, address, a->address_length);
3890  }
3891 }
3892 
3893 static clib_error_t *
3895  unformat_input_t * input, vlib_cli_command_t * cmd)
3896 {
3897  vnet_main_t *vnm = vnet_get_main ();
3899  clib_error_t *error = 0;
3900  u32 sw_if_index;
3901 
3902  sw_if_index = ~0;
3903 
3904  if (unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
3905  {
3906  u32 ri;
3907 
3908  /* look up the radv_t information for this interface */
3910  sw_if_index, ~0);
3911 
3913 
3914  if (ri != ~0)
3915  {
3917  ip6_radv_t *radv_info;
3918  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3919 
3920  vlib_cli_output (vm, "%U is admin %s\n",
3922  vnet_get_sw_interface (vnm, sw_if_index),
3923  (vnet_sw_interface_is_admin_up (vnm, sw_if_index) ?
3924  "up" : "down"));
3925 
3926  u32 ai;
3927  u32 *link_scope = 0, *global_scope = 0;
3928  u32 *local_scope = 0, *unknown_scope = 0;
3930 
3932  sw_if_index, ~0);
3934 
3935  while (ai != (u32) ~ 0)
3936  {
3937  a = pool_elt_at_index (lm->if_address_pool, ai);
3940 
3941  if (ip6_address_is_link_local_unicast (address))
3942  vec_add1 (link_scope, ai);
3943  else if (ip6_address_is_global_unicast (address))
3944  vec_add1 (global_scope, ai);
3945  else if (ip6_address_is_local_unicast (address))
3946  vec_add1 (local_scope, ai);
3947  else
3948  vec_add1 (unknown_scope, ai);
3949 
3950  ai = a->next_this_sw_interface;
3951  }
3952 
3953  if (vec_len (link_scope))
3954  {
3955  vlib_cli_output (vm, "\tLink-local address(es):\n");
3956  ip6_print_addrs (vm, link_scope);
3957  vec_free (link_scope);
3958  }
3959 
3960  if (vec_len (local_scope))
3961  {
3962  vlib_cli_output (vm, "\tLocal unicast address(es):\n");
3963  ip6_print_addrs (vm, local_scope);
3964  vec_free (local_scope);
3965  }
3966 
3967  if (vec_len (global_scope))
3968  {
3969  vlib_cli_output (vm, "\tGlobal unicast address(es):\n");
3970  ip6_print_addrs (vm, global_scope);
3971  vec_free (global_scope);
3972  }
3973 
3974  if (vec_len (unknown_scope))
3975  {
3976  vlib_cli_output (vm, "\tOther-scope address(es):\n");
3977  ip6_print_addrs (vm, unknown_scope);
3978  vec_free (unknown_scope);
3979  }
3980 
3981  vlib_cli_output (vm, "\tLink-local address(es):\n");
3982  vlib_cli_output (vm, "\t\t%U\n", format_ip6_address,
3983  &radv_info->link_local_address);
3984 
3985  vlib_cli_output (vm, "\tJoined group address(es):\n");
3986  ip6_mldp_group_t *m;
3987  /* *INDENT-OFF* */
3988  pool_foreach (m, radv_info->mldp_group_pool,
3989  ({
3990  vlib_cli_output (vm, "\t\t%U\n", format_ip6_address,
3991  &m->mcast_address);
3992  }));
3993  /* *INDENT-ON* */
3994 
3995  vlib_cli_output (vm, "\tAdvertised Prefixes:\n");
3996  ip6_radv_prefix_t *p;
3997  /* *INDENT-OFF* */
3998  pool_foreach (p, radv_info->adv_prefixes_pool,
3999  ({
4000  vlib_cli_output (vm, "\t\tprefix %U, length %d\n",
4001  format_ip6_address, &p->prefix, p->prefix_len);
4002  }));
4003  /* *INDENT-ON* */
4004 
4005  vlib_cli_output (vm, "\tMTU is %d\n", radv_info->adv_link_mtu);
4006  vlib_cli_output (vm, "\tICMP error messages are unlimited\n");
4007  vlib_cli_output (vm, "\tICMP redirects are disabled\n");
4008  vlib_cli_output (vm, "\tICMP unreachables are not sent\n");
4009  vlib_cli_output (vm, "\tND DAD is disabled\n");
4010  //vlib_cli_output (vm, "\tND reachable time is %d milliseconds\n",);
4011  vlib_cli_output (vm, "\tND advertised reachable time is %d\n",
4013  vlib_cli_output (vm,
4014  "\tND advertised retransmit interval is %d (msec)\n",
4015  radv_info->
4016  adv_time_in_msec_between_retransmitted_neighbor_solicitations);
4017 
4018  u32 ra_interval = radv_info->max_radv_interval;
4019  u32 ra_interval_min = radv_info->min_radv_interval;
4020  vlib_cli_output (vm,
4021  "\tND router advertisements are sent every %d seconds (min interval is %d)\n",
4022  ra_interval, ra_interval_min);
4023  vlib_cli_output (vm,
4024  "\tND router advertisements live for %d seconds\n",
4025  radv_info->adv_router_lifetime_in_sec);
4026  vlib_cli_output (vm,
4027  "\tHosts %s stateless autoconfig for addresses\n",
4028  (radv_info->adv_managed_flag) ? "use" :
4029  " don't use");
4030  vlib_cli_output (vm, "\tND router advertisements sent %d\n",
4031  radv_info->n_advertisements_sent);
4032  vlib_cli_output (vm, "\tND router solicitations received %d\n",
4033  radv_info->n_solicitations_rcvd);
4034  vlib_cli_output (vm, "\tND router solicitations dropped %d\n",
4035  radv_info->n_solicitations_dropped);
4036  }
4037  else
4038  {
4039  error = clib_error_return (0, "IPv6 not enabled on interface",
4040  format_unformat_error, input);
4041 
4042  }
4043  }
4044  return error;
4045 }
4046 
4047 /*?
4048  * This command is used to display various IPv6 attributes on a given
4049  * interface.
4050  *
4051  * @cliexpar
4052  * Example of how to display IPv6 settings:
4053  * @cliexstart{show ip6 interface GigabitEthernet2/0/0}
4054  * GigabitEthernet2/0/0 is admin up
4055  * Link-local address(es):
4056  * fe80::ab8/64
4057  * Joined group address(es):
4058  * ff02::1
4059  * ff02::2
4060  * ff02::16
4061  * ff02::1:ff00:ab8
4062  * Advertised Prefixes:
4063  * prefix fe80::fe:28ff:fe9c:75b3, length 64
4064  * MTU is 1500
4065  * ICMP error messages are unlimited
4066  * ICMP redirects are disabled
4067  * ICMP unreachables are not sent
4068  * ND DAD is disabled
4069  * ND advertised reachable time is 0
4070  * ND advertised retransmit interval is 0 (msec)
4071  * ND router advertisements are sent every 200 seconds (min interval is 150)
4072  * ND router advertisements live for 600 seconds
4073  * Hosts use stateless autoconfig for addresses
4074  * ND router advertisements sent 19336
4075  * ND router solicitations received 0
4076  * ND router solicitations dropped 0
4077  * @cliexend
4078  * Example of output if IPv6 is not enabled on the interface:
4079  * @cliexstart{show ip6 interface GigabitEthernet2/0/0}
4080  * show ip6 interface: IPv6 not enabled on interface
4081  * @cliexend
4082 ?*/
4083 /* *INDENT-OFF* */
4084 VLIB_CLI_COMMAND (show_ip6_interface_command, static) =
4085 {
4086  .path = "show ip6 interface",
4087  .function = show_ip6_interface_cmd,
4088  .short_help = "show ip6 interface <interface>",
4089 };
4090 /* *INDENT-ON* */
4091 
4092 clib_error_t *
4094 {
4095  clib_error_t *error = 0;
4097  u32 ri;
4098 
4099  /* look up the radv_t information for this interface */
4101  ~0);
4103 
4104  /* if not created - do nothing */
4105  if (ri != ~0)
4106  {
4107  ip6_radv_t *radv_info;
4108 
4109  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
4110 
4111  /* check radv_info ref count for other ip6 addresses on this interface */
4112  /* This implicitly excludes the link local address */
4113  if (radv_info->ref_count == 0)
4114  {
4115  /* essentially "disables" ipv6 on this interface */
4116  ip6_ll_prefix_t ilp = {
4117  .ilp_addr = radv_info->link_local_address,
4118  .ilp_sw_if_index = sw_if_index,
4119  };
4121  ip6_sw_interface_enable_disable (sw_if_index, 0);
4122  ip6_mfib_interface_enable_disable (sw_if_index, 0);
4124  0);
4125  }
4126  }
4127  return error;
4128 }
4129 
4130 int
4132 {
4134  u32 ri = ~0;
4135 
4136  /* look up the radv_t information for this interface */
4138  ~0);
4139 
4141 
4142  return ri != ~0;
4143 }
4144 
4145 clib_error_t *
4147 {
4148  clib_error_t *error = 0;
4150  u32 ri;
4151  int is_add = 1;
4152 
4153  /* look up the radv_t information for this interface */
4155  ~0);
4156 
4158 
4159  /* if not created yet */
4160  if (ri == ~0)
4161  {
4162  vnet_main_t *vnm = vnet_get_main ();
4163  vnet_sw_interface_t *sw_if0;
4164 
4165  sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
4166  if (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
4167  {
4168  ethernet_interface_t *eth_if0;
4169 
4170  eth_if0 =
4172  if (eth_if0)
4173  {
4174  /* create radv_info. for this interface. This holds all the info needed for router adverts */
4175  ri =
4176  ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, is_add);
4177 
4178  if (ri != ~0)
4179  {
4180  ip6_radv_t *radv_info;
4181  ip6_address_t link_local_address;
4182 
4183  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
4184 
4186  (&link_local_address, eth_if0->address);
4187 
4188  sw_if0 = vnet_get_sw_interface (vnm, sw_if_index);
4189  if (sw_if0->type == VNET_SW_INTERFACE_TYPE_SUB ||
4190  sw_if0->type == VNET_SW_INTERFACE_TYPE_PIPE ||
4191  sw_if0->type == VNET_SW_INTERFACE_TYPE_P2P)
4192  {
4193  /* make up an interface id */
4194  link_local_address.as_u64[1] =
4195  random_u64 (&radv_info->randomizer);
4196 
4197  link_local_address.as_u64[0] =
4198  clib_host_to_net_u64 (0xFE80000000000000ULL);
4199  /* clear u bit */
4200  link_local_address.as_u8[8] &= 0xfd;
4201  }
4202  {
4203  ip6_ll_prefix_t ilp = {
4204  .ilp_addr = link_local_address,
4205  .ilp_sw_if_index = sw_if_index,
4206  };
4207 
4209  }
4210 
4211  /* essentially "enables" ipv6 on this interface */
4212  ip6_mfib_interface_enable_disable (sw_if_index, 1);
4213  ip6_sw_interface_enable_disable (sw_if_index, 1);
4214 
4215  if (!error)
4216  {
4217  radv_info->link_local_address = link_local_address;
4218  }
4219  }
4220  }
4221  }
4222  }
4223  return error;
4224 }
4225 
4226 int
4228 {
4230  ip6_radv_t *radv_info;
4231  u32 ri;
4232 
4233  if (vec_len (nm->if_radv_pool_index_by_sw_if_index) <= sw_if_index)
4234  return 0;
4235 
4237 
4238  if (ri == ~0)
4239  return 0;
4240 
4241  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
4242  *addr = radv_info->link_local_address;
4243 
4244  return (!0);
4245 }
4246 
4247 static clib_error_t *
4249  unformat_input_t * input, vlib_cli_command_t * cmd)
4250 {
4251  vnet_main_t *vnm = vnet_get_main ();
4252  clib_error_t *error = 0;
4253  u32 sw_if_index;
4254 
4255  sw_if_index = ~0;
4256 
4257  if (unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
4258  {
4259  enable_ip6_interface (vm, sw_if_index);
4260  }
4261  else
4262  {
4263  error = clib_error_return (0, "unknown interface\n'",
4264  format_unformat_error, input);
4265 
4266  }
4267  return error;
4268 }
4269 
4270 /*?
4271  * This command is used to enable IPv6 on a given interface.
4272  *
4273  * @cliexpar
4274  * Example of how enable IPv6 on a given interface:
4275  * @cliexcmd{enable ip6 interface GigabitEthernet2/0/0}
4276 ?*/
4277 /* *INDENT-OFF* */
4278 VLIB_CLI_COMMAND (enable_ip6_interface_command, static) =
4279 {
4280  .path = "enable ip6 interface",
4281  .function = enable_ip6_interface_cmd,
4282  .short_help = "enable ip6 interface <interface>",
4283 };
4284 /* *INDENT-ON* */
4285 
4286 static clib_error_t *
4288  unformat_input_t * input, vlib_cli_command_t * cmd)
4289 {
4290  vnet_main_t *vnm = vnet_get_main ();
4291  clib_error_t *error = 0;
4292  u32 sw_if_index;
4293 
4294  sw_if_index = ~0;
4295 
4296  if (unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
4297  {
4298  error = disable_ip6_interface (vm, sw_if_index);
4299  }
4300  else
4301  {
4302  error = clib_error_return (0, "unknown interface\n'",
4303  format_unformat_error, input);
4304 
4305  }
4306  return error;
4307 }
4308 
4309 /*?
4310  * This command is used to disable IPv6 on a given interface.
4311  *
4312  * @cliexpar
4313  * Example of how disable IPv6 on a given interface:
4314  * @cliexcmd{disable ip6 interface GigabitEthernet2/0/0}
4315 ?*/
4316 /* *INDENT-OFF* */
4317 VLIB_CLI_COMMAND (disable_ip6_interface_command, static) =
4318 {
4319  .path = "disable ip6 interface",
4320  .function = disable_ip6_interface_cmd,
4321  .short_help = "disable ip6 interface <interface>",
4322 };
4323 /* *INDENT-ON* */
4324 
4325 /*?
4326  * This command is used to configure the neighbor discovery
4327  * parameters on a given interface. Use the '<em>show ip6 interface</em>'
4328  * command to display some of the current neighbor discovery parameters
4329  * on a given interface. This command has three formats:
4330  *
4331  *
4332  * <b>Format 1 - Router Advertisement Options:</b> (Only one can be entered in a single command)
4333  *
4334  * '<em><b>ip6 nd <interface> [no] [ra-managed-config-flag] | [ra-other-config-flag] | [ra-suppress] | [ra-suppress-link-layer] | [ra-send-unicast] | [ra-lifetime <lifetime>] | [ra-initial <cnt> <interval>] | [ra-interval <max-interval> [<min-interval>]] | [ra-cease]</b></em>'
4335  *
4336  * Where:
4337  *
4338  * <em>[no] ra-managed-config-flag</em> - Advertises in ICMPv6
4339  * router-advertisement messages to use stateful address
4340  * auto-configuration to obtain address information (sets the M-bit).
4341  * Default is the M-bit is not set and the '<em>no</em>' option
4342  * returns it to this default state.
4343  *
4344  * <em>[no] ra-other-config-flag</em> - Indicates in ICMPv6
4345  * router-advertisement messages that hosts use stateful auto
4346  * configuration to obtain nonaddress related information (sets
4347  * the O-bit). Default is the O-bit is not set and the '<em>no</em>'
4348  * option returns it to this default state.
4349  *
4350  * <em>[no] ra-suppress</em> - Disables sending ICMPv6 router-advertisement
4351  * messages. The '<em>no</em>' option implies to enable sending ICMPv6
4352  * router-advertisement messages.
4353  *
4354  * <em>[no] ra-suppress-link-layer</em> - Indicates not to include the
4355  * optional source link-layer address in the ICMPv6 router-advertisement
4356  * messages. Default is to include the optional source link-layer address
4357  * and the '<em>no</em>' option returns it to this default state.
4358  *
4359  * <em>[no] ra-send-unicast</em> - Use the source address of the
4360  * router-solicitation message if availiable. The default is to use
4361  * multicast address of all nodes, and the '<em>no</em>' option returns
4362  * it to this default state.
4363  *
4364  * <em>[no] ra-lifetime <lifetime></em> - Advertises the lifetime of a
4365  * default router in ICMPv6 router-advertisement messages. The range is
4366  * from 0 to 9000 seconds. '<em><lifetime></em>' must be greater than
4367  * '<em><max-interval></em>'. The default value is 600 seconds and the
4368  * '<em>no</em>' option returns it to this default value.
4369  *
4370  * <em>[no] ra-initial <cnt> <interval></em> - Number of initial ICMPv6
4371  * router-advertisement messages sent and the interval between each
4372  * message. Range for count is 1 - 3 and default is 3. Range for interval
4373  * is 1 to 16 seconds, and default is 16 seconds. The '<em>no</em>' option
4374  * returns both to their default value.
4375  *
4376  * <em>[no] ra-interval <max-interval> [<min-interval>]</em> - Configures the
4377  * interval between sending ICMPv6 router-advertisement messages. The
4378  * range for max-interval is from 4 to 200 seconds. min-interval can not
4379  * be more than 75% of max-interval. If not set, min-interval will be
4380  * set to 75% of max-interval. The range for min-interval is from 3 to
4381  * 150 seconds. The '<em>no</em>' option returns both to their default
4382  * value.
4383  *
4384  * <em>[no] ra-cease</em> - Cease sending ICMPv6 router-advertisement messages.
4385  * The '<em>no</em>' options implies to start (or restart) sending
4386  * ICMPv6 router-advertisement messages.
4387  *
4388  *
4389  * <b>Format 2 - Prefix Options:</b>
4390  *
4391  * '<em><b>ip6 nd <interface> [no] prefix <ip6-address>/<width> [<valid-lifetime> <pref-lifetime> | infinite] [no-advertise] [off-link] [no-autoconfig] [no-onlink]</b></em>'
4392  *
4393  * Where:
4394  *
4395  * <em>no</em> - All additional flags are ignored and the prefix is deleted.
4396  *
4397  * <em><valid-lifetime> <pref-lifetime></em> - '<em><valid-lifetime></em>' is the
4398  * length of time in seconds during what the prefix is valid for the purpose of
4399  * on-link determination. Range is 7203 to 2592000 seconds and default is 2592000
4400  * seconds (30 days). '<em><pref-lifetime></em>' is the prefered-lifetime and is the
4401  * length of time in seconds during what addresses generated from the prefix remain
4402  * preferred. Range is 0 to 604800 seconds and default is 604800 seconds (7 days).
4403  *
4404  * <em>infinite</em> - Both '<em><valid-lifetime></em>' and '<em><<pref-lifetime></em>'
4405  * are inifinte, no timeout.
4406  *
4407  * <em>no-advertise</em> - Do not send full router address in prefix
4408  * advertisement. Default is to advertise (i.e. - This flag is off by default).
4409  *
4410  * <em>off-link</em> - Prefix is off-link, clear L-bit in packet. Default is on-link
4411  * (i.e. - This flag is off and L-bit in packet is set by default and this prefix can
4412  * be used for on-link determination). '<em>no-onlink</em>' also controls the L-bit.
4413  *
4414  * <em>no-autoconfig</em> - Do not use prefix for autoconfiguration, clear A-bit in packet.
4415  * Default is autoconfig (i.e. - This flag is off and A-bit in packet is set by default.
4416  *
4417  * <em>no-onlink</em> - Do not use prefix for onlink determination, clear L-bit in packet.
4418  * Default is on-link (i.e. - This flag is off and L-bit in packet is set by default and
4419  * this prefix can be used for on-link determination). '<em>off-link</em>' also controls
4420  * the L-bit.
4421  *
4422  *
4423  * <b>Format 3: - Default of Prefix:</b>
4424  *
4425  * '<em><b>ip6 nd <interface> [no] prefix <ip6-address>/<width> default</b></em>'
4426  *
4427  * When a new prefix is added (or existing one is being overwritten) <em>default</em>
4428  * uses default values for the prefix. If <em>no</em> is used, the <em>default</em>
4429  * is ignored and the prefix is deleted.
4430  *
4431  *
4432  * @cliexpar
4433  * Example of how set a router advertisement option:
4434  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 ra-interval 100 20}
4435  * Example of how to add a prefix:
4436  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 prefix fe80::fe:28ff:fe9c:75b3/64 infinite no-advertise}
4437  * Example of how to delete a prefix:
4438  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 no prefix fe80::fe:28ff:fe9c:75b3/64}
4439 ?*/
4440 /* *INDENT-OFF* */
4441 VLIB_CLI_COMMAND (ip6_nd_command, static) =
4442 {
4443  .path = "ip6 nd",
4444  .short_help = "ip6 nd <interface> ...",
4445  .function = ip6_neighbor_cmd,
4446 };
4447 /* *INDENT-ON* */
4448 
4449 clib_error_t *
4452 {
4453  clib_error_t *error = 0;
4455  u32 ri;
4456  ip6_radv_t *radv_info;
4457  vnet_main_t *vnm = vnet_get_main ();
4458  ip6_ll_prefix_t pfx = { 0, };
4459 
4460  if (!ip6_address_is_link_local_unicast (address))
4461  return (error = clib_error_return (0, "address not link-local",
4463 
4464  /* call enable ipv6 */
4465  enable_ip6_interface (vm, sw_if_index);
4466 
4468 
4469  if (ri != ~0)
4470  {
4471  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
4472 
4474 
4475  pfx.ilp_addr = radv_info->link_local_address;
4477 
4478  pfx.ilp_addr = *address;
4480 
4481  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
4482  radv_info->link_local_address = *address;
4483  }
4484  else
4485  {
4486  vnm->api_errno = VNET_API_ERROR_IP6_NOT_ENABLED;
4487  error = clib_error_return (0, "ip6 not enabled for interface",
4489  }
4490  return error;
4491 }
4492 
4493 /**
4494  * @brief callback when an interface address is added or deleted
4495  */
4496 static void
4498  uword opaque,
4499  u32 sw_if_index,
4502  u32 if_address_index, u32 is_delete)
4503 {
4504  vnet_main_t *vnm = vnet_get_main ();
4506  u32 ri;
4507  vlib_main_t *vm = vnm->vlib_main;
4508  ip6_radv_t *radv_info;
4509  ip6_address_t a;
4510 
4511  /* create solicited node multicast address for this interface adddress */
4513 
4514  a.as_u8[0xd] = address->as_u8[0xd];
4515  a.as_u8[0xe] = address->as_u8[0xe];
4516  a.as_u8[0xf] = address->as_u8[0xf];
4517 
4518  if (!is_delete)
4519  {
4520  /* try to create radv_info - does nothing if ipv6 already enabled */
4521  enable_ip6_interface (vm, sw_if_index);
4522 
4523  /* look up the radv_t information for this interface */
4525  sw_if_index, ~0);
4527  if (ri != ~0)
4528  {
4529  /* get radv_info */
4530  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
4531 
4532  /* add address */
4533  if (!ip6_address_is_link_local_unicast (address))
4534  radv_info->ref_count++;
4535 
4536  ip6_neighbor_add_mld_prefix (radv_info, &a);
4537  }
4538  }
4539  else
4540  {
4541 
4542  /* delete */
4543  /* look up the radv_t information for this interface */
4545  sw_if_index, ~0);
4547 
4548  if (ri != ~0)
4549  {
4550  /* get radv_info */
4551  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
4552 
4553  ip6_neighbor_del_mld_prefix (radv_info, &a);
4554 
4555  /* if interface up send MLDP "report" */
4556  radv_info->all_routers_mcast = 0;
4557 
4558  /* add address */
4559  if (!ip6_address_is_link_local_unicast (address))
4560  radv_info->ref_count--;
4561  }
4562  /* Ensure that IPv6 is disabled, and LL removed after ref_count reaches 0 */
4563  disable_ip6_interface (vm, sw_if_index);
4564  }
4565 }
4566 
4567 clib_error_t *
4568 ip6_set_neighbor_limit (u32 neighbor_limit)
4569 {
4571 
4572  nm->limit_neighbor_cache_size = neighbor_limit;
4573  return 0;
4574 }
4575 
4576 static void
4578  uword opaque,
4579  u32 sw_if_index,
4580  u32 new_fib_index, u32 old_fib_index)
4581 {
4583  ip6_neighbor_t *n = NULL;
4584  u32 i, *to_re_add = 0;
4585 
4586  /* *INDENT-OFF* */
4587  pool_foreach (n, nm->neighbor_pool,
4588  ({
4589  if (n->key.sw_if_index == sw_if_index)
4590  vec_add1 (to_re_add, n - nm->neighbor_pool);
4591  }));
4592  /* *INDENT-ON* */
4593 
4594  for (i = 0; i < vec_len (to_re_add); i++)
4595  {
4596  n = pool_elt_at_index (nm->neighbor_pool, to_re_add[i]);
4597  ip6_neighbor_adj_fib_remove (n, old_fib_index);
4598  ip6_neighbor_adj_fib_add (n, new_fib_index);
4599  }
4600  vec_free (to_re_add);
4601 }
4602 
4603 static clib_error_t *
4605 {
4607  ip6_main_t *im = &ip6_main;
4608 
4610  /* value size */ sizeof (uword),
4611  /* key size */ sizeof (ip6_neighbor_key_t));
4612 
4613  icmp6_register_type (vm, ICMP6_neighbor_solicitation,
4615  icmp6_register_type (vm, ICMP6_neighbor_advertisement,
4617  icmp6_register_type (vm, ICMP6_router_solicitation,
4619  icmp6_register_type (vm, ICMP6_router_advertisement,
4621 
4622  /* handler node for ip6 neighbor discovery events and timers */
4624 
4625  /* add call backs */
4628 
4629  /* when an interface address changes... */
4631  cb.function_opaque = 0;
4633 
4636  cbt.function_opaque = 0;
4637  vec_add1 (im->table_bind_callbacks, cbt);
4638 
4640  /* value size */ sizeof (uword),
4641  /* key size */ sizeof (ip6_address_t));
4642 
4644  /* value size */ sizeof (uword),
4645  /* key size */ sizeof (ip6_address_t));
4646 
4647  /* default, configurable */
4648  nm->limit_neighbor_cache_size = 50000;
4649 
4650  nm->wc_ip6_nd_publisher_node = (uword) ~ 0;
4651 
4652  nm->ip6_ra_publisher_node = (uword) ~ 0;
4653 
4654 #if 0
4655  /* $$$$ Hack fix for today */
4657  (im->discover_neighbor_next_index_by_hw_if_index, 32, 0 /* drop */ );
4658 #endif
4659 
4660  return 0;
4661 }
4662 
4664 
4665 
4666 void
4668  void *address_arg,
4669  uword node_index,
4670  uword type_opaque, uword data)
4671 {
4673  ip6_address_t *address = address_arg;
4674  uword *p;
4676 
4677  pool_get (nm->pending_resolutions, pr);
4678 
4679  pr->next_index = ~0;
4680  pr->node_index = node_index;
4681  pr->type_opaque = type_opaque;
4682  pr->data = data;
4683 
4684  p = mhash_get (&nm->pending_resolutions_by_address, address);
4685  if (p)
4686  {
4687  /* Insert new resolution at the head of the list */
4688  pr->next_index = p[0];
4689  mhash_unset (&nm->pending_resolutions_by_address, address, 0);
4690  }
4691 
4693  pr - nm->pending_resolutions, 0 /* old value */ );
4694 }
4695 
4696 int
4698  void *data_callback,
4699  u32 pid,
4700  void *address_arg,
4701  uword node_index,
4702  uword type_opaque, uword data, int is_add)
4703 {
4705  ip6_address_t *address = address_arg;
4706 
4707  /* Try to find an existing entry */
4708  u32 *first = (u32 *) mhash_get (&nm->mac_changes_by_address, address);
4709  u32 *p = first;
4711  while (p && *p != ~0)
4712  {
4713  mc = pool_elt_at_index (nm->mac_changes, *p);
4714  if (mc->node_index == node_index && mc->type_opaque == type_opaque
4715  && mc->pid == pid)
4716  break;
4717  p = &mc->next_index;
4718  }
4719 
4720  int found = p && *p != ~0;
4721  if (is_add)
4722  {
4723  if (found)
4724  return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
4725 
4726  pool_get (nm->mac_changes, mc);
4727  /* *INDENT-OFF* */
4728  *mc = (pending_resolution_t)
4729  {
4730  .next_index = ~0,
4731  .node_index = node_index,
4732  .type_opaque = type_opaque,
4733  .data = data,
4734  .data_callback = data_callback,
4735  .pid = pid,
4736  };
4737  /* *INDENT-ON* */
4738 
4739  /* Insert new resolution at the end of the list */
4740  u32 new_idx = mc - nm->mac_changes;
4741  if (p)
4742  p[0] = new_idx;
4743  else
4744  mhash_set (&nm->mac_changes_by_address, address, new_idx, 0);
4745  }
4746  else
4747  {
4748  if (!found)
4749  return VNET_API_ERROR_NO_SUCH_ENTRY;
4750 
4751  /* Clients may need to clean up pool entries, too */
4752  void (*fp) (u32, u8 *) = data_callback;
4753  if (fp)
4754  (*fp) (mc->data, 0 /* no new mac addrs */ );
4755 
4756  /* Remove the entry from the list and delete the entry */
4757  *p = mc->next_index;
4758  pool_put (nm->mac_changes, mc);
4759 
4760  /* Remove from hash if we deleted the last entry */
4761  if (*p == ~0 && p == first)
4762  mhash_unset (&nm->mac_changes_by_address, address, 0);
4763  }
4764  return 0;
4765 }
4766 
4767 int
4769  vlib_node_runtime_t * node,
4770  vlib_buffer_t * p0,
4771  ethernet_header_t * eth,
4772  ip6_header_t * ip, u32 sw_if_index, u16 bd_index)
4773 {
4775  icmp6_neighbor_solicitation_or_advertisement_header_t *ndh;
4776 
4777  ndh = ip6_next_header (ip);
4778  if (ndh->icmp.type != ICMP6_neighbor_solicitation &&
4779  ndh->icmp.type != ICMP6_neighbor_advertisement)
4780  return 0;
4781 
4782  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
4783  (p0->flags & VLIB_BUFFER_IS_TRACED)))
4784  {
4785  u8 *t0 = vlib_add_trace (vm, node, p0,
4786  sizeof (icmp6_input_trace_t));
4787  clib_memcpy (t0, ip, sizeof (icmp6_input_trace_t));
4788  }
4789 
4790  /* Check if anyone want ND events for L2 BDs */
4791  if (PREDICT_FALSE
4792  (nm->wc_ip6_nd_publisher_node != (uword) ~ 0
4794  {
4795  vnet_nd_wc_publish (sw_if_index, eth->src_address, &ip->src_address);
4796  }
4797 
4798  /* Check if MAC entry exsist for solicited target IP */
4799  if (ndh->icmp.type == ICMP6_neighbor_solicitation)
4800  {
4801  icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *opt;
4802  l2_bridge_domain_t *bd_config;
4803  u8 *macp;
4804 
4805  opt = (void *) (ndh + 1);
4806  if ((opt->header.type !=
4807  ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address) ||
4808  (opt->header.n_data_u64s != 1))
4809  return 0; /* source link layer address option not present */
4810 
4811  bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
4812  macp =
4813  (u8 *) hash_get_mem (bd_config->mac_by_ip6, &ndh->target_address);
4814  if (macp)
4815  { /* found ip-mac entry, generate eighbor advertisement response */
4816  int bogus_length;
4817  vlib_node_runtime_t *error_node =
4819  ip->dst_address = ip->src_address;
4820  ip->src_address = ndh->target_address;
4821  ip->hop_limit = 255;
4822  opt->header.type =
4823  ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
4824  clib_memcpy (opt->ethernet_address, macp, 6);
4825  ndh->icmp.type = ICMP6_neighbor_advertisement;
4826  ndh->advertisement_flags = clib_host_to_net_u32
4829  ndh->icmp.checksum = 0;
4830  ndh->icmp.checksum =
4831  ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip, &bogus_length);
4832  clib_memcpy (eth->dst_address, eth->src_address, 6);
4833  clib_memcpy (eth->src_address, macp, 6);
4834  vlib_error_count (vm, error_node->node_index,
4835  ICMP6_ERROR_NEIGHBOR_ADVERTISEMENTS_TX, 1);
4836  return 1;
4837  }
4838  }
4839 
4840  return 0;
4841 
4842 }
4843 
4844 int
4846 {
4847  u32 fib_index;
4848 
4849  fib_prefix_t pfx = {
4850  .fp_len = 128,
4851  .fp_proto = FIB_PROTOCOL_IP6,
4852  .fp_addr = {
4853  .ip6 = *addr,
4854  },
4855  };
4856  ip46_address_t nh = {
4857  .ip6 = *addr,
4858  };
4859 
4860  fib_index = ip6_fib_table_get_index_for_sw_if_index (sw_if_index);
4861 
4862  if (~0 == fib_index)
4863  return VNET_API_ERROR_NO_SUCH_FIB;
4864 
4865  if (is_del)
4866  {
4867  fib_table_entry_path_remove (fib_index,
4868  &pfx,
4870  DPO_PROTO_IP6,
4871  &nh,
4872  sw_if_index,
4873  ~0, 1, FIB_ROUTE_PATH_FLAG_NONE);
4874  /* flush the ND cache of this address if it's there */
4875  vnet_unset_ip6_ethernet_neighbor (vlib_get_main (), sw_if_index, addr);
4876  }
4877  else
4878  {
4879  fib_table_entry_path_add (fib_index,
4880  &pfx,
4883  DPO_PROTO_IP6,
4884  &nh,
4885  sw_if_index,
4886  ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
4887  }
4888  return (0);
4889 }
4890 
4891 static clib_error_t *
4893  unformat_input_t * input, vlib_cli_command_t * cmd)
4894 {
4895  vnet_main_t *vnm = vnet_get_main ();
4896  clib_error_t *error = 0;
4898  u32 sw_if_index;
4899  u8 is_del = 0;
4900 
4901  if (unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
4902  {
4903  /* get the rest of the command */
4904  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
4905  {
4906  if (unformat (input, "%U", unformat_ip6_address, &addr))
4907  break;
4908  else if (unformat (input, "delete") || unformat (input, "del"))
4909  is_del = 1;
4910  else
4911  return (unformat_parse_error (input));
4912  }
4913  }
4914 
4915  ip6_neighbor_proxy_add_del (sw_if_index, &addr, is_del);
4916 
4917  return error;
4918 }
4919 
4920 /* *INDENT-OFF* */
4921 VLIB_CLI_COMMAND (set_ip6_nd_proxy_command, static) =
4922 {
4923  .path = "set ip6 nd proxy",
4924  .short_help = "set ip6 nd proxy <HOST> <INTERFACE>",
4925  .function = set_ip6_nd_proxy_cmd,
4926 };
4927 /* *INDENT-ON* */
4928 
4929 void
4931 {
4933  ip6_neighbor_t *n;
4934  adj_index_t ai;
4935 
4936  /* *INDENT-OFF* */
4937  pool_foreach (n, nm->neighbor_pool,
4938  ({
4939  if (n->key.sw_if_index == sw_if_index)
4940  {
4941  adj_nbr_walk_nh6 (sw_if_index,
4942  &n->key.ip6_address,
4943  ip6_nd_mk_complete_walk, n);
4944  }
4945  }));
4946  /* *INDENT-ON* */
4947 
4949 
4950  if (ADJ_INDEX_INVALID != ai)
4952 }
4953 
4954 void
4956 {
4957  ip6_main_t *i6m = &ip6_main;
4958  ip6_address_t *ip6_addr = ip6_interface_first_address (i6m, sw_if_index);
4959 
4960  send_ip6_na_w_addr (vm, ip6_addr, sw_if_index);
4961 }
4962 
4963 void
4965  const ip6_address_t * ip6_addr, u32 sw_if_index)
4966 {
4967  ip6_main_t *i6m = &ip6_main;
4968  vnet_main_t *vnm = vnet_get_main ();
4969  u8 *rewrite, rewrite_len;
4970  vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
4971  u8 dst_address[6];
4972 
4973  if (ip6_addr)
4974  {
4975  clib_warning
4976  ("Sending unsolicitated NA IP6 address %U on sw_if_idex %d",
4977  format_ip6_address, ip6_addr, sw_if_index);
4978 
4979  /* Form unsolicited neighbor advertisement packet from NS pkt template */
4980  int bogus_length;
4981  u32 bi = 0;
4982  icmp6_neighbor_solicitation_header_t *h =
4985  &bi);
4986  if (!h)
4987  return;
4988 
4989  ip6_set_reserved_multicast_address (&h->ip.dst_address,
4990  IP6_MULTICAST_SCOPE_link_local,
4991  IP6_MULTICAST_GROUP_ID_all_hosts);
4992  h->ip.src_address = ip6_addr[0];
4993  h->neighbor.icmp.type = ICMP6_neighbor_advertisement;
4994  h->neighbor.target_address = ip6_addr[0];
4995  h->neighbor.advertisement_flags = clib_host_to_net_u32
4997  h->link_layer_option.header.type =
4998  ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
4999  clib_memcpy (h->link_layer_option.ethernet_address,
5000  hi->hw_address, vec_len (hi->hw_address));
5001  h->neighbor.icmp.checksum =
5002  ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
5003  ASSERT (bogus_length == 0);
5004 
5005  /* Setup MAC header with IP6 Etype and mcast DMAC */
5006  vlib_buffer_t *b = vlib_get_buffer (vm, bi);
5007  ip6_multicast_ethernet_address (dst_address,
5008  IP6_MULTICAST_GROUP_ID_all_hosts);
5009  rewrite =
5010  ethernet_build_rewrite (vnm, sw_if_index, VNET_LINK_IP6, dst_address);
5011  rewrite_len = vec_len (rewrite);
5012  vlib_buffer_advance (b, -rewrite_len);
5014  clib_memcpy (e->dst_address, rewrite, rewrite_len);
5015  vec_free (rewrite);
5016 
5017  /* Send unsolicited ND advertisement packet out the specified interface */
5018  vnet_buffer (b)->sw_if_index[VLIB_RX] =
5019  vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
5021  u32 *to_next = vlib_frame_vector_args (f);
5022  to_next[0] = bi;
5023  f->n_vectors = 1;
5025  }
5026 }
5027 
5028 /*
5029  * fd.io coding-style-patch-verification: ON
5030  *
5031  * Local Variables:
5032  * eval: (c-set-style "gnu")
5033  * End:
5034  */
#define ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:439
ip6_radv_t * if_radv_pool
Definition: ip6_neighbor.c:202
#define MIN_DELAY_BETWEEN_RAS
Definition: ip6_neighbor.c:132
static void ip6_neighbor_adj_fib_add(ip6_neighbor_t *n, u32 fib_index)
Definition: ip6_neighbor.c:715
#define vnet_rewrite_one_header(rw0, p0, most_likely_size)
Definition: rewrite.h:277
#define DEF_DEF_RTR_LIFETIME
Definition: ip6_neighbor.c:127
static void ip6_nd_mk_incomplete(adj_index_t ai)
Definition: ip6_neighbor.c:518
vmrglw vmrglh hi
#define pool_next_index(P, I)
Return next occupied pool index after i, useful for safe iteration.
Definition: pool.h:519
fib_node_index_t fib_table_entry_path_add(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, dpo_proto_t next_hop_proto, const ip46_address_t *next_hop, u32 next_hop_sw_if_index, u32 next_hop_fib_index, u32 next_hop_weight, fib_mpls_label_t *next_hop_labels, fib_route_path_flags_t path_flags)
Add one path to an entry (aka route) in the FIB.
Definition: fib_table.c:522
Definition: mhash.h:46
typedef address
Definition: ip_types.api:30
#define VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST
Definition: rewrite.h:302
icmp6_router_solicitation_or_advertisement_next_t
u32 n_solicitations_rcvd
Definition: ip6_neighbor.c:153
ip6_discover_neighbor_next_t
static void ip6_neighbor_syslog(vlib_main_t *vm, int priority, char *fmt,...)
u32 flags
Definition: vhost_user.h:115
vl_api_address_t src
Definition: vxlan_gbp.api:32
#define ICMP6_ROUTER_DISCOVERY_FLAG_OTHER_CONFIG_VIA_DHCP
static uword random_default_seed(void)
Default random seed (unix/linux user-mode)
Definition: random.h:91
static void vlib_buffer_reset(vlib_buffer_t *b)
Reset current header & length to state they were in when packet was received.
Definition: buffer.h:262
static vlib_node_registration_t ip6_icmp_neighbor_solicitation_node
(constructor) VLIB_REGISTER_NODE (ip6_icmp_neighbor_solicitation_node)
static f64 vlib_process_wait_for_event_or_clock(vlib_main_t *vm, f64 dt)
Suspend a cooperative multi-tasking thread Waits for an event, or for the indicated number of seconds...
Definition: node_funcs.h:673
void send_ip6_na_w_addr(vlib_main_t *vm, const ip6_address_t *ip6_addr, u32 sw_if_index)
a
Definition: bitmap.h:538
static void vlib_buffer_free(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Free buffers Frees the entire buffer chain for each buffer.
Definition: buffer_funcs.h:529
int ip6_neighbor_ra_prefix(vlib_main_t *vm, u32 sw_if_index, ip6_address_t *prefix_addr, u8 prefix_len, u8 use_default, u32 val_lifetime, u32 pref_lifetime, u8 no_advertise, u8 off_link, u8 no_autoconfig, u8 no_onlink, u8 is_no)
An indication that the rewrite is incomplete, i.e.
Definition: adj_nbr.h:90
static void ip6_nbr_probe(ip_adjacency_t *adj)
Definition: ip6_neighbor.c:438
clib_error_t * ip6_neighbor_set_link_local_address(vlib_main_t *vm, u32 sw_if_index, ip6_address_t *address)
static clib_error_t * ip6_neighbor_init(vlib_main_t *vm)
f64 last_radv_time
Definition: ip6_neighbor.c:142
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:371
ip_interface_address_t * if_address_pool
Pool of addresses that are assigned to interfaces.
Definition: lookup.h:125
An indication that the rewrite is complete, i.e.
Definition: adj_nbr.h:98
vnet_main_t * vnet_get_main(void)
Definition: misc.c:47
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
static char * log_level_strings[]
ip6_multicast_address_scope_t
Definition: ip6_packet.h:157
static void stop_sending_rs(vlib_main_t *vm, ip6_radv_t *ra)
static void ip6_nd_mk_complete(adj_index_t ai, ip6_neighbor_t *nbr)
Definition: ip6_neighbor.c:508
mhash_t neighbor_index_by_key
Definition: ip6_neighbor.c:198
void icmp6_send_router_solicitation(vlib_main_t *vm, u32 sw_if_index, u8 stop, icmp6_send_router_solicitation_params_t *params)
#define PREDICT_TRUE(x)
Definition: clib.h:112
static void ip6_neighbor_del_mld_prefix(ip6_radv_t *radv_info, ip6_address_t *addr)
Delete a multicast Address from the advertised MLD set.
u8 as_u8[16]
Definition: ip6_packet.h:48
u64 as_u64[2]
Definition: ip6_packet.h:51
unsigned long u64
Definition: types.h:89
static clib_error_t * set_ip6_nd_proxy_cmd(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
int send_unicast
Definition: ip6_neighbor.c:113
ip6_address_t prefix
Definition: ip6_neighbor.c:45
static void vlib_error_count(vlib_main_t *vm, uword node_index, uword counter, uword increment)
Definition: error_funcs.h:57
Multicast Adjacency.
Definition: adj.h:82
static ip6_address_t * ip6_interface_address_matching_destination(ip6_main_t *im, ip6_address_t *dst, u32 sw_if_index, ip_interface_address_t **result_ia)
Definition: ip6.h:338
clib_error_t * call_ip6_neighbor_callbacks(void *data, _vnet_ip6_neighbor_function_list_elt_t *elt)
#define clib_memcpy_fast(a, b, c)
Definition: string.h:81
f64 last_multicast_time
Definition: ip6_neighbor.c:143
void send_ip6_na(vlib_main_t *vm, u32 sw_if_index)
vnet_link_t adj_get_link_type(adj_index_t ai)
Return the link type of the adjacency.
Definition: adj.c:468
#define NULL
Definition: clib.h:58
uword mhash_unset(mhash_t *h, void *key, uword *old_value)
Definition: mhash.c:353
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
u32 index
Definition: node.h:304
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:232
Broadcasr Adjacency.
Definition: adj.h:85
ip6_radv_prefix_t * adv_prefixes_pool
Definition: ip6_neighbor.c:98
IP unicast adjacency.
Definition: adj.h:221
#define ethernet_buffer_header_size(b)
Determine the size of the Ethernet headers of the current frame in the buffer.
Definition: ethernet.h:453
u8 src_address[6]
Definition: packet.h:56
static void wc_nd_signal_report(wc_nd_report_t *r)
Definition: ip6_neighbor.c:283
ip6_neighbor_t * ip6_neighbors_entries(u32 sw_if_index)
pending_resolution_t * pending_resolutions
Definition: ip6_neighbor.c:188
u32 thread_index
Definition: main.h:179
static vlib_cli_command_t set_ip6_neighbor_command
(constructor) VLIB_CLI_COMMAND (set_ip6_neighbor_command)
static uword ip6_discover_neighbor_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int is_glean)
This packet is to be rewritten and forwarded to the next processing node.
Definition: adj.h:73
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:525
ip6_address_t * ip6_interface_first_address(ip6_main_t *im, u32 sw_if_index)
get first IPv6 interface address
Definition: ip6_forward.c:174
word vnet_sw_interface_compare(vnet_main_t *vnm, uword sw_if_index0, uword sw_if_index1)
Definition: interface.c:1185
static u64 clib_cpu_time_now(void)
Definition: time.h:75
#define IP6_NBR_MK_KEY(k, sw_if_index, addr)
Definition: ip6_neighbor.c:531
static int logmask
int ip6_get_ll_address(u32 sw_if_index, ip6_address_t *addr)
int i
int ip6_neighbor_proxy_add_del(u32 sw_if_index, ip6_address_t *addr, u8 is_del)
adj_index_t adj_glean_get(fib_protocol_t proto, u32 sw_if_index)
Get an existing glean.
Definition: adj_glean.c:119
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:983
#define STRUCT_OFFSET_OF(t, f)
Definition: clib.h:65
u32 adv_pref_lifetime_in_secs
Definition: ip6_neighbor.c:50
#define DEF_ADV_PREF_LIFETIME
Definition: ip6_neighbor.c:63
static void set_unset_ip6_neighbor_rpc(vlib_main_t *vm, u32 sw_if_index, const ip6_address_t *a, const u8 *link_layer_address, int is_add, int is_static, int is_no_fib_entry)
Definition: ip6_neighbor.c:416
static vnet_sw_interface_t * vnet_get_sw_interface(vnet_main_t *vnm, u32 sw_if_index)
u32 ip6_neighbor_sw_interface_add_del(vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
create and initialize router advertisement parameters with default values for this intfc ...
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
u8 * va_format(u8 *s, const char *fmt, va_list *va)
Definition: format.c:387
static u32 vnet_sw_interface_get_mtu(vnet_main_t *vnm, u32 sw_if_index, vnet_mtu_t af)
static uword ip6_address_is_local_unicast(const ip6_address_t *a)
Definition: ip6_packet.h:328
unformat_function_t unformat_vnet_sw_interface
static u64 random_u64(u64 *seed)
64-bit random number generator Again, constants courtesy of Donald Knuth.
Definition: random.h:126
int vnet_add_del_ip6_nd_change_event(vnet_main_t *vnm, void *data_callback, u32 pid, void *address_arg, uword node_index, uword type_opaque, uword data, int is_add)
u32 adv_neighbor_reachable_time_in_msec
Definition: ip6_neighbor.c:87
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:493
Definition: fib_entry.h:277
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:236
vhost_vring_addr_t addr
Definition: vhost_user.h:121
ip6_address_t src_address
Definition: ip6_packet.h:378
format_function_t format_vnet_sw_if_index_name
unsigned char u8
Definition: types.h:56
static vlib_buffer_t * vlib_buffer_copy(vlib_main_t *vm, vlib_buffer_t *b)
Definition: buffer_funcs.h:685
void * data_callback
Definition: arp.c:68
clib_error_t * disable_ip6_interface(vlib_main_t *vm, u32 sw_if_index)
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
double f64
Definition: types.h:142
vnet_link_t ia_link
link/ether-type 1 bytes
Definition: adj.h:242
#define clib_memcpy(d, s, n)
Definition: string.h:180
vlib_node_registration_t ip6_rewrite_mcast_node
(constructor) VLIB_REGISTER_NODE (ip6_rewrite_mcast_node)
Definition: ip6_forward.c:2061
static uword ip6_neighbor_process_timer_event(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Adjacency to punt this packet.
Definition: adj.h:55
vlib_packet_template_t discover_neighbor_packet_template
Definition: ip6.h:220
ip6_neighbor_flags_t flags
Definition: ip6_neighbor.h:42
static vlib_buffer_t * create_buffer_for_rs(vlib_main_t *vm, ip6_radv_t *radv_info)
void adj_glean_update_rewrite(adj_index_t adj_index)
adj_glean_update_rewrite
Definition: adj_glean.c:101
ethernet_main_t ethernet_main
Definition: init.c:45
fib_node_index_t ip6_fib_table_lookup_exact_match(u32 fib_index, const ip6_address_t *addr, u32 len)
Definition: ip6_fib.c:218
static void ip6_print_addrs(vlib_main_t *vm, u32 *addrs)
static ip_adjacency_t * adj_get(adj_index_t adj_index)
Get a pointer to an adjacency object from its index.
Definition: adj.h:433
static u64 ip6_address_hash_to_u64(const ip6_address_t *a)
Definition: ip6_packet.h:357
ip6_neighbor_t * ip6_neighbors_pool(void)
union ip_adjacency_t_::@42 sub_type
#define static_always_inline
Definition: clib.h:99
u8 * format_ethernet_address(u8 *s, va_list *args)
Definition: format.c:44
void * vlib_packet_template_get_packet(vlib_main_t *vm, vlib_packet_template_t *t, u32 *bi_result)
Definition: buffer.c:688
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:490
static int vnet_nd_wc_publish(u32 sw_if_index, u8 *mac, ip6_address_t *ip6)
publish wildcard arp event
Definition: ip6_neighbor.c:269
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:163
static uword ip6_glean(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
static uword vlib_process_get_events(vlib_main_t *vm, uword **data_vector)
Return the first event type which has occurred and a vector of per-event data of that type...
Definition: node_funcs.h:516
u32 local_interface_sw_if_index
Definition: vnet.h:54
VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(ip6_neighbor_sw_interface_up_down)
u8 link_layer_addr_len
Definition: ip6_neighbor.c:95
u32 sw_if_index
Definition: vxlan_gbp.api:37
uword wc_ip6_nd_publisher_node
Definition: ip6_neighbor.c:209
#define ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE
u8 dst_address[6]
Definition: packet.h:55
enum adj_walk_rc_t_ adj_walk_rc_t
return codes from a adjacency walker callback function
static clib_error_t * disable_ip6_interface_cmd(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
static u8 * format_ip6_neighbor_ip6_entry(u8 *s, va_list *va)
Definition: ip6_neighbor.c:338
static uword ip6_icmp_neighbor_discovery_event_process(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
static clib_error_t * show_ip6_neighbors(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
vnet_hw_interface_flags_t flags
Definition: interface.h:516
#define DEF_ADV_VALID_LIFETIME
Definition: ip6_neighbor.c:62
int vnet_set_ip6_ethernet_neighbor(vlib_main_t *vm, u32 sw_if_index, const ip6_address_t *a, const u8 *link_layer_address, uword n_bytes_link_layer_address, int is_static, int is_no_fib_entry)
Definition: ip6_neighbor.c:775
mhash_t address_to_mldp_index
Definition: ip6_neighbor.c:107
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
static vnet_sw_interface_t * vnet_get_sup_sw_interface(vnet_main_t *vnm, u32 sw_if_index)
Aggregrate type for a prefix.
Definition: fib_types.h:203
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:181
#define clib_error_return(e, args...)
Definition: error.h:99
static u32 ip6_src_lookup_for_packet(ip6_main_t *im, vlib_buffer_t *b, ip6_header_t *i)
return the DPO that the LB stacks on.
Definition: ip6_fib.h:119
void vl_api_rpc_call_main_thread(void *fp, u8 *data, u32 data_length)
Definition: vlib_api.c:623
void adj_unlock(adj_index_t adj_index)
Release a reference counting lock on the adjacency.
Definition: adj.c:318
unsigned int u32
Definition: types.h:88
f64 max_radv_interval
Definition: ip6_neighbor.c:136
static void ip6_link_local_address_from_ethernet_address(ip6_address_t *a, const u8 *ethernet_address)
Definition: ip6_packet.h:207
static clib_error_t * set_ip6_neighbor(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
u32 * neighbor_input_next_index_by_hw_if_index
Definition: ip6_neighbor.c:194
int vnet_ip6_nd_term(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_buffer_t *p0, ethernet_header_t *eth, ip6_header_t *ip, u32 sw_if_index, u16 bd_index)
u16 fp_len
The mask length.
Definition: fib_types.h:207
const u8 * ethernet_ip6_mcast_dst_addr(void)
Definition: interface.c:66
#define VLIB_FRAME_SIZE
Definition: node.h:401
static void ra_signal_report(ra_report_t *r)
Definition: ip6_neighbor.c:315
static f64 random_f64_from_to(f64 from, f64 to)
u32 ip6_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip6_fib.c:326
u32 time_in_msec_between_retransmitted_neighbor_solicitations
Definition: ip6_neighbor.h:137
static u32 vlib_get_buffer_index(vlib_main_t *vm, void *p)
Translate buffer pointer into buffer index.
Definition: buffer_funcs.h:158
#define MAX_DELAY_BETWEEN_RAS
Definition: ip6_neighbor.c:133
#define fl(x, y)
Definition: fib_entry.h:275
unformat_function_t unformat_line_input
Definition: format.h:282
static heap_elt_t * first(heap_header_t *h)
Definition: heap.c:59
throttle_t nd_throttle
ND throttling.
Definition: ip6.h:241
f64 max_delay_between_radv
Definition: ip6_neighbor.c:139
u32 adv_time_in_msec_between_retransmitted_neighbor_solicitations
Definition: ip6_neighbor.c:88
#define pool_flush(VAR, POOL, BODY)
Remove all elements from a pool in a safe way.
Definition: pool.h:550
vnet_api_error_t api_errno
Definition: vnet.h:78
Definition: fib_entry.h:280
IPv6 ND (seen in the link-local tables)
Definition: fib_entry.h:102
format_function_t format_vnet_sw_interface_name
void adj_mcast_update_rewrite(adj_index_t adj_index, u8 *rewrite, u8 offset)
adj_mcast_update_rewrite
Definition: adj_mcast.c:102
#define ADJ_INDEX_INVALID
Invalid ADJ index - used when no adj is known likewise blazoned capitals INVALID speak volumes where ...
Definition: adj_types.h:36
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:511
vlib_main_t * vlib_main
Definition: vnet.h:80
f64 min_radv_interval
Definition: ip6_neighbor.c:137
void vnet_register_ip6_neighbor_resolution_event(vnet_main_t *vnm, void *address_arg, uword node_index, uword type_opaque, uword data)
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:114
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:934
Adjacency source.
Definition: fib_entry.h:108
ip46_address_t fp_addr
The address type is not deriveable from the fp_addr member.
Definition: fib_types.h:226
u32 neighbor_reachable_time_in_msec
Definition: ip6_neighbor.h:136
uword type_opaque
Definition: arp.c:65
static void ip6_neighbor_add_mld_grp(ip6_radv_t *a, ip6_multicast_address_scope_t scope, ip6_multicast_link_local_group_id_t group)
Add a multicast Address to the advertised MLD set.
u8 address_length
Definition: ip_types.api:37
long ctx[MAX_CONNS]
Definition: main.c:144
int all_routers_mcast
Definition: ip6_neighbor.c:117
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
static char * ip6_discover_neighbor_error_strings[]
static clib_error_t * enable_ip6_interface_cmd(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
#define DEF_MAX_RADV_INTERVAL
Definition: ip6_neighbor.c:124
#define IP6_MLDP_ALERT_TYPE
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:190
u8 link_layer_address[8]
Definition: ip6_neighbor.c:94
f64 next_multicast_time
Definition: ip6_neighbor.c:144
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:214
#define VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX
Definition: buffer.h:442
u32 ip6_ll_fib_get(u32 sw_if_index)
For use in the data plane.
Definition: ip6_ll_table.c:28
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:286
#define foreach_log_level
enum icmp6_neighbor_discovery_option_type icmp6_neighbor_discovery_option_type_t
static void * vlib_process_signal_event_data(vlib_main_t *vm, uword node_index, uword type_opaque, uword n_data_elts, uword n_data_elt_bytes)
Definition: node_funcs.h:828
#define ELOG_DATA(em, f)
Definition: elog.h:484
ip6_table_bind_callback_t * table_bind_callbacks
Functions to call when interface to table biding changes.
Definition: ip6.h:217
int ip6_address_compare(ip6_address_t *a1, ip6_address_t *a2)
Definition: ip46_cli.c:60
static u64 throttle_seed(throttle_t *t, u32 thread_index, f64 time_now)
Definition: throttle.h:41
#define PREDICT_FALSE(x)
Definition: clib.h:111
This packet matches an "interface route" and packets need to be passed to ARP to find rewrite string ...
Definition: adj.h:68
vnet_sw_interface_flags_t flags
Definition: interface.h:706
vnet_main_t vnet_main
Definition: misc.c:43
ip6_discover_neighbor_error_t
int adv_other_flag
Definition: ip6_neighbor.c:85
u32 node_index
Node index.
Definition: node.h:518
mhash_t address_to_prefix_index
Definition: ip6_neighbor.c:101
u16 router_lifetime_in_sec
Definition: ip6_neighbor.h:135
#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:218
static uword mhash_set(mhash_t *h, void *key, uword new_value, uword *old_value)
Definition: mhash.h:117
#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:338
ra_report_prefix_info_t * prefixes
Definition: ip6_neighbor.h:140
static uword ip6_discover_neighbor(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
ip6_add_del_interface_address_callback_t * add_del_interface_address_callbacks
Definition: ip6.h:214
void ra_set_publisher_node(uword node_index, uword event_type)
Definition: ip6_neighbor.c:330
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:139
void ip6_link_local_address_from_ethernet_mac_address(ip6_address_t *ip, u8 *mac)
Definition: ip6_forward.c:2721
static void ip6_neighbor_add_mld_prefix(ip6_radv_t *radv_info, ip6_address_t *addr)
Add a multicast Address to the advertised MLD set.
int failed_device_check
Definition: ip6_neighbor.c:116
vlib_node_registration_t ip6_icmp_input_node
(constructor) VLIB_REGISTER_NODE (ip6_icmp_input_node)
Definition: icmp6.c:240
unformat_function_t unformat_ip6_address
Definition: format.h:91
#define pool_free(p)
Free a pool.
Definition: pool.h:404
ip6_mldp_group_t * mldp_group_pool
Definition: ip6_neighbor.c:104
static_always_inline uword icmp6_neighbor_solicitation_or_advertisement(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, uword is_solicitation)
void wc_nd_set_publisher_node(uword node_index, uword event_type)
Definition: ip6_neighbor.c:299
clib_error_t * enable_ip6_interface(vlib_main_t *vm, u32 sw_if_index)
void ip6_mfib_interface_enable_disable(u32 sw_if_index, int is_enable)
Add/remove the interface from the accepting list of the special MFIB entries.
Definition: ip6_mfib.c:232
icmp6_neighbor_solicitation_or_advertisement_next_t
int adv_managed_flag
Definition: ip6_neighbor.c:84
static uword icmp6_neighbor_advertisement(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
This packet matches an "incomplete adjacency" and packets need to be passed to ARP to find rewrite st...
Definition: adj.h:63
static int ip6_src_address_for_packet(ip_lookup_main_t *lm, u32 sw_if_index, const ip6_address_t *dst, ip6_address_t *src)
Definition: ip6.h:307
int fib_entry_is_sourced(fib_node_index_t fib_entry_index, fib_source_t source)
u32 n_solicitations_dropped
Definition: ip6_neighbor.c:154
Adjacency to drop this packet.
Definition: adj.h:53
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
static void vlib_buffer_copy_trace_flag(vlib_main_t *vm, vlib_buffer_t *b, u32 bi_target)
Definition: trace_funcs.h:147
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
void mhash_init(mhash_t *h, uword n_value_bytes, uword n_key_bytes)
Definition: mhash.c:168
static u8 get_mac_address(u32 sw_if_index, u8 *address)
u8 router_address[16]
Definition: ip6_neighbor.h:132
u16 n_vectors
Definition: node.h:420
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:212
format_function_t format_ip6_address
Definition: format.h:93
static ip6_address_t ip6a_zero
Definition: ip6_neighbor.c:235
vlib_main_t * vm
Definition: buffer.c:301
static int ra_publish(ra_report_t *r)
Definition: ip6_neighbor.c:307
vl_api_address_t dst
Definition: vxlan_gbp.api:33
ip6_address_t mcast_address
Definition: ip6_neighbor.c:73
static void ip6_neighbor_adj_fib_remove(ip6_neighbor_t *n, u32 fib_index)
Definition: ip6_neighbor.c:372
log_level_t
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
Multicast Midchain Adjacency.
Definition: adj.h:89
u8 curr_hop_limit
Definition: ip6_neighbor.c:83
f64 sleep_interval
Definition: ip6_neighbor.c:162
#define clib_warning(format, args...)
Definition: error.h:59
ip6_address_t * mcast_source_address_pool
Definition: ip6_neighbor.c:75
static vlib_node_runtime_t * vlib_node_get_runtime(vlib_main_t *vm, u32 node_index)
Get node runtime by node index.
Definition: node_funcs.h:89
static void ip6_neighbor_table_bind(ip6_main_t *im, uword opaque, u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
#define DEF_CURR_HOP_LIMIT
Definition: ip6_neighbor.c:126
elog_main_t elog_main
Definition: main.h:157
int adv_link_layer_address
Definition: ip6_neighbor.c:114
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:30
static vlib_cli_command_t show_ip6_neighbors_command
(constructor) VLIB_CLI_COMMAND (show_ip6_neighbors_command)
fib_node_index_t fib_entry_index
Definition: ip6_neighbor.h:44
u32 adj_index_t
An index for adjacencies.
Definition: adj_types.h:30
#define ARRAY_LEN(x)
Definition: clib.h:62
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:452
uword * mac_by_ip6
Definition: l2_bd.h:102
#define ELOG_TYPE_DECLARE(f)
Definition: elog.h:442
vlib_node_t * vlib_get_node_by_name(vlib_main_t *vm, u8 *name)
Definition: node.c:45
static bool check_send_rs(vlib_main_t *vm, ip6_radv_t *radv_info, f64 current_time, f64 *due_time)
u8 current_hop_limit
Definition: ip6_neighbor.h:133
static void * ip6_next_header(ip6_header_t *i)
Definition: ip6_packet.h:405
ip6_address_t ilp_addr
the IP6 address
Definition: ip6_ll_types.h:34
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:155
u32 initial_adverts_count
Definition: ip6_neighbor.c:147
This packets follow a mid-chain adjacency.
Definition: adj.h:76
u32 * if_address_pool_index_by_sw_if_index
Head of doubly linked list of interface addresses for each software interface.
Definition: lookup.h:132
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:944
ip6_add_del_interface_address_function_t * function
Definition: ip6.h:103
#define MAX_INITIAL_RTR_ADVERTISEMENTS
Definition: ip6_neighbor.c:131
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:537
ip6_address_t link_local_address
Definition: ip6_neighbor.c:157
uword unformat_ethernet_address(unformat_input_t *input, va_list *args)
Definition: format.c:233
#define ASSERT(truth)
vlib_node_registration_t send_rs_process_node
(constructor) VLIB_REGISTER_NODE (send_rs_process_node)
int prefix_option
Definition: ip6_neighbor.c:115
static uword * mhash_get(mhash_t *h, const void *key)
Definition: mhash.h:110
ip6_address_t ip6_address
Definition: ip6_neighbor.h:26
ip6_main_t ip6_main
Definition: ip6_forward.c:2624
ip_lookup_main_t lookup_main
Definition: ip6.h:178
u32 n_advertisements_sent
Definition: ip6_neighbor.c:152
static void mhash_free(mhash_t *h)
Definition: mhash.h:149
static vlib_buffer_free_list_index_t vlib_buffer_get_free_list_index(vlib_buffer_t *b)
Definition: buffer_funcs.h:396
static clib_error_t * show_ip6_interface_cmd(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
u32 vlib_register_node(vlib_main_t *vm, vlib_node_registration_t *r)
Definition: node.c:520
f64 min_delay_between_radv
Definition: ip6_neighbor.c:138
#define DEF_MIN_RADV_INTERVAL
Definition: ip6_neighbor.c:125
static_always_inline uword icmp6_router_solicitation(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
static int ip6_neighbor_sort(void *a1, void *a2)
Definition: ip6_neighbor.c:990
static uword send_rs_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f0)
u32 * if_radv_pool_index_by_sw_if_index
Definition: ip6_neighbor.c:200
u16 adv_router_lifetime_in_sec
Definition: ip6_neighbor.c:86
static f64 random_f64(u32 *seed)
Generate f64 random number in the interval [0,1].
Definition: random.h:145
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:233
Aggregrate type for a prefix in the IPv6 Link-local table.
Definition: ip6_ll_types.h:24
size_t count
Definition: vapi.c:47
ip6_multicast_link_local_group_id_t
Definition: ip6_packet.h:164
static uword ip6_address_is_link_local_unicast(const ip6_address_t *a)
Definition: ip6_packet.h:321
Route added as a result of interface configuration.
Definition: fib_entry.h:54
void fib_table_entry_path_remove(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, dpo_proto_t next_hop_proto, const ip46_address_t *next_hop, u32 next_hop_sw_if_index, u32 next_hop_fib_index, u32 next_hop_weight, fib_route_path_flags_t path_flags)
remove one path to an entry (aka route) in the FIB.
Definition: fib_table.c:682
u8 mac_address[6]
u8 keep_sending_rs
Definition: ip6_neighbor.c:160
mhash_t pending_resolutions_by_address
Definition: ip6_neighbor.c:187
static uword icmp6_neighbor_solicitation(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
static adj_walk_rc_t ip6_nd_mk_incomplete_walk(adj_index_t ai, void *ctx)
Definition: ip6_neighbor.c:568
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
static uword vnet_sw_interface_is_admin_up(vnet_main_t *vnm, u32 sw_if_index)
vlib_buffer_t * buffer
Definition: ip6_neighbor.c:166
int vlib_buffer_add_data(vlib_main_t *vm, vlib_buffer_free_list_index_t free_list_index, u32 *buffer_index, void *data, u32 n_data_bytes)
Definition: buffer.c:709
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:57
icmp6_send_router_solicitation_params_t params
Definition: ip6_neighbor.c:161
#define unformat_parse_error(input)
Definition: format.h:268
ip6_address_t ip6_neighbor_get_link_local_address(u32 sw_if_index)
Definition: ip6_neighbor.c:241
static ip6_neighbor_t * force_reuse_neighbor_entry(void)
Definition: ip6_neighbor.c:744
struct _vlib_node_registration vlib_node_registration_t
u32 ip_version_traffic_class_and_flow_label
Definition: ip6_packet.h:365
void ethernet_ndp_change_mac(u32 sw_if_index)
fib_entry_flag_t fib_entry_get_flags_for_source(fib_node_index_t fib_entry_index, fib_source_t source)
This packets needs to go to ICMP error.
Definition: adj.h:79
This packet is for one of our own IP addresses.
Definition: adj.h:58
static vlib_node_registration_t ip6_icmp_router_solicitation_node
(constructor) VLIB_REGISTER_NODE (ip6_icmp_router_solicitation_node)
Definition: defs.h:47
void vlib_trace_frame_buffers_only(vlib_main_t *vm, vlib_node_runtime_t *node, u32 *buffers, uword n_buffers, uword next_buffer_stride, uword n_buffer_data_bytes_in_trace)
Definition: trace.c:47
static void ip6_neighbor_send_mldpv2_report(u32 sw_if_index)
l2input_main_t l2input_main
Definition: l2_input.c:122
vlib_node_registration_t ip6_icmp_neighbor_discovery_event_node
u16 payload_length
Definition: ip6_packet.h:369
static void * vlib_process_get_event_data(vlib_main_t *vm, uword *return_event_type_opaque)
Definition: node_funcs.h:463
static void ip6_neighbor_set_unset_rpc_callback(ip6_neighbor_set_unset_rpc_args_t *a)
Definition: ip6_neighbor.c:978
static uword ip6_address_is_global_unicast(const ip6_address_t *a)
Definition: ip6_packet.h:335
ethernet_interface_t * ethernet_get_interface(ethernet_main_t *em, u32 hw_if_index)
Definition: interface.c:888
int vnet_unset_ip6_ethernet_neighbor(vlib_main_t *vm, u32 sw_if_index, const ip6_address_t *a)
Definition: ip6_neighbor.c:936
static void ip6_set_solicited_node_multicast_address(ip6_address_t *a, u32 id)
Definition: ip6_packet.h:195
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:31
ip6_neighbor_key_t key
Definition: ip6_neighbor.h:40
u32 opaque2[12]
More opaque data, see ../vnet/vnet/buffer.h.
Definition: buffer.h:164
A for-us/local path.
Definition: fib_types.h:332
u32 elog_string(elog_main_t *em, char *fmt,...)
add a string to the event-log string table
Definition: elog.c:562
void icmp6_register_type(vlib_main_t *vm, icmp6_type_t type, u32 node_index)
Definition: icmp6.c:753
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
ip_lookup_next_t lookup_next_index
Next hop after ip4-lookup.
Definition: adj.h:236
#define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b)
Definition: buffer.h:495
u64 uword
Definition: types.h:112
ip6_neighbor_public_main_t ip6_neighbor_public_main
Definition: ip6_neighbor.c:234
format_function_t format_vlib_time
Definition: node_funcs.h:1145
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:984
static void unformat_free(unformat_input_t *i)
Definition: format.h:162
int ip6_neighbor_ra_config(vlib_main_t *vm, u32 sw_if_index, u8 suppress, u8 managed, u8 other, u8 ll_option, u8 send_unicast, u8 cease, u8 use_lifetime, u32 lifetime, u32 initial_count, u32 initial_interval, u32 max_interval, u32 min_interval, u8 is_no)
static void ip6_neighbor_add_del_interface_address(ip6_main_t *im, uword opaque, u32 sw_if_index, ip6_address_t *address, u32 address_length, u32 if_address_index, u32 is_delete)
callback when an interface address is added or deleted
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:244
u32 ilp_sw_if_index
The interface.
Definition: ip6_ll_types.h:29
ip6_table_bind_function_t * function
Definition: ip6.h:113
void ip6_ll_table_entry_delete(const ip6_ll_prefix_t *ilp)
Delete a IP6 link-local entry.
Definition: ip6_ll_table.c:139
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:80
l2_bridge_domain_t * bd_configs
Definition: l2_input.h:64
typedef prefix
Definition: ip_types.api:35
#define ICMP6_ROUTER_DISCOVERY_FLAG_ADDRESS_CONFIG_VIA_DHCP
vlib_node_registration_t ip6_glean_node
(constructor) VLIB_REGISTER_NODE (ip6_glean_node)
#define hash_get_mem(h, key)
Definition: hash.h:269
struct clib_bihash_value offset
template key/value backing page structure
static uword ip6_address_is_unspecified(const ip6_address_t *a)
Definition: ip6_packet.h:305
static vlib_node_registration_t ip6_icmp_neighbor_advertisement_node
(constructor) VLIB_REGISTER_NODE (ip6_icmp_neighbor_advertisement_node)
static void vlib_buffer_init_for_free_list(vlib_buffer_t *dst, vlib_buffer_free_list_t *fl)
#define vnet_buffer(b)
Definition: buffer.h:368
static clib_error_t * ip6_neighbor_sw_interface_up_down(vnet_main_t *vnm, u32 sw_if_index, u32 flags)
Definition: ip6_neighbor.c:576
f64 initial_adverts_interval
Definition: ip6_neighbor.c:148
static u32 random_u32(u32 *seed)
32-bit random number generator
Definition: random.h:69
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
vnet_sw_interface_type_t type
Definition: interface.h:704
adj_index_t mcast_adj_index
Definition: ip6_neighbor.c:121
uword node_index
Definition: arp.c:64
ip6_icmp_neighbor_discovery_event_type_t
Definition: ip6_neighbor.c:218
adj_index_t adj_mcast_add_or_lock(fib_protocol_t proto, vnet_link_t link_type, u32 sw_if_index)
Mcast Adjacency.
Definition: adj_mcast.c:51
vlib_node_registration_t ip6_discover_neighbor_node
(constructor) VLIB_REGISTER_NODE (ip6_discover_neighbor_node)
#define vec_foreach(var, vec)
Vector iterator.
void ip6_ethernet_update_adjacency(vnet_main_t *vnm, u32 sw_if_index, u32 ai)
Definition: ip6_neighbor.c:624
void ip6_forward_next_trace(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, vlib_rx_or_tx_t which_adj_index)
Definition: ip6_forward.c:852
u16 flags
Copy of main node flags.
Definition: node.h:531
u32 adv_valid_lifetime_in_secs
Definition: ip6_neighbor.c:49
static void ip6_multicast_ethernet_address(u8 *ethernet_address, u32 group_id)
Definition: ip6_packet.h:224
static vlib_buffer_free_list_t * vlib_buffer_get_free_list(vlib_main_t *vm, vlib_buffer_free_list_index_t free_list_index)
Definition: buffer_funcs.h:657
u32 initial_adverts_sent
Definition: ip6_neighbor.c:149
static void * ip_interface_address_get_address(ip_lookup_main_t *lm, ip_interface_address_t *a)
Definition: lookup.h:175
static ip6_neighbor_t * ip6_nd_find(u32 sw_if_index, const ip6_address_t *addr)
Definition: ip6_neighbor.c:539
mhash_t mac_changes_by_address
Definition: ip6_neighbor.c:191
static adj_walk_rc_t ip6_nd_mk_complete_walk(adj_index_t ai, void *ctx)
Definition: ip6_neighbor.c:558
#define MAX_INITIAL_RTR_ADVERT_INTERVAL
Definition: ip6_neighbor.c:130
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:326
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:488
fib_node_index_t ip6_ll_table_entry_update(const ip6_ll_prefix_t *ilp, fib_route_path_flags_t flags)
Update an entry in the table.
Definition: ip6_ll_table.c:105
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:117
static u32 vlib_buffer_alloc(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Allocate buffers into supplied array.
Definition: buffer_funcs.h:485
clib_error_t * ip6_neighbor_cmd(vlib_main_t *vm, unformat_input_t *main_input, vlib_cli_command_t *cmd)
f64 max_rtr_default_lifetime
Definition: ip6_neighbor.c:140
static vlib_node_registration_t ip6_icmp_router_advertisement_node
(constructor) VLIB_REGISTER_NODE (ip6_icmp_router_advertisement_node)
ip6_neighbor_t * neighbor_pool
Definition: ip6_neighbor.c:196
void adj_nbr_update_rewrite(adj_index_t adj_index, adj_nbr_rewrite_flag_t flags, u8 *rewrite)
adj_nbr_update_rewrite
Definition: adj_nbr.c:298
vl_api_mac_address_t mac
Definition: gbp.api:118
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:762
ip6_address_t dst_address
Definition: ip6_neighbor.h:122
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:62
u8 link_layer_address[8]
Definition: ip6_neighbor.h:41
struct ip_adjacency_t_::@42::@43 nbr
IP_LOOKUP_NEXT_ARP/IP_LOOKUP_NEXT_REWRITE.
static_always_inline uword icmp6_router_advertisement(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
void ip6_sw_interface_enable_disable(u32 sw_if_index, u32 is_enable)
Definition: ip6_forward.c:142
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
#define MAX_DEF_RTR_LIFETIME
Definition: ip6_neighbor.c:128
u32 adv_link_mtu
Definition: ip6_neighbor.c:91
Definition: defs.h:46
static ip6_neighbor_main_t ip6_neighbor_main
Definition: ip6_neighbor.c:233
pending_resolution_t * mac_changes
Definition: ip6_neighbor.c:192
ip6_address_t dst_address
Definition: ip6_packet.h:378
int ip6_interface_enabled(vlib_main_t *vm, u32 sw_if_index)
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:170
static void ip6_set_reserved_multicast_address(ip6_address_t *a, ip6_multicast_address_scope_t scope, u16 id)
Definition: ip6_packet.h:185
IPv6 Proxy ND.
Definition: fib_entry.h:98
clib_error_t * ip6_set_neighbor_limit(u32 neighbor_limit)
format_function_t format_icmp6_input_trace
Definition: icmp6.h:65
static int throttle_check(throttle_t *t, u32 thread_index, u64 hash, u64 seed)
Definition: throttle.h:54
u8 * format_ip6_forward_next_trace(u8 *s, va_list *args)
Definition: ip6_forward.c:802
void adj_nbr_walk_nh6(u32 sw_if_index, const ip6_address_t *addr, adj_walk_cb_t cb, void *ctx)
Walk adjacencies on a link with a given v6 next-hop.
Definition: adj_nbr.c:626
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128