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