FD.io VPP  v19.08-27-gf4dcae4
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 == 0)
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  ci0 = vlib_get_buffer_index (vm, c0);
2407 
2408  f = vlib_get_frame_to_node (vm, next_index);
2409  to_next = vlib_frame_vector_args (f);
2410  to_next[0] = ci0;
2411  f->n_vectors = 1;
2412  vlib_put_frame_to_node (vm, next_index, f);
2413 
2414  if (params->mrc != 0 && --radv_info->n_left == 0)
2415  stop_sending_rs (vm, radv_info);
2416  else
2417  {
2418  radv_info->sleep_interval =
2419  (2 + random_f64_from_to (-0.1, 0.1)) * radv_info->sleep_interval;
2420  if (radv_info->sleep_interval > params->mrt)
2421  radv_info->sleep_interval =
2422  (1 + random_f64_from_to (-0.1, 0.1)) * params->mrt;
2423 
2424  radv_info->due_time = current_time + radv_info->sleep_interval;
2425 
2426  if (params->mrd != 0
2427  && current_time > radv_info->start_time + params->mrd)
2428  stop_sending_rs (vm, radv_info);
2429  else
2430  *due_time = radv_info->due_time;
2431  }
2432 
2433  return radv_info->keep_sending_rs;
2434 }
2435 
2436 static uword
2438  vlib_frame_t * f0)
2439 {
2441  ip6_radv_t *radv_info;
2442  uword *event_data = 0;
2443  f64 sleep_time = 1e9;
2444  f64 current_time;
2445  f64 due_time;
2446  f64 dt = 0;
2447 
2448  while (true)
2449  {
2450  vlib_process_wait_for_event_or_clock (vm, sleep_time);
2451  vlib_process_get_events (vm, &event_data);
2452  vec_reset_length (event_data);
2453 
2454  current_time = vlib_time_now (vm);
2455  do
2456  {
2457  due_time = current_time + 1e9;
2458  /* *INDENT-OFF* */
2459  pool_foreach (radv_info, nm->if_radv_pool,
2460  ({
2461  if (check_send_rs (vm, radv_info, current_time, &dt)
2462  && (dt < due_time))
2463  due_time = dt;
2464  }));
2465  /* *INDENT-ON* */
2466  current_time = vlib_time_now (vm);
2467  }
2468  while (due_time < current_time);
2469 
2470  sleep_time = due_time - current_time;
2471  }
2472 
2473  return 0;
2474 }
2475 
2476 /* *INDENT-OFF* */
2478  .function = send_rs_process,
2479  .type = VLIB_NODE_TYPE_PROCESS,
2480  .name = "send-rs-process",
2481 };
2482 /* *INDENT-ON* */
2483 
2484 void
2487  params)
2488 {
2490  u32 rai;
2491  ip6_radv_t *ra = 0;
2492 
2493  ASSERT (~0 != sw_if_index);
2494 
2496  ra = pool_elt_at_index (nm->if_radv_pool, rai);
2497 
2498  stop_sending_rs (vm, ra);
2499 
2500  if (!stop)
2501  {
2502  ra->keep_sending_rs = 1;
2503  ra->params = *params;
2504  ra->n_left = params->mrc;
2505  ra->start_time = vlib_time_now (vm);
2506  ra->sleep_interval = (1 + random_f64_from_to (-0.1, 0.1)) * params->irt;
2507  ra->due_time = 0; /* send first packet ASAP */
2508  ra->buffer = create_buffer_for_rs (vm, ra);
2509  if (!ra->buffer)
2510  ra->keep_sending_rs = 0;
2511  else
2513  }
2514 }
2515 
2516 /**
2517  * @brief Add a multicast Address to the advertised MLD set
2518  */
2519 static void
2521 {
2522  ip6_mldp_group_t *mcast_group_info;
2523  uword *p;
2524 
2525  /* lookup mldp info for this interface */
2526  p = mhash_get (&radv_info->address_to_mldp_index, addr);
2527  mcast_group_info =
2528  p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
2529 
2530  /* add address */
2531  if (!mcast_group_info)
2532  {
2533  /* add */
2534  u32 mi;
2535  pool_get (radv_info->mldp_group_pool, mcast_group_info);
2536 
2537  mi = mcast_group_info - radv_info->mldp_group_pool;
2538  mhash_set (&radv_info->address_to_mldp_index, addr, mi, /* old_value */
2539  0);
2540 
2541  mcast_group_info->type = 4;
2542  mcast_group_info->mcast_source_address_pool = 0;
2543  mcast_group_info->num_sources = 0;
2544  clib_memcpy (&mcast_group_info->mcast_address, addr,
2545  sizeof (ip6_address_t));
2546  }
2547 }
2548 
2549 /**
2550  * @brief Delete a multicast Address from the advertised MLD set
2551  */
2552 static void
2554 {
2555  ip6_mldp_group_t *mcast_group_info;
2556  uword *p;
2557 
2558  p = mhash_get (&radv_info->address_to_mldp_index, &addr);
2559  mcast_group_info =
2560  p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
2561 
2562  if (mcast_group_info)
2563  {
2564  mhash_unset (&radv_info->address_to_mldp_index, &addr,
2565  /* old_value */ 0);
2566  pool_put (radv_info->mldp_group_pool, mcast_group_info);
2567  }
2568 }
2569 
2570 /**
2571  * @brief Add a multicast Address to the advertised MLD set
2572  */
2573 static void
2577 {
2579 
2580  ip6_set_reserved_multicast_address (&addr, scope, group);
2581 
2582  ip6_neighbor_add_mld_prefix (a, &addr);
2583 }
2584 
2585 /**
2586  * @brief create and initialize router advertisement parameters with default
2587  * values for this intfc
2588  */
2589 u32
2591  u32 sw_if_index, u32 is_add)
2592 {
2594  ip6_radv_t *a = 0;
2595  u32 ri = ~0;
2596  vnet_sw_interface_t *sw_if0;
2597  ethernet_interface_t *eth_if0 = 0;
2598 
2599  /* lookup radv container - ethernet interfaces only */
2600  sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
2601  if (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
2602  eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
2603 
2604  if (!eth_if0)
2605  return ri;
2606 
2608  ~0);
2610 
2611  if (ri != ~0)
2612  {
2613  a = pool_elt_at_index (nm->if_radv_pool, ri);
2614 
2615  if (!is_add)
2616  {
2617  ip6_radv_prefix_t *p;
2618  ip6_mldp_group_t *m;
2619 
2620  /* release the lock on the interface's mcast adj */
2622 
2623  /* clean up prefix and MDP pools */
2624  /* *INDENT-OFF* */
2626  ({
2627  mhash_unset (&a->address_to_prefix_index, &p->prefix, 0);
2628  }));
2629  pool_flush (m, a->mldp_group_pool,
2630  ({
2631  mhash_unset (&a->address_to_mldp_index, &m->mcast_address, 0);
2632  }));
2633  /* *INDENT-ON* */
2634 
2637 
2640 
2641  if (a->keep_sending_rs)
2642  a->keep_sending_rs = 0;
2643 
2644  pool_put (nm->if_radv_pool, a);
2646  ri = ~0;
2647  }
2648  }
2649  else
2650  {
2651  if (is_add)
2652  {
2653  pool_get (nm->if_radv_pool, a);
2654 
2655  ri = a - nm->if_radv_pool;
2657 
2658  /* initialize default values (most of which are zero) */
2659  clib_memset (a, 0, sizeof (a[0]));
2660 
2661  a->sw_if_index = sw_if_index;
2666 
2667  /* send ll address source address option */
2668  a->adv_link_layer_address = 1;
2669 
2673  a->seed = (u32) clib_cpu_time_now ();
2674  (void) random_u32 (&a->seed);
2675  a->randomizer = clib_cpu_time_now ();
2676  (void) random_u64 (&a->randomizer);
2677 
2681 
2682  /* deafult is to send */
2683  a->send_radv = 1;
2684 
2685  /* fill in radv_info for this interface that will be needed later */
2686  a->adv_link_mtu =
2687  vnet_sw_interface_get_mtu (vnm, sw_if_index, VNET_MTU_IP6);
2688 
2689  clib_memcpy (a->link_layer_address, eth_if0->address, 6);
2690 
2691  /* fill in default link-local address (this may be overridden) */
2693  (&a->link_local_address, eth_if0->address);
2694 
2695  mhash_init (&a->address_to_prefix_index, sizeof (uword),
2696  sizeof (ip6_address_t));
2697  mhash_init (&a->address_to_mldp_index, sizeof (uword),
2698  sizeof (ip6_address_t));
2699 
2701  VNET_LINK_IP6,
2702  sw_if_index);
2703 
2704  a->keep_sending_rs = 0;
2705 
2706  /* add multicast groups we will always be reporting */
2708  IP6_MULTICAST_SCOPE_link_local,
2709  IP6_MULTICAST_GROUP_ID_all_hosts);
2711  IP6_MULTICAST_SCOPE_link_local,
2712  IP6_MULTICAST_GROUP_ID_all_routers);
2714  IP6_MULTICAST_SCOPE_link_local,
2715  IP6_MULTICAST_GROUP_ID_mldv2_routers);
2716  }
2717  }
2718  return ri;
2719 }
2720 
2721 /* send an mldpv2 report */
2722 static void
2724 {
2725  vnet_main_t *vnm = vnet_get_main ();
2726  vlib_main_t *vm = vnm->vlib_main;
2728  vnet_sw_interface_t *sw_if0;
2729  ethernet_interface_t *eth_if0;
2730  u32 ri;
2731  int bogus_length;
2732 
2733  ip6_radv_t *radv_info;
2734  u16 payload_length;
2735  vlib_buffer_t *b0;
2736  ip6_header_t *ip0;
2737  u32 *to_next;
2738  vlib_frame_t *f;
2739  u32 bo0;
2740  u32 n_to_alloc = 1;
2741  u32 n_allocated;
2742 
2743  icmp6_multicast_listener_report_header_t *rh0;
2744  icmp6_multicast_listener_report_packet_t *rp0;
2745 
2746  sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
2748  eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
2749 
2750  if (!eth_if0 || !vnet_sw_interface_is_admin_up (vnm, sw_if_index))
2751  return;
2752 
2753  /* look up the radv_t information for this interface */
2755  ~0);
2756 
2758 
2759  if (ri == ~0)
2760  return;
2761 
2762  /* send report now - build a mldpv2 report packet */
2763  n_allocated = vlib_buffer_alloc (vm, &bo0, n_to_alloc);
2764  if (PREDICT_FALSE (n_allocated == 0))
2765  {
2766  alloc_fail:
2767  clib_warning ("buffer allocation failure");
2768  return;
2769  }
2770 
2771  b0 = vlib_get_buffer (vm, bo0);
2772 
2773  /* adjust the sizeof the buffer to just include the ipv6 header */
2774  b0->current_length = sizeof (icmp6_multicast_listener_report_packet_t);
2775 
2776  payload_length = sizeof (icmp6_multicast_listener_report_header_t);
2777 
2778  b0->error = ICMP6_ERROR_NONE;
2779 
2780  rp0 = vlib_buffer_get_current (b0);
2781  ip0 = (ip6_header_t *) & rp0->ip;
2782  rh0 = (icmp6_multicast_listener_report_header_t *) & rp0->report_hdr;
2783 
2784  clib_memset (rp0, 0x0, sizeof (icmp6_multicast_listener_report_packet_t));
2785 
2787  clib_host_to_net_u32 (0x6 << 28);
2788 
2789  ip0->protocol = IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS;
2790  /* for DEBUG - vnet driver won't seem to emit router alerts */
2791  /* ip0->protocol = IP_PROTOCOL_ICMP6; */
2792  ip0->hop_limit = 1;
2793 
2794  rh0->icmp.type = ICMP6_multicast_listener_report_v2;
2795 
2796  /* source address MUST be the link-local address */
2797  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
2798  ip0->src_address = radv_info->link_local_address;
2799 
2800  /* destination is all mldpv2 routers */
2802  IP6_MULTICAST_SCOPE_link_local,
2803  IP6_MULTICAST_GROUP_ID_mldv2_routers);
2804 
2805  /* add reports here */
2806  ip6_mldp_group_t *m;
2807  int num_addr_records = 0;
2808  icmp6_multicast_address_record_t rr;
2809 
2810  /* fill in the hop-by-hop extension header (router alert) info */
2811  rh0->ext_hdr.next_hdr = IP_PROTOCOL_ICMP6;
2812  rh0->ext_hdr.n_data_u64s = 0;
2813 
2814  rh0->alert.type = IP6_MLDP_ALERT_TYPE;
2815  rh0->alert.len = 2;
2816  rh0->alert.value = 0;
2817 
2818  rh0->pad.type = 1;
2819  rh0->pad.len = 0;
2820 
2821  rh0->icmp.checksum = 0;
2822 
2823  /* *INDENT-OFF* */
2824  pool_foreach (m, radv_info->mldp_group_pool,
2825  ({
2826  rr.type = m->type;
2827  rr.aux_data_len_u32s = 0;
2828  rr.num_sources = clib_host_to_net_u16 (m->num_sources);
2829  clib_memcpy(&rr.mcast_addr, &m->mcast_address, sizeof(ip6_address_t));
2830 
2831  num_addr_records++;
2832 
2833  if(vlib_buffer_add_data (vm, &bo0, (void *)&rr,
2834  sizeof(icmp6_multicast_address_record_t)))
2835  {
2836  vlib_buffer_free (vm, &bo0, 1);
2837  goto alloc_fail;
2838  }
2839 
2840  payload_length += sizeof( icmp6_multicast_address_record_t);
2841  }));
2842  /* *INDENT-ON* */
2843 
2844  rh0->rsvd = 0;
2845  rh0->num_addr_records = clib_host_to_net_u16 (num_addr_records);
2846 
2847  /* update lengths */
2848  ip0->payload_length = clib_host_to_net_u16 (payload_length);
2849 
2850  rh0->icmp.checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0,
2851  &bogus_length);
2852  ASSERT (bogus_length == 0);
2853 
2854  /*
2855  * OK to override w/ no regard for actual FIB, because
2856  * ip6-rewrite only looks at the adjacency.
2857  */
2858  vnet_buffer (b0)->sw_if_index[VLIB_RX] =
2860 
2861  vnet_buffer (b0)->ip.adj_index[VLIB_TX] = radv_info->mcast_adj_index;
2862  b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
2863 
2864  vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "ip6-rewrite-mcast");
2865 
2866  f = vlib_get_frame_to_node (vm, node->index);
2867  to_next = vlib_frame_vector_args (f);
2868  to_next[0] = bo0;
2869  f->n_vectors = 1;
2870 
2871  vlib_put_frame_to_node (vm, node->index, f);
2872  return;
2873 }
2874 
2875 /* *INDENT-OFF* */
2877 {
2878  .function = icmp6_router_solicitation,
2879  .name = "icmp6-router-solicitation",
2880 
2881  .vector_size = sizeof (u32),
2882 
2883  .format_trace = format_icmp6_input_trace,
2884 
2885  .n_next_nodes = ICMP6_ROUTER_SOLICITATION_N_NEXT,
2886  .next_nodes = {
2887  [ICMP6_ROUTER_SOLICITATION_NEXT_DROP] = "ip6-drop",
2888  [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW] = "ip6-rewrite-mcast",
2889  [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX] = "interface-output",
2890  },
2891 };
2892 /* *INDENT-ON* */
2893 
2894 /* send a RA or update the timer info etc.. */
2895 static uword
2897  vlib_node_runtime_t * node,
2898  vlib_frame_t * frame)
2899 {
2900  vnet_main_t *vnm = vnet_get_main ();
2902  ip6_radv_t *radv_info;
2903  vlib_frame_t *f = 0;
2904  u32 n_this_frame = 0;
2905  u32 n_left_to_next = 0;
2906  u32 *to_next = 0;
2907  u32 bo0;
2908  icmp6_router_solicitation_header_t *h0;
2909  vlib_buffer_t *b0;
2910  f64 now = vlib_time_now (vm);
2911 
2912  /* Interface ip6 radv info list */
2913  /* *INDENT-OFF* */
2914  pool_foreach (radv_info, nm->if_radv_pool,
2915  ({
2916  if( !vnet_sw_interface_is_admin_up (vnm, radv_info->sw_if_index))
2917  {
2918  radv_info->initial_adverts_sent = radv_info->initial_adverts_count-1;
2919  radv_info->next_multicast_time = now;
2920  radv_info->last_multicast_time = now;
2921  radv_info->last_radv_time = 0;
2922  radv_info->all_routers_mcast = 0;
2923  continue;
2924  }
2925 
2926  /* Make sure that we've joined the all-routers multicast group */
2927  if(!radv_info->all_routers_mcast)
2928  {
2929  /* send MDLP_REPORT_EVENT message */
2930  ip6_neighbor_send_mldpv2_report(radv_info->sw_if_index);
2931  radv_info->all_routers_mcast = 1;
2932  }
2933 
2934  /* is it time to send a multicast RA on this interface? */
2935  if(radv_info->send_radv && (now >= radv_info->next_multicast_time))
2936  {
2937  u32 n_to_alloc = 1;
2938  u32 n_allocated;
2939 
2940  f64 rfn = (radv_info->max_radv_interval - radv_info->min_radv_interval) *
2941  random_f64 (&radv_info->seed) + radv_info->min_radv_interval;
2942 
2943  /* multicast send - compute next multicast send time */
2944  if( radv_info->initial_adverts_sent > 0)
2945  {
2946  radv_info->initial_adverts_sent--;
2947  if(rfn > radv_info-> initial_adverts_interval)
2948  rfn = radv_info-> initial_adverts_interval;
2949 
2950  /* check to see if we are ceasing to send */
2951  if( radv_info->initial_adverts_sent == 0)
2952  if(radv_info->cease_radv)
2953  radv_info->send_radv = 0;
2954  }
2955 
2956  radv_info->next_multicast_time = rfn + now;
2957  radv_info->last_multicast_time = now;
2958 
2959  /* send advert now - build a "solicted" router advert with unspecified source address */
2960  n_allocated = vlib_buffer_alloc (vm, &bo0, n_to_alloc);
2961 
2962  if (PREDICT_FALSE(n_allocated == 0))
2963  {
2964  clib_warning ("buffer allocation failure");
2965  continue;
2966  }
2967  b0 = vlib_get_buffer (vm, bo0);
2968  b0->current_length = sizeof( icmp6_router_solicitation_header_t);
2969  b0->error = ICMP6_ERROR_NONE;
2970  vnet_buffer (b0)->sw_if_index[VLIB_RX] = radv_info->sw_if_index;
2971 
2972  h0 = vlib_buffer_get_current (b0);
2973 
2974  clib_memset (h0, 0, sizeof (icmp6_router_solicitation_header_t));
2975 
2976  h0->ip.ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (0x6 << 28);
2977  h0->ip.payload_length = clib_host_to_net_u16 (sizeof (icmp6_router_solicitation_header_t)
2978  - STRUCT_OFFSET_OF (icmp6_router_solicitation_header_t, neighbor));
2979  h0->ip.protocol = IP_PROTOCOL_ICMP6;
2980  h0->ip.hop_limit = 255;
2981 
2982  /* set src/dst address as "unspecified" this marks this packet as internally generated rather than recieved */
2983  h0->ip.src_address.as_u64[0] = 0;
2984  h0->ip.src_address.as_u64[1] = 0;
2985 
2986  h0->ip.dst_address.as_u64[0] = 0;
2987  h0->ip.dst_address.as_u64[1] = 0;
2988 
2989  h0->neighbor.icmp.type = ICMP6_router_solicitation;
2990 
2991  if (PREDICT_FALSE(f == 0))
2992  {
2994  to_next = vlib_frame_vector_args (f);
2995  n_left_to_next = VLIB_FRAME_SIZE;
2996  n_this_frame = 0;
2997  }
2998 
2999  n_this_frame++;
3000  n_left_to_next--;
3001  to_next[0] = bo0;
3002  to_next += 1;
3003 
3004  if (PREDICT_FALSE(n_left_to_next == 0))
3005  {
3006  f->n_vectors = n_this_frame;
3008  f = 0;
3009  }
3010  }
3011  }));
3012  /* *INDENT-ON* */
3013 
3014  if (f)
3015  {
3016  ASSERT (n_this_frame);
3017  f->n_vectors = n_this_frame;
3019  }
3020  return 0;
3021 }
3022 
3023 static uword
3025  vlib_node_runtime_t * node,
3026  vlib_frame_t * frame)
3027 {
3028  uword event_type;
3030 
3031  /* init code here */
3032 
3033  while (1)
3034  {
3035  vlib_process_wait_for_event_or_clock (vm, 1. /* seconds */ );
3036 
3037  event_data = vlib_process_get_event_data (vm, &event_type);
3038 
3039  if (!event_data)
3040  {
3041  /* No events found: timer expired. */
3042  /* process interface list and send RAs as appropriate, update timer info */
3043  ip6_neighbor_process_timer_event (vm, node, frame);
3044  }
3045  else
3046  {
3047  switch (event_type)
3048  {
3049 
3050  case ICMP6_ND_EVENT_INIT:
3051  break;
3052 
3053  case ~0:
3054  break;
3055 
3056  default:
3057  ASSERT (0);
3058  }
3059 
3060  if (event_data)
3061  _vec_len (event_data) = 0;
3062  }
3063  }
3064  return frame->n_vectors;
3065 }
3066 
3067 /* *INDENT-OFF* */
3069 {
3070  .function = icmp6_router_advertisement,
3071  .name = "icmp6-router-advertisement",
3072 
3073  .vector_size = sizeof (u32),
3074 
3075  .format_trace = format_icmp6_input_trace,
3076 
3077  .n_next_nodes = 1,
3078  .next_nodes = {
3079  [0] = "ip6-drop",
3080  },
3081 };
3082 /* *INDENT-ON* */
3083 
3085 
3087  .name = "ip6-icmp-neighbor-discovery-event-process",
3088  .type = VLIB_NODE_TYPE_PROCESS,
3089 };
3090 
3091 static uword
3093  vlib_node_runtime_t * node, vlib_frame_t * frame)
3094 {
3095  return icmp6_neighbor_solicitation_or_advertisement (vm, node, frame,
3096  /* is_solicitation */
3097  1);
3098 }
3099 
3100 static uword
3102  vlib_node_runtime_t * node,
3103  vlib_frame_t * frame)
3104 {
3105  return icmp6_neighbor_solicitation_or_advertisement (vm, node, frame,
3106  /* is_solicitation */
3107  0);
3108 }
3109 
3110 /* *INDENT-OFF* */
3112 {
3113  .function = icmp6_neighbor_solicitation,
3114  .name = "icmp6-neighbor-solicitation",
3115 
3116  .vector_size = sizeof (u32),
3117 
3118  .format_trace = format_icmp6_input_trace,
3119 
3120  .n_next_nodes = ICMP6_NEIGHBOR_SOLICITATION_N_NEXT,
3121  .next_nodes = {
3123  [ICMP6_NEIGHBOR_SOLICITATION_NEXT_REPLY] = "interface-output",
3124  },
3125 };
3126 /* *INDENT-ON* */
3127 
3128 /* *INDENT-OFF* */
3130 {
3131  .function = icmp6_neighbor_advertisement,
3132  .name = "icmp6-neighbor-advertisement",
3133 
3134  .vector_size = sizeof (u32),
3135 
3136  .format_trace = format_icmp6_input_trace,
3137 
3138  .n_next_nodes = 1,
3139  .next_nodes = {
3140  [0] = "ip6-drop",
3141  },
3142 };
3143 /* *INDENT-ON* */
3144 
3145 typedef enum
3146 {
3151 
3152 typedef enum
3153 {
3158 
3159 static uword
3161  vlib_node_runtime_t * node,
3162  vlib_frame_t * frame, int is_glean)
3163 {
3164  vnet_main_t *vnm = vnet_get_main ();
3165  ip6_main_t *im = &ip6_main;
3166  ip_lookup_main_t *lm = &im->lookup_main;
3167  u32 *from, *to_next_drop;
3168  uword n_left_from, n_left_to_next_drop;
3169  u64 seed;
3170  u32 thread_index = vm->thread_index;
3171  int bogus_length;
3173 
3174  if (node->flags & VLIB_NODE_FLAG_TRACE)
3175  ip6_forward_next_trace (vm, node, frame, VLIB_TX);
3176 
3177  seed = throttle_seed (&im->nd_throttle, thread_index, vlib_time_now (vm));
3178 
3179  from = vlib_frame_vector_args (frame);
3180  n_left_from = frame->n_vectors;
3181 
3182  while (n_left_from > 0)
3183  {
3185  to_next_drop, n_left_to_next_drop);
3186 
3187  while (n_left_from > 0 && n_left_to_next_drop > 0)
3188  {
3189  u32 pi0, adj_index0, sw_if_index0, drop0, r0, next0;
3190  vnet_hw_interface_t *hw_if0;
3191  ip6_radv_t *radv_info;
3192  ip_adjacency_t *adj0;
3193  vlib_buffer_t *p0;
3194  ip6_header_t *ip0;
3195 
3196  pi0 = from[0];
3197 
3198  p0 = vlib_get_buffer (vm, pi0);
3199 
3200  adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
3201 
3202  ip0 = vlib_buffer_get_current (p0);
3203 
3204  adj0 = adj_get (adj_index0);
3205 
3206  if (!is_glean)
3207  {
3208  ip0->dst_address.as_u64[0] =
3209  adj0->sub_type.nbr.next_hop.ip6.as_u64[0];
3210  ip0->dst_address.as_u64[1] =
3211  adj0->sub_type.nbr.next_hop.ip6.as_u64[1];
3212  }
3213 
3214  sw_if_index0 = adj0->rewrite_header.sw_if_index;
3215  vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
3216 
3217  /* combine the address and interface for a hash */
3218  r0 = ip6_address_hash_to_u64 (&ip0->dst_address) ^ sw_if_index0;
3219 
3220  drop0 = throttle_check (&im->nd_throttle, thread_index, r0, seed);
3221 
3222  from += 1;
3223  n_left_from -= 1;
3224  to_next_drop[0] = pi0;
3225  to_next_drop += 1;
3226  n_left_to_next_drop -= 1;
3227 
3228  hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
3229 
3230  /* If the interface is link-down, drop the pkt */
3231  if (!(hw_if0->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
3232  drop0 = 1;
3233 
3234  if (vec_len (nm->if_radv_pool_index_by_sw_if_index) > sw_if_index0)
3235  {
3236  u32 ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index0];
3237 
3238  if (ri != ~0)
3239  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3240  else
3241  drop0 = 1;
3242  }
3243  else
3244  drop0 = 1;
3245 
3246  /*
3247  * the adj has been updated to a rewrite but the node the DPO that got
3248  * us here hasn't - yet. no big deal. we'll drop while we wait.
3249  */
3251  drop0 = 1;
3252 
3253  p0->error =
3256 
3257  if (drop0)
3258  continue;
3259 
3260  {
3261  u32 bi0 = 0;
3262  icmp6_neighbor_solicitation_header_t *h0;
3263  vlib_buffer_t *b0;
3264 
3266  (vm, &im->discover_neighbor_packet_template, &bi0);
3267  if (!h0)
3268  continue;
3269 
3270  /* copy the persistent fields from the original */
3271  b0 = vlib_get_buffer (vm, bi0);
3272  clib_memcpy_fast (b0->opaque2, p0->opaque2, sizeof (p0->opaque2));
3273 
3274  /*
3275  * Build ethernet header.
3276  * Choose source address based on destination lookup
3277  * adjacency.
3278  */
3279  if (!ip6_src_address_for_packet (lm,
3280  sw_if_index0,
3281  &ip0->dst_address,
3282  &h0->ip.src_address))
3283  {
3284  /* There is no address on the interface */
3285  p0->error =
3287  vlib_buffer_free (vm, &bi0, 1);
3288  continue;
3289  }
3290 
3291  /*
3292  * Destination address is a solicited node multicast address.
3293  * We need to fill in
3294  * the low 24 bits with low 24 bits of target's address.
3295  */
3296  h0->ip.dst_address.as_u8[13] = ip0->dst_address.as_u8[13];
3297  h0->ip.dst_address.as_u8[14] = ip0->dst_address.as_u8[14];
3298  h0->ip.dst_address.as_u8[15] = ip0->dst_address.as_u8[15];
3299 
3300  h0->neighbor.target_address = ip0->dst_address;
3301 
3302  clib_memcpy (h0->link_layer_option.ethernet_address,
3303  hw_if0->hw_address, vec_len (hw_if0->hw_address));
3304 
3305  /* $$$$ appears we need this; why is the checksum non-zero? */
3306  h0->neighbor.icmp.checksum = 0;
3307  h0->neighbor.icmp.checksum =
3308  ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h0->ip,
3309  &bogus_length);
3310 
3311  ASSERT (bogus_length == 0);
3312 
3313  vlib_buffer_copy_trace_flag (vm, p0, bi0);
3314  vnet_buffer (b0)->sw_if_index[VLIB_TX]
3315  = vnet_buffer (p0)->sw_if_index[VLIB_TX];
3316 
3317  vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
3318  radv_info->mcast_adj_index;
3319 
3320  b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
3322 
3323  vlib_set_next_frame_buffer (vm, node, next0, bi0);
3324  }
3325  }
3326 
3328  n_left_to_next_drop);
3329  }
3330 
3331  return frame->n_vectors;
3332 }
3333 
3334 static uword
3336  vlib_node_runtime_t * node, vlib_frame_t * frame)
3337 {
3338  return (ip6_discover_neighbor_inline (vm, node, frame, 0));
3339 }
3340 
3341 static uword
3343 {
3344  return (ip6_discover_neighbor_inline (vm, node, frame, 1));
3345 }
3346 
3348  [IP6_DISCOVER_NEIGHBOR_ERROR_DROP] = "address overflow drops",
3349  [IP6_DISCOVER_NEIGHBOR_ERROR_REQUEST_SENT] = "neighbor solicitations sent",
3351  = "no source address for ND solicitation",
3352 };
3353 
3354 /* *INDENT-OFF* */
3356 {
3357  .function = ip6_glean,
3358  .name = "ip6-glean",
3359  .vector_size = sizeof (u32),
3360  .format_trace = format_ip6_forward_next_trace,
3362  .error_strings = ip6_discover_neighbor_error_strings,
3363  .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
3364  .next_nodes =
3365  {
3366  [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "ip6-drop",
3367  [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "ip6-rewrite-mcast",
3368  },
3369 };
3371 {
3372  .function = ip6_discover_neighbor,
3373  .name = "ip6-discover-neighbor",
3374  .vector_size = sizeof (u32),
3375  .format_trace = format_ip6_forward_next_trace,
3377  .error_strings = ip6_discover_neighbor_error_strings,
3378  .n_next_nodes = IP6_DISCOVER_NEIGHBOR_N_NEXT,
3379  .next_nodes =
3380  {
3381  [IP6_DISCOVER_NEIGHBOR_NEXT_DROP] = "ip6-drop",
3382  [IP6_DISCOVER_NEIGHBOR_NEXT_REPLY_TX] = "ip6-rewrite-mcast",
3383  },
3384 };
3385 /* *INDENT-ON* */
3386 
3387 /* API support functions */
3388 int
3390  u8 suppress, u8 managed, u8 other,
3391  u8 ll_option, u8 send_unicast, u8 cease,
3392  u8 use_lifetime, u32 lifetime,
3393  u32 initial_count, u32 initial_interval,
3394  u32 max_interval, u32 min_interval, u8 is_no)
3395 {
3397  int error;
3398  u32 ri;
3399 
3400  /* look up the radv_t information for this interface */
3402  ~0);
3404  error = (ri != ~0) ? 0 : VNET_API_ERROR_INVALID_SW_IF_INDEX;
3405 
3406  if (!error)
3407  {
3408 
3409  ip6_radv_t *radv_info;
3410  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3411 
3412  if ((max_interval != 0) && (min_interval == 0))
3413  min_interval = .75 * max_interval;
3414 
3415  max_interval =
3416  (max_interval !=
3417  0) ? ((is_no) ? DEF_MAX_RADV_INTERVAL : max_interval) :
3418  radv_info->max_radv_interval;
3419  min_interval =
3420  (min_interval !=
3421  0) ? ((is_no) ? DEF_MIN_RADV_INTERVAL : min_interval) :
3422  radv_info->min_radv_interval;
3423  lifetime =
3424  (use_lifetime !=
3425  0) ? ((is_no) ? DEF_DEF_RTR_LIFETIME : lifetime) :
3426  radv_info->adv_router_lifetime_in_sec;
3427 
3428  if (lifetime)
3429  {
3430  if (lifetime > MAX_DEF_RTR_LIFETIME)
3431  lifetime = MAX_DEF_RTR_LIFETIME;
3432 
3433  if (lifetime <= max_interval)
3434  return VNET_API_ERROR_INVALID_VALUE;
3435  }
3436 
3437  if (min_interval != 0)
3438  {
3439  if ((min_interval > .75 * max_interval) || (min_interval < 3))
3440  return VNET_API_ERROR_INVALID_VALUE;
3441  }
3442 
3443  if ((initial_count > MAX_INITIAL_RTR_ADVERTISEMENTS) ||
3444  (initial_interval > MAX_INITIAL_RTR_ADVERT_INTERVAL))
3445  return VNET_API_ERROR_INVALID_VALUE;
3446 
3447  /*
3448  if "flag" is set and is_no is true then restore default value else set value corresponding to "flag"
3449  if "flag" is clear don't change corresponding value
3450  */
3451  radv_info->send_radv =
3452  (suppress != 0) ? ((is_no != 0) ? 1 : 0) : radv_info->send_radv;
3453  radv_info->adv_managed_flag =
3454  (managed != 0) ? ((is_no) ? 0 : 1) : radv_info->adv_managed_flag;
3455  radv_info->adv_other_flag =
3456  (other != 0) ? ((is_no) ? 0 : 1) : radv_info->adv_other_flag;
3457  radv_info->adv_link_layer_address =
3458  (ll_option !=
3459  0) ? ((is_no) ? 1 : 0) : radv_info->adv_link_layer_address;
3460  radv_info->send_unicast =
3461  (send_unicast != 0) ? ((is_no) ? 0 : 1) : radv_info->send_unicast;
3462  radv_info->cease_radv =
3463  (cease != 0) ? ((is_no) ? 0 : 1) : radv_info->cease_radv;
3464 
3465  radv_info->min_radv_interval = min_interval;
3466  radv_info->max_radv_interval = max_interval;
3467  radv_info->adv_router_lifetime_in_sec = lifetime;
3468 
3469  radv_info->initial_adverts_count =
3470  (initial_count !=
3471  0) ? ((is_no) ? MAX_INITIAL_RTR_ADVERTISEMENTS : initial_count) :
3472  radv_info->initial_adverts_count;
3473  radv_info->initial_adverts_interval =
3474  (initial_interval !=
3475  0) ? ((is_no) ? MAX_INITIAL_RTR_ADVERT_INTERVAL : initial_interval) :
3476  radv_info->initial_adverts_interval;
3477 
3478  /* restart */
3479  if ((cease != 0) && (is_no))
3480  radv_info->send_radv = 1;
3481 
3482  radv_info->initial_adverts_sent = radv_info->initial_adverts_count - 1;
3483  radv_info->next_multicast_time = vlib_time_now (vm);
3484  radv_info->last_multicast_time = vlib_time_now (vm);
3485  radv_info->last_radv_time = 0;
3486  }
3487  return (error);
3488 }
3489 
3490 int
3492  ip6_address_t * prefix_addr, u8 prefix_len,
3493  u8 use_default, u32 val_lifetime, u32 pref_lifetime,
3494  u8 no_advertise, u8 off_link, u8 no_autoconfig,
3495  u8 no_onlink, u8 is_no)
3496 {
3498  int error;
3499 
3500  u32 ri;
3501 
3502  /* look up the radv_t information for this interface */
3504  ~0);
3505 
3507 
3508  error = (ri != ~0) ? 0 : VNET_API_ERROR_INVALID_SW_IF_INDEX;
3509 
3510  if (!error)
3511  {
3512  f64 now = vlib_time_now (vm);
3513  ip6_radv_t *radv_info;
3514  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3515 
3516  /* prefix info add, delete or update */
3518 
3519  /* lookup prefix info for this address on this interface */
3520  uword *p = mhash_get (&radv_info->address_to_prefix_index, prefix_addr);
3521 
3522  prefix = p ? pool_elt_at_index (radv_info->adv_prefixes_pool, p[0]) : 0;
3523 
3524  if (is_no)
3525  {
3526  /* delete */
3527  if (!prefix)
3528  return VNET_API_ERROR_INVALID_VALUE; /* invalid prefix */
3529 
3530  if (prefix->prefix_len != prefix_len)
3531  return VNET_API_ERROR_INVALID_VALUE_2;
3532 
3533  /* FIXME - Should the DP do this or the CP ? */
3534  /* do specific delete processing here before returning */
3535  /* try to remove from routing table */
3536 
3537  mhash_unset (&radv_info->address_to_prefix_index, prefix_addr,
3538  /* old_value */ 0);
3539  pool_put (radv_info->adv_prefixes_pool, prefix);
3540 
3541  radv_info->initial_adverts_sent =
3542  radv_info->initial_adverts_count - 1;
3543  radv_info->next_multicast_time = vlib_time_now (vm);
3544  radv_info->last_multicast_time = vlib_time_now (vm);
3545  radv_info->last_radv_time = 0;
3546  return (error);
3547  }
3548 
3549  /* adding or changing */
3550  if (!prefix)
3551  {
3552  /* add */
3553  u32 pi;
3554  pool_get (radv_info->adv_prefixes_pool, prefix);
3555  pi = prefix - radv_info->adv_prefixes_pool;
3556  mhash_set (&radv_info->address_to_prefix_index, prefix_addr, pi,
3557  /* old_value */ 0);
3558 
3559  clib_memset (prefix, 0x0, sizeof (ip6_radv_prefix_t));
3560 
3561  prefix->prefix_len = prefix_len;
3562  clib_memcpy (&prefix->prefix, prefix_addr, sizeof (ip6_address_t));
3563 
3564  /* initialize default values */
3565  prefix->adv_on_link_flag = 1; /* L bit set */
3566  prefix->adv_autonomous_flag = 1; /* A bit set */
3569  prefix->enabled = 1;
3570  prefix->decrement_lifetime_flag = 1;
3571  prefix->deprecated_prefix_flag = 1;
3572 
3573  if (off_link == 0)
3574  {
3575  /* FIXME - Should the DP do this or the CP ? */
3576  /* insert prefix into routing table as a connected prefix */
3577  }
3578 
3579  if (use_default)
3580  goto restart;
3581  }
3582  else
3583  {
3584 
3585  if (prefix->prefix_len != prefix_len)
3586  return VNET_API_ERROR_INVALID_VALUE_2;
3587 
3588  if (off_link != 0)
3589  {
3590  /* FIXME - Should the DP do this or the CP ? */
3591  /* remove from routing table if already there */
3592  }
3593  }
3594 
3595  if ((val_lifetime == ~0) || (pref_lifetime == ~0))
3596  {
3597  prefix->adv_valid_lifetime_in_secs = ~0;
3598  prefix->adv_pref_lifetime_in_secs = ~0;
3599  prefix->decrement_lifetime_flag = 0;
3600  }
3601  else
3602  {
3603  prefix->adv_valid_lifetime_in_secs = val_lifetime;;
3604  prefix->adv_pref_lifetime_in_secs = pref_lifetime;
3605  }
3606 
3607  /* copy remaining */
3608  prefix->enabled = !(no_advertise != 0);
3609  prefix->adv_on_link_flag = !((off_link != 0) || (no_onlink != 0));
3610  prefix->adv_autonomous_flag = !(no_autoconfig != 0);
3611 
3612  restart:
3613  /* restart */
3614  /* fill in the expiration times */
3615  prefix->valid_lifetime_expires =
3616  now + prefix->adv_valid_lifetime_in_secs;
3617  prefix->pref_lifetime_expires = now + prefix->adv_pref_lifetime_in_secs;
3618 
3619  radv_info->initial_adverts_sent = radv_info->initial_adverts_count - 1;
3620  radv_info->next_multicast_time = vlib_time_now (vm);
3621  radv_info->last_multicast_time = vlib_time_now (vm);
3622  radv_info->last_radv_time = 0;
3623  }
3624  return (error);
3625 }
3626 
3627 clib_error_t *
3629  vlib_cli_command_t * cmd)
3630 {
3631  vnet_main_t *vnm = vnet_get_main ();
3633  clib_error_t *error = 0;
3634  u8 is_no = 0;
3635  u8 suppress = 0, managed = 0, other = 0;
3636  u8 suppress_ll_option = 0, send_unicast = 0, cease = 0;
3637  u8 use_lifetime = 0;
3638  u32 sw_if_index, ra_lifetime = 0, ra_initial_count =
3639  0, ra_initial_interval = 0;
3640  u32 ra_max_interval = 0, ra_min_interval = 0;
3641 
3642  unformat_input_t _line_input, *line_input = &_line_input;
3643  vnet_sw_interface_t *sw_if0;
3644 
3645  int add_radv_info = 1;
3646  __attribute__ ((unused)) ip6_radv_t *radv_info = 0;
3647  ip6_address_t ip6_addr;
3648  u32 addr_len;
3649 
3650 
3651  /* Get a line of input. */
3652  if (!unformat_user (main_input, unformat_line_input, line_input))
3653  return 0;
3654 
3655  /* get basic radv info for this interface */
3656  if (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3657  {
3658 
3659  if (unformat_user (line_input,
3660  unformat_vnet_sw_interface, vnm, &sw_if_index))
3661  {
3662  u32 ri;
3663  ethernet_interface_t *eth_if0 = 0;
3664 
3665  sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
3666  if (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
3667  eth_if0 =
3669 
3670  if (!eth_if0)
3671  {
3672  error =
3673  clib_error_return (0, "Interface must be of ethernet type");
3674  goto done;
3675  }
3676 
3677  /* look up the radv_t information for this interface */
3679  sw_if_index, ~0);
3680 
3682 
3683  if (ri != ~0)
3684  {
3685  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3686  }
3687  else
3688  {
3689  error = clib_error_return (0, "unknown interface %U'",
3690  format_unformat_error, line_input);
3691  goto done;
3692  }
3693  }
3694  else
3695  {
3696  error = clib_error_return (0, "invalid interface name %U'",
3697  format_unformat_error, line_input);
3698  goto done;
3699  }
3700  }
3701 
3702  /* get the rest of the command */
3703  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3704  {
3705  if (unformat (line_input, "no"))
3706  is_no = 1;
3707  else if (unformat (line_input, "prefix %U/%d",
3708  unformat_ip6_address, &ip6_addr, &addr_len))
3709  {
3710  add_radv_info = 0;
3711  break;
3712  }
3713  else if (unformat (line_input, "ra-managed-config-flag"))
3714  {
3715  managed = 1;
3716  break;
3717  }
3718  else if (unformat (line_input, "ra-other-config-flag"))
3719  {
3720  other = 1;
3721  break;
3722  }
3723  else if (unformat (line_input, "ra-suppress") ||
3724  unformat (line_input, "ra-surpress"))
3725  {
3726  suppress = 1;
3727  break;
3728  }
3729  else if (unformat (line_input, "ra-suppress-link-layer") ||
3730  unformat (line_input, "ra-surpress-link-layer"))
3731  {
3732  suppress_ll_option = 1;
3733  break;
3734  }
3735  else if (unformat (line_input, "ra-send-unicast"))
3736  {
3737  send_unicast = 1;
3738  break;
3739  }
3740  else if (unformat (line_input, "ra-lifetime"))
3741  {
3742  if (!unformat (line_input, "%d", &ra_lifetime))
3743  {
3744  error = unformat_parse_error (line_input);
3745  goto done;
3746  }
3747  use_lifetime = 1;
3748  break;
3749  }
3750  else if (unformat (line_input, "ra-initial"))
3751  {
3752  if (!unformat
3753  (line_input, "%d %d", &ra_initial_count, &ra_initial_interval))
3754  {
3755  error = unformat_parse_error (line_input);
3756  goto done;
3757  }
3758  break;
3759  }
3760  else if (unformat (line_input, "ra-interval"))
3761  {
3762  if (!unformat (line_input, "%d", &ra_max_interval))
3763  {
3764  error = unformat_parse_error (line_input);
3765  goto done;
3766  }
3767 
3768  if (!unformat (line_input, "%d", &ra_min_interval))
3769  ra_min_interval = 0;
3770  break;
3771  }
3772  else if (unformat (line_input, "ra-cease"))
3773  {
3774  cease = 1;
3775  break;
3776  }
3777  else
3778  {
3779  error = unformat_parse_error (line_input);
3780  goto done;
3781  }
3782  }
3783 
3784  if (add_radv_info)
3785  {
3786  ip6_neighbor_ra_config (vm, sw_if_index,
3787  suppress, managed, other,
3788  suppress_ll_option, send_unicast, cease,
3789  use_lifetime, ra_lifetime,
3790  ra_initial_count, ra_initial_interval,
3791  ra_max_interval, ra_min_interval, is_no);
3792  }
3793  else
3794  {
3795  u32 valid_lifetime_in_secs = 0;
3796  u32 pref_lifetime_in_secs = 0;
3797  u8 use_prefix_default_values = 0;
3798  u8 no_advertise = 0;
3799  u8 off_link = 0;
3800  u8 no_autoconfig = 0;
3801  u8 no_onlink = 0;
3802 
3803  /* get the rest of the command */
3804  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3805  {
3806  if (unformat (line_input, "default"))
3807  {
3808  use_prefix_default_values = 1;
3809  break;
3810  }
3811  else if (unformat (line_input, "infinite"))
3812  {
3813  valid_lifetime_in_secs = ~0;
3814  pref_lifetime_in_secs = ~0;
3815  break;
3816  }
3817  else if (unformat (line_input, "%d %d", &valid_lifetime_in_secs,
3818  &pref_lifetime_in_secs))
3819  break;
3820  else
3821  break;
3822  }
3823 
3824 
3825  /* get the rest of the command */
3826  while (!use_prefix_default_values &&
3828  {
3829  if (unformat (line_input, "no-advertise"))
3830  no_advertise = 1;
3831  else if (unformat (line_input, "off-link"))
3832  off_link = 1;
3833  else if (unformat (line_input, "no-autoconfig"))
3834  no_autoconfig = 1;
3835  else if (unformat (line_input, "no-onlink"))
3836  no_onlink = 1;
3837  else
3838  {
3839  error = unformat_parse_error (line_input);
3840  goto done;
3841  }
3842  }
3843 
3844  ip6_neighbor_ra_prefix (vm, sw_if_index,
3845  &ip6_addr, addr_len,
3846  use_prefix_default_values,
3847  valid_lifetime_in_secs,
3848  pref_lifetime_in_secs,
3849  no_advertise,
3850  off_link, no_autoconfig, no_onlink, is_no);
3851  }
3852 
3853 done:
3854  unformat_free (line_input);
3855 
3856  return error;
3857 }
3858 
3859 static void
3861 {
3863  u32 i;
3864 
3865  for (i = 0; i < vec_len (addrs); i++)
3866  {
3868  pool_elt_at_index (lm->if_address_pool, addrs[i]);
3870 
3871  vlib_cli_output (vm, "\t\t%U/%d",
3872  format_ip6_address, address, a->address_length);
3873  }
3874 }
3875 
3876 static clib_error_t *
3878  unformat_input_t * input, vlib_cli_command_t * cmd)
3879 {
3880  vnet_main_t *vnm = vnet_get_main ();
3882  clib_error_t *error = 0;
3883  u32 sw_if_index;
3884 
3885  sw_if_index = ~0;
3886 
3887  if (unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
3888  {
3889  u32 ri;
3890 
3891  /* look up the radv_t information for this interface */
3893  sw_if_index, ~0);
3894 
3896 
3897  if (ri != ~0)
3898  {
3900  ip6_radv_t *radv_info;
3901  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3902 
3903  vlib_cli_output (vm, "%U is admin %s\n",
3905  vnet_get_sw_interface (vnm, sw_if_index),
3906  (vnet_sw_interface_is_admin_up (vnm, sw_if_index) ?
3907  "up" : "down"));
3908 
3909  u32 ai;
3910  u32 *link_scope = 0, *global_scope = 0;
3911  u32 *local_scope = 0, *unknown_scope = 0;
3913 
3915  sw_if_index, ~0);
3917 
3918  while (ai != (u32) ~ 0)
3919  {
3920  a = pool_elt_at_index (lm->if_address_pool, ai);
3923 
3924  if (ip6_address_is_link_local_unicast (address))
3925  vec_add1 (link_scope, ai);
3926  else if (ip6_address_is_global_unicast (address))
3927  vec_add1 (global_scope, ai);
3928  else if (ip6_address_is_local_unicast (address))
3929  vec_add1 (local_scope, ai);
3930  else
3931  vec_add1 (unknown_scope, ai);
3932 
3933  ai = a->next_this_sw_interface;
3934  }
3935 
3936  if (vec_len (link_scope))
3937  {
3938  vlib_cli_output (vm, "\tLink-local address(es):\n");
3939  ip6_print_addrs (vm, link_scope);
3940  vec_free (link_scope);
3941  }
3942 
3943  if (vec_len (local_scope))
3944  {
3945  vlib_cli_output (vm, "\tLocal unicast address(es):\n");
3946  ip6_print_addrs (vm, local_scope);
3947  vec_free (local_scope);
3948  }
3949 
3950  if (vec_len (global_scope))
3951  {
3952  vlib_cli_output (vm, "\tGlobal unicast address(es):\n");
3953  ip6_print_addrs (vm, global_scope);
3954  vec_free (global_scope);
3955  }
3956 
3957  if (vec_len (unknown_scope))
3958  {
3959  vlib_cli_output (vm, "\tOther-scope address(es):\n");
3960  ip6_print_addrs (vm, unknown_scope);
3961  vec_free (unknown_scope);
3962  }
3963 
3964  vlib_cli_output (vm, "\tLink-local address(es):\n");
3965  vlib_cli_output (vm, "\t\t%U\n", format_ip6_address,
3966  &radv_info->link_local_address);
3967 
3968  vlib_cli_output (vm, "\tJoined group address(es):\n");
3969  ip6_mldp_group_t *m;
3970  /* *INDENT-OFF* */
3971  pool_foreach (m, radv_info->mldp_group_pool,
3972  ({
3973  vlib_cli_output (vm, "\t\t%U\n", format_ip6_address,
3974  &m->mcast_address);
3975  }));
3976  /* *INDENT-ON* */
3977 
3978  vlib_cli_output (vm, "\tAdvertised Prefixes:\n");
3979  ip6_radv_prefix_t *p;
3980  /* *INDENT-OFF* */
3981  pool_foreach (p, radv_info->adv_prefixes_pool,
3982  ({
3983  vlib_cli_output (vm, "\t\tprefix %U, length %d\n",
3984  format_ip6_address, &p->prefix, p->prefix_len);
3985  }));
3986  /* *INDENT-ON* */
3987 
3988  vlib_cli_output (vm, "\tMTU is %d\n", radv_info->adv_link_mtu);
3989  vlib_cli_output (vm, "\tICMP error messages are unlimited\n");
3990  vlib_cli_output (vm, "\tICMP redirects are disabled\n");
3991  vlib_cli_output (vm, "\tICMP unreachables are not sent\n");
3992  vlib_cli_output (vm, "\tND DAD is disabled\n");
3993  //vlib_cli_output (vm, "\tND reachable time is %d milliseconds\n",);
3994  vlib_cli_output (vm, "\tND advertised reachable time is %d\n",
3996  vlib_cli_output (vm,
3997  "\tND advertised retransmit interval is %d (msec)\n",
3998  radv_info->
3999  adv_time_in_msec_between_retransmitted_neighbor_solicitations);
4000 
4001  u32 ra_interval = radv_info->max_radv_interval;
4002  u32 ra_interval_min = radv_info->min_radv_interval;
4003  vlib_cli_output (vm,
4004  "\tND router advertisements are sent every %d seconds (min interval is %d)\n",
4005  ra_interval, ra_interval_min);
4006  vlib_cli_output (vm,
4007  "\tND router advertisements live for %d seconds\n",
4008  radv_info->adv_router_lifetime_in_sec);
4009  vlib_cli_output (vm,
4010  "\tHosts %s stateless autoconfig for addresses\n",
4011  (radv_info->adv_managed_flag) ? "use" :
4012  " don't use");
4013  vlib_cli_output (vm, "\tND router advertisements sent %d\n",
4014  radv_info->n_advertisements_sent);
4015  vlib_cli_output (vm, "\tND router solicitations received %d\n",
4016  radv_info->n_solicitations_rcvd);
4017  vlib_cli_output (vm, "\tND router solicitations dropped %d\n",
4018  radv_info->n_solicitations_dropped);
4019  }
4020  else
4021  {
4022  error = clib_error_return (0, "IPv6 not enabled on interface",
4023  format_unformat_error, input);
4024 
4025  }
4026  }
4027  return error;
4028 }
4029 
4030 /*?
4031  * This command is used to display various IPv6 attributes on a given
4032  * interface.
4033  *
4034  * @cliexpar
4035  * Example of how to display IPv6 settings:
4036  * @cliexstart{show ip6 interface GigabitEthernet2/0/0}
4037  * GigabitEthernet2/0/0 is admin up
4038  * Link-local address(es):
4039  * fe80::ab8/64
4040  * Joined group address(es):
4041  * ff02::1
4042  * ff02::2
4043  * ff02::16
4044  * ff02::1:ff00:ab8
4045  * Advertised Prefixes:
4046  * prefix fe80::fe:28ff:fe9c:75b3, length 64
4047  * MTU is 1500
4048  * ICMP error messages are unlimited
4049  * ICMP redirects are disabled
4050  * ICMP unreachables are not sent
4051  * ND DAD is disabled
4052  * ND advertised reachable time is 0
4053  * ND advertised retransmit interval is 0 (msec)
4054  * ND router advertisements are sent every 200 seconds (min interval is 150)
4055  * ND router advertisements live for 600 seconds
4056  * Hosts use stateless autoconfig for addresses
4057  * ND router advertisements sent 19336
4058  * ND router solicitations received 0
4059  * ND router solicitations dropped 0
4060  * @cliexend
4061  * Example of output if IPv6 is not enabled on the interface:
4062  * @cliexstart{show ip6 interface GigabitEthernet2/0/0}
4063  * show ip6 interface: IPv6 not enabled on interface
4064  * @cliexend
4065 ?*/
4066 /* *INDENT-OFF* */
4067 VLIB_CLI_COMMAND (show_ip6_interface_command, static) =
4068 {
4069  .path = "show ip6 interface",
4070  .function = show_ip6_interface_cmd,
4071  .short_help = "show ip6 interface <interface>",
4072 };
4073 /* *INDENT-ON* */
4074 
4075 clib_error_t *
4077 {
4078  clib_error_t *error = 0;
4080  u32 ri;
4081 
4082  /* look up the radv_t information for this interface */
4084  ~0);
4086 
4087  /* if not created - do nothing */
4088  if (ri != ~0)
4089  {
4090  ip6_radv_t *radv_info;
4091 
4092  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
4093 
4094  /* check radv_info ref count for other ip6 addresses on this interface */
4095  /* This implicitly excludes the link local address */
4096  if (radv_info->ref_count == 0)
4097  {
4098  /* essentially "disables" ipv6 on this interface */
4099  ip6_ll_prefix_t ilp = {
4100  .ilp_addr = radv_info->link_local_address,
4101  .ilp_sw_if_index = sw_if_index,
4102  };
4104  ip6_sw_interface_enable_disable (sw_if_index, 0);
4105  ip6_mfib_interface_enable_disable (sw_if_index, 0);
4107  0);
4108  }
4109  }
4110  return error;
4111 }
4112 
4113 int
4115 {
4117  u32 ri = ~0;
4118 
4119  /* look up the radv_t information for this interface */
4121  ~0);
4122 
4124 
4125  return ri != ~0;
4126 }
4127 
4128 clib_error_t *
4130 {
4131  clib_error_t *error = 0;
4133  u32 ri;
4134  int is_add = 1;
4135 
4136  /* look up the radv_t information for this interface */
4138  ~0);
4139 
4141 
4142  /* if not created yet */
4143  if (ri == ~0)
4144  {
4145  vnet_main_t *vnm = vnet_get_main ();
4146  vnet_sw_interface_t *sw_if0;
4147 
4148  sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
4149  if (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
4150  {
4151  ethernet_interface_t *eth_if0;
4152 
4153  eth_if0 =
4155  if (eth_if0)
4156  {
4157  /* create radv_info. for this interface. This holds all the info needed for router adverts */
4158  ri =
4159  ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, is_add);
4160 
4161  if (ri != ~0)
4162  {
4163  ip6_radv_t *radv_info;
4164  ip6_address_t link_local_address;
4165 
4166  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
4167 
4169  (&link_local_address, eth_if0->address);
4170 
4171  sw_if0 = vnet_get_sw_interface (vnm, sw_if_index);
4172  if (sw_if0->type == VNET_SW_INTERFACE_TYPE_SUB ||
4173  sw_if0->type == VNET_SW_INTERFACE_TYPE_PIPE ||
4174  sw_if0->type == VNET_SW_INTERFACE_TYPE_P2P)
4175  {
4176  /* make up an interface id */
4177  link_local_address.as_u64[1] =
4178  random_u64 (&radv_info->randomizer);
4179 
4180  link_local_address.as_u64[0] =
4181  clib_host_to_net_u64 (0xFE80000000000000ULL);
4182  /* clear u bit */
4183  link_local_address.as_u8[8] &= 0xfd;
4184  }
4185  {
4186  ip6_ll_prefix_t ilp = {
4187  .ilp_addr = link_local_address,
4188  .ilp_sw_if_index = sw_if_index,
4189  };
4190 
4192  }
4193 
4194  /* essentially "enables" ipv6 on this interface */
4195  ip6_mfib_interface_enable_disable (sw_if_index, 1);
4196  ip6_sw_interface_enable_disable (sw_if_index, 1);
4197 
4198  if (!error)
4199  {
4200  radv_info->link_local_address = link_local_address;
4201  }
4202  }
4203  }
4204  }
4205  }
4206  return error;
4207 }
4208 
4209 int
4211 {
4213  ip6_radv_t *radv_info;
4214  u32 ri;
4215 
4216  if (vec_len (nm->if_radv_pool_index_by_sw_if_index) <= sw_if_index)
4217  return 0;
4218 
4220 
4221  if (ri == ~0)
4222  return 0;
4223 
4224  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
4225  *addr = radv_info->link_local_address;
4226 
4227  return (!0);
4228 }
4229 
4230 static clib_error_t *
4232  unformat_input_t * input, vlib_cli_command_t * cmd)
4233 {
4234  vnet_main_t *vnm = vnet_get_main ();
4235  clib_error_t *error = 0;
4236  u32 sw_if_index;
4237 
4238  sw_if_index = ~0;
4239 
4240  if (unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
4241  {
4242  enable_ip6_interface (vm, sw_if_index);
4243  }
4244  else
4245  {
4246  error = clib_error_return (0, "unknown interface\n'",
4247  format_unformat_error, input);
4248 
4249  }
4250  return error;
4251 }
4252 
4253 /*?
4254  * This command is used to enable IPv6 on a given interface.
4255  *
4256  * @cliexpar
4257  * Example of how enable IPv6 on a given interface:
4258  * @cliexcmd{enable ip6 interface GigabitEthernet2/0/0}
4259 ?*/
4260 /* *INDENT-OFF* */
4261 VLIB_CLI_COMMAND (enable_ip6_interface_command, static) =
4262 {
4263  .path = "enable ip6 interface",
4264  .function = enable_ip6_interface_cmd,
4265  .short_help = "enable ip6 interface <interface>",
4266 };
4267 /* *INDENT-ON* */
4268 
4269 static clib_error_t *
4271  unformat_input_t * input, vlib_cli_command_t * cmd)
4272 {
4273  vnet_main_t *vnm = vnet_get_main ();
4274  clib_error_t *error = 0;
4275  u32 sw_if_index;
4276 
4277  sw_if_index = ~0;
4278 
4279  if (unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
4280  {
4281  error = disable_ip6_interface (vm, sw_if_index);
4282  }
4283  else
4284  {
4285  error = clib_error_return (0, "unknown interface\n'",
4286  format_unformat_error, input);
4287 
4288  }
4289  return error;
4290 }
4291 
4292 /*?
4293  * This command is used to disable IPv6 on a given interface.
4294  *
4295  * @cliexpar
4296  * Example of how disable IPv6 on a given interface:
4297  * @cliexcmd{disable ip6 interface GigabitEthernet2/0/0}
4298 ?*/
4299 /* *INDENT-OFF* */
4300 VLIB_CLI_COMMAND (disable_ip6_interface_command, static) =
4301 {
4302  .path = "disable ip6 interface",
4303  .function = disable_ip6_interface_cmd,
4304  .short_help = "disable ip6 interface <interface>",
4305 };
4306 /* *INDENT-ON* */
4307 
4308 /*?
4309  * This command is used to configure the neighbor discovery
4310  * parameters on a given interface. Use the '<em>show ip6 interface</em>'
4311  * command to display some of the current neighbor discovery parameters
4312  * on a given interface. This command has three formats:
4313  *
4314  *
4315  * <b>Format 1 - Router Advertisement Options:</b> (Only one can be entered in a single command)
4316  *
4317  * '<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>'
4318  *
4319  * Where:
4320  *
4321  * <em>[no] ra-managed-config-flag</em> - Advertises in ICMPv6
4322  * router-advertisement messages to use stateful address
4323  * auto-configuration to obtain address information (sets the M-bit).
4324  * Default is the M-bit is not set and the '<em>no</em>' option
4325  * returns it to this default state.
4326  *
4327  * <em>[no] ra-other-config-flag</em> - Indicates in ICMPv6
4328  * router-advertisement messages that hosts use stateful auto
4329  * configuration to obtain nonaddress related information (sets
4330  * the O-bit). Default is the O-bit is not set and the '<em>no</em>'
4331  * option returns it to this default state.
4332  *
4333  * <em>[no] ra-suppress</em> - Disables sending ICMPv6 router-advertisement
4334  * messages. The '<em>no</em>' option implies to enable sending ICMPv6
4335  * router-advertisement messages.
4336  *
4337  * <em>[no] ra-suppress-link-layer</em> - Indicates not to include the
4338  * optional source link-layer address in the ICMPv6 router-advertisement
4339  * messages. Default is to include the optional source link-layer address
4340  * and the '<em>no</em>' option returns it to this default state.
4341  *
4342  * <em>[no] ra-send-unicast</em> - Use the source address of the
4343  * router-solicitation message if availiable. The default is to use
4344  * multicast address of all nodes, and the '<em>no</em>' option returns
4345  * it to this default state.
4346  *
4347  * <em>[no] ra-lifetime <lifetime></em> - Advertises the lifetime of a
4348  * default router in ICMPv6 router-advertisement messages. The range is
4349  * from 0 to 9000 seconds. '<em><lifetime></em>' must be greater than
4350  * '<em><max-interval></em>'. The default value is 600 seconds and the
4351  * '<em>no</em>' option returns it to this default value.
4352  *
4353  * <em>[no] ra-initial <cnt> <interval></em> - Number of initial ICMPv6
4354  * router-advertisement messages sent and the interval between each
4355  * message. Range for count is 1 - 3 and default is 3. Range for interval
4356  * is 1 to 16 seconds, and default is 16 seconds. The '<em>no</em>' option
4357  * returns both to their default value.
4358  *
4359  * <em>[no] ra-interval <max-interval> [<min-interval>]</em> - Configures the
4360  * interval between sending ICMPv6 router-advertisement messages. The
4361  * range for max-interval is from 4 to 200 seconds. min-interval can not
4362  * be more than 75% of max-interval. If not set, min-interval will be
4363  * set to 75% of max-interval. The range for min-interval is from 3 to
4364  * 150 seconds. The '<em>no</em>' option returns both to their default
4365  * value.
4366  *
4367  * <em>[no] ra-cease</em> - Cease sending ICMPv6 router-advertisement messages.
4368  * The '<em>no</em>' options implies to start (or restart) sending
4369  * ICMPv6 router-advertisement messages.
4370  *
4371  *
4372  * <b>Format 2 - Prefix Options:</b>
4373  *
4374  * '<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>'
4375  *
4376  * Where:
4377  *
4378  * <em>no</em> - All additional flags are ignored and the prefix is deleted.
4379  *
4380  * <em><valid-lifetime> <pref-lifetime></em> - '<em><valid-lifetime></em>' is the
4381  * length of time in seconds during what the prefix is valid for the purpose of
4382  * on-link determination. Range is 7203 to 2592000 seconds and default is 2592000
4383  * seconds (30 days). '<em><pref-lifetime></em>' is the prefered-lifetime and is the
4384  * length of time in seconds during what addresses generated from the prefix remain
4385  * preferred. Range is 0 to 604800 seconds and default is 604800 seconds (7 days).
4386  *
4387  * <em>infinite</em> - Both '<em><valid-lifetime></em>' and '<em><<pref-lifetime></em>'
4388  * are inifinte, no timeout.
4389  *
4390  * <em>no-advertise</em> - Do not send full router address in prefix
4391  * advertisement. Default is to advertise (i.e. - This flag is off by default).
4392  *
4393  * <em>off-link</em> - Prefix is off-link, clear L-bit in packet. Default is on-link
4394  * (i.e. - This flag is off and L-bit in packet is set by default and this prefix can
4395  * be used for on-link determination). '<em>no-onlink</em>' also controls the L-bit.
4396  *
4397  * <em>no-autoconfig</em> - Do not use prefix for autoconfiguration, clear A-bit in packet.
4398  * Default is autoconfig (i.e. - This flag is off and A-bit in packet is set by default.
4399  *
4400  * <em>no-onlink</em> - Do not use prefix for onlink determination, clear L-bit in packet.
4401  * Default is on-link (i.e. - This flag is off and L-bit in packet is set by default and
4402  * this prefix can be used for on-link determination). '<em>off-link</em>' also controls
4403  * the L-bit.
4404  *
4405  *
4406  * <b>Format 3: - Default of Prefix:</b>
4407  *
4408  * '<em><b>ip6 nd <interface> [no] prefix <ip6-address>/<width> default</b></em>'
4409  *
4410  * When a new prefix is added (or existing one is being overwritten) <em>default</em>
4411  * uses default values for the prefix. If <em>no</em> is used, the <em>default</em>
4412  * is ignored and the prefix is deleted.
4413  *
4414  *
4415  * @cliexpar
4416  * Example of how set a router advertisement option:
4417  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 ra-interval 100 20}
4418  * Example of how to add a prefix:
4419  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 prefix fe80::fe:28ff:fe9c:75b3/64 infinite no-advertise}
4420  * Example of how to delete a prefix:
4421  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 no prefix fe80::fe:28ff:fe9c:75b3/64}
4422 ?*/
4423 /* *INDENT-OFF* */
4424 VLIB_CLI_COMMAND (ip6_nd_command, static) =
4425 {
4426  .path = "ip6 nd",
4427  .short_help = "ip6 nd <interface> ...",
4428  .function = ip6_neighbor_cmd,
4429 };
4430 /* *INDENT-ON* */
4431 
4432 clib_error_t *
4435 {
4436  clib_error_t *error = 0;
4438  u32 ri;
4439  ip6_radv_t *radv_info;
4440  vnet_main_t *vnm = vnet_get_main ();
4441  ip6_ll_prefix_t pfx = { 0, };
4442 
4443  if (!ip6_address_is_link_local_unicast (address))
4444  return (error = clib_error_return (0, "address not link-local",
4446 
4447  /* call enable ipv6 */
4448  enable_ip6_interface (vm, sw_if_index);
4449 
4451 
4452  if (ri != ~0)
4453  {
4454  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
4455 
4457 
4458  pfx.ilp_addr = radv_info->link_local_address;
4460 
4461  pfx.ilp_addr = *address;
4463 
4464  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
4465  radv_info->link_local_address = *address;
4466  }
4467  else
4468  {
4469  vnm->api_errno = VNET_API_ERROR_IP6_NOT_ENABLED;
4470  error = clib_error_return (0, "ip6 not enabled for interface",
4472  }
4473  return error;
4474 }
4475 
4476 /**
4477  * @brief callback when an interface address is added or deleted
4478  */
4479 static void
4481  uword opaque,
4482  u32 sw_if_index,
4484  u32 address_length,
4485  u32 if_address_index, u32 is_delete)
4486 {
4487  vnet_main_t *vnm = vnet_get_main ();
4489  u32 ri;
4490  vlib_main_t *vm = vnm->vlib_main;
4491  ip6_radv_t *radv_info;
4492  ip6_address_t a;
4493 
4494  /* create solicited node multicast address for this interface address */
4496 
4497  a.as_u8[0xd] = address->as_u8[0xd];
4498  a.as_u8[0xe] = address->as_u8[0xe];
4499  a.as_u8[0xf] = address->as_u8[0xf];
4500 
4501  if (!is_delete)
4502  {
4503  /* try to create radv_info - does nothing if ipv6 already enabled */
4504  enable_ip6_interface (vm, sw_if_index);
4505 
4506  /* look up the radv_t information for this interface */
4508  sw_if_index, ~0);
4510  if (ri != ~0)
4511  {
4512  /* get radv_info */
4513  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
4514 
4515  /* add address */
4516  if (!ip6_address_is_link_local_unicast (address))
4517  radv_info->ref_count++;
4518 
4519  ip6_neighbor_add_mld_prefix (radv_info, &a);
4520  }
4521  }
4522  else
4523  {
4524 
4525  /* delete */
4526  /* look up the radv_t information for this interface */
4528  sw_if_index, ~0);
4530 
4531  if (ri != ~0)
4532  {
4533  /* get radv_info */
4534  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
4535 
4536  ip6_neighbor_del_mld_prefix (radv_info, &a);
4537 
4538  /* if interface up send MLDP "report" */
4539  radv_info->all_routers_mcast = 0;
4540 
4541  /* add address */
4542  if (!ip6_address_is_link_local_unicast (address))
4543  radv_info->ref_count--;
4544  }
4545  /* Ensure that IPv6 is disabled, and LL removed after ref_count reaches 0 */
4546  disable_ip6_interface (vm, sw_if_index);
4547  }
4548 }
4549 
4550 clib_error_t *
4551 ip6_set_neighbor_limit (u32 neighbor_limit)
4552 {
4554 
4555  nm->limit_neighbor_cache_size = neighbor_limit;
4556  return 0;
4557 }
4558 
4559 static void
4561  uword opaque,
4562  u32 sw_if_index,
4563  u32 new_fib_index, u32 old_fib_index)
4564 {
4566  ip6_neighbor_t *n = NULL;
4567  u32 i, *to_re_add = 0;
4568 
4569  /* *INDENT-OFF* */
4570  pool_foreach (n, nm->neighbor_pool,
4571  ({
4572  if (n->key.sw_if_index == sw_if_index)
4573  vec_add1 (to_re_add, n - nm->neighbor_pool);
4574  }));
4575  /* *INDENT-ON* */
4576 
4577  for (i = 0; i < vec_len (to_re_add); i++)
4578  {
4579  n = pool_elt_at_index (nm->neighbor_pool, to_re_add[i]);
4580  ip6_neighbor_adj_fib_remove (n, old_fib_index);
4581  ip6_neighbor_adj_fib_add (n, new_fib_index);
4582  }
4583  vec_free (to_re_add);
4584 }
4585 
4586 static clib_error_t *
4588 {
4590  ip6_main_t *im = &ip6_main;
4591 
4593  /* value size */ sizeof (uword),
4594  /* key size */ sizeof (ip6_neighbor_key_t));
4595 
4596  icmp6_register_type (vm, ICMP6_neighbor_solicitation,
4598  icmp6_register_type (vm, ICMP6_neighbor_advertisement,
4600  icmp6_register_type (vm, ICMP6_router_solicitation,
4602  icmp6_register_type (vm, ICMP6_router_advertisement,
4604 
4605  /* handler node for ip6 neighbor discovery events and timers */
4607 
4608  /* add call backs */
4611 
4612  /* when an interface address changes... */
4614  cb.function_opaque = 0;
4616 
4619  cbt.function_opaque = 0;
4620  vec_add1 (im->table_bind_callbacks, cbt);
4621 
4623  /* value size */ sizeof (uword),
4624  /* key size */ sizeof (ip6_address_t));
4625 
4627  /* value size */ sizeof (uword),
4628  /* key size */ sizeof (ip6_address_t));
4629 
4630  /* default, configurable */
4631  nm->limit_neighbor_cache_size = 50000;
4632 
4633  nm->wc_ip6_nd_publisher_node = (uword) ~ 0;
4634 
4635  nm->ip6_ra_publisher_node = (uword) ~ 0;
4636 
4637 #if 0
4638  /* $$$$ Hack fix for today */
4640  (im->discover_neighbor_next_index_by_hw_if_index, 32, 0 /* drop */ );
4641 #endif
4642 
4643  return 0;
4644 }
4645 
4647 
4648 
4649 void
4651  void *address_arg,
4652  uword node_index,
4653  uword type_opaque, uword data)
4654 {
4656  ip6_address_t *address = address_arg;
4657  uword *p;
4659 
4660  pool_get (nm->pending_resolutions, pr);
4661 
4662  pr->next_index = ~0;
4663  pr->node_index = node_index;
4664  pr->type_opaque = type_opaque;
4665  pr->data = data;
4666 
4667  p = mhash_get (&nm->pending_resolutions_by_address, address);
4668  if (p)
4669  {
4670  /* Insert new resolution at the head of the list */
4671  pr->next_index = p[0];
4672  mhash_unset (&nm->pending_resolutions_by_address, address, 0);
4673  }
4674 
4676  pr - nm->pending_resolutions, 0 /* old value */ );
4677 }
4678 
4679 int
4682  u32 pid,
4683  void *address_arg,
4684  uword node_index,
4685  uword type_opaque, uword data, int is_add)
4686 {
4688  ip6_address_t *address = address_arg;
4689 
4690  /* Try to find an existing entry */
4691  u32 *first = (u32 *) mhash_get (&nm->mac_changes_by_address, address);
4692  u32 *p = first;
4694  while (p && *p != ~0)
4695  {
4696  mc = pool_elt_at_index (nm->mac_changes, *p);
4697  if (mc->node_index == node_index && mc->type_opaque == type_opaque
4698  && mc->pid == pid)
4699  break;
4700  p = &mc->next_index;
4701  }
4702 
4703  int found = p && *p != ~0;
4704  if (is_add)
4705  {
4706  if (found)
4707  return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
4708 
4709  pool_get (nm->mac_changes, mc);
4710  /* *INDENT-OFF* */
4711  *mc = (pending_resolution_t)
4712  {
4713  .next_index = ~0,
4714  .node_index = node_index,
4715  .type_opaque = type_opaque,
4716  .data = data,
4717  .data_callback = data_callback,
4718  .pid = pid,
4719  };
4720  /* *INDENT-ON* */
4721 
4722  /* Insert new resolution at the end of the list */
4723  u32 new_idx = mc - nm->mac_changes;
4724  if (p)
4725  p[0] = new_idx;
4726  else
4727  mhash_set (&nm->mac_changes_by_address, address, new_idx, 0);
4728  }
4729  else
4730  {
4731  if (!found)
4732  return VNET_API_ERROR_NO_SUCH_ENTRY;
4733 
4734  /* Clients may need to clean up pool entries, too */
4735  if (data_callback)
4736  (data_callback) (mc->data, NULL /* no new mac addrs */ , 0, NULL);
4737 
4738  /* Remove the entry from the list and delete the entry */
4739  *p = mc->next_index;
4740  pool_put (nm->mac_changes, mc);
4741 
4742  /* Remove from hash if we deleted the last entry */
4743  if (*p == ~0 && p == first)
4744  mhash_unset (&nm->mac_changes_by_address, address, 0);
4745  }
4746  return 0;
4747 }
4748 
4749 int
4751  vlib_node_runtime_t * node,
4752  vlib_buffer_t * p0,
4753  ethernet_header_t * eth,
4754  ip6_header_t * ip, u32 sw_if_index, u16 bd_index)
4755 {
4757  icmp6_neighbor_solicitation_or_advertisement_header_t *ndh;
4759 
4760  mac_address_from_bytes (&mac, eth->src_address);
4761  ndh = ip6_next_header (ip);
4762  if (ndh->icmp.type != ICMP6_neighbor_solicitation &&
4763  ndh->icmp.type != ICMP6_neighbor_advertisement)
4764  return 0;
4765 
4766  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
4767  (p0->flags & VLIB_BUFFER_IS_TRACED)))
4768  {
4769  u8 *t0 = vlib_add_trace (vm, node, p0,
4770  sizeof (icmp6_input_trace_t));
4771  clib_memcpy (t0, ip, sizeof (icmp6_input_trace_t));
4772  }
4773 
4774  /* Check if anyone want ND events for L2 BDs */
4775  if (PREDICT_FALSE
4776  (nm->wc_ip6_nd_publisher_node != (uword) ~ 0
4778  {
4779  vnet_nd_wc_publish (sw_if_index, &mac, &ip->src_address);
4780  }
4781 
4782  /* Check if MAC entry exsist for solicited target IP */
4783  if (ndh->icmp.type == ICMP6_neighbor_solicitation)
4784  {
4785  icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *opt;
4786  l2_bridge_domain_t *bd_config;
4787  u8 *macp;
4788 
4789  opt = (void *) (ndh + 1);
4790  if ((opt->header.type !=
4791  ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address) ||
4792  (opt->header.n_data_u64s != 1))
4793  return 0; /* source link layer address option not present */
4794 
4795  bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
4796  macp =
4797  (u8 *) hash_get_mem (bd_config->mac_by_ip6, &ndh->target_address);
4798  if (macp)
4799  { /* found ip-mac entry, generate eighbor advertisement response */
4800  int bogus_length;
4801  vlib_node_runtime_t *error_node =
4803  ip->dst_address = ip->src_address;
4804  ip->src_address = ndh->target_address;
4805  ip->hop_limit = 255;
4806  opt->header.type =
4807  ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
4808  clib_memcpy (opt->ethernet_address, macp, 6);
4809  ndh->icmp.type = ICMP6_neighbor_advertisement;
4810  ndh->advertisement_flags = clib_host_to_net_u32
4813  ndh->icmp.checksum = 0;
4814  ndh->icmp.checksum =
4815  ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip, &bogus_length);
4816  clib_memcpy (eth->dst_address, eth->src_address, 6);
4817  clib_memcpy (eth->src_address, macp, 6);
4818  vlib_error_count (vm, error_node->node_index,
4819  ICMP6_ERROR_NEIGHBOR_ADVERTISEMENTS_TX, 1);
4820  return 1;
4821  }
4822  }
4823 
4824  return 0;
4825 
4826 }
4827 
4828 int
4830 {
4831  u32 fib_index;
4832 
4833  fib_prefix_t pfx = {
4834  .fp_len = 128,
4835  .fp_proto = FIB_PROTOCOL_IP6,
4836  .fp_addr = {
4837  .ip6 = *addr,
4838  },
4839  };
4840  ip46_address_t nh = {
4841  .ip6 = *addr,
4842  };
4843 
4844  fib_index = ip6_fib_table_get_index_for_sw_if_index (sw_if_index);
4845 
4846  if (~0 == fib_index)
4847  return VNET_API_ERROR_NO_SUCH_FIB;
4848 
4849  if (is_del)
4850  {
4851  fib_table_entry_path_remove (fib_index,
4852  &pfx,
4854  DPO_PROTO_IP6,
4855  &nh,
4856  sw_if_index,
4857  ~0, 1, FIB_ROUTE_PATH_FLAG_NONE);
4858  /* flush the ND cache of this address if it's there */
4859  vnet_unset_ip6_ethernet_neighbor (vlib_get_main (), sw_if_index, addr);
4860  }
4861  else
4862  {
4863  fib_table_entry_path_add (fib_index,
4864  &pfx,
4867  DPO_PROTO_IP6,
4868  &nh,
4869  sw_if_index,
4870  ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
4871  }
4872  return (0);
4873 }
4874 
4875 static clib_error_t *
4877  unformat_input_t * input, vlib_cli_command_t * cmd)
4878 {
4879  vnet_main_t *vnm = vnet_get_main ();
4880  clib_error_t *error = 0;
4882  u32 sw_if_index;
4883  u8 is_del = 0;
4884 
4885  if (unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
4886  {
4887  /* get the rest of the command */
4888  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
4889  {
4890  if (unformat (input, "%U", unformat_ip6_address, &addr))
4891  break;
4892  else if (unformat (input, "delete") || unformat (input, "del"))
4893  is_del = 1;
4894  else
4895  return (unformat_parse_error (input));
4896  }
4897  }
4898 
4899  ip6_neighbor_proxy_add_del (sw_if_index, &addr, is_del);
4900 
4901  return error;
4902 }
4903 
4904 /* *INDENT-OFF* */
4905 VLIB_CLI_COMMAND (set_ip6_nd_proxy_command, static) =
4906 {
4907  .path = "set ip6 nd proxy",
4908  .short_help = "set ip6 nd proxy <HOST> <INTERFACE>",
4909  .function = set_ip6_nd_proxy_cmd,
4910 };
4911 /* *INDENT-ON* */
4912 
4913 void
4915 {
4917  ip6_neighbor_t *n;
4918  adj_index_t ai;
4919 
4920  /* *INDENT-OFF* */
4921  pool_foreach (n, nm->neighbor_pool,
4922  ({
4923  if (n->key.sw_if_index == sw_if_index)
4924  {
4925  adj_nbr_walk_nh6 (sw_if_index,
4926  &n->key.ip6_address,
4927  ip6_nd_mk_complete_walk, n);
4928  }
4929  }));
4930  /* *INDENT-ON* */
4931 
4933 
4934  if (ADJ_INDEX_INVALID != ai)
4936 }
4937 
4938 void
4940 {
4941  ip6_main_t *i6m = &ip6_main;
4942  ip6_address_t *ip6_addr = ip6_interface_first_address (i6m, sw_if_index);
4943 
4944  send_ip6_na_w_addr (vm, ip6_addr, sw_if_index);
4945 }
4946 
4947 void
4949  const ip6_address_t * ip6_addr, u32 sw_if_index)
4950 {
4951  ip6_main_t *i6m = &ip6_main;
4952  vnet_main_t *vnm = vnet_get_main ();
4953  u8 *rewrite, rewrite_len;
4954  vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
4955  u8 dst_address[6];
4956 
4957  if (ip6_addr)
4958  {
4959  clib_warning
4960  ("Sending unsolicitated NA IP6 address %U on sw_if_idex %d",
4961  format_ip6_address, ip6_addr, sw_if_index);
4962 
4963  /* Form unsolicited neighbor advertisement packet from NS pkt template */
4964  int bogus_length;
4965  u32 bi = 0;
4966  icmp6_neighbor_solicitation_header_t *h =
4969  &bi);
4970  if (!h)
4971  return;
4972 
4973  ip6_set_reserved_multicast_address (&h->ip.dst_address,
4974  IP6_MULTICAST_SCOPE_link_local,
4975  IP6_MULTICAST_GROUP_ID_all_hosts);
4976  h->ip.src_address = ip6_addr[0];
4977  h->neighbor.icmp.type = ICMP6_neighbor_advertisement;
4978  h->neighbor.target_address = ip6_addr[0];
4979  h->neighbor.advertisement_flags = clib_host_to_net_u32
4981  h->link_layer_option.header.type =
4982  ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
4983  clib_memcpy (h->link_layer_option.ethernet_address,
4984  hi->hw_address, vec_len (hi->hw_address));
4985  h->neighbor.icmp.checksum =
4986  ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
4987  ASSERT (bogus_length == 0);
4988 
4989  /* Setup MAC header with IP6 Etype and mcast DMAC */
4990  vlib_buffer_t *b = vlib_get_buffer (vm, bi);
4991  ip6_multicast_ethernet_address (dst_address,
4992  IP6_MULTICAST_GROUP_ID_all_hosts);
4993  rewrite =
4994  ethernet_build_rewrite (vnm, sw_if_index, VNET_LINK_IP6, dst_address);
4995  rewrite_len = vec_len (rewrite);
4996  vlib_buffer_advance (b, -rewrite_len);
4998  clib_memcpy (e->dst_address, rewrite, rewrite_len);
4999  vec_free (rewrite);
5000 
5001  /* Send unsolicited ND advertisement packet out the specified interface */
5002  vnet_buffer (b)->sw_if_index[VLIB_RX] =
5003  vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
5005  u32 *to_next = vlib_frame_vector_args (f);
5006  to_next[0] = bi;
5007  f->n_vectors = 1;
5009  }
5010 }
5011 
5012 /*
5013  * fd.io coding-style-patch-verification: ON
5014  *
5015  * Local Variables:
5016  * eval: (c-set-style "gnu")
5017  * End:
5018  */
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:125
An indication that the rewrite is complete, i.e.
Definition: adj_nbr.h:98
vnet_main_t * vnet_get_main(void)
Definition: misc.c: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:400
#define PREDICT_TRUE(x)
Definition: clib.h:112
static void ip6_neighbor_del_mld_prefix(ip6_radv_t *radv_info, ip6_address_t *addr)
Delete a multicast Address from the advertised MLD set.
u8 as_u8[16]
Definition: ip6_packet.h:48
u64 as_u64[2]
Definition: ip6_packet.h:51
unsigned long u64
Definition: types.h:89
static clib_error_t * set_ip6_nd_proxy_cmd(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
int send_unicast
Definition: ip6_neighbor.c: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:339
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:468
#define NULL
Definition: clib.h:58
uword mhash_unset(mhash_t *h, void *key, uword *old_value)
Definition: mhash.c:346
u32 index
Definition: node.h:279
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:258
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:410
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:197
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:178
word vnet_sw_interface_compare(vnet_main_t *vnm, uword sw_if_index0, uword sw_if_index1)
Definition: interface.c:1206
static u64 clib_cpu_time_now(void)
Definition: time.h:75
#define IP6_NBR_MK_KEY(k, sw_if_index, addr)
Definition: ip6_neighbor.c: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
clib_memset(h->entries, 0, sizeof(h->entries[0])*entries)
#define STRUCT_OFFSET_OF(t, f)
Definition: clib.h:65
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:249
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:468
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:2110
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:441
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:99
void * vlib_packet_template_get_packet(vlib_main_t *vm, vlib_packet_template_t *t, u32 *bi_result)
Definition: buffer.c:389
#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:505
#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)
Aggregrate type for a prefix.
Definition: fib_types.h:203
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:187
#define clib_error_return(e, args...)
Definition: error.h:99
static u32 ip6_src_lookup_for_packet(ip6_main_t *im, vlib_buffer_t *b, ip6_header_t *i)
return the DPO that the LB stacks on.
Definition: ip6_fib.h:119
void vl_api_rpc_call_main_thread(void *fp, u8 *data, u32 data_length)
Definition: vlib_api.c:600
void adj_unlock(adj_index_t adj_index)
Release a reference counting lock on the adjacency.
Definition: adj.c:318
unsigned int u32
Definition: types.h:88
f64 max_radv_interval
Definition: ip6_neighbor.c: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:376
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:326
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
void adj_mcast_update_rewrite(adj_index_t adj_index, u8 *rewrite, u8 offset)
adj_mcast_update_rewrite
Definition: adj_mcast.c:102
#define ADJ_INDEX_INVALID
Invalid ADJ index - used when no adj is known likewise blazoned capitals INVALID speak volumes where ...
Definition: adj_types.h:36
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:514
static_always_inline void mac_address_from_bytes(mac_address_t *mac, const u8 *bytes)
Definition: mac_address.h:92
vlib_main_t * vlib_main
Definition: vnet.h:80
f64 min_radv_interval
Definition: ip6_neighbor.c:138
void vnet_register_ip6_neighbor_resolution_event(vnet_main_t *vnm, void *address_arg, uword node_index, uword type_opaque, uword data)
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:934
Adjacency source.
Definition: fib_entry.h:113
ip46_address_t fp_addr
The address type is not deriveable from the fp_addr member.
Definition: fib_types.h:226
u32 neighbor_reachable_time_in_msec
Definition: ip6_neighbor.h:128
uword type_opaque
Definition: arp.c:74
vlib_frame_t * data_callback(flow_report_main_t *frm, flow_report_t *fr, vlib_frame_t *f, u32 *to_next, u32 node_index)
static void ip6_neighbor_add_mld_grp(ip6_radv_t *a, ip6_multicast_address_scope_t scope, ip6_multicast_link_local_group_id_t group)
Add a multicast Address to the advertised MLD set.
static int vnet_nd_wc_publish(u32 sw_if_index, const mac_address_t *mac, const ip6_address_t *ip6)
publish wildcard arp event
Definition: ip6_neighbor.c:270
long ctx[MAX_CONNS]
Definition: main.c:144
int all_routers_mcast
Definition: ip6_neighbor.c:118
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
static char * ip6_discover_neighbor_error_strings[]
static clib_error_t * enable_ip6_interface_cmd(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
#define DEF_MAX_RADV_INTERVAL
Definition: ip6_neighbor.c:125
#define IP6_MLDP_ALERT_TYPE
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:196
u8 link_layer_address[8]
Definition: ip6_neighbor.c:95
f64 next_multicast_time
Definition: ip6_neighbor.c:145
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
u32 ip6_ll_fib_get(u32 sw_if_index)
For use in the data plane.
Definition: ip6_ll_table.c:28
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:286
#define foreach_log_level
enum icmp6_neighbor_discovery_option_type icmp6_neighbor_discovery_option_type_t
static void * vlib_process_signal_event_data(vlib_main_t *vm, uword node_index, uword type_opaque, uword n_data_elts, uword n_data_elt_bytes)
Definition: node_funcs.h:828
#define ELOG_DATA(em, f)
Definition: elog.h:484
ip6_table_bind_callback_t * table_bind_callbacks
Functions to call when interface to table biding changes.
Definition: ip6.h:218
int ip6_address_compare(ip6_address_t *a1, ip6_address_t *a2)
Definition: ip46_cli.c:60
static u64 throttle_seed(throttle_t *t, u32 thread_index, f64 time_now)
Definition: throttle.h:41
#define PREDICT_FALSE(x)
Definition: clib.h:111
This packet matches an "interface route" and packets need to be passed to ARP to find rewrite string ...
Definition: adj.h:68
vnet_sw_interface_flags_t flags
Definition: interface.h:699
vnet_main_t vnet_main
Definition: misc.c:43
ip6_discover_neighbor_error_t
int adv_other_flag
Definition: ip6_neighbor.c:86
u32 node_index
Node index.
Definition: node.h:494
mhash_t address_to_prefix_index
Definition: ip6_neighbor.c:102
u16 router_lifetime_in_sec
Definition: ip6_neighbor.h:127
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
static uword mhash_set(mhash_t *h, void *key, uword new_value, uword *old_value)
Definition: mhash.h:117
vl_api_address_t dst
Definition: gre.api:52
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:338
ra_report_prefix_info_t * prefixes
Definition: ip6_neighbor.h:132
static uword ip6_discover_neighbor(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
ip6_add_del_interface_address_callback_t * add_del_interface_address_callbacks
Definition: ip6.h:215
void ra_set_publisher_node(uword node_index, uword event_type)
Definition: ip6_neighbor.c:331
int vnet_add_del_ip6_nd_change_event(vnet_main_t *vnm, ip6_nd_change_event_cb_t data_callback, u32 pid, void *address_arg, uword node_index, uword type_opaque, uword data, int is_add)
uword unformat_mac_address_t(unformat_input_t *input, va_list *args)
Definition: mac_address.c:37
static void ip6_neighbor_add_mld_prefix(ip6_radv_t *radv_info, ip6_address_t *addr)
Add a multicast Address to the advertised MLD set.
int failed_device_check
Definition: ip6_neighbor.c:117
i32 priority
Definition: ipsec.api:92
vlib_node_registration_t ip6_icmp_input_node
(constructor) VLIB_REGISTER_NODE (ip6_icmp_input_node)
Definition: icmp6.c:240
unformat_function_t unformat_ip6_address
Definition: format.h:91
#define pool_free(p)
Free a pool.
Definition: pool.h:407
ip6_mldp_group_t * mldp_group_pool
Definition: ip6_neighbor.c:105
struct ip_adjacency_t_::@48::@49 nbr
IP_LOOKUP_NEXT_ARP/IP_LOOKUP_NEXT_REWRITE.
static_always_inline uword icmp6_neighbor_solicitation_or_advertisement(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, uword is_solicitation)
void wc_nd_set_publisher_node(uword node_index, uword event_type)
Definition: ip6_neighbor.c:300
clib_error_t * enable_ip6_interface(vlib_main_t *vm, u32 sw_if_index)
void ip6_mfib_interface_enable_disable(u32 sw_if_index, int is_enable)
Add/remove the interface from the accepting list of the special MFIB entries.
Definition: ip6_mfib.c:232
icmp6_neighbor_solicitation_or_advertisement_next_t
int adv_managed_flag
Definition: ip6_neighbor.c:85
static uword icmp6_neighbor_advertisement(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
This packet matches an "incomplete adjacency" and packets need to be passed to ARP to find rewrite st...
Definition: adj.h:63
static int ip6_src_address_for_packet(ip_lookup_main_t *lm, u32 sw_if_index, const ip6_address_t *dst, ip6_address_t *src)
Definition: ip6.h:308
int fib_entry_is_sourced(fib_node_index_t fib_entry_index, fib_source_t source)
u32 n_solicitations_dropped
Definition: ip6_neighbor.c:155
Adjacency to drop this packet.
Definition: adj.h:53
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
static void vlib_buffer_copy_trace_flag(vlib_main_t *vm, vlib_buffer_t *b, u32 bi_target)
Definition: trace_funcs.h:162
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
void mhash_init(mhash_t *h, uword n_value_bytes, uword n_key_bytes)
Definition: mhash.c:168
static u8 get_mac_address(u32 sw_if_index, u8 *address)
u16 n_vectors
Definition: node.h:395
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:213
format_function_t format_ip6_address
Definition: format.h:93
static ip6_address_t ip6a_zero
Definition: ip6_neighbor.c:236
vlib_main_t * vm
Definition: buffer.c:312
static int ra_publish(ra_report_t *r)
Definition: ip6_neighbor.c:308
ip6_address_t mcast_address
Definition: ip6_neighbor.c:74
static void ip6_neighbor_adj_fib_remove(ip6_neighbor_t *n, u32 fib_index)
Definition: ip6_neighbor.c:361
log_level_t
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:341
Multicast Midchain Adjacency.
Definition: adj.h:89
u8 curr_hop_limit
Definition: ip6_neighbor.c:84
f64 sleep_interval
Definition: ip6_neighbor.c:163
#define clib_warning(format, args...)
Definition: error.h:59
ip6_address_t * mcast_source_address_pool
Definition: ip6_neighbor.c:76
static vlib_node_runtime_t * vlib_node_get_runtime(vlib_main_t *vm, u32 node_index)
Get node runtime by node index.
Definition: node_funcs.h:89
static void ip6_neighbor_table_bind(ip6_main_t *im, uword opaque, u32 sw_if_index, u32 new_fib_index, u32 old_fib_index)
#define DEF_CURR_HOP_LIMIT
Definition: ip6_neighbor.c:127
u8 * format_ip_neighbor_flags(u8 *s, va_list *args)
Definition: ip_neighbor.c:51
elog_main_t elog_main
Definition: main.h:172
int adv_link_layer_address
Definition: ip6_neighbor.c:115
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:30
static vlib_cli_command_t show_ip6_neighbors_command
(constructor) VLIB_CLI_COMMAND (show_ip6_neighbors_command)
fib_node_index_t fib_entry_index
Definition: ip6_neighbor.h:39
u32 adj_index_t
An index for adjacencies.
Definition: adj_types.h:30
#define ARRAY_LEN(x)
Definition: clib.h:62
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:458
uword * mac_by_ip6
Definition: l2_bd.h:102
#define ELOG_TYPE_DECLARE(f)
Definition: elog.h:442
vlib_node_t * vlib_get_node_by_name(vlib_main_t *vm, u8 *name)
Definition: node.c:45
static bool check_send_rs(vlib_main_t *vm, ip6_radv_t *radv_info, f64 current_time, f64 *due_time)
u8 current_hop_limit
Definition: ip6_neighbor.h:125
static void * ip6_next_header(ip6_header_t *i)
Definition: ip6_packet.h:410
ip6_address_t ilp_addr
the IP6 address
Definition: ip6_ll_types.h:34
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:155
u32 initial_adverts_count
Definition: ip6_neighbor.c:148
This packets follow a mid-chain adjacency.
Definition: adj.h:76
u32 * if_address_pool_index_by_sw_if_index
Head of doubly linked list of interface addresses for each software interface.
Definition: lookup.h:132
u16 ip6_tcp_udp_icmp_compute_checksum(vlib_main_t *vm, vlib_buffer_t *p0, ip6_header_t *ip0, int *bogus_lengthp)
Definition: ip6_forward.c:906
ip6_add_del_interface_address_function_t * function
Definition: ip6.h:104
#define MAX_INITIAL_RTR_ADVERTISEMENTS
Definition: ip6_neighbor.c:132
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:513
ip6_address_t link_local_address
Definition: ip6_neighbor.c:158
#define ASSERT(truth)
vlib_node_registration_t send_rs_process_node
(constructor) VLIB_REGISTER_NODE (send_rs_process_node)
int prefix_option
Definition: ip6_neighbor.c:116
static uword * mhash_get(mhash_t *h, const void *key)
Definition: mhash.h:110
ip6_address_t ip6_address
Definition: ip6_neighbor.h:28
ip6_main_t ip6_main
Definition: ip6_forward.c:2671
ip_lookup_main_t lookup_main
Definition: ip6.h:179
u32 n_advertisements_sent
Definition: ip6_neighbor.c:153
static void mhash_free(mhash_t *h)
Definition: mhash.h:149
static clib_error_t * show_ip6_interface_cmd(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
u32 vlib_register_node(vlib_main_t *vm, vlib_node_registration_t *r)
Definition: node.c:520
int vnet_set_ip6_ethernet_neighbor(vlib_main_t *vm, u32 sw_if_index, const ip6_address_t *a, const mac_address_t *mac, ip_neighbor_flags_t flags)
Definition: ip6_neighbor.c:760
f64 min_delay_between_radv
Definition: ip6_neighbor.c:139
#define DEF_MIN_RADV_INTERVAL
Definition: ip6_neighbor.c:126
static_always_inline uword icmp6_router_solicitation(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
static int ip6_neighbor_sort(void *a1, void *a2)
Definition: ip6_neighbor.c:965
static uword send_rs_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f0)
u32 * if_radv_pool_index_by_sw_if_index
Definition: ip6_neighbor.c:201
u16 adv_router_lifetime_in_sec
Definition: ip6_neighbor.c:87
static f64 random_f64(u32 *seed)
Generate f64 random number in the interval [0,1].
Definition: random.h:145
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:248
Aggregrate type for a prefix in the IPv6 Link-local table.
Definition: ip6_ll_types.h:24
size_t count
Definition: vapi.c:47
ip6_multicast_link_local_group_id_t
Definition: ip6_packet.h:179
static uword ip6_address_is_link_local_unicast(const ip6_address_t *a)
Definition: ip6_packet.h:326
Route added as a result of interface configuration.
Definition: fib_entry.h:59
void fib_table_entry_path_remove(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, dpo_proto_t next_hop_proto, const ip46_address_t *next_hop, u32 next_hop_sw_if_index, u32 next_hop_fib_index, u32 next_hop_weight, fib_route_path_flags_t path_flags)
remove one path to an entry (aka route) in the FIB.
Definition: fib_table.c:693
u8 keep_sending_rs
Definition: ip6_neighbor.c:161
mhash_t pending_resolutions_by_address
Definition: ip6_neighbor.c:188
static uword icmp6_neighbor_solicitation(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
static adj_walk_rc_t ip6_nd_mk_incomplete_walk(adj_index_t ai, void *ctx)
Definition: ip6_neighbor.c:553
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
static uword vnet_sw_interface_is_admin_up(vnet_main_t *vnm, u32 sw_if_index)
vlib_buffer_t * buffer
Definition: ip6_neighbor.c:167
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
icmp6_send_router_solicitation_params_t params
Definition: ip6_neighbor.c:162
#define unformat_parse_error(input)
Definition: format.h:269
ip6_address_t ip6_neighbor_get_link_local_address(u32 sw_if_index)
Definition: ip6_neighbor.c:242
static ip6_neighbor_t * force_reuse_neighbor_entry(void)
Definition: ip6_neighbor.c:729
struct _vlib_node_registration vlib_node_registration_t
u32 ip_version_traffic_class_and_flow_label
Definition: ip6_packet.h:370
void ethernet_ndp_change_mac(u32 sw_if_index)
fib_entry_flag_t fib_entry_get_flags_for_source(fib_node_index_t fib_entry_index, fib_source_t source)
This packets needs to go to ICMP error.
Definition: adj.h:79
This packet is for one of our own IP addresses.
Definition: adj.h:58
static vlib_node_registration_t ip6_icmp_router_solicitation_node
(constructor) VLIB_REGISTER_NODE (ip6_icmp_router_solicitation_node)
Definition: defs.h:47
void vlib_trace_frame_buffers_only(vlib_main_t *vm, vlib_node_runtime_t *node, u32 *buffers, uword n_buffers, uword next_buffer_stride, uword n_buffer_data_bytes_in_trace)
Definition: trace.c:47
static void ip6_neighbor_send_mldpv2_report(u32 sw_if_index)
l2input_main_t l2input_main
Definition: l2_input.c:128
vlib_node_registration_t ip6_icmp_neighbor_discovery_event_node
u16 payload_length
Definition: ip6_packet.h:374
static void * vlib_process_get_event_data(vlib_main_t *vm, uword *return_event_type_opaque)
Definition: node_funcs.h:463
static void ip6_neighbor_set_unset_rpc_callback(ip6_neighbor_set_unset_rpc_args_t *a)
Definition: ip6_neighbor.c:954
static uword ip6_address_is_global_unicast(const ip6_address_t *a)
Definition: ip6_packet.h:340
vl_api_address_t ip
Definition: l2.api:489
ethernet_interface_t * ethernet_get_interface(ethernet_main_t *em, u32 hw_if_index)
Definition: interface.c:886
int vnet_unset_ip6_ethernet_neighbor(vlib_main_t *vm, u32 sw_if_index, const ip6_address_t *a)
Definition: ip6_neighbor.c:912
static void ip6_set_solicited_node_multicast_address(ip6_address_t *a, u32 id)
Definition: ip6_packet.h:217
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:31
ip6_neighbor_key_t key
Definition: ip6_neighbor.h:35
A for-us/local path.
Definition: fib_types.h:332
u32 elog_string(elog_main_t *em, char *fmt,...)
add a string to the event-log string table
Definition: elog.c:562
void icmp6_register_type(vlib_main_t *vm, icmp6_type_t type, u32 node_index)
Definition: icmp6.c:750
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
ip_lookup_next_t lookup_next_index
Next hop after ip4-lookup.
Definition: adj.h:236
#define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b)
Definition: buffer.h:489
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
ip6_neighbor_public_main_t ip6_neighbor_public_main
Definition: ip6_neighbor.c:235
format_function_t format_vlib_time
Definition: node_funcs.h:1145
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:980
static void unformat_free(unformat_input_t *i)
Definition: format.h:163
int ip6_neighbor_ra_config(vlib_main_t *vm, u32 sw_if_index, u8 suppress, u8 managed, u8 other, u8 ll_option, u8 send_unicast, u8 cease, u8 use_lifetime, u32 lifetime, u32 initial_count, u32 initial_interval, u32 max_interval, u32 min_interval, u8 is_no)
static void ip6_neighbor_add_del_interface_address(ip6_main_t *im, uword opaque, u32 sw_if_index, ip6_address_t *address, u32 address_length, u32 if_address_index, u32 is_delete)
callback when an interface address is added or deleted
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:244
u32 ilp_sw_if_index
The interface.
Definition: ip6_ll_types.h:29
ip6_table_bind_function_t * function
Definition: ip6.h:114
void ip6_ll_table_entry_delete(const ip6_ll_prefix_t *ilp)
Delete a IP6 link-local entry.
Definition: ip6_ll_table.c:139
u8 * ethernet_build_rewrite(vnet_main_t *vnm, u32 sw_if_index, vnet_link_t link_type, const void *dst_address)
build a rewrite string to use for sending packets of type &#39;link_type&#39; to &#39;dst_address&#39; ...
Definition: interface.c:81
static void ip6_address_copy(ip6_address_t *dst, const ip6_address_t *src)
Definition: ip6_packet.h:200
l2_bridge_domain_t * bd_configs
Definition: l2_input.h:64
#define ICMP6_ROUTER_DISCOVERY_FLAG_ADDRESS_CONFIG_VIA_DHCP
vlib_node_registration_t ip6_glean_node
(constructor) VLIB_REGISTER_NODE (ip6_glean_node)
#define hash_get_mem(h, key)
Definition: hash.h:269
struct clib_bihash_value offset
template key/value backing page structure
static uword ip6_address_is_unspecified(const ip6_address_t *a)
Definition: ip6_packet.h:310
static vlib_node_registration_t ip6_icmp_neighbor_advertisement_node
(constructor) VLIB_REGISTER_NODE (ip6_icmp_neighbor_advertisement_node)
#define vnet_buffer(b)
Definition: buffer.h:361
static clib_error_t * ip6_neighbor_sw_interface_up_down(vnet_main_t *vnm, u32 sw_if_index, u32 flags)
Definition: ip6_neighbor.c:561
f64 initial_adverts_interval
Definition: ip6_neighbor.c:149
static u32 random_u32(u32 *seed)
32-bit random number generator
Definition: random.h:69
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
vnet_sw_interface_type_t type
Definition: interface.h:697
adj_index_t mcast_adj_index
Definition: ip6_neighbor.c:122
uword node_index
Definition: arp.c:73
ip6_icmp_neighbor_discovery_event_type_t
Definition: ip6_neighbor.c:219
u8 * format_mac_address_t(u8 *s, va_list *args)
Definition: mac_address.c:27
ip_neighbor_flags_t flags
Definition: ip6_neighbor.h:37
adj_index_t adj_mcast_add_or_lock(fib_protocol_t proto, vnet_link_t link_type, u32 sw_if_index)
Mcast Adjacency.
Definition: adj_mcast.c:51
vlib_node_registration_t ip6_discover_neighbor_node
(constructor) VLIB_REGISTER_NODE (ip6_discover_neighbor_node)
#define vec_foreach(var, vec)
Vector iterator.
arp_change_event_cb_t data_callback
Definition: arp.c:77
void ip6_ethernet_update_adjacency(vnet_main_t *vnm, u32 sw_if_index, u32 ai)
Definition: ip6_neighbor.c:609
void ip6_forward_next_trace(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, vlib_rx_or_tx_t which_adj_index)
Definition: ip6_forward.c:814
u16 flags
Copy of main node flags.
Definition: node.h:507
u32 adv_valid_lifetime_in_secs
Definition: ip6_neighbor.c:50
static void ip6_multicast_ethernet_address(u8 *ethernet_address, u32 group_id)
Definition: ip6_packet.h:229
u32 initial_adverts_sent
Definition: ip6_neighbor.c:150
static void * ip_interface_address_get_address(ip_lookup_main_t *lm, ip_interface_address_t *a)
Definition: lookup.h:175
static ip6_neighbor_t * ip6_nd_find(u32 sw_if_index, const ip6_address_t *addr)
Definition: ip6_neighbor.c:524
mhash_t mac_changes_by_address
Definition: ip6_neighbor.c:192
static_always_inline int mac_address_cmp(const mac_address_t *a, const mac_address_t *b)
Definition: mac_address.h:134
static adj_walk_rc_t ip6_nd_mk_complete_walk(adj_index_t ai, void *ctx)
Definition: ip6_neighbor.c:543
#define MAX_INITIAL_RTR_ADVERT_INTERVAL
Definition: ip6_neighbor.c:131
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:301
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:486
fib_node_index_t ip6_ll_table_entry_update(const ip6_ll_prefix_t *ilp, fib_route_path_flags_t flags)
Update an entry in the table.
Definition: ip6_ll_table.c:105
static u32 vlib_buffer_alloc(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Allocate buffers into supplied array.
Definition: buffer_funcs.h:612
clib_error_t * ip6_neighbor_cmd(vlib_main_t *vm, unformat_input_t *main_input, vlib_cli_command_t *cmd)
f64 max_rtr_default_lifetime
Definition: ip6_neighbor.c:141
static vlib_node_registration_t ip6_icmp_router_advertisement_node
(constructor) VLIB_REGISTER_NODE (ip6_icmp_router_advertisement_node)
ip6_neighbor_t * neighbor_pool
Definition: ip6_neighbor.c:197
void adj_nbr_update_rewrite(adj_index_t adj_index, adj_nbr_rewrite_flag_t flags, u8 *rewrite)
adj_nbr_update_rewrite
Definition: adj_nbr.c:298
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:768
vl_api_gbp_scope_t scope
Definition: gbp.api:73
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
static_always_inline uword icmp6_router_advertisement(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
void ip6_sw_interface_enable_disable(u32 sw_if_index, u32 is_enable)
Definition: ip6_forward.c:146
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
#define MAX_DEF_RTR_LIFETIME
Definition: ip6_neighbor.c:129
u32 adv_link_mtu
Definition: ip6_neighbor.c:92
Definition: defs.h:46
static ip6_neighbor_main_t ip6_neighbor_main
Definition: ip6_neighbor.c:234
pending_resolution_t * mac_changes
Definition: ip6_neighbor.c:193
ip6_address_t dst_address
Definition: ip6_packet.h:383
int ip6_interface_enabled(vlib_main_t *vm, u32 sw_if_index)
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:171
static void ip6_set_reserved_multicast_address(ip6_address_t *a, ip6_multicast_address_scope_t scope, u16 id)
Definition: ip6_packet.h:207
IPv6 Proxy ND.
Definition: fib_entry.h:103
clib_error_t * ip6_set_neighbor_limit(u32 neighbor_limit)
format_function_t format_icmp6_input_trace
Definition: icmp6.h:65
static int throttle_check(throttle_t *t, u32 thread_index, u64 hash, u64 seed)
Definition: throttle.h:54
u8 * format_ip6_forward_next_trace(u8 *s, va_list *args)
Definition: ip6_forward.c:762
void adj_nbr_walk_nh6(u32 sw_if_index, const ip6_address_t *addr, adj_walk_cb_t cb, void *ctx)
Walk adjacencies on a link with a given v6 next-hop.
Definition: adj_nbr.c:626
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128