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