FD.io VPP  v17.01.1-3-gc6833f8
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 <vppinfra/md5.h>
23 #include <vnet/adj/adj.h>
24 #include <vnet/fib/fib_table.h>
25 #include <vnet/fib/ip6_fib.h>
26 
27 /**
28  * @file
29  * @brief IPv6 Neighbor Adjacency and Neighbor Discovery.
30  *
31  * The files contains the API and CLI code for managing IPv6 neighbor
32  * adjacency tables and neighbor discovery logic.
33  */
34 
35 /* can't use sizeof link_layer_address, that's 8 */
36 #define ETHER_MAC_ADDR_LEN 6
37 
38 /* advertised prefix option */
39 typedef struct
40 {
41  /* basic advertised information */
48 
49  /* advertised values are computed from these times if decrementing */
52 
53  /* local information */
54  int enabled;
57 
58 #define MIN_ADV_VALID_LIFETIME 7203 /* seconds */
59 #define DEF_ADV_VALID_LIFETIME 2592000
60 #define DEF_ADV_PREF_LIFETIME 604800
61 
62  /* extensions are added here, mobile, DNS etc.. */
64 
65 
66 typedef struct
67 {
68  /* group information */
74 
75 /* configured router advertisement information per ipv6 interface */
76 typedef struct
77 {
78 
79  /* advertised config information, zero means unspecified */
86 
87  /* mtu option */
89 
90  /* source link layer option */
91  u8 link_layer_address[8];
93 
94  /* prefix option */
96 
97  /* Hash table mapping address to index in interface advertised prefix pool. */
99 
100  /* MLDP group information */
102 
103  /* Hash table mapping address to index in mldp address pool. */
105 
106  /* local information */
109  int send_radv; /* radv on/off on this interface - set by config */
110  int cease_radv; /* we are ceasing to send - set byf config */
122 
123  /* timing information */
124 #define DEF_MAX_RADV_INTERVAL 200
125 #define DEF_MIN_RADV_INTERVAL .75 * DEF_MAX_RADV_INTERVAL
126 #define DEF_CURR_HOP_LIMIT 64
127 #define DEF_DEF_RTR_LIFETIME 3 * DEF_MAX_RADV_INTERVAL
128 #define MAX_DEF_RTR_LIFETIME 9000
129 
130 #define MAX_INITIAL_RTR_ADVERT_INTERVAL 16 /* seconds */
131 #define MAX_INITIAL_RTR_ADVERTISEMENTS 3 /*transmissions */
132 #define MIN_DELAY_BETWEEN_RAS 3 /* seconds */
133 #define MAX_DELAY_BETWEEN_RAS 1800 /* seconds */
134 #define MAX_RA_DELAY_TIME .5 /* seconds */
135 
141 
145 
146 
150 
151  /* stats */
155 
156  /* Link local address to use (defaults to underlying physical for logical interfaces */
158 
159 } ip6_radv_t;
160 
161 typedef struct
162 {
163  u32 next_index;
164  uword node_index;
165  uword type_opaque;
166  uword data;
167  /* Used for nd event notification only */
168  void *data_callback;
169  u32 pid;
171 
172 
173 typedef struct
174 {
175  /* Hash tables mapping name to opcode. */
177 
178  /* lite beer "glean" adjacency handling */
181 
182  /* Mac address change notification */
185 
187 
189 
191 
193 
195 
196  /* Neighbor attack mitigation */
199 
201 
203 static ip6_address_t ip6a_zero; /* ip6 address 0 */
204 
205 static u8 *
207 {
208  vlib_main_t *vm = va_arg (*va, vlib_main_t *);
209  ip6_neighbor_t *n = va_arg (*va, ip6_neighbor_t *);
210  vnet_main_t *vnm = vnet_get_main ();
212  u8 *flags = 0;
213 
214  if (!n)
215  return format (s, "%=12s%=20s%=6s%=20s%=40s", "Time", "Address", "Flags",
216  "Link layer", "Interface");
217 
219  flags = format (flags, "D");
220 
222  flags = format (flags, "S");
223 
224  si = vnet_get_sw_interface (vnm, n->key.sw_if_index);
225  s = format (s, "%=12U%=20U%=6s%=20U%=40U",
228  flags ? (char *) flags : "",
231 
232  vec_free (flags);
233  return s;
234 }
235 
236 static clib_error_t *
238  u32 sw_if_index, u32 flags)
239 {
241  ip6_neighbor_t *n;
242 
243  if (!(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
244  {
245  u32 i, *to_delete = 0;
246 
247  /* *INDENT-OFF* */
248  pool_foreach (n, nm->neighbor_pool,
249  ({
250  if (n->key.sw_if_index == sw_if_index)
251  vec_add1 (to_delete, n - nm->neighbor_pool);
252  }));
253  /* *INDENT-ON* */
254 
255  for (i = 0; i < vec_len (to_delete); i++)
256  {
257  n = pool_elt_at_index (nm->neighbor_pool, to_delete[i]);
258  mhash_unset (&nm->neighbor_index_by_key, &n->key, 0);
260  pool_put (nm->neighbor_pool, n);
261  }
262 
263  vec_free (to_delete);
264  }
265 
266  return 0;
267 }
268 
270 
271 static void
273 {
275  vnet_main_t *vnm = vnet_get_main ();
276  vlib_main_t *vm = vnm->vlib_main;
277  ip6_neighbor_t *e;
278  u32 index;
279 
281  nm->neighbor_delete_rotor = index;
282 
283  /* Try again from elt 0, could happen if an intfc goes down */
284  if (index == ~0)
285  {
287  nm->neighbor_delete_rotor = index;
288  }
289 
290  /* Nothing left in the pool */
291  if (index == ~0)
292  return;
293 
294  e = pool_elt_at_index (nm->neighbor_pool, index);
295 
297  &e->key.ip6_address,
300 }
301 
302 typedef struct
303 {
306  u8 link_layer_address[6];
310 
313 
314 static void set_unset_ip6_neighbor_rpc
315  (vlib_main_t * vm,
316  u32 sw_if_index,
317  ip6_address_t * a, u8 * link_layer_addreess, int is_add, int is_static)
318 {
320  void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
321 
322  args.sw_if_index = sw_if_index;
323  args.is_add = is_add;
324  args.is_static = is_static;
325  clib_memcpy (&args.addr, a, sizeof (*a));
326  clib_memcpy (args.link_layer_address, link_layer_addreess, 6);
327 
329  (u8 *) & args, sizeof (args));
330 }
331 
332 static void
334 {
335  icmp6_neighbor_solicitation_header_t *h;
336  vnet_main_t *vnm = vnet_get_main ();
337  ip6_main_t *im = &ip6_main;
339  ip6_address_t *dst, *src;
342  vlib_buffer_t *b;
343  int bogus_length;
344  vlib_main_t *vm;
345  u32 bi = 0;
346 
347  vm = vlib_get_main ();
348 
349  si = vnet_get_sw_interface (vnm, adj->rewrite_header.sw_if_index);
350  dst = &adj->sub_type.nbr.next_hop.ip6;
351 
353  {
354  return;
355  }
357  adj->rewrite_header.
358  sw_if_index, &ia);
359  if (!src)
360  {
361  return;
362  }
363 
366  &bi);
367 
368  hi = vnet_get_sup_hw_interface (vnm, adj->rewrite_header.sw_if_index);
369 
370  h->ip.dst_address.as_u8[13] = dst->as_u8[13];
371  h->ip.dst_address.as_u8[14] = dst->as_u8[14];
372  h->ip.dst_address.as_u8[15] = dst->as_u8[15];
373  h->ip.src_address = src[0];
374  h->neighbor.target_address = dst[0];
375 
376  clib_memcpy (h->link_layer_option.ethernet_address,
377  hi->hw_address, vec_len (hi->hw_address));
378 
379  h->neighbor.icmp.checksum =
380  ip6_tcp_udp_icmp_compute_checksum (vm, 0, &h->ip, &bogus_length);
381  ASSERT (bogus_length == 0);
382 
383  b = vlib_get_buffer (vm, bi);
384  vnet_buffer (b)->sw_if_index[VLIB_RX] =
385  vnet_buffer (b)->sw_if_index[VLIB_TX] = adj->rewrite_header.sw_if_index;
386 
387  /* Add encapsulation string for software interface (e.g. ethernet header). */
388  vnet_rewrite_one_header (adj[0], h, sizeof (ethernet_header_t));
389  vlib_buffer_advance (b, -adj->rewrite_header.data_bytes);
390 
391  {
393  u32 *to_next = vlib_frame_vector_args (f);
394  to_next[0] = bi;
395  f->n_vectors = 1;
397  }
398 }
399 
400 static void
402 {
405  nbr->key.sw_if_index,
406  adj_get_link_type (ai),
407  nbr->link_layer_address));
408 }
409 
410 static void
412 {
413  ip_adjacency_t *adj = adj_get (ai);
414 
418  adj->rewrite_header.
419  sw_if_index,
420  adj_get_link_type (ai),
422 }
423 
424 #define IP6_NBR_MK_KEY(k, sw_if_index, addr) \
425 { \
426  k.sw_if_index = sw_if_index; \
427  k.ip6_address = *addr; \
428  k.pad = 0; \
429 }
430 
431 static ip6_neighbor_t *
432 ip6_nd_find (u32 sw_if_index, const ip6_address_t * addr)
433 {
435  ip6_neighbor_t *n = NULL;
437  uword *p;
438 
439  IP6_NBR_MK_KEY (k, sw_if_index, addr);
440 
441  p = mhash_get (&nm->neighbor_index_by_key, &k);
442  if (p)
443  {
444  n = pool_elt_at_index (nm->neighbor_pool, p[0]);
445  }
446 
447  return (n);
448 }
449 
450 static adj_walk_rc_t
452 {
453  ip6_neighbor_t *nbr = ctx;
454 
455  ip6_nd_mk_complete (ai, nbr);
456 
457  return (ADJ_WALK_RC_CONTINUE);
458 }
459 
460 static adj_walk_rc_t
462 {
464 
465  return (ADJ_WALK_RC_CONTINUE);
466 }
467 
468 void
470 {
471  ip6_neighbor_t *nbr;
472  ip_adjacency_t *adj;
473 
474  adj = adj_get (ai);
475 
476  nbr = ip6_nd_find (sw_if_index, &adj->sub_type.nbr.next_hop.ip6);
477 
478  if (NULL != nbr)
479  {
480  adj_nbr_walk_nh6 (sw_if_index, &nbr->key.ip6_address,
482  }
483  else
484  {
485  /*
486  * no matching ND entry.
487  * construct the rewrite required to for an ND packet, and stick
488  * that in the adj's pipe to smoke.
489  */
493  sw_if_index,
496 
497  /*
498  * since the FIB has added this adj for a route, it makes sense it may
499  * want to forward traffic sometime soon. Let's send a speculative ND.
500  * just one. If we were to do periodically that wouldn't be bad either,
501  * but that's more code than i'm prepared to write at this time for
502  * relatively little reward.
503  */
504  ip6_nbr_probe (adj);
505  }
506 }
507 
508 int
510  u32 sw_if_index,
511  ip6_address_t * a,
512  u8 * link_layer_address,
513  uword n_bytes_link_layer_address,
514  int is_static)
515 {
518  ip6_neighbor_t *n = 0;
519  int make_new_nd_cache_entry = 1;
520  uword *p;
521  u32 next_index;
522  pending_resolution_t *pr, *mc;
523 
524  if (os_get_cpu_number ())
525  {
526  set_unset_ip6_neighbor_rpc (vm, sw_if_index, a, link_layer_address,
527  1 /* set new neighbor */ , is_static);
528  return 0;
529  }
530 
531  k.sw_if_index = sw_if_index;
532  k.ip6_address = a[0];
533  k.pad = 0;
534 
535  p = mhash_get (&nm->neighbor_index_by_key, &k);
536  if (p)
537  {
538  n = pool_elt_at_index (nm->neighbor_pool, p[0]);
539  /* Refuse to over-write static neighbor entry. */
540  if (!is_static && (n->flags & IP6_NEIGHBOR_FLAG_STATIC))
541  return -2;
542  make_new_nd_cache_entry = 0;
543  }
544 
545  if (make_new_nd_cache_entry)
546  {
547  fib_prefix_t pfx = {
548  .fp_len = 128,
549  .fp_proto = FIB_PROTOCOL_IP6,
550  .fp_addr = {
551  .ip6 = k.ip6_address,
552  }
553  ,
554  };
555  u32 fib_index;
556 
557  pool_get (nm->neighbor_pool, n);
558  mhash_set (&nm->neighbor_index_by_key, &k, n - nm->neighbor_pool,
559  /* old value */ 0);
560  n->key = k;
561 
563  link_layer_address, n_bytes_link_layer_address);
564 
565  /*
566  * create the adj-fib. the entry in the FIB table for and to the peer.
567  */
571  }
572  else
573  {
574  /*
575  * prevent a DoS attack from the data-plane that
576  * spams us with no-op updates to the MAC address
577  */
578  if (0 == memcmp (n->link_layer_address,
579  link_layer_address, n_bytes_link_layer_address))
580  return -1;
581 
583  link_layer_address, n_bytes_link_layer_address);
584  }
585 
586  /* Update time stamp and flags. */
588  if (is_static)
590  else
592 
593  adj_nbr_walk_nh6 (sw_if_index,
595 
596  /* Customer(s) waiting for this address to be resolved? */
598  if (p)
599  {
600  next_index = p[0];
601 
602  while (next_index != (u32) ~ 0)
603  {
604  pr = pool_elt_at_index (nm->pending_resolutions, next_index);
606  pr->type_opaque, pr->data);
607  next_index = pr->next_index;
608  pool_put (nm->pending_resolutions, pr);
609  }
610 
612  }
613 
614  /* Customer(s) requesting ND event for this address? */
615  p = mhash_get (&nm->mac_changes_by_address, a);
616  if (p)
617  {
618  next_index = p[0];
619 
620  while (next_index != (u32) ~ 0)
621  {
622  int (*fp) (u32, u8 *, u32, ip6_address_t *);
623  int rv = 1;
624  mc = pool_elt_at_index (nm->mac_changes, next_index);
625  fp = mc->data_callback;
626 
627  /* Call the user's data callback, return 1 to suppress dup events */
628  if (fp)
629  rv =
630  (*fp) (mc->data, link_layer_address, sw_if_index, &ip6a_zero);
631  /*
632  * Signal the resolver process, as long as the user
633  * says they want to be notified
634  */
635  if (rv == 0)
637  mc->type_opaque, mc->data);
638  next_index = mc->next_index;
639  }
640  }
641 
642  return 0;
643 }
644 
645 int
647  u32 sw_if_index,
648  ip6_address_t * a,
649  u8 * link_layer_address,
650  uword n_bytes_link_layer_address)
651 {
654  ip6_neighbor_t *n;
655  uword *p;
656  int rv = 0;
657 
658  if (os_get_cpu_number ())
659  {
660  set_unset_ip6_neighbor_rpc (vm, sw_if_index, a, link_layer_address,
661  0 /* unset */ , 0);
662  return 0;
663  }
664 
665  k.sw_if_index = sw_if_index;
666  k.ip6_address = a[0];
667  k.pad = 0;
668 
669  p = mhash_get (&nm->neighbor_index_by_key, &k);
670  if (p == 0)
671  {
672  rv = -1;
673  goto out;
674  }
675 
676  n = pool_elt_at_index (nm->neighbor_pool, p[0]);
677  mhash_unset (&nm->neighbor_index_by_key, &n->key, 0);
678 
679  adj_nbr_walk_nh6 (sw_if_index,
681 
683  pool_put (nm->neighbor_pool, n);
684 
685 out:
686  return rv;
687 }
688 
691 {
692  vlib_main_t *vm = vlib_get_main ();
693  if (a->is_add)
695  a->link_layer_address, 6, a->is_static);
696  else
698  a->link_layer_address, 6);
699 }
700 
701 static int
702 ip6_neighbor_sort (void *a1, void *a2)
703 {
704  vnet_main_t *vnm = vnet_get_main ();
705  ip6_neighbor_t *n1 = a1, *n2 = a2;
706  int cmp;
707  cmp = vnet_sw_interface_compare (vnm, n1->key.sw_if_index,
708  n2->key.sw_if_index);
709  if (!cmp)
710  cmp = ip6_address_compare (&n1->key.ip6_address, &n2->key.ip6_address);
711  return cmp;
712 }
713 
716 {
718  ip6_neighbor_t *n, *ns = 0;
719 
720  /* *INDENT-OFF* */
721  pool_foreach (n, nm->neighbor_pool,
722  ({
723  if (sw_if_index != ~0 && n->key.sw_if_index != sw_if_index)
724  continue;
725  vec_add1 (ns, n[0]);
726  }));
727  /* *INDENT-ON* */
728 
729  if (ns)
731  return ns;
732 }
733 
734 static clib_error_t *
736  unformat_input_t * input, vlib_cli_command_t * cmd)
737 {
738  vnet_main_t *vnm = vnet_get_main ();
739  ip6_neighbor_t *n, *ns;
740  clib_error_t *error = 0;
741  u32 sw_if_index;
742 
743  /* Filter entries by interface if given. */
744  sw_if_index = ~0;
745  (void) unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index);
746 
747  ns = ip6_neighbors_entries (sw_if_index);
748  if (ns)
749  {
751  vec_foreach (n, ns)
752  {
754  }
755  vec_free (ns);
756  }
757 
758  return error;
759 }
760 
761 /*?
762  * This command is used to display the adjacent IPv6 hosts found via
763  * neighbor discovery. Optionally, limit the output to the specified
764  * interface.
765  *
766  * @cliexpar
767  * Example of how to display the IPv6 neighbor adjacency table:
768  * @cliexstart{show ip6 neighbors}
769  * Time Address Flags Link layer Interface
770  * 34.0910 ::a:1:1:0:7 02:fe:6a:07:39:6f GigabitEthernet2/0/0
771  * 173.2916 ::b:5:1:c:2 02:fe:50:62:3a:94 GigabitEthernet2/0/0
772  * 886.6654 ::1:1:c:0:9 S 02:fe:e4:45:27:5b GigabitEthernet3/0/0
773  * @cliexend
774  * Example of how to display the IPv6 neighbor adjacency table for given interface:
775  * @cliexstart{show ip6 neighbors GigabitEthernet2/0/0}
776  * Time Address Flags Link layer Interface
777  * 34.0910 ::a:1:1:0:7 02:fe:6a:07:39:6f GigabitEthernet2/0/0
778  * 173.2916 ::b:5:1:c:2 02:fe:50:62:3a:94 GigabitEthernet2/0/0
779  * @cliexend
780 ?*/
781 /* *INDENT-OFF* */
783  .path = "show ip6 neighbors",
784  .function = show_ip6_neighbors,
785  .short_help = "show ip6 neighbors [<interface>]",
786 };
787 /* *INDENT-ON* */
788 
789 static clib_error_t *
791  unformat_input_t * input, vlib_cli_command_t * cmd)
792 {
793  vnet_main_t *vnm = vnet_get_main ();
795  u8 mac_address[6];
796  int addr_valid = 0;
797  int is_del = 0;
798  int is_static = 0;
799  u32 sw_if_index;
800 
802  {
803  /* intfc, ip6-address, mac-address */
804  if (unformat (input, "%U %U %U",
805  unformat_vnet_sw_interface, vnm, &sw_if_index,
806  unformat_ip6_address, &addr,
807  unformat_ethernet_address, mac_address))
808  addr_valid = 1;
809 
810  else if (unformat (input, "delete") || unformat (input, "del"))
811  is_del = 1;
812  else if (unformat (input, "static"))
813  is_static = 1;
814  else
815  break;
816  }
817 
818  if (!addr_valid)
819  return clib_error_return (0, "Missing interface, ip6 or hw address");
820 
821  if (!is_del)
822  vnet_set_ip6_ethernet_neighbor (vm, sw_if_index, &addr,
823  mac_address, sizeof (mac_address),
824  is_static);
825  else
826  vnet_unset_ip6_ethernet_neighbor (vm, sw_if_index, &addr,
827  mac_address, sizeof (mac_address));
828  return 0;
829 }
830 
831 /*?
832  * This command is used to manually add an entry to the IPv6 neighbor
833  * adjacency table. Optionally, the entry can be added as static. It is
834  * also used to remove an entry from the table. Use the '<em>show ip6
835  * neighbors</em>' command to display all learned and manually entered entries.
836  *
837  * @cliexpar
838  * Example of how to add a static entry to the IPv6 neighbor adjacency table:
839  * @cliexcmd{set ip6 neighbor GigabitEthernet2/0/0 ::1:1:c:0:9 02:fe:e4:45:27:5b static}
840  * Example of how to delete an entry from the IPv6 neighbor adjacency table:
841  * @cliexcmd{set ip6 neighbor del GigabitEthernet2/0/0 ::1:1:c:0:9 02:fe:e4:45:27:5b}
842 ?*/
843 /* *INDENT-OFF* */
845 {
846  .path = "set ip6 neighbor",
847  .function = set_ip6_neighbor,
848  .short_help = "set ip6 neighbor [del] <interface> <ip6-address> <mac-address> [static]",
849 };
850 /* *INDENT-ON* */
851 
852 typedef enum
853 {
858 
861  vlib_node_runtime_t * node,
862  vlib_frame_t * frame,
863  uword is_solicitation)
864 {
865  vnet_main_t *vnm = vnet_get_main ();
866  ip6_main_t *im = &ip6_main;
867  uword n_packets = frame->n_vectors;
868  u32 *from, *to_next;
869  u32 n_left_from, n_left_to_next, next_index, n_advertisements_sent;
871  vlib_node_runtime_t *error_node =
873  int bogus_length;
874 
875  from = vlib_frame_vector_args (frame);
876  n_left_from = n_packets;
877  next_index = node->cached_next_index;
878 
879  if (node->flags & VLIB_NODE_FLAG_TRACE)
880  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
881  /* stride */ 1,
882  sizeof (icmp6_input_trace_t));
883 
884  option_type =
885  (is_solicitation
886  ? ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address
887  : ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address);
888  n_advertisements_sent = 0;
889 
890  while (n_left_from > 0)
891  {
892  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
893 
894  while (n_left_from > 0 && n_left_to_next > 0)
895  {
896  vlib_buffer_t *p0;
897  ip6_header_t *ip0;
898  icmp6_neighbor_solicitation_or_advertisement_header_t *h0;
899  icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *o0;
900  u32 bi0, options_len0, sw_if_index0, next0, error0;
901  u32 ip6_sadd_link_local, ip6_sadd_unspecified;
902  int is_rewrite0;
903  u32 ni0;
904 
905  bi0 = to_next[0] = from[0];
906 
907  from += 1;
908  to_next += 1;
909  n_left_from -= 1;
910  n_left_to_next -= 1;
911 
912  p0 = vlib_get_buffer (vm, bi0);
913  ip0 = vlib_buffer_get_current (p0);
914  h0 = ip6_next_header (ip0);
915  options_len0 =
916  clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
917 
918  error0 = ICMP6_ERROR_NONE;
919  sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
920  ip6_sadd_link_local =
922  ip6_sadd_unspecified =
924 
925  /* Check that source address is unspecified, link-local or else on-link. */
926  if (!ip6_sadd_unspecified && !ip6_sadd_link_local)
927  {
928  u32 src_adj_index0 = ip6_src_lookup_for_packet (im, p0, ip0);
929 
930  if (ADJ_INDEX_INVALID != src_adj_index0)
931  {
932  ip_adjacency_t *adj0 =
933  ip_get_adjacency (&im->lookup_main, src_adj_index0);
934 
935  /* Allow all realistic-looking rewrite adjacencies to pass */
936  ni0 = adj0->lookup_next_index;
937  is_rewrite0 = (ni0 >= IP_LOOKUP_NEXT_ARP) &&
938  (ni0 < IP6_LOOKUP_N_NEXT);
939 
940  error0 = ((adj0->rewrite_header.sw_if_index != sw_if_index0
941  || !is_rewrite0)
942  ?
943  ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_NOT_ON_LINK
944  : error0);
945  }
946  else
947  {
948  error0 =
949  ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_NOT_ON_LINK;
950  }
951  }
952 
953  o0 = (void *) (h0 + 1);
954  o0 = ((options_len0 == 8 && o0->header.type == option_type
955  && o0->header.n_data_u64s == 1) ? o0 : 0);
956 
957  /* If src address unspecified or link local, donot learn neighbor MAC */
958  if (PREDICT_TRUE (error0 == ICMP6_ERROR_NONE && o0 != 0 &&
959  !ip6_sadd_unspecified && !ip6_sadd_link_local))
960  {
962  if (nm->limit_neighbor_cache_size &&
963  pool_elts (nm->neighbor_pool) >=
966  vnet_set_ip6_ethernet_neighbor (vm, sw_if_index0,
967  is_solicitation ?
968  &ip0->src_address :
969  &h0->target_address,
970  o0->ethernet_address,
971  sizeof (o0->ethernet_address),
972  0);
973  }
974 
975  if (is_solicitation && error0 == ICMP6_ERROR_NONE)
976  {
977  /* Check that target address is local to this router. */
978  fib_node_index_t fei;
979  u32 fib_index;
980 
981  fib_index =
983 
984  if (~0 == fib_index)
985  {
986  error0 = ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_UNKNOWN;
987  }
988  else
989  {
990  fei = ip6_fib_table_lookup_exact_match (fib_index,
991  &h0->target_address,
992  128);
993 
994  if (FIB_NODE_INDEX_INVALID == fei ||
998  {
999  error0 =
1000  ICMP6_ERROR_NEIGHBOR_SOLICITATION_SOURCE_UNKNOWN;
1001  }
1002  }
1003  }
1004 
1005  if (is_solicitation)
1006  next0 = (error0 != ICMP6_ERROR_NONE
1009  else
1010  {
1011  next0 = 0;
1012  error0 = error0 == ICMP6_ERROR_NONE ?
1013  ICMP6_ERROR_NEIGHBOR_ADVERTISEMENTS_RX : error0;
1014  }
1015 
1016  if (is_solicitation && error0 == ICMP6_ERROR_NONE)
1017  {
1018  vnet_sw_interface_t *sw_if0;
1019  ethernet_interface_t *eth_if0;
1020  ethernet_header_t *eth0;
1021 
1022  /* dst address is either source address or the all-nodes mcast addr */
1023  if (!ip6_sadd_unspecified)
1024  ip0->dst_address = ip0->src_address;
1025  else
1027  IP6_MULTICAST_SCOPE_link_local,
1028  IP6_MULTICAST_GROUP_ID_all_hosts);
1029 
1030  ip0->src_address = h0->target_address;
1031  ip0->hop_limit = 255;
1032  h0->icmp.type = ICMP6_neighbor_advertisement;
1033 
1034  sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
1036  eth_if0 =
1038  if (eth_if0 && o0)
1039  {
1040  clib_memcpy (o0->ethernet_address, eth_if0->address, 6);
1041  o0->header.type =
1042  ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
1043  }
1044 
1045  h0->advertisement_flags = clib_host_to_net_u32
1048 
1049  h0->icmp.checksum = 0;
1050  h0->icmp.checksum =
1051  ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0,
1052  &bogus_length);
1053  ASSERT (bogus_length == 0);
1054 
1055  /* Reuse current MAC header, copy SMAC to DMAC and
1056  * interface MAC to SMAC */
1058  eth0 = vlib_buffer_get_current (p0);
1059  clib_memcpy (eth0->dst_address, eth0->src_address, 6);
1060  if (eth_if0)
1061  clib_memcpy (eth0->src_address, eth_if0->address, 6);
1062 
1063  /* Setup input and output sw_if_index for packet */
1064  ASSERT (vnet_buffer (p0)->sw_if_index[VLIB_RX] == sw_if_index0);
1065  vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index0;
1066  vnet_buffer (p0)->sw_if_index[VLIB_RX] =
1068 
1069  n_advertisements_sent++;
1070  }
1071 
1072  p0->error = error_node->errors[error0];
1073 
1074  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1075  to_next, n_left_to_next,
1076  bi0, next0);
1077  }
1078 
1079  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1080  }
1081 
1082  /* Account for advertisements sent. */
1083  vlib_error_count (vm, error_node->node_index,
1084  ICMP6_ERROR_NEIGHBOR_ADVERTISEMENTS_TX,
1085  n_advertisements_sent);
1086 
1087  return frame->n_vectors;
1088 }
1089 
1090 /* for "syslogging" - use elog for now */
1091 #define foreach_log_level \
1092  _ (DEBUG, "DEBUG") \
1093  _ (INFO, "INFORMATION") \
1094  _ (NOTICE, "NOTICE") \
1095  _ (WARNING, "WARNING") \
1096  _ (ERR, "ERROR") \
1097  _ (CRIT, "CRITICAL") \
1098  _ (ALERT, "ALERT") \
1099  _ (EMERG, "EMERGENCY")
1100 
1101 typedef enum
1102 {
1103 #define _(f,s) LOG_##f,
1105 #undef _
1106 } log_level_t;
1107 
1108 static char *log_level_strings[] = {
1109 #define _(f,s) s,
1111 #undef _
1112 };
1113 
1114 static int logmask = 1 << LOG_DEBUG;
1115 
1116 static void
1117 ip6_neighbor_syslog (vlib_main_t * vm, int priority, char *fmt, ...)
1118 {
1119  /* just use elog for now */
1120  u8 *what;
1121  va_list va;
1122 
1123  if ((priority > LOG_EMERG) || !(logmask & (1 << priority)))
1124  return;
1125 
1126  va_start (va, fmt);
1127  if (fmt)
1128  {
1129  what = va_format (0, fmt, &va);
1130 
1131  ELOG_TYPE_DECLARE (e) =
1132  {
1133  .format = "ip6 nd: (%s): %s",.format_args = "T4T4",};
1134  struct
1135  {
1136  u32 s[2];
1137  } *ed;
1138  ed = ELOG_DATA (&vm->elog_main, e);
1139  ed->s[0] = elog_string (&vm->elog_main, log_level_strings[priority]);
1140  ed->s[1] = elog_string (&vm->elog_main, (char *) what);
1141  }
1142  va_end (va);
1143  return;
1144 }
1145 
1146 /* ipv6 neighbor discovery - router advertisements */
1147 typedef enum
1148 {
1154 
1157  vlib_node_runtime_t * node, vlib_frame_t * frame)
1158 {
1159  vnet_main_t *vnm = vnet_get_main ();
1160  ip6_main_t *im = &ip6_main;
1162  uword n_packets = frame->n_vectors;
1163  u32 *from, *to_next;
1164  u32 n_left_from, n_left_to_next, next_index;
1165  u32 n_advertisements_sent = 0;
1166  int bogus_length;
1167 
1169 
1170  vlib_node_runtime_t *error_node =
1172 
1173  from = vlib_frame_vector_args (frame);
1174  n_left_from = n_packets;
1175  next_index = node->cached_next_index;
1176 
1177  if (node->flags & VLIB_NODE_FLAG_TRACE)
1178  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
1179  /* stride */ 1,
1180  sizeof (icmp6_input_trace_t));
1181 
1182  /* source may append his LL address */
1183  option_type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
1184 
1185  while (n_left_from > 0)
1186  {
1187  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1188 
1189  while (n_left_from > 0 && n_left_to_next > 0)
1190  {
1191  vlib_buffer_t *p0;
1192  ip6_header_t *ip0;
1193  ip6_radv_t *radv_info = 0;
1194 
1195  icmp6_neighbor_discovery_header_t *h0;
1196  icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *o0;
1197 
1198  u32 bi0, options_len0, sw_if_index0, next0, error0;
1199  u32 is_solicitation = 1, is_dropped = 0;
1200  u32 is_unspecified, is_link_local;
1201 
1202  bi0 = to_next[0] = from[0];
1203 
1204  from += 1;
1205  to_next += 1;
1206  n_left_from -= 1;
1207  n_left_to_next -= 1;
1208 
1209  p0 = vlib_get_buffer (vm, bi0);
1210  ip0 = vlib_buffer_get_current (p0);
1211  h0 = ip6_next_header (ip0);
1212  options_len0 =
1213  clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
1214  is_unspecified = ip6_address_is_unspecified (&ip0->src_address);
1215  is_link_local =
1217 
1218  error0 = ICMP6_ERROR_NONE;
1219  sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1220 
1221  /* check if solicitation (not from nd_timer node) */
1223  is_solicitation = 0;
1224 
1225  /* Check that source address is unspecified, link-local or else on-link. */
1226  if (!is_unspecified && !is_link_local)
1227  {
1228  u32 src_adj_index0 = ip6_src_lookup_for_packet (im, p0, ip0);
1229 
1230  if (ADJ_INDEX_INVALID != src_adj_index0)
1231  {
1233  src_adj_index0);
1234 
1235  error0 = (adj0->rewrite_header.sw_if_index != sw_if_index0
1236  ?
1237  ICMP6_ERROR_ROUTER_SOLICITATION_SOURCE_NOT_ON_LINK
1238  : error0);
1239  }
1240  else
1241  {
1242  error0 = ICMP6_ERROR_ROUTER_SOLICITATION_SOURCE_NOT_ON_LINK;
1243  }
1244  }
1245 
1246  /* check for source LL option and process */
1247  o0 = (void *) (h0 + 1);
1248  o0 = ((options_len0 == 8
1249  && o0->header.type == option_type
1250  && o0->header.n_data_u64s == 1) ? o0 : 0);
1251 
1252  /* if src address unspecified IGNORE any options */
1253  if (PREDICT_TRUE (error0 == ICMP6_ERROR_NONE && o0 != 0 &&
1254  !is_unspecified && !is_link_local))
1255  {
1257  if (nm->limit_neighbor_cache_size &&
1258  pool_elts (nm->neighbor_pool) >=
1261 
1262  vnet_set_ip6_ethernet_neighbor (vm, sw_if_index0,
1263  &ip0->src_address,
1264  o0->ethernet_address,
1265  sizeof (o0->ethernet_address),
1266  0);
1267  }
1268 
1269  /* default is to drop */
1271 
1272  if (error0 == ICMP6_ERROR_NONE)
1273  {
1274  vnet_sw_interface_t *sw_if0;
1275  ethernet_interface_t *eth_if0;
1276  u32 adj_index0;
1277 
1278  sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
1280  eth_if0 =
1282 
1283  /* only support ethernet interface type for now */
1284  error0 =
1285  (!eth_if0) ? ICMP6_ERROR_ROUTER_SOLICITATION_UNSUPPORTED_INTF
1286  : error0;
1287 
1288  if (error0 == ICMP6_ERROR_NONE)
1289  {
1290  u32 ri;
1291 
1292  /* adjust the sizeof the buffer to just include the ipv6 header */
1293  p0->current_length -=
1294  (options_len0 +
1295  sizeof (icmp6_neighbor_discovery_header_t));
1296 
1297  /* look up the radv_t information for this interface */
1299  (nm->if_radv_pool_index_by_sw_if_index, sw_if_index0, ~0);
1300 
1301  ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index0];
1302 
1303  if (ri != ~0)
1304  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
1305 
1306  error0 =
1307  ((!radv_info) ?
1308  ICMP6_ERROR_ROUTER_SOLICITATION_RADV_NOT_CONFIG :
1309  error0);
1310 
1311  if (error0 == ICMP6_ERROR_NONE)
1312  {
1313  f64 now = vlib_time_now (vm);
1314 
1315  /* for solicited adverts - need to rate limit */
1316  if (is_solicitation)
1317  {
1318  if ((now - radv_info->last_radv_time) <
1320  is_dropped = 1;
1321  else
1322  radv_info->last_radv_time = now;
1323  }
1324 
1325  /* send now */
1326  icmp6_router_advertisement_header_t rh;
1327 
1328  rh.icmp.type = ICMP6_router_advertisement;
1329  rh.icmp.code = 0;
1330  rh.icmp.checksum = 0;
1331 
1332  rh.current_hop_limit = radv_info->curr_hop_limit;
1333  rh.router_lifetime_in_sec =
1334  clib_host_to_net_u16
1335  (radv_info->adv_router_lifetime_in_sec);
1336  rh.
1337  time_in_msec_between_retransmitted_neighbor_solicitations
1338  =
1339  clib_host_to_net_u32 (radv_info->
1340  adv_time_in_msec_between_retransmitted_neighbor_solicitations);
1341  rh.neighbor_reachable_time_in_msec =
1342  clib_host_to_net_u32 (radv_info->
1343  adv_neighbor_reachable_time_in_msec);
1344 
1345  rh.flags =
1346  (radv_info->adv_managed_flag) ?
1348  0;
1349  rh.flags |=
1350  ((radv_info->adv_other_flag) ?
1352  0);
1353 
1354 
1355  u16 payload_length =
1356  sizeof (icmp6_router_advertisement_header_t);
1357 
1359  p0->free_list_index,
1360  bi0,
1361  (void *) &rh,
1362  sizeof
1363  (icmp6_router_advertisement_header_t));
1364 
1365  if (radv_info->adv_link_layer_address)
1366  {
1367  icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
1368  h;
1369 
1370  h.header.type =
1371  ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
1372  h.header.n_data_u64s = 1;
1373 
1374  /* copy ll address */
1375  clib_memcpy (&h.ethernet_address[0],
1376  eth_if0->address, 6);
1377 
1379  p0->free_list_index,
1380  bi0,
1381  (void *) &h,
1382  sizeof
1383  (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t));
1384 
1385  payload_length +=
1386  sizeof
1387  (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t);
1388  }
1389 
1390  /* add MTU option */
1391  if (radv_info->adv_link_mtu)
1392  {
1393  icmp6_neighbor_discovery_mtu_option_t h;
1394 
1395  h.unused = 0;
1396  h.mtu =
1397  clib_host_to_net_u32 (radv_info->adv_link_mtu);
1398  h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_mtu;
1399  h.header.n_data_u64s = 1;
1400 
1401  payload_length +=
1402  sizeof (icmp6_neighbor_discovery_mtu_option_t);
1403 
1405  p0->free_list_index,
1406  bi0,
1407  (void *) &h,
1408  sizeof
1409  (icmp6_neighbor_discovery_mtu_option_t));
1410  }
1411 
1412  /* add advertised prefix options */
1413  ip6_radv_prefix_t *pr_info;
1414 
1415  /* *INDENT-OFF* */
1416  pool_foreach (pr_info, radv_info->adv_prefixes_pool,
1417  ({
1418  if(pr_info->enabled &&
1419  (!pr_info->decrement_lifetime_flag
1420  || (pr_info->pref_lifetime_expires >0)))
1421  {
1422  /* advertise this prefix */
1423  icmp6_neighbor_discovery_prefix_information_option_t h;
1424 
1425  h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_prefix_information;
1426  h.header.n_data_u64s = (sizeof(icmp6_neighbor_discovery_prefix_information_option_t) >> 3);
1427 
1428  h.dst_address_length = pr_info->prefix_len;
1429 
1430  h.flags = (pr_info->adv_on_link_flag) ? ICMP6_NEIGHBOR_DISCOVERY_PREFIX_INFORMATION_FLAG_ON_LINK : 0;
1431  h.flags |= (pr_info->adv_autonomous_flag) ? ICMP6_NEIGHBOR_DISCOVERY_PREFIX_INFORMATION_AUTO : 0;
1432 
1433  if(radv_info->cease_radv && pr_info->deprecated_prefix_flag)
1434  {
1435  h.valid_time = clib_host_to_net_u32(MIN_ADV_VALID_LIFETIME);
1436  h.preferred_time = 0;
1437  }
1438  else
1439  {
1440  if(pr_info->decrement_lifetime_flag)
1441  {
1442  pr_info->adv_valid_lifetime_in_secs = ((pr_info->valid_lifetime_expires > now)) ?
1443  (pr_info->valid_lifetime_expires - now) : 0;
1444 
1445  pr_info->adv_pref_lifetime_in_secs = ((pr_info->pref_lifetime_expires > now)) ?
1446  (pr_info->pref_lifetime_expires - now) : 0;
1447  }
1448 
1449  h.valid_time = clib_host_to_net_u32(pr_info->adv_valid_lifetime_in_secs);
1450  h.preferred_time = clib_host_to_net_u32(pr_info->adv_pref_lifetime_in_secs) ;
1451  }
1452  h.unused = 0;
1453 
1454  clib_memcpy(&h.dst_address, &pr_info->prefix, sizeof(ip6_address_t));
1455 
1456  payload_length += sizeof( icmp6_neighbor_discovery_prefix_information_option_t);
1457 
1458  vlib_buffer_add_data (vm,
1459  p0->free_list_index,
1460  bi0,
1461  (void *)&h, sizeof(icmp6_neighbor_discovery_prefix_information_option_t));
1462 
1463  }
1464  }));
1465  /* *INDENT-ON* */
1466 
1467  /* add additional options before here */
1468 
1469  /* finish building the router advertisement... */
1470  if (!is_unspecified && radv_info->send_unicast)
1471  {
1472  ip0->dst_address = ip0->src_address;
1473  }
1474  else
1475  {
1476  /* target address is all-nodes mcast addr */
1478  (&ip0->dst_address,
1479  IP6_MULTICAST_SCOPE_link_local,
1480  IP6_MULTICAST_GROUP_ID_all_hosts);
1481  }
1482 
1483  /* source address MUST be the link-local address */
1484  ip0->src_address = radv_info->link_local_address;
1485 
1486  ip0->hop_limit = 255;
1487  ip0->payload_length =
1488  clib_host_to_net_u16 (payload_length);
1489 
1490  icmp6_router_advertisement_header_t *rh0 =
1491  (icmp6_router_advertisement_header_t *) (ip0 + 1);
1492  rh0->icmp.checksum =
1493  ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0,
1494  &bogus_length);
1495  ASSERT (bogus_length == 0);
1496 
1497  /* setup output if and adjacency */
1498  vnet_buffer (p0)->sw_if_index[VLIB_RX] =
1500 
1501  if (is_solicitation)
1502  {
1503  ethernet_header_t *eth0;
1504  /* Reuse current MAC header, copy SMAC to DMAC and
1505  * interface MAC to SMAC */
1506  vlib_buffer_reset (p0);
1507  eth0 = vlib_buffer_get_current (p0);
1508  clib_memcpy (eth0->dst_address, eth0->src_address,
1509  6);
1510  clib_memcpy (eth0->src_address, eth_if0->address,
1511  6);
1512  next0 =
1513  is_dropped ? next0 :
1515  vnet_buffer (p0)->sw_if_index[VLIB_TX] =
1516  sw_if_index0;
1517  }
1518  else
1519  {
1520  adj_index0 = radv_info->all_nodes_adj_index;
1521  if (adj_index0 == 0)
1522  error0 = ICMP6_ERROR_DST_LOOKUP_MISS;
1523  else
1524  {
1525  ip_adjacency_t *adj0 =
1527  adj_index0);
1528  error0 =
1529  ((adj0->rewrite_header.sw_if_index !=
1530  sw_if_index0
1531  || adj0->lookup_next_index !=
1533  ICMP6_ERROR_ROUTER_SOLICITATION_DEST_UNKNOWN
1534  : error0);
1535  next0 =
1536  is_dropped ? next0 :
1538  vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
1539  adj_index0;
1540  }
1541  }
1543 
1544  radv_info->n_solicitations_dropped += is_dropped;
1545  radv_info->n_solicitations_rcvd += is_solicitation;
1546 
1547  if ((error0 == ICMP6_ERROR_NONE) && !is_dropped)
1548  {
1549  radv_info->n_advertisements_sent++;
1550  n_advertisements_sent++;
1551  }
1552  }
1553  }
1554  }
1555 
1556  p0->error = error_node->errors[error0];
1557 
1558  if (error0 != ICMP6_ERROR_NONE)
1559  vlib_error_count (vm, error_node->node_index, error0, 1);
1560 
1561  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1562  to_next, n_left_to_next,
1563  bi0, next0);
1564 
1565  }
1566 
1567  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1568  }
1569 
1570  /* Account for router advertisements sent. */
1571  vlib_error_count (vm, error_node->node_index,
1572  ICMP6_ERROR_ROUTER_ADVERTISEMENTS_TX,
1573  n_advertisements_sent);
1574 
1575  return frame->n_vectors;
1576 }
1577 
1578  /* validate advertised info for consistancy (see RFC-4861 section 6.2.7) - log any inconsistencies, packet will always be dropped */
1581  vlib_node_runtime_t * node, vlib_frame_t * frame)
1582 {
1583  vnet_main_t *vnm = vnet_get_main ();
1585  uword n_packets = frame->n_vectors;
1586  u32 *from, *to_next;
1587  u32 n_left_from, n_left_to_next, next_index;
1588  u32 n_advertisements_rcvd = 0;
1589 
1590  vlib_node_runtime_t *error_node =
1592 
1593  from = vlib_frame_vector_args (frame);
1594  n_left_from = n_packets;
1595  next_index = node->cached_next_index;
1596 
1597  if (node->flags & VLIB_NODE_FLAG_TRACE)
1598  vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
1599  /* stride */ 1,
1600  sizeof (icmp6_input_trace_t));
1601 
1602  while (n_left_from > 0)
1603  {
1604  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1605 
1606  while (n_left_from > 0 && n_left_to_next > 0)
1607  {
1608  vlib_buffer_t *p0;
1609  ip6_header_t *ip0;
1610  ip6_radv_t *radv_info = 0;
1611  icmp6_router_advertisement_header_t *h0;
1612  u32 bi0, options_len0, sw_if_index0, next0, error0;
1613 
1614  bi0 = to_next[0] = from[0];
1615 
1616  from += 1;
1617  to_next += 1;
1618  n_left_from -= 1;
1619  n_left_to_next -= 1;
1620 
1621  p0 = vlib_get_buffer (vm, bi0);
1622  ip0 = vlib_buffer_get_current (p0);
1623  h0 = ip6_next_header (ip0);
1624  options_len0 =
1625  clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
1626 
1627  error0 = ICMP6_ERROR_NONE;
1628  sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
1629 
1630  /* Check that source address is link-local */
1631  error0 = (!ip6_address_is_link_local_unicast (&ip0->src_address)) ?
1632  ICMP6_ERROR_ROUTER_ADVERTISEMENT_SOURCE_NOT_LINK_LOCAL : error0;
1633 
1634  /* default is to drop */
1636 
1637  n_advertisements_rcvd++;
1638 
1639  if (error0 == ICMP6_ERROR_NONE)
1640  {
1641  vnet_sw_interface_t *sw_if0;
1642  ethernet_interface_t *eth_if0;
1643 
1644  sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
1646  eth_if0 =
1648 
1649  /* only support ethernet interface type for now */
1650  error0 =
1651  (!eth_if0) ? ICMP6_ERROR_ROUTER_SOLICITATION_UNSUPPORTED_INTF
1652  : error0;
1653 
1654  if (error0 == ICMP6_ERROR_NONE)
1655  {
1656  u32 ri;
1657 
1658  /* look up the radv_t information for this interface */
1660  (nm->if_radv_pool_index_by_sw_if_index, sw_if_index0, ~0);
1661 
1662  ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index0];
1663 
1664  if (ri != ~0)
1665  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
1666 
1667  error0 =
1668  ((!radv_info) ?
1669  ICMP6_ERROR_ROUTER_SOLICITATION_RADV_NOT_CONFIG :
1670  error0);
1671 
1672  if (error0 == ICMP6_ERROR_NONE)
1673  {
1674  /* validate advertised information */
1675  if ((h0->current_hop_limit && radv_info->curr_hop_limit)
1676  && (h0->current_hop_limit !=
1677  radv_info->curr_hop_limit))
1678  {
1679  ip6_neighbor_syslog (vm, LOG_WARNING,
1680  "our AdvCurHopLimit on %U doesn't agree with %U",
1682  vnm, sw_if_index0,
1684  &ip0->src_address);
1685  }
1686 
1687  if ((h0->flags &
1689  != radv_info->adv_managed_flag)
1690  {
1691  ip6_neighbor_syslog (vm, LOG_WARNING,
1692  "our AdvManagedFlag on %U doesn't agree with %U",
1694  vnm, sw_if_index0,
1696  &ip0->src_address);
1697  }
1698 
1699  if ((h0->flags &
1701  != radv_info->adv_other_flag)
1702  {
1703  ip6_neighbor_syslog (vm, LOG_WARNING,
1704  "our AdvOtherConfigFlag on %U doesn't agree with %U",
1706  vnm, sw_if_index0,
1708  &ip0->src_address);
1709  }
1710 
1711  if ((h0->
1712  time_in_msec_between_retransmitted_neighbor_solicitations
1713  && radv_info->
1714  adv_time_in_msec_between_retransmitted_neighbor_solicitations)
1715  && (h0->
1716  time_in_msec_between_retransmitted_neighbor_solicitations
1717  !=
1718  clib_host_to_net_u32 (radv_info->
1719  adv_time_in_msec_between_retransmitted_neighbor_solicitations)))
1720  {
1721  ip6_neighbor_syslog (vm, LOG_WARNING,
1722  "our AdvRetransTimer on %U doesn't agree with %U",
1724  vnm, sw_if_index0,
1726  &ip0->src_address);
1727  }
1728 
1729  if ((h0->neighbor_reachable_time_in_msec &&
1731  (h0->neighbor_reachable_time_in_msec !=
1732  clib_host_to_net_u32
1734  {
1735  ip6_neighbor_syslog (vm, LOG_WARNING,
1736  "our AdvReachableTime on %U doesn't agree with %U",
1738  vnm, sw_if_index0,
1740  &ip0->src_address);
1741  }
1742 
1743  /* check for MTU or prefix options or .. */
1744  u8 *opt_hdr = (u8 *) (h0 + 1);
1745  while (options_len0 > 0)
1746  {
1747  icmp6_neighbor_discovery_option_header_t *o0 =
1748  (icmp6_neighbor_discovery_option_header_t *)
1749  opt_hdr;
1750  int opt_len = o0->n_data_u64s << 3;
1752  o0->type;
1753 
1754  if (options_len0 < 2)
1755  {
1756  ip6_neighbor_syslog (vm, LOG_ERR,
1757  "malformed RA packet on %U from %U",
1759  vnm, sw_if_index0,
1761  &ip0->src_address);
1762  break;
1763  }
1764 
1765  if (opt_len == 0)
1766  {
1767  ip6_neighbor_syslog (vm, LOG_ERR,
1768  " zero length option in RA on %U from %U",
1770  vnm, sw_if_index0,
1772  &ip0->src_address);
1773  break;
1774  }
1775  else if (opt_len > options_len0)
1776  {
1777  ip6_neighbor_syslog (vm, LOG_ERR,
1778  "option length in RA packet greater than total length on %U from %U",
1780  vnm, sw_if_index0,
1782  &ip0->src_address);
1783  break;
1784  }
1785 
1786  options_len0 -= opt_len;
1787  opt_hdr += opt_len;
1788 
1789  switch (option_type)
1790  {
1791  case ICMP6_NEIGHBOR_DISCOVERY_OPTION_mtu:
1792  {
1793  icmp6_neighbor_discovery_mtu_option_t *h =
1794  (icmp6_neighbor_discovery_mtu_option_t
1795  *) (o0);
1796 
1797  if (opt_len < sizeof (*h))
1798  break;
1799 
1800  if ((h->mtu && radv_info->adv_link_mtu) &&
1801  (h->mtu !=
1802  clib_host_to_net_u32
1803  (radv_info->adv_link_mtu)))
1804  {
1805  ip6_neighbor_syslog (vm, LOG_WARNING,
1806  "our AdvLinkMTU on %U doesn't agree with %U",
1808  vnm, sw_if_index0,
1810  &ip0->src_address);
1811  }
1812  }
1813  break;
1814 
1815  case ICMP6_NEIGHBOR_DISCOVERY_OPTION_prefix_information:
1816  {
1817  icmp6_neighbor_discovery_prefix_information_option_t
1818  * h =
1819  (icmp6_neighbor_discovery_prefix_information_option_t
1820  *) (o0);
1821 
1822  /* validate advertised prefix options */
1823  ip6_radv_prefix_t *pr_info;
1824  u32 preferred, valid;
1825 
1826  if (opt_len < sizeof (*h))
1827  break;
1828 
1829  preferred =
1830  clib_net_to_host_u32 (h->preferred_time);
1831  valid = clib_net_to_host_u32 (h->valid_time);
1832 
1833  /* look for matching prefix - if we our advertising it, it better be consistant */
1834  /* *INDENT-OFF* */
1835  pool_foreach (pr_info, radv_info->adv_prefixes_pool,
1836  ({
1837 
1838  ip6_address_t mask;
1839  ip6_address_mask_from_width(&mask, pr_info->prefix_len);
1840 
1841  if(pr_info->enabled &&
1842  (pr_info->prefix_len == h->dst_address_length) &&
1843  ip6_address_is_equal_masked (&pr_info->prefix, &h->dst_address, &mask))
1844  {
1845  /* found it */
1846  if(!pr_info->decrement_lifetime_flag &&
1847  valid != pr_info->adv_valid_lifetime_in_secs)
1848  {
1849  ip6_neighbor_syslog(vm, LOG_WARNING,
1850  "our ADV validlifetime on %U for %U does not agree with %U",
1851  format_vnet_sw_if_index_name, vnm, sw_if_index0,format_ip6_address, &pr_info->prefix,
1852  format_ip6_address, &h->dst_address);
1853  }
1854  if(!pr_info->decrement_lifetime_flag &&
1855  preferred != pr_info->adv_pref_lifetime_in_secs)
1856  {
1857  ip6_neighbor_syslog(vm, LOG_WARNING,
1858  "our ADV preferredlifetime on %U for %U does not agree with %U",
1859  format_vnet_sw_if_index_name, vnm, sw_if_index0,format_ip6_address, &pr_info->prefix,
1860  format_ip6_address, &h->dst_address);
1861  }
1862  }
1863  break;
1864  }));
1865  /* *INDENT-ON* */
1866  break;
1867  }
1868  default:
1869  /* skip this one */
1870  break;
1871  }
1872  }
1873  }
1874  }
1875  }
1876 
1877  p0->error = error_node->errors[error0];
1878 
1879  if (error0 != ICMP6_ERROR_NONE)
1880  vlib_error_count (vm, error_node->node_index, error0, 1);
1881 
1882  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1883  to_next, n_left_to_next,
1884  bi0, next0);
1885  }
1886 
1887  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1888  }
1889 
1890  /* Account for router advertisements sent. */
1891  vlib_error_count (vm, error_node->node_index,
1892  ICMP6_ERROR_ROUTER_ADVERTISEMENTS_RX,
1893  n_advertisements_rcvd);
1894 
1895  return frame->n_vectors;
1896 }
1897 
1898 /* create and initialize router advertisement parameters with default values for this intfc */
1899 static u32
1901  u32 sw_if_index, u32 is_add)
1902 {
1904  ip6_radv_t *a = 0;
1905  u32 ri = ~0;
1906  vnet_sw_interface_t *sw_if0;
1907  ethernet_interface_t *eth_if0 = 0;
1908 
1909  /* lookup radv container - ethernet interfaces only */
1910  sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
1911  if (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
1912  eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
1913 
1914  if (!eth_if0)
1915  return ri;
1916 
1918  ~0);
1919  ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
1920 
1921  if (ri != ~0)
1922  {
1923  a = pool_elt_at_index (nm->if_radv_pool, ri);
1924 
1925  if (!is_add)
1926  {
1927  u32 i, *to_delete = 0;
1928  ip6_radv_prefix_t *p;
1929  ip6_mldp_group_t *m;
1930 
1931  /* remove adjacencies */
1935 
1936  /* clean up prefix_pool */
1937  /* *INDENT-OFF* */
1939  ({
1940  vec_add1 (to_delete, p - a->adv_prefixes_pool);
1941  }));
1942  /* *INDENT-ON* */
1943 
1944  for (i = 0; i < vec_len (to_delete); i++)
1945  {
1946  p = pool_elt_at_index (a->adv_prefixes_pool, to_delete[i]);
1948  pool_put (a->adv_prefixes_pool, p);
1949  }
1950 
1951  vec_free (to_delete);
1952  to_delete = 0;
1953 
1954  /* clean up mldp group pool */
1955  /* *INDENT-OFF* */
1957  ({
1958  vec_add1 (to_delete, m - a->mldp_group_pool);
1959  }));
1960  /* *INDENT-ON* */
1961 
1962  for (i = 0; i < vec_len (to_delete); i++)
1963  {
1964  m = pool_elt_at_index (a->mldp_group_pool, to_delete[i]);
1966  pool_put (a->mldp_group_pool, m);
1967  }
1968 
1969  vec_free (to_delete);
1970 
1971  pool_put (nm->if_radv_pool, a);
1972  nm->if_radv_pool_index_by_sw_if_index[sw_if_index] = ~0;
1973  ri = ~0;
1974  }
1975  }
1976  else
1977  {
1978  if (is_add)
1979  {
1980  vnet_hw_interface_t *hw_if0;
1981 
1982  hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index);
1983 
1984  pool_get (nm->if_radv_pool, a);
1985 
1986  ri = a - nm->if_radv_pool;
1987  nm->if_radv_pool_index_by_sw_if_index[sw_if_index] = ri;
1988 
1989  /* initialize default values (most of which are zero) */
1990  memset (a, 0, sizeof (a[0]));
1991 
1992  a->sw_if_index = sw_if_index;
1993  a->fib_index = ~0;
1998 
1999  a->adv_link_layer_address = 1; /* send ll address source address option */
2000 
2004  a->seed = (u32) clib_cpu_time_now ();
2005  (void) random_u32 (&a->seed);
2006  a->randomizer = clib_cpu_time_now ();
2007  (void) random_u64 (&a->randomizer);
2008 
2012 
2013  /* deafult is to send */
2014  a->send_radv = 1;
2015 
2016  /* fill in radv_info for this interface that will be needed later */
2018 
2019  clib_memcpy (a->link_layer_address, eth_if0->address, 6);
2020 
2021  /* fill in default link-local address (this may be overridden) */
2023  (&a->link_local_address, eth_if0->address);
2024 
2025  mhash_init (&a->address_to_prefix_index, sizeof (uword),
2026  sizeof (ip6_address_t));
2027  mhash_init (&a->address_to_mldp_index, sizeof (uword),
2028  sizeof (ip6_address_t));
2029 
2030  {
2031  u8 link_layer_address[6] = { 0x33, 0x33, 0x00, 0x00, 0x00,
2032  IP6_MULTICAST_GROUP_ID_all_hosts
2033  };
2034 
2035  a->all_nodes_adj_index =
2037  sw_if_index, link_layer_address);
2038  }
2039 
2040  {
2041  u8 link_layer_address[6] = { 0x33, 0x33, 0x00, 0x00, 0x00,
2042  IP6_MULTICAST_GROUP_ID_all_routers
2043  };
2044 
2047  sw_if_index, link_layer_address);
2048  }
2049 
2050  {
2051  u8 link_layer_address[6] = { 0x33, 0x33, 0x00, 0x00, 0x00,
2052  IP6_MULTICAST_GROUP_ID_mldv2_routers
2053  };
2054 
2057  VNET_LINK_IP6,
2058  sw_if_index, link_layer_address);
2059  }
2060 
2061  /* add multicast groups we will always be reporting */
2063  ip6_mldp_group_t *mcast_group_info;
2064 
2066  IP6_MULTICAST_SCOPE_link_local,
2067  IP6_MULTICAST_GROUP_ID_all_hosts);
2068 
2069  /* lookup mldp info for this interface */
2070 
2071  uword *p = mhash_get (&a->address_to_mldp_index, &addr);
2072  mcast_group_info =
2073  p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
2074 
2075  /* add address */
2076  if (!mcast_group_info)
2077  {
2078  /* add */
2079  u32 mi;
2080  pool_get (a->mldp_group_pool, mcast_group_info);
2081 
2082  mi = mcast_group_info - a->mldp_group_pool;
2083  mhash_set (&a->address_to_mldp_index, &addr, mi, /* old_value */
2084  0);
2085 
2086  mcast_group_info->type = 4;
2087  mcast_group_info->mcast_source_address_pool = 0;
2088  mcast_group_info->num_sources = 0;
2089  clib_memcpy (&mcast_group_info->mcast_address, &addr,
2090  sizeof (ip6_address_t));
2091  }
2092 
2094  IP6_MULTICAST_SCOPE_link_local,
2095  IP6_MULTICAST_GROUP_ID_all_routers);
2096 
2097  p = mhash_get (&a->address_to_mldp_index, &addr);
2098  mcast_group_info =
2099  p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
2100 
2101  if (!mcast_group_info)
2102  {
2103  /* add */
2104  u32 mi;
2105  pool_get (a->mldp_group_pool, mcast_group_info);
2106 
2107  mi = mcast_group_info - a->mldp_group_pool;
2108  mhash_set (&a->address_to_mldp_index, &addr, mi, /* old_value */
2109  0);
2110 
2111  mcast_group_info->type = 4;
2112  mcast_group_info->mcast_source_address_pool = 0;
2113  mcast_group_info->num_sources = 0;
2114  clib_memcpy (&mcast_group_info->mcast_address, &addr,
2115  sizeof (ip6_address_t));
2116  }
2117 
2119  IP6_MULTICAST_SCOPE_link_local,
2120  IP6_MULTICAST_GROUP_ID_mldv2_routers);
2121 
2122  p = mhash_get (&a->address_to_mldp_index, &addr);
2123  mcast_group_info =
2124  p ? pool_elt_at_index (a->mldp_group_pool, p[0]) : 0;
2125 
2126  if (!mcast_group_info)
2127  {
2128  /* add */
2129  u32 mi;
2130  pool_get (a->mldp_group_pool, mcast_group_info);
2131 
2132  mi = mcast_group_info - a->mldp_group_pool;
2133  mhash_set (&a->address_to_mldp_index, &addr, mi, /* old_value */
2134  0);
2135 
2136  mcast_group_info->type = 4;
2137  mcast_group_info->mcast_source_address_pool = 0;
2138  mcast_group_info->num_sources = 0;
2139  clib_memcpy (&mcast_group_info->mcast_address, &addr,
2140  sizeof (ip6_address_t));
2141  }
2142  }
2143  }
2144  return ri;
2145 }
2146 
2147 /* send an mldpv2 report */
2148 static void
2150 {
2151  vnet_main_t *vnm = vnet_get_main ();
2152  vlib_main_t *vm = vnm->vlib_main;
2154  vnet_sw_interface_t *sw_if0;
2155  ethernet_interface_t *eth_if0;
2156  u32 ri;
2157  int bogus_length;
2158 
2159  ip6_radv_t *radv_info;
2160  u16 payload_length;
2161  vlib_buffer_t *b0;
2162  ip6_header_t *ip0;
2163  u32 *to_next;
2164  vlib_frame_t *f;
2165  u32 bo0;
2166  u32 n_to_alloc = 1;
2167  u32 n_allocated;
2168 
2169  icmp6_multicast_listener_report_header_t *rh0;
2170  icmp6_multicast_listener_report_packet_t *rp0;
2171 
2172  sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
2174  eth_if0 = ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
2175 
2176  if (!eth_if0 || !vnet_sw_interface_is_admin_up (vnm, sw_if_index))
2177  return;
2178 
2179  /* look up the radv_t information for this interface */
2181  ~0);
2182 
2183  ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2184 
2185  if (ri == ~0)
2186  return;
2187 
2188  /* send report now - build a mldpv2 report packet */
2189  n_allocated = vlib_buffer_alloc_from_free_list (vm,
2190  &bo0,
2191  n_to_alloc,
2193  if (PREDICT_FALSE (n_allocated == 0))
2194  {
2195  clib_warning ("buffer allocation failure");
2196  return;
2197  }
2198 
2199  b0 = vlib_get_buffer (vm, bo0);
2200 
2201  /* adjust the sizeof the buffer to just include the ipv6 header */
2202  b0->current_length = sizeof (icmp6_multicast_listener_report_packet_t);
2203 
2204  payload_length = sizeof (icmp6_multicast_listener_report_header_t);
2205 
2206  b0->error = ICMP6_ERROR_NONE;
2207 
2208  rp0 = vlib_buffer_get_current (b0);
2209  ip0 = (ip6_header_t *) & rp0->ip;
2210  rh0 = (icmp6_multicast_listener_report_header_t *) & rp0->report_hdr;
2211 
2212  memset (rp0, 0x0, sizeof (icmp6_multicast_listener_report_packet_t));
2213 
2215  clib_host_to_net_u32 (0x6 << 28);
2216 
2217  ip0->protocol = IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS;
2218  /* for DEBUG - vnet driver won't seem to emit router alerts */
2219  /* ip0->protocol = IP_PROTOCOL_ICMP6; */
2220  ip0->hop_limit = 1;
2221 
2222  rh0->icmp.type = ICMP6_multicast_listener_report_v2;
2223 
2224  /* source address MUST be the link-local address */
2225  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
2226  ip0->src_address = radv_info->link_local_address;
2227 
2228  /* destination is all mldpv2 routers */
2230  IP6_MULTICAST_SCOPE_link_local,
2231  IP6_MULTICAST_GROUP_ID_mldv2_routers);
2232 
2233  /* add reports here */
2234  ip6_mldp_group_t *m;
2235  int num_addr_records = 0;
2236  icmp6_multicast_address_record_t rr;
2237 
2238  /* fill in the hop-by-hop extension header (router alert) info */
2239  rh0->ext_hdr.next_hdr = IP_PROTOCOL_ICMP6;
2240  rh0->ext_hdr.n_data_u64s = 0;
2241 
2242  rh0->alert.type = IP6_MLDP_ALERT_TYPE;
2243  rh0->alert.len = 2;
2244  rh0->alert.value = 0;
2245 
2246  rh0->pad.type = 1;
2247  rh0->pad.len = 0;
2248 
2249  rh0->icmp.checksum = 0;
2250 
2251  /* *INDENT-OFF* */
2252  pool_foreach (m, radv_info->mldp_group_pool,
2253  ({
2254  rr.type = m->type;
2255  rr.aux_data_len_u32s = 0;
2256  rr.num_sources = clib_host_to_net_u16 (m->num_sources);
2257  clib_memcpy(&rr.mcast_addr, &m->mcast_address, sizeof(ip6_address_t));
2258 
2259  num_addr_records++;
2260 
2261  vlib_buffer_add_data
2262  (vm, b0->free_list_index, bo0,
2263  (void *)&rr, sizeof(icmp6_multicast_address_record_t));
2264 
2265  payload_length += sizeof( icmp6_multicast_address_record_t);
2266  }));
2267  /* *INDENT-ON* */
2268 
2269  rh0->rsvd = 0;
2270  rh0->num_addr_records = clib_host_to_net_u16 (num_addr_records);
2271 
2272  /* update lengths */
2273  ip0->payload_length = clib_host_to_net_u16 (payload_length);
2274 
2275  rh0->icmp.checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0,
2276  &bogus_length);
2277  ASSERT (bogus_length == 0);
2278 
2279  /*
2280  * OK to override w/ no regard for actual FIB, because
2281  * ip6-rewrite only looks at the adjacency.
2282  */
2283  vnet_buffer (b0)->sw_if_index[VLIB_RX] =
2285 
2286  vnet_buffer (b0)->ip.adj_index[VLIB_TX] =
2287  radv_info->all_mldv2_routers_adj_index;
2289 
2290  vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "ip6-rewrite");
2291 
2292  f = vlib_get_frame_to_node (vm, node->index);
2293  to_next = vlib_frame_vector_args (f);
2294  to_next[0] = bo0;
2295  f->n_vectors = 1;
2296 
2297  vlib_put_frame_to_node (vm, node->index, f);
2298  return;
2299 }
2300 
2301 /* *INDENT-OFF* */
2303 {
2304  .function = icmp6_router_solicitation,
2305  .name = "icmp6-router-solicitation",
2306 
2307  .vector_size = sizeof (u32),
2308 
2309  .format_trace = format_icmp6_input_trace,
2310 
2311  .n_next_nodes = ICMP6_ROUTER_SOLICITATION_N_NEXT,
2312  .next_nodes = {
2313  [ICMP6_ROUTER_SOLICITATION_NEXT_DROP] = "error-drop",
2314  [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW] = "ip6-rewrite",
2315  [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX] = "interface-output",
2316  },
2317 };
2318 /* *INDENT-ON* */
2319 
2320 /* send a RA or update the timer info etc.. */
2321 static uword
2323  vlib_node_runtime_t * node,
2324  vlib_frame_t * frame)
2325 {
2326  vnet_main_t *vnm = vnet_get_main ();
2328  ip6_radv_t *radv_info;
2329  vlib_frame_t *f = 0;
2330  u32 n_this_frame = 0;
2331  u32 n_left_to_next = 0;
2332  u32 *to_next = 0;
2333  u32 bo0;
2334  icmp6_router_solicitation_header_t *h0;
2335  vlib_buffer_t *b0;
2336  f64 now = vlib_time_now (vm);
2337 
2338  /* Interface ip6 radv info list */
2339  /* *INDENT-OFF* */
2340  pool_foreach (radv_info, nm->if_radv_pool,
2341  ({
2342  if( !vnet_sw_interface_is_admin_up (vnm, radv_info->sw_if_index))
2343  {
2344  radv_info->initial_adverts_sent = radv_info->initial_adverts_count-1;
2345  radv_info->next_multicast_time = now;
2346  radv_info->last_multicast_time = now;
2347  radv_info->last_radv_time = 0;
2348  radv_info->all_routers_mcast = 0;
2349  continue;
2350  }
2351 
2352  /* Make sure that we've joined the all-routers multicast group */
2353  if(!radv_info->all_routers_mcast)
2354  {
2355  /* send MDLP_REPORT_EVENT message */
2356  ip6_neighbor_send_mldpv2_report(radv_info->sw_if_index);
2357  radv_info->all_routers_mcast = 1;
2358  }
2359 
2360  /* is it time to send a multicast RA on this interface? */
2361  if(radv_info->send_radv && (now >= radv_info->next_multicast_time))
2362  {
2363  u32 n_to_alloc = 1;
2364  u32 n_allocated;
2365 
2366  f64 rfn = (radv_info->max_radv_interval - radv_info->min_radv_interval) *
2367  random_f64 (&radv_info->seed) + radv_info->min_radv_interval;
2368 
2369  /* multicast send - compute next multicast send time */
2370  if( radv_info->initial_adverts_sent > 0)
2371  {
2372  radv_info->initial_adverts_sent--;
2373  if(rfn > radv_info-> initial_adverts_interval)
2374  rfn = radv_info-> initial_adverts_interval;
2375 
2376  /* check to see if we are ceasing to send */
2377  if( radv_info->initial_adverts_sent == 0)
2378  if(radv_info->cease_radv)
2379  radv_info->send_radv = 0;
2380  }
2381 
2382  radv_info->next_multicast_time = rfn + now;
2383  radv_info->last_multicast_time = now;
2384 
2385  /* send advert now - build a "solicted" router advert with unspecified source address */
2386  n_allocated = vlib_buffer_alloc_from_free_list
2387  (vm, &bo0, n_to_alloc, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
2388 
2389  if (PREDICT_FALSE(n_allocated == 0))
2390  {
2391  clib_warning ("buffer allocation failure");
2392  continue;
2393  }
2394  b0 = vlib_get_buffer (vm, bo0);
2395  b0->current_length = sizeof( icmp6_router_solicitation_header_t);
2396  b0->error = ICMP6_ERROR_NONE;
2397  vnet_buffer (b0)->sw_if_index[VLIB_RX] = radv_info->sw_if_index;
2398 
2399  h0 = vlib_buffer_get_current (b0);
2400 
2401  memset (h0, 0, sizeof (icmp6_router_solicitation_header_t));
2402 
2403  h0->ip.ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (0x6 << 28);
2404  h0->ip.payload_length = clib_host_to_net_u16 (sizeof (icmp6_router_solicitation_header_t)
2405  - STRUCT_OFFSET_OF (icmp6_router_solicitation_header_t, neighbor));
2406  h0->ip.protocol = IP_PROTOCOL_ICMP6;
2407  h0->ip.hop_limit = 255;
2408 
2409  /* set src/dst address as "unspecified" this marks this packet as internally generated rather than recieved */
2410  h0->ip.src_address.as_u64[0] = 0;
2411  h0->ip.src_address.as_u64[1] = 0;
2412 
2413  h0->ip.dst_address.as_u64[0] = 0;
2414  h0->ip.dst_address.as_u64[1] = 0;
2415 
2416  h0->neighbor.icmp.type = ICMP6_router_solicitation;
2417 
2418  if (PREDICT_FALSE(f == 0))
2419  {
2421  to_next = vlib_frame_vector_args (f);
2422  n_left_to_next = VLIB_FRAME_SIZE;
2423  n_this_frame = 0;
2424  }
2425 
2426  n_this_frame++;
2427  n_left_to_next--;
2428  to_next[0] = bo0;
2429  to_next += 1;
2430 
2431  if (PREDICT_FALSE(n_left_to_next == 0))
2432  {
2433  f->n_vectors = n_this_frame;
2435  f = 0;
2436  }
2437  }
2438  }));
2439  /* *INDENT-ON* */
2440 
2441  if (f)
2442  {
2443  ASSERT (n_this_frame);
2444  f->n_vectors = n_this_frame;
2446  }
2447  return 0;
2448 }
2449 
2450 static uword
2452  vlib_node_runtime_t * node,
2453  vlib_frame_t * frame)
2454 {
2455  uword event_type;
2457 
2458  /* init code here */
2459 
2460  while (1)
2461  {
2462  vlib_process_wait_for_event_or_clock (vm, 1. /* seconds */ );
2463 
2464  event_data = vlib_process_get_event_data (vm, &event_type);
2465 
2466  if (!event_data)
2467  {
2468  /* No events found: timer expired. */
2469  /* process interface list and send RAs as appropriate, update timer info */
2470  ip6_neighbor_process_timer_event (vm, node, frame);
2471  }
2472  else
2473  {
2474  switch (event_type)
2475  {
2476 
2477  case ICMP6_ND_EVENT_INIT:
2478  break;
2479 
2480  case ~0:
2481  break;
2482 
2483  default:
2484  ASSERT (0);
2485  }
2486 
2487  if (event_data)
2488  _vec_len (event_data) = 0;
2489  }
2490  }
2491  return frame->n_vectors;
2492 }
2493 
2494 /* *INDENT-OFF* */
2496 {
2497  .function = icmp6_router_advertisement,
2498  .name = "icmp6-router-advertisement",
2499 
2500  .vector_size = sizeof (u32),
2501 
2502  .format_trace = format_icmp6_input_trace,
2503 
2504  .n_next_nodes = 1,
2505  .next_nodes = {
2506  [0] = "error-drop",
2507  },
2508 };
2509 /* *INDENT-ON* */
2510 
2512 
2514  .name = "ip6-icmp-neighbor-discovery-event-process",
2515  .type = VLIB_NODE_TYPE_PROCESS,
2516 };
2517 
2518 static uword
2520  vlib_node_runtime_t * node, vlib_frame_t * frame)
2521 {
2522  return icmp6_neighbor_solicitation_or_advertisement (vm, node, frame,
2523  /* is_solicitation */
2524  1);
2525 }
2526 
2527 static uword
2529  vlib_node_runtime_t * node,
2530  vlib_frame_t * frame)
2531 {
2532  return icmp6_neighbor_solicitation_or_advertisement (vm, node, frame,
2533  /* is_solicitation */
2534  0);
2535 }
2536 
2537 /* *INDENT-OFF* */
2539 {
2540  .function = icmp6_neighbor_solicitation,
2541  .name = "icmp6-neighbor-solicitation",
2542 
2543  .vector_size = sizeof (u32),
2544 
2545  .format_trace = format_icmp6_input_trace,
2546 
2547  .n_next_nodes = ICMP6_NEIGHBOR_SOLICITATION_N_NEXT,
2548  .next_nodes = {
2549  [ICMP6_NEIGHBOR_SOLICITATION_NEXT_DROP] = "error-drop",
2550  [ICMP6_NEIGHBOR_SOLICITATION_NEXT_REPLY] = "interface-output",
2551  },
2552 };
2553 /* *INDENT-ON* */
2554 
2555 /* *INDENT-OFF* */
2557 {
2558  .function = icmp6_neighbor_advertisement,
2559  .name = "icmp6-neighbor-advertisement",
2560 
2561  .vector_size = sizeof (u32),
2562 
2563  .format_trace = format_icmp6_input_trace,
2564 
2565  .n_next_nodes = 1,
2566  .next_nodes = {
2567  [0] = "error-drop",
2568  },
2569 };
2570 /* *INDENT-ON* */
2571 
2572 /* API support functions */
2573 int
2575  u8 suppress, u8 managed, u8 other,
2576  u8 ll_option, u8 send_unicast, u8 cease,
2577  u8 use_lifetime, u32 lifetime,
2578  u32 initial_count, u32 initial_interval,
2579  u32 max_interval, u32 min_interval, u8 is_no)
2580 {
2582  int error;
2583  u32 ri;
2584 
2585  /* look up the radv_t information for this interface */
2587  ~0);
2588  ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2589  error = (ri != ~0) ? 0 : VNET_API_ERROR_INVALID_SW_IF_INDEX;
2590 
2591  if (!error)
2592  {
2593 
2594  ip6_radv_t *radv_info;
2595  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
2596 
2597  if ((max_interval != 0) && (min_interval == 0))
2598  min_interval = .75 * max_interval;
2599 
2600  max_interval =
2601  (max_interval !=
2602  0) ? ((is_no) ? DEF_MAX_RADV_INTERVAL : max_interval) :
2603  radv_info->max_radv_interval;
2604  min_interval =
2605  (min_interval !=
2606  0) ? ((is_no) ? DEF_MIN_RADV_INTERVAL : min_interval) :
2607  radv_info->min_radv_interval;
2608  lifetime =
2609  (use_lifetime !=
2610  0) ? ((is_no) ? DEF_DEF_RTR_LIFETIME : lifetime) :
2611  radv_info->adv_router_lifetime_in_sec;
2612 
2613  if (lifetime)
2614  {
2615  if (lifetime > MAX_DEF_RTR_LIFETIME)
2616  lifetime = MAX_DEF_RTR_LIFETIME;
2617 
2618  if (lifetime <= max_interval)
2619  return VNET_API_ERROR_INVALID_VALUE;
2620  }
2621 
2622  if (min_interval != 0)
2623  {
2624  if ((min_interval > .75 * max_interval) || (min_interval < 3))
2625  return VNET_API_ERROR_INVALID_VALUE;
2626  }
2627 
2628  if ((initial_count > MAX_INITIAL_RTR_ADVERTISEMENTS) ||
2629  (initial_interval > MAX_INITIAL_RTR_ADVERT_INTERVAL))
2630  return VNET_API_ERROR_INVALID_VALUE;
2631 
2632  /*
2633  if "flag" is set and is_no is true then restore default value else set value corresponding to "flag"
2634  if "flag" is clear don't change corresponding value
2635  */
2636  radv_info->send_radv =
2637  (suppress != 0) ? ((is_no != 0) ? 1 : 0) : radv_info->send_radv;
2638  radv_info->adv_managed_flag =
2639  (managed != 0) ? ((is_no) ? 0 : 1) : radv_info->adv_managed_flag;
2640  radv_info->adv_other_flag =
2641  (other != 0) ? ((is_no) ? 0 : 1) : radv_info->adv_other_flag;
2642  radv_info->adv_link_layer_address =
2643  (ll_option !=
2644  0) ? ((is_no) ? 1 : 0) : radv_info->adv_link_layer_address;
2645  radv_info->send_unicast =
2646  (send_unicast != 0) ? ((is_no) ? 0 : 1) : radv_info->send_unicast;
2647  radv_info->cease_radv =
2648  (cease != 0) ? ((is_no) ? 0 : 1) : radv_info->cease_radv;
2649 
2650  radv_info->min_radv_interval = min_interval;
2651  radv_info->max_radv_interval = max_interval;
2652  radv_info->adv_router_lifetime_in_sec = lifetime;
2653 
2654  radv_info->initial_adverts_count =
2655  (initial_count !=
2656  0) ? ((is_no) ? MAX_INITIAL_RTR_ADVERTISEMENTS : initial_count) :
2657  radv_info->initial_adverts_count;
2658  radv_info->initial_adverts_interval =
2659  (initial_interval !=
2660  0) ? ((is_no) ? MAX_INITIAL_RTR_ADVERT_INTERVAL : initial_interval) :
2661  radv_info->initial_adverts_interval;
2662 
2663  /* restart */
2664  if ((cease != 0) && (is_no))
2665  radv_info->send_radv = 1;
2666 
2667  radv_info->initial_adverts_sent = radv_info->initial_adverts_count - 1;
2668  radv_info->next_multicast_time = vlib_time_now (vm);
2669  radv_info->last_multicast_time = vlib_time_now (vm);
2670  radv_info->last_radv_time = 0;
2671  }
2672  return (error);
2673 }
2674 
2675 int
2677  ip6_address_t * prefix_addr, u8 prefix_len,
2678  u8 use_default, u32 val_lifetime, u32 pref_lifetime,
2679  u8 no_advertise, u8 off_link, u8 no_autoconfig,
2680  u8 no_onlink, u8 is_no)
2681 {
2683  int error;
2684 
2685  u32 ri;
2686 
2687  /* look up the radv_t information for this interface */
2689  ~0);
2690 
2691  ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2692 
2693  error = (ri != ~0) ? 0 : VNET_API_ERROR_INVALID_SW_IF_INDEX;
2694 
2695  if (!error)
2696  {
2697  f64 now = vlib_time_now (vm);
2698  ip6_radv_t *radv_info;
2699  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
2700 
2701  /* prefix info add, delete or update */
2702  ip6_radv_prefix_t *prefix;
2703 
2704  /* lookup prefix info for this address on this interface */
2705  uword *p = mhash_get (&radv_info->address_to_prefix_index, prefix_addr);
2706 
2707  prefix = p ? pool_elt_at_index (radv_info->adv_prefixes_pool, p[0]) : 0;
2708 
2709  if (is_no)
2710  {
2711  /* delete */
2712  if (!prefix)
2713  return VNET_API_ERROR_INVALID_VALUE; /* invalid prefix */
2714 
2715  if (prefix->prefix_len != prefix_len)
2716  return VNET_API_ERROR_INVALID_VALUE_2;
2717 
2718  /* FIXME - Should the DP do this or the CP ? */
2719  /* do specific delete processing here before returning */
2720  /* try to remove from routing table */
2721 
2722  mhash_unset (&radv_info->address_to_prefix_index, prefix_addr,
2723  /* old_value */ 0);
2724  pool_put (radv_info->adv_prefixes_pool, prefix);
2725 
2726  radv_info->initial_adverts_sent =
2727  radv_info->initial_adverts_count - 1;
2728  radv_info->next_multicast_time = vlib_time_now (vm);
2729  radv_info->last_multicast_time = vlib_time_now (vm);
2730  radv_info->last_radv_time = 0;
2731  return (error);
2732  }
2733 
2734  /* adding or changing */
2735  if (!prefix)
2736  {
2737  /* add */
2738  u32 pi;
2739  pool_get (radv_info->adv_prefixes_pool, prefix);
2740  pi = prefix - radv_info->adv_prefixes_pool;
2741  mhash_set (&radv_info->address_to_prefix_index, prefix_addr, pi,
2742  /* old_value */ 0);
2743 
2744  memset (prefix, 0x0, sizeof (ip6_radv_prefix_t));
2745 
2746  prefix->prefix_len = prefix_len;
2747  clib_memcpy (&prefix->prefix, prefix_addr, sizeof (ip6_address_t));
2748 
2749  /* initialize default values */
2750  prefix->adv_on_link_flag = 1; /* L bit set */
2751  prefix->adv_autonomous_flag = 1; /* A bit set */
2754  prefix->enabled = 1;
2755  prefix->decrement_lifetime_flag = 1;
2756  prefix->deprecated_prefix_flag = 1;
2757 
2758  if (off_link == 0)
2759  {
2760  /* FIXME - Should the DP do this or the CP ? */
2761  /* insert prefix into routing table as a connected prefix */
2762  }
2763 
2764  if (use_default)
2765  goto restart;
2766  }
2767  else
2768  {
2769 
2770  if (prefix->prefix_len != prefix_len)
2771  return VNET_API_ERROR_INVALID_VALUE_2;
2772 
2773  if (off_link != 0)
2774  {
2775  /* FIXME - Should the DP do this or the CP ? */
2776  /* remove from routing table if already there */
2777  }
2778  }
2779 
2780  if ((val_lifetime == ~0) || (pref_lifetime == ~0))
2781  {
2782  prefix->adv_valid_lifetime_in_secs = ~0;
2783  prefix->adv_pref_lifetime_in_secs = ~0;
2784  prefix->decrement_lifetime_flag = 0;
2785  }
2786  else
2787  {
2788  prefix->adv_valid_lifetime_in_secs = val_lifetime;;
2789  prefix->adv_pref_lifetime_in_secs = pref_lifetime;
2790  }
2791 
2792  /* copy remaining */
2793  prefix->enabled = !(no_advertise != 0);
2794  prefix->adv_on_link_flag = !((off_link != 0) || (no_onlink != 0));
2795  prefix->adv_autonomous_flag = !(no_autoconfig != 0);
2796 
2797  restart:
2798  /* restart */
2799  /* fill in the expiration times */
2800  prefix->valid_lifetime_expires =
2801  now + prefix->adv_valid_lifetime_in_secs;
2802  prefix->pref_lifetime_expires = now + prefix->adv_pref_lifetime_in_secs;
2803 
2804  radv_info->initial_adverts_sent = radv_info->initial_adverts_count - 1;
2805  radv_info->next_multicast_time = vlib_time_now (vm);
2806  radv_info->last_multicast_time = vlib_time_now (vm);
2807  radv_info->last_radv_time = 0;
2808  }
2809  return (error);
2810 }
2811 
2812 clib_error_t *
2814  vlib_cli_command_t * cmd)
2815 {
2816  vnet_main_t *vnm = vnet_get_main ();
2818  clib_error_t *error = 0;
2819  u8 is_no = 0;
2820  u8 suppress = 0, managed = 0, other = 0;
2821  u8 suppress_ll_option = 0, send_unicast = 0, cease = 0;
2822  u8 use_lifetime = 0;
2823  u32 sw_if_index, ra_lifetime = 0, ra_initial_count =
2824  0, ra_initial_interval = 0;
2825  u32 ra_max_interval = 0, ra_min_interval = 0;
2826 
2827  unformat_input_t _line_input, *line_input = &_line_input;
2828  vnet_sw_interface_t *sw_if0;
2829 
2830  int add_radv_info = 1;
2831  __attribute__ ((unused)) ip6_radv_t *radv_info = 0;
2832  ip6_address_t ip6_addr;
2833  u32 addr_len;
2834 
2835 
2836  /* Get a line of input. */
2837  if (!unformat_user (main_input, unformat_line_input, line_input))
2838  return 0;
2839 
2840  /* get basic radv info for this interface */
2841  if (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2842  {
2843 
2844  if (unformat_user (line_input,
2845  unformat_vnet_sw_interface, vnm, &sw_if_index))
2846  {
2847  u32 ri;
2848  ethernet_interface_t *eth_if0 = 0;
2849 
2850  sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
2851  if (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
2852  eth_if0 =
2854 
2855  if (!eth_if0)
2856  {
2857  error =
2858  clib_error_return (0, "Interface must be of ethernet type");
2859  goto done;
2860  }
2861 
2862  /* look up the radv_t information for this interface */
2864  sw_if_index, ~0);
2865 
2866  ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
2867 
2868  if (ri != ~0)
2869  {
2870  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
2871  }
2872  else
2873  {
2874  error = clib_error_return (0, "unknown interface %U'",
2875  format_unformat_error, line_input);
2876  goto done;
2877  }
2878  }
2879  else
2880  {
2881  error = clib_error_return (0, "invalid interface name %U'",
2882  format_unformat_error, line_input);
2883  goto done;
2884  }
2885  }
2886 
2887  /* get the rest of the command */
2888  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2889  {
2890  if (unformat (line_input, "no"))
2891  is_no = 1;
2892  else if (unformat (line_input, "prefix %U/%d",
2893  unformat_ip6_address, &ip6_addr, &addr_len))
2894  {
2895  add_radv_info = 0;
2896  break;
2897  }
2898  else if (unformat (line_input, "ra-managed-config-flag"))
2899  {
2900  managed = 1;
2901  break;
2902  }
2903  else if (unformat (line_input, "ra-other-config-flag"))
2904  {
2905  other = 1;
2906  break;
2907  }
2908  else if (unformat (line_input, "ra-suppress") ||
2909  unformat (line_input, "ra-surpress"))
2910  {
2911  suppress = 1;
2912  break;
2913  }
2914  else if (unformat (line_input, "ra-suppress-link-layer") ||
2915  unformat (line_input, "ra-surpress-link-layer"))
2916  {
2917  suppress_ll_option = 1;
2918  break;
2919  }
2920  else if (unformat (line_input, "ra-send-unicast"))
2921  {
2922  send_unicast = 1;
2923  break;
2924  }
2925  else if (unformat (line_input, "ra-lifetime"))
2926  {
2927  if (!unformat (line_input, "%d", &ra_lifetime))
2928  return (error = unformat_parse_error (line_input));
2929  use_lifetime = 1;
2930  break;
2931  }
2932  else if (unformat (line_input, "ra-initial"))
2933  {
2934  if (!unformat
2935  (line_input, "%d %d", &ra_initial_count, &ra_initial_interval))
2936  return (error = unformat_parse_error (line_input));
2937  break;
2938  }
2939  else if (unformat (line_input, "ra-interval"))
2940  {
2941  if (!unformat (line_input, "%d", &ra_max_interval))
2942  return (error = unformat_parse_error (line_input));
2943 
2944  if (!unformat (line_input, "%d", &ra_min_interval))
2945  ra_min_interval = 0;
2946  break;
2947  }
2948  else if (unformat (line_input, "ra-cease"))
2949  {
2950  cease = 1;
2951  break;
2952  }
2953  else
2954  return (unformat_parse_error (line_input));
2955  }
2956 
2957  if (add_radv_info)
2958  {
2959  ip6_neighbor_ra_config (vm, sw_if_index,
2960  suppress, managed, other,
2961  suppress_ll_option, send_unicast, cease,
2962  use_lifetime, ra_lifetime,
2963  ra_initial_count, ra_initial_interval,
2964  ra_max_interval, ra_min_interval, is_no);
2965  }
2966  else
2967  {
2968  u32 valid_lifetime_in_secs = 0;
2969  u32 pref_lifetime_in_secs = 0;
2970  u8 use_prefix_default_values = 0;
2971  u8 no_advertise = 0;
2972  u8 off_link = 0;
2973  u8 no_autoconfig = 0;
2974  u8 no_onlink = 0;
2975 
2976  /* get the rest of the command */
2977  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2978  {
2979  if (unformat (line_input, "default"))
2980  {
2981  use_prefix_default_values = 1;
2982  break;
2983  }
2984  else if (unformat (line_input, "infinite"))
2985  {
2986  valid_lifetime_in_secs = ~0;
2987  pref_lifetime_in_secs = ~0;
2988  break;
2989  }
2990  else if (unformat (line_input, "%d %d", &valid_lifetime_in_secs,
2991  &pref_lifetime_in_secs))
2992  break;
2993  else
2994  break;
2995  }
2996 
2997 
2998  /* get the rest of the command */
2999  while (!use_prefix_default_values &&
3001  {
3002  if (unformat (line_input, "no-advertise"))
3003  no_advertise = 1;
3004  else if (unformat (line_input, "off-link"))
3005  off_link = 1;
3006  else if (unformat (line_input, "no-autoconfig"))
3007  no_autoconfig = 1;
3008  else if (unformat (line_input, "no-onlink"))
3009  no_onlink = 1;
3010  else
3011  return (unformat_parse_error (line_input));
3012  }
3013 
3014  ip6_neighbor_ra_prefix (vm, sw_if_index,
3015  &ip6_addr, addr_len,
3016  use_prefix_default_values,
3017  valid_lifetime_in_secs,
3018  pref_lifetime_in_secs,
3019  no_advertise,
3020  off_link, no_autoconfig, no_onlink, is_no);
3021  }
3022 
3023  unformat_free (line_input);
3024 
3025 done:
3026  return error;
3027 }
3028 
3029 static void
3031 {
3033  u32 i;
3034 
3035  for (i = 0; i < vec_len (addrs); i++)
3036  {
3038  pool_elt_at_index (lm->if_address_pool, addrs[i]);
3040 
3041  vlib_cli_output (vm, "\t\t%U/%d",
3042  format_ip6_address, address, a->address_length);
3043  }
3044 }
3045 
3046 static clib_error_t *
3048  unformat_input_t * input, vlib_cli_command_t * cmd)
3049 {
3050  vnet_main_t *vnm = vnet_get_main ();
3052  clib_error_t *error = 0;
3053  u32 sw_if_index;
3054 
3055  sw_if_index = ~0;
3056 
3057  if (unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
3058  {
3059  u32 ri;
3060 
3061  /* look up the radv_t information for this interface */
3063  sw_if_index, ~0);
3064 
3065  ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3066 
3067  if (ri != ~0)
3068  {
3070  ip6_radv_t *radv_info;
3071  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3072 
3073  vlib_cli_output (vm, "%U is admin %s\n",
3075  vnet_get_sw_interface (vnm, sw_if_index),
3076  (vnet_sw_interface_is_admin_up (vnm, sw_if_index) ?
3077  "up" : "down"));
3078 
3079  u32 ai;
3080  u32 *link_scope = 0, *global_scope = 0;
3081  u32 *local_scope = 0, *unknown_scope = 0;
3083 
3085  sw_if_index, ~0);
3086  ai = lm->if_address_pool_index_by_sw_if_index[sw_if_index];
3087 
3088  while (ai != (u32) ~ 0)
3089  {
3090  a = pool_elt_at_index (lm->if_address_pool, ai);
3091  ip6_address_t *address =
3093 
3094  if (ip6_address_is_link_local_unicast (address))
3095  vec_add1 (link_scope, ai);
3096  else if (ip6_address_is_global_unicast (address))
3097  vec_add1 (global_scope, ai);
3098  else if (ip6_address_is_local_unicast (address))
3099  vec_add1 (local_scope, ai);
3100  else
3101  vec_add1 (unknown_scope, ai);
3102 
3103  ai = a->next_this_sw_interface;
3104  }
3105 
3106  if (vec_len (link_scope))
3107  {
3108  vlib_cli_output (vm, "\tLink-local address(es):\n");
3109  ip6_print_addrs (vm, link_scope);
3110  vec_free (link_scope);
3111  }
3112 
3113  if (vec_len (local_scope))
3114  {
3115  vlib_cli_output (vm, "\tLocal unicast address(es):\n");
3116  ip6_print_addrs (vm, local_scope);
3117  vec_free (local_scope);
3118  }
3119 
3120  if (vec_len (global_scope))
3121  {
3122  vlib_cli_output (vm, "\tGlobal unicast address(es):\n");
3123  ip6_print_addrs (vm, global_scope);
3124  vec_free (global_scope);
3125  }
3126 
3127  if (vec_len (unknown_scope))
3128  {
3129  vlib_cli_output (vm, "\tOther-scope address(es):\n");
3130  ip6_print_addrs (vm, unknown_scope);
3131  vec_free (unknown_scope);
3132  }
3133 
3134  vlib_cli_output (vm, "\tJoined group address(es):\n");
3135  ip6_mldp_group_t *m;
3136  /* *INDENT-OFF* */
3137  pool_foreach (m, radv_info->mldp_group_pool,
3138  ({
3139  vlib_cli_output (vm, "\t\t%U\n", format_ip6_address,
3140  &m->mcast_address);
3141  }));
3142  /* *INDENT-ON* */
3143 
3144  vlib_cli_output (vm, "\tAdvertised Prefixes:\n");
3145  ip6_radv_prefix_t *p;
3146  /* *INDENT-OFF* */
3147  pool_foreach (p, radv_info->adv_prefixes_pool,
3148  ({
3149  vlib_cli_output (vm, "\t\tprefix %U, length %d\n",
3150  format_ip6_address, &p->prefix, p->prefix_len);
3151  }));
3152  /* *INDENT-ON* */
3153 
3154  vlib_cli_output (vm, "\tMTU is %d\n", radv_info->adv_link_mtu);
3155  vlib_cli_output (vm, "\tICMP error messages are unlimited\n");
3156  vlib_cli_output (vm, "\tICMP redirects are disabled\n");
3157  vlib_cli_output (vm, "\tICMP unreachables are not sent\n");
3158  vlib_cli_output (vm, "\tND DAD is disabled\n");
3159  //vlib_cli_output (vm, "\tND reachable time is %d milliseconds\n",);
3160  vlib_cli_output (vm, "\tND advertised reachable time is %d\n",
3162  vlib_cli_output (vm,
3163  "\tND advertised retransmit interval is %d (msec)\n",
3164  radv_info->
3165  adv_time_in_msec_between_retransmitted_neighbor_solicitations);
3166 
3167  u32 ra_interval = radv_info->max_radv_interval;
3168  u32 ra_interval_min = radv_info->min_radv_interval;
3169  vlib_cli_output (vm,
3170  "\tND router advertisements are sent every %d seconds (min interval is %d)\n",
3171  ra_interval, ra_interval_min);
3172  vlib_cli_output (vm,
3173  "\tND router advertisements live for %d seconds\n",
3174  radv_info->adv_router_lifetime_in_sec);
3175  vlib_cli_output (vm,
3176  "\tHosts %s stateless autoconfig for addresses\n",
3177  (radv_info->adv_managed_flag) ? "use" :
3178  " don't use");
3179  vlib_cli_output (vm, "\tND router advertisements sent %d\n",
3180  radv_info->n_advertisements_sent);
3181  vlib_cli_output (vm, "\tND router solicitations received %d\n",
3182  radv_info->n_solicitations_rcvd);
3183  vlib_cli_output (vm, "\tND router solicitations dropped %d\n",
3184  radv_info->n_solicitations_dropped);
3185  }
3186  else
3187  {
3188  error = clib_error_return (0, "IPv6 not enabled on interface",
3189  format_unformat_error, input);
3190 
3191  }
3192  }
3193  return error;
3194 }
3195 
3196 /*?
3197  * This command is used to display various IPv6 attributes on a given
3198  * interface.
3199  *
3200  * @cliexpar
3201  * Example of how to display IPv6 settings:
3202  * @cliexstart{show ip6 interface GigabitEthernet2/0/0}
3203  * GigabitEthernet2/0/0 is admin up
3204  * Link-local address(es):
3205  * fe80::ab8/64
3206  * Joined group address(es):
3207  * ff02::1
3208  * ff02::2
3209  * ff02::16
3210  * ff02::1:ff00:ab8
3211  * Advertised Prefixes:
3212  * prefix fe80::fe:28ff:fe9c:75b3, length 64
3213  * MTU is 1500
3214  * ICMP error messages are unlimited
3215  * ICMP redirects are disabled
3216  * ICMP unreachables are not sent
3217  * ND DAD is disabled
3218  * ND advertised reachable time is 0
3219  * ND advertised retransmit interval is 0 (msec)
3220  * ND router advertisements are sent every 200 seconds (min interval is 150)
3221  * ND router advertisements live for 600 seconds
3222  * Hosts use stateless autoconfig for addresses
3223  * ND router advertisements sent 19336
3224  * ND router solicitations received 0
3225  * ND router solicitations dropped 0
3226  * @cliexend
3227  * Example of output if IPv6 is not enabled on the interface:
3228  * @cliexstart{show ip6 interface GigabitEthernet2/0/0}
3229  * show ip6 interface: IPv6 not enabled on interface
3230  * @cliexend
3231 ?*/
3232 /* *INDENT-OFF* */
3233 VLIB_CLI_COMMAND (show_ip6_interface_command, static) =
3234 {
3235  .path = "show ip6 interface",
3236  .function = show_ip6_interface_cmd,
3237  .short_help = "show ip6 interface <interface>",
3238 };
3239 /* *INDENT-ON* */
3240 
3241 clib_error_t *
3243 {
3244  clib_error_t *error = 0;
3246  u32 ri;
3247 
3248  /* look up the radv_t information for this interface */
3250  ~0);
3251  ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3252 
3253  /* if not created - do nothing */
3254  if (ri != ~0)
3255  {
3256  vnet_main_t *vnm = vnet_get_main ();
3257  ip6_radv_t *radv_info;
3258 
3259  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3260 
3261  /* check radv_info ref count for other ip6 addresses on this interface */
3262  if (radv_info->ref_count == 0)
3263  {
3264  /* essentially "disables" ipv6 on this interface */
3265  error = ip6_add_del_interface_address (vm, sw_if_index,
3266  &radv_info->
3267  link_local_address, 128,
3268  1 /* is_del */ );
3269 
3270  ip6_neighbor_sw_interface_add_del (vnm, sw_if_index,
3271  0 /* is_add */ );
3272  }
3273  }
3274  return error;
3275 }
3276 
3277 int
3279 {
3281  u32 ri = ~0;
3282 
3283  /* look up the radv_t information for this interface */
3285  ~0);
3286 
3287  ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3288 
3289  return ri != ~0;
3290 }
3291 
3292 clib_error_t *
3294 {
3295  clib_error_t *error = 0;
3297  u32 ri;
3298  int is_add = 1;
3299 
3300  /* look up the radv_t information for this interface */
3302  ~0);
3303 
3304  ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3305 
3306  /* if not created yet */
3307  if (ri == ~0)
3308  {
3309  vnet_main_t *vnm = vnet_get_main ();
3310  vnet_sw_interface_t *sw_if0;
3311 
3312  sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index);
3313  if (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
3314  {
3315  ethernet_interface_t *eth_if0;
3316 
3317  eth_if0 =
3319  if (eth_if0)
3320  {
3321  /* create radv_info. for this interface. This holds all the info needed for router adverts */
3322  ri =
3323  ip6_neighbor_sw_interface_add_del (vnm, sw_if_index, is_add);
3324 
3325  if (ri != ~0)
3326  {
3327  ip6_radv_t *radv_info;
3328  ip6_address_t link_local_address;
3329 
3330  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3331 
3333  (&link_local_address, eth_if0->address);
3334 
3335  sw_if0 = vnet_get_sw_interface (vnm, sw_if_index);
3336  if (sw_if0->type == VNET_SW_INTERFACE_TYPE_SUB)
3337  {
3338  /* make up an interface id */
3339  md5_context_t m;
3340  u8 digest[16];
3341 
3342  link_local_address.as_u64[0] = radv_info->randomizer;
3343 
3344  md5_init (&m);
3345  md5_add (&m, &link_local_address, 16);
3346  md5_finish (&m, digest);
3347 
3348  clib_memcpy (&link_local_address, digest, 16);
3349 
3350  radv_info->randomizer = link_local_address.as_u64[0];
3351 
3352  link_local_address.as_u64[0] =
3353  clib_host_to_net_u64 (0xFE80000000000000ULL);
3354  /* clear u bit */
3355  link_local_address.as_u8[8] &= 0xfd;
3356  }
3357 
3358  /* essentially "enables" ipv6 on this interface */
3359  error = ip6_add_del_interface_address (vm, sw_if_index,
3360  &link_local_address,
3361  128
3362  /* address width */ ,
3363  0 /* is_del */ );
3364 
3365  if (error)
3366  ip6_neighbor_sw_interface_add_del (vnm, sw_if_index,
3367  !is_add);
3368  else
3369  {
3370  radv_info->link_local_address = link_local_address;
3371  }
3372  }
3373  }
3374  }
3375  }
3376  return error;
3377 }
3378 
3379 static clib_error_t *
3381  unformat_input_t * input, vlib_cli_command_t * cmd)
3382 {
3383  vnet_main_t *vnm = vnet_get_main ();
3384  clib_error_t *error = 0;
3385  u32 sw_if_index;
3386 
3387  sw_if_index = ~0;
3388 
3389  if (unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
3390  {
3391  enable_ip6_interface (vm, sw_if_index);
3392  }
3393  else
3394  {
3395  error = clib_error_return (0, "unknown interface\n'",
3396  format_unformat_error, input);
3397 
3398  }
3399  return error;
3400 }
3401 
3402 /*?
3403  * This command is used to enable IPv6 on a given interface.
3404  *
3405  * @cliexpar
3406  * Example of how enable IPv6 on a given interface:
3407  * @cliexcmd{enable ip6 interface GigabitEthernet2/0/0}
3408 ?*/
3409 /* *INDENT-OFF* */
3410 VLIB_CLI_COMMAND (enable_ip6_interface_command, static) =
3411 {
3412  .path = "enable ip6 interface",
3413  .function = enable_ip6_interface_cmd,
3414  .short_help = "enable ip6 interface <interface>",
3415 };
3416 /* *INDENT-ON* */
3417 
3418 static clib_error_t *
3420  unformat_input_t * input, vlib_cli_command_t * cmd)
3421 {
3422  vnet_main_t *vnm = vnet_get_main ();
3423  clib_error_t *error = 0;
3424  u32 sw_if_index;
3425 
3426  sw_if_index = ~0;
3427 
3428  if (unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
3429  {
3430  error = disable_ip6_interface (vm, sw_if_index);
3431  }
3432  else
3433  {
3434  error = clib_error_return (0, "unknown interface\n'",
3435  format_unformat_error, input);
3436 
3437  }
3438  return error;
3439 }
3440 
3441 /*?
3442  * This command is used to disable IPv6 on a given interface.
3443  *
3444  * @cliexpar
3445  * Example of how disable IPv6 on a given interface:
3446  * @cliexcmd{disable ip6 interface GigabitEthernet2/0/0}
3447 ?*/
3448 /* *INDENT-OFF* */
3449 VLIB_CLI_COMMAND (disable_ip6_interface_command, static) =
3450 {
3451  .path = "disable ip6 interface",
3452  .function = disable_ip6_interface_cmd,
3453  .short_help = "disable ip6 interface <interface>",
3454 };
3455 /* *INDENT-ON* */
3456 
3457 /*?
3458  * This command is used to configure the neighbor discovery
3459  * parameters on a given interface. Use the '<em>show ip6 interface</em>'
3460  * command to display some of the current neighbor discovery parameters
3461  * on a given interface. This command has three formats:
3462  *
3463  *
3464  * <b>Format 1 - Router Advertisement Options:</b> (Only one can be entered in a single command)
3465  *
3466  * '<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>'
3467  *
3468  * Where:
3469  *
3470  * <em>[no] ra-managed-config-flag</em> - Advertises in ICMPv6
3471  * router-advertisement messages to use stateful address
3472  * auto-configuration to obtain address information (sets the M-bit).
3473  * Default is the M-bit is not set and the '<em>no</em>' option
3474  * returns it to this default state.
3475  *
3476  * <em>[no] ra-other-config-flag</em> - Indicates in ICMPv6
3477  * router-advertisement messages that hosts use stateful auto
3478  * configuration to obtain nonaddress related information (sets
3479  * the O-bit). Default is the O-bit is not set and the '<em>no</em>'
3480  * option returns it to this default state.
3481  *
3482  * <em>[no] ra-suppress</em> - Disables sending ICMPv6 router-advertisement
3483  * messages. The '<em>no</em>' option implies to enable sending ICMPv6
3484  * router-advertisement messages.
3485  *
3486  * <em>[no] ra-suppress-link-layer</em> - Indicates not to include the
3487  * optional source link-layer address in the ICMPv6 router-advertisement
3488  * messages. Default is to include the optional source link-layer address
3489  * and the '<em>no</em>' option returns it to this default state.
3490  *
3491  * <em>[no] ra-send-unicast</em> - Use the source address of the
3492  * router-solicitation message if availiable. The default is to use
3493  * multicast address of all nodes, and the '<em>no</em>' option returns
3494  * it to this default state.
3495  *
3496  * <em>[no] ra-lifetime <lifetime></em> - Advertises the lifetime of a
3497  * default router in ICMPv6 router-advertisement messages. The range is
3498  * from 0 to 9000 seconds. '<em><lifetime></em>' must be greater than
3499  * '<em><max-interval></em>'. The default value is 600 seconds and the
3500  * '<em>no</em>' option returns it to this default value.
3501  *
3502  * <em>[no] ra-initial <cnt> <interval></em> - Number of initial ICMPv6
3503  * router-advertisement messages sent and the interval between each
3504  * message. Range for count is 1 - 3 and default is 3. Range for interval
3505  * is 1 to 16 seconds, and default is 16 seconds. The '<em>no</em>' option
3506  * returns both to their default value.
3507  *
3508  * <em>[no] ra-interval <max-interval> [<min-interval>]</em> - Configures the
3509  * interval between sending ICMPv6 router-advertisement messages. The
3510  * range for max-interval is from 4 to 200 seconds. min-interval can not
3511  * be more than 75% of max-interval. If not set, min-interval will be
3512  * set to 75% of max-interval. The range for min-interval is from 3 to
3513  * 150 seconds. The '<em>no</em>' option returns both to their default
3514  * value.
3515  *
3516  * <em>[no] ra-cease</em> - Cease sending ICMPv6 router-advertisement messages.
3517  * The '<em>no</em>' options implies to start (or restart) sending
3518  * ICMPv6 router-advertisement messages.
3519  *
3520  *
3521  * <b>Format 2 - Prefix Options:</b>
3522  *
3523  * '<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>'
3524  *
3525  * Where:
3526  *
3527  * <em>no</em> - All additional flags are ignored and the prefix is deleted.
3528  *
3529  * <em><valid-lifetime> <pref-lifetime></em> - '<em><valid-lifetime></em>' is the
3530  * length of time in seconds during what the prefix is valid for the purpose of
3531  * on-link determination. Range is 7203 to 2592000 seconds and default is 2592000
3532  * seconds (30 days). '<em><pref-lifetime></em>' is the prefered-lifetime and is the
3533  * length of time in seconds during what addresses generated from the prefix remain
3534  * preferred. Range is 0 to 604800 seconds and default is 604800 seconds (7 days).
3535  *
3536  * <em>infinite</em> - Both '<em><valid-lifetime></em>' and '<em><<pref-lifetime></em>'
3537  * are inifinte, no timeout.
3538  *
3539  * <em>no-advertise</em> - Do not send full router address in prefix
3540  * advertisement. Default is to advertise (i.e. - This flag is off by default).
3541  *
3542  * <em>off-link</em> - Prefix is off-link, clear L-bit in packet. Default is on-link
3543  * (i.e. - This flag is off and L-bit in packet is set by default and this prefix can
3544  * be used for on-link determination). '<em>no-onlink</em>' also controls the L-bit.
3545  *
3546  * <em>no-autoconfig</em> - Do not use prefix for autoconfiguration, clear A-bit in packet.
3547  * Default is autoconfig (i.e. - This flag is off and A-bit in packet is set by default.
3548  *
3549  * <em>no-onlink</em> - Do not use prefix for onlink determination, clear L-bit in packet.
3550  * Default is on-link (i.e. - This flag is off and L-bit in packet is set by default and
3551  * this prefix can be used for on-link determination). '<em>off-link</em>' also controls
3552  * the L-bit.
3553  *
3554  *
3555  * <b>Format 3: - Default of Prefix:</b>
3556  *
3557  * '<em><b>ip6 nd <interface> [no] prefix <ip6-address>/<width> default</b></em>'
3558  *
3559  * When a new prefix is added (or existing one is being overwritten) <em>default</em>
3560  * uses default values for the prefix. If <em>no</em> is used, the <em>default</em>
3561  * is ignored and the prefix is deleted.
3562  *
3563  *
3564  * @cliexpar
3565  * Example of how set a router advertisement option:
3566  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 ra-interval 100 20}
3567  * Example of how to add a prefix:
3568  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 prefix fe80::fe:28ff:fe9c:75b3/64 infinite no-advertise}
3569  * Example of how to delete a prefix:
3570  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 no prefix fe80::fe:28ff:fe9c:75b3/64}
3571 ?*/
3572 /* *INDENT-OFF* */
3573 VLIB_CLI_COMMAND (ip6_nd_command, static) =
3574 {
3575  .path = "ip6 nd",
3576  .short_help = "ip6 nd <interface> ...",
3577  .function = ip6_neighbor_cmd,
3578 };
3579 /* *INDENT-ON* */
3580 
3581 clib_error_t *
3583  u32 sw_if_index,
3584  ip6_address_t * address, u8 address_length)
3585 {
3586  clib_error_t *error = 0;
3588  u32 ri;
3589  ip6_radv_t *radv_info;
3590  vnet_main_t *vnm = vnet_get_main ();
3591 
3592  if (!ip6_address_is_link_local_unicast (address))
3593  {
3594  vnm->api_errno = VNET_API_ERROR_ADDRESS_NOT_LINK_LOCAL;
3595  return (error = clib_error_return (0, "address not link-local",
3597  }
3598 
3599  /* call enable ipv6 */
3600  enable_ip6_interface (vm, sw_if_index);
3601 
3602  ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3603 
3604  if (ri != ~0)
3605  {
3606  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3607 
3608  /* save if link local address (overwrite default) */
3609 
3610  /* delete the old one */
3611  error = ip6_add_del_interface_address (vm, sw_if_index,
3612  &radv_info->link_local_address,
3613  128, 1 /* is_del */ );
3614 
3615  if (!error)
3616  {
3617  /* add the new one */
3618  error = ip6_add_del_interface_address (vm, sw_if_index,
3619  address, 128,
3620  0 /* is_del */ );
3621 
3622  if (!error)
3623  {
3624  radv_info->link_local_address = *address;
3625  }
3626  }
3627  }
3628  else
3629  {
3630  vnm->api_errno = VNET_API_ERROR_IP6_NOT_ENABLED;
3631  error = clib_error_return (0, "ip6 not enabled for interface",
3633  }
3634  return error;
3635 }
3636 
3637 clib_error_t *
3639  unformat_input_t * input,
3640  vlib_cli_command_t * cmd)
3641 {
3642  vnet_main_t *vnm = vnet_get_main ();
3643  clib_error_t *error = 0;
3644  u32 sw_if_index;
3645  ip6_address_t ip6_addr;
3646  u32 addr_len = 0;
3647 
3648  if (unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
3649  {
3650  /* get the rest of the command */
3651  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3652  {
3653  if (unformat (input, "%U/%d",
3654  unformat_ip6_address, &ip6_addr, &addr_len))
3655  break;
3656  else
3657  return (unformat_parse_error (input));
3658  }
3659  }
3660  error = set_ip6_link_local_address (vm, sw_if_index, &ip6_addr, addr_len);
3661  return error;
3662 }
3663 
3664 /*?
3665  * This command is used to assign an IPv6 Link-local address to an
3666  * interface. This command will enable IPv6 on an interface if it
3667  * is not already enabled. Use the '<em>show ip6 interface</em>' command
3668  * to display the assigned Link-local address.
3669  *
3670  * @cliexpar
3671  * Example of how to assign an IPv6 Link-local address to an interface:
3672  * @cliexcmd{set ip6 link-local address GigabitEthernet2/0/0 FE80::AB8/64}
3673 ?*/
3674 /* *INDENT-OFF* */
3675 VLIB_CLI_COMMAND (set_ip6_link_local_address_command, static) =
3676 {
3677  .path = "set ip6 link-local address",
3678  .short_help = "set ip6 link-local address <interface> <ip6-address>/<width>",
3679  .function = set_ip6_link_local_address_cmd,
3680 };
3681 /* *INDENT-ON* */
3682 
3683 /* callback when an interface address is added or deleted */
3684 static void
3686  uword opaque,
3687  u32 sw_if_index,
3688  ip6_address_t * address,
3689  u32 address_length,
3690  u32 if_address_index, u32 is_delete)
3691 {
3692  vnet_main_t *vnm = vnet_get_main ();
3694  u32 ri;
3695  vlib_main_t *vm = vnm->vlib_main;
3696  ip6_radv_t *radv_info;
3697  ip6_address_t a;
3698  ip6_mldp_group_t *mcast_group_info;
3699 
3700  /* create solicited node multicast address for this interface adddress */
3702 
3703  a.as_u8[0xd] = address->as_u8[0xd];
3704  a.as_u8[0xe] = address->as_u8[0xe];
3705  a.as_u8[0xf] = address->as_u8[0xf];
3706 
3707  if (!is_delete)
3708  {
3709  /* try to create radv_info - does nothing if ipv6 already enabled */
3710  enable_ip6_interface (vm, sw_if_index);
3711 
3712  /* look up the radv_t information for this interface */
3714  sw_if_index, ~0);
3715  ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3716  if (ri != ~0)
3717  {
3718  /* get radv_info */
3719  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3720 
3721  /* add address */
3722  if (!ip6_address_is_link_local_unicast (address))
3723  radv_info->ref_count++;
3724 
3725  /* lookup prefix info for this address on this interface */
3726  uword *p = mhash_get (&radv_info->address_to_mldp_index, &a);
3727  mcast_group_info =
3728  p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
3729 
3730  /* add -solicted node multicast address */
3731  if (!mcast_group_info)
3732  {
3733  /* add */
3734  u32 mi;
3735  pool_get (radv_info->mldp_group_pool, mcast_group_info);
3736 
3737  mi = mcast_group_info - radv_info->mldp_group_pool;
3738  mhash_set (&radv_info->address_to_mldp_index, &a, mi,
3739  /* old_value */ 0);
3740 
3741  mcast_group_info->type = 4;
3742  mcast_group_info->mcast_source_address_pool = 0;
3743  mcast_group_info->num_sources = 0;
3744  clib_memcpy (&mcast_group_info->mcast_address, &a,
3745  sizeof (ip6_address_t));
3746  }
3747  }
3748  }
3749  else
3750  {
3751 
3752  /* delete */
3753  /* look up the radv_t information for this interface */
3755  sw_if_index, ~0);
3756  ri = nm->if_radv_pool_index_by_sw_if_index[sw_if_index];
3757  if (ri != ~0)
3758  {
3759  /* get radv_info */
3760  radv_info = pool_elt_at_index (nm->if_radv_pool, ri);
3761 
3762  /* lookup prefix info for this address on this interface */
3763  uword *p = mhash_get (&radv_info->address_to_mldp_index, &a);
3764  mcast_group_info =
3765  p ? pool_elt_at_index (radv_info->mldp_group_pool, p[0]) : 0;
3766 
3767  if (mcast_group_info)
3768  {
3769  mhash_unset (&radv_info->address_to_mldp_index, &a,
3770  /* old_value */ 0);
3771  pool_put (radv_info->mldp_group_pool, mcast_group_info);
3772  }
3773 
3774  /* if interface up send MLDP "report" */
3775  radv_info->all_routers_mcast = 0;
3776 
3777  /* add address */
3778  if (!ip6_address_is_link_local_unicast (address))
3779  radv_info->ref_count--;
3780  }
3781  }
3782 }
3783 
3784 clib_error_t *
3785 ip6_set_neighbor_limit (u32 neighbor_limit)
3786 {
3788 
3789  nm->limit_neighbor_cache_size = neighbor_limit;
3790  return 0;
3791 }
3792 
3793 static clib_error_t *
3795 {
3797  ip6_main_t *im = &ip6_main;
3798 
3800  /* value size */ sizeof (uword),
3801  /* key size */ sizeof (ip6_neighbor_key_t));
3802 
3803  icmp6_register_type (vm, ICMP6_neighbor_solicitation,
3805  icmp6_register_type (vm, ICMP6_neighbor_advertisement,
3807  icmp6_register_type (vm, ICMP6_router_solicitation,
3809  icmp6_register_type (vm, ICMP6_router_advertisement,
3811 
3812  /* handler node for ip6 neighbor discovery events and timers */
3814 
3815  /* add call backs */
3817  memset (&cb, 0x0, sizeof (ip6_add_del_interface_address_callback_t));
3818 
3819  /* when an interface address changes... */
3821  cb.function_opaque = 0;
3823 
3825  /* value size */ sizeof (uword),
3826  /* key size */ sizeof (ip6_address_t));
3827 
3829  /* value size */ sizeof (uword),
3830  /* key size */ sizeof (ip6_address_t));
3831 
3832  /* default, configurable */
3833  nm->limit_neighbor_cache_size = 50000;
3834 
3835 #if 0
3836  /* $$$$ Hack fix for today */
3838  (im->discover_neighbor_next_index_by_hw_if_index, 32, 0 /* drop */ );
3839 #endif
3840 
3841  return 0;
3842 }
3843 
3845 
3846 
3847 void
3849  void *address_arg,
3850  uword node_index,
3851  uword type_opaque, uword data)
3852 {
3854  ip6_address_t *address = address_arg;
3855  uword *p;
3857 
3858  pool_get (nm->pending_resolutions, pr);
3859 
3860  pr->next_index = ~0;
3861  pr->node_index = node_index;
3862  pr->type_opaque = type_opaque;
3863  pr->data = data;
3864 
3865  p = mhash_get (&nm->pending_resolutions_by_address, address);
3866  if (p)
3867  {
3868  /* Insert new resolution at the head of the list */
3869  pr->next_index = p[0];
3870  mhash_unset (&nm->pending_resolutions_by_address, address, 0);
3871  }
3872 
3874  pr - nm->pending_resolutions, 0 /* old value */ );
3875 }
3876 
3877 int
3879  void *data_callback,
3880  u32 pid,
3881  void *address_arg,
3882  uword node_index,
3883  uword type_opaque, uword data, int is_add)
3884 {
3886  ip6_address_t *address = address_arg;
3887  uword *p;
3889  void (*fp) (u32, u8 *) = data_callback;
3890 
3891  if (is_add)
3892  {
3893  pool_get (nm->mac_changes, mc);
3894 
3895  mc->next_index = ~0;
3896  mc->node_index = node_index;
3897  mc->type_opaque = type_opaque;
3898  mc->data = data;
3899  mc->data_callback = data_callback;
3900  mc->pid = pid;
3901 
3902  p = mhash_get (&nm->mac_changes_by_address, address);
3903  if (p)
3904  {
3905  /* Insert new resolution at the head of the list */
3906  mc->next_index = p[0];
3907  mhash_unset (&nm->mac_changes_by_address, address, 0);
3908  }
3909 
3910  mhash_set (&nm->mac_changes_by_address, address,
3911  mc - nm->mac_changes, 0);
3912  return 0;
3913  }
3914  else
3915  {
3916  u32 index;
3917  pending_resolution_t *mc_last = 0;
3918 
3919  p = mhash_get (&nm->mac_changes_by_address, address);
3920  if (p == 0)
3921  return VNET_API_ERROR_NO_SUCH_ENTRY;
3922 
3923  index = p[0];
3924 
3925  while (index != (u32) ~ 0)
3926  {
3927  mc = pool_elt_at_index (nm->mac_changes, index);
3928  if (mc->node_index == node_index &&
3929  mc->type_opaque == type_opaque && mc->pid == pid)
3930  {
3931  /* Clients may need to clean up pool entries, too */
3932  if (fp)
3933  (*fp) (mc->data, 0 /* no new mac addrs */ );
3934  if (index == p[0])
3935  {
3936  mhash_unset (&nm->mac_changes_by_address, address, 0);
3937  if (mc->next_index != ~0)
3938  mhash_set (&nm->mac_changes_by_address, address,
3939  mc->next_index, 0);
3940  pool_put (nm->mac_changes, mc);
3941  return 0;
3942  }
3943  else
3944  {
3945  ASSERT (mc_last);
3946  mc_last->next_index = mc->next_index;
3947  pool_put (nm->mac_changes, mc);
3948  return 0;
3949  }
3950  }
3951  mc_last = mc;
3952  index = mc->next_index;
3953  }
3954 
3955  return VNET_API_ERROR_NO_SUCH_ENTRY;
3956  }
3957 }
3958 
3959 int
3961  vlib_node_runtime_t * node,
3962  vlib_buffer_t * p0,
3963  ethernet_header_t * eth,
3964  ip6_header_t * ip, u32 sw_if_index, u16 bd_index, u8 shg)
3965 {
3967  icmp6_neighbor_solicitation_or_advertisement_header_t *ndh;
3969  uword *p;
3970 
3971  ndh = ip6_next_header (ip);
3972  if (ndh->icmp.type != ICMP6_neighbor_solicitation &&
3973  ndh->icmp.type != ICMP6_neighbor_advertisement)
3974  return 0;
3975 
3976  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
3977  (p0->flags & VLIB_BUFFER_IS_TRACED)))
3978  {
3979  u8 *t0 = vlib_add_trace (vm, node, p0,
3980  sizeof (icmp6_input_trace_t));
3981  clib_memcpy (t0, ip, sizeof (icmp6_input_trace_t));
3982  }
3983 
3984  /* Check if anyone want ND events for L2 BDs */
3985  p = mhash_get (&nm->mac_changes_by_address, &ip6a_zero);
3986  if (p && shg == 0 && /* Only SHG 0 interface which is more likely local */
3988  {
3989  u32 next_index = p[0];
3990  while (next_index != (u32) ~ 0)
3991  {
3992  int (*fp) (u32, u8 *, u32, ip6_address_t *);
3993  int rv = 1;
3994  mc = pool_elt_at_index (nm->mac_changes, next_index);
3995  fp = mc->data_callback;
3996  /* Call the callback, return 1 to suppress dup events */
3997  if (fp)
3998  rv = (*fp) (mc->data,
3999  eth->src_address, sw_if_index, &ip->src_address);
4000  /* Signal the resolver process */
4001  if (rv == 0)
4003  mc->type_opaque, mc->data);
4004  next_index = mc->next_index;
4005  }
4006  }
4007 
4008  /* Check if MAC entry exsist for solicited target IP */
4009  if (ndh->icmp.type == ICMP6_neighbor_solicitation)
4010  {
4011  icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *opt;
4012  l2_bridge_domain_t *bd_config;
4013  u8 *macp;
4014 
4015  opt = (void *) (ndh + 1);
4016  if ((opt->header.type !=
4017  ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address) ||
4018  (opt->header.n_data_u64s != 1))
4019  return 0; /* source link layer address option not present */
4020 
4021  bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
4022  macp =
4023  (u8 *) hash_get_mem (bd_config->mac_by_ip6, &ndh->target_address);
4024  if (macp)
4025  { /* found ip-mac entry, generate eighbor advertisement response */
4026  int bogus_length;
4027  vlib_node_runtime_t *error_node =
4029  ip->dst_address = ip->src_address;
4030  ip->src_address = ndh->target_address;
4031  ip->hop_limit = 255;
4032  opt->header.type =
4033  ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
4034  clib_memcpy (opt->ethernet_address, macp, 6);
4035  ndh->icmp.type = ICMP6_neighbor_advertisement;
4036  ndh->advertisement_flags = clib_host_to_net_u32
4039  ndh->icmp.checksum = 0;
4040  ndh->icmp.checksum =
4041  ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip, &bogus_length);
4042  clib_memcpy (eth->dst_address, eth->src_address, 6);
4043  clib_memcpy (eth->src_address, macp, 6);
4044  vlib_error_count (vm, error_node->node_index,
4045  ICMP6_ERROR_NEIGHBOR_ADVERTISEMENTS_TX, 1);
4046  return 1;
4047  }
4048  }
4049 
4050  return 0;
4051 
4052 }
4053 
4054 void
4056 {
4058  ip6_neighbor_t *n;
4059 
4060  /* *INDENT-OFF* */
4061  pool_foreach (n, nm->neighbor_pool,
4062  ({
4063  if (n->key.sw_if_index == sw_if_index)
4064  {
4065  adj_nbr_walk_nh6 (sw_if_index,
4066  &n->key.ip6_address,
4067  ip6_nd_mk_complete_walk, n);
4068  }
4069  }));
4070  /* *INDENT-ON* */
4071 }
4072 
4073 /*
4074  * fd.io coding-style-patch-verification: ON
4075  *
4076  * Local Variables:
4077  * eval: (c-set-style "gnu")
4078  * End:
4079  */
#define ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED
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:459
fib_node_index_t fib_table_entry_update_one_path(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, fib_protocol_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, mpls_label_t *next_hop_labels, fib_route_path_flags_t path_flags)
Update the entry to have just one path.
Definition: fib_table.c:726
ip6_radv_t * if_radv_pool
Definition: ip6_neighbor.c:194
#define MIN_DELAY_BETWEEN_RAS
Definition: ip6_neighbor.c:132
#define vnet_rewrite_one_header(rw0, p0, most_likely_size)
Definition: rewrite.h:253
#define DEF_DEF_RTR_LIFETIME
Definition: ip6_neighbor.c:127
static void ip6_nd_mk_incomplete(adj_index_t ai)
Definition: ip6_neighbor.c:411
vmrglw vmrglh hi
#define pool_next_index(P, I)
Return next occupied pool index after i, useful for safe iteration.
Definition: pool.h:377
Definition: mhash.h:46
void md5_finish(md5_context_t *c, u8 *digest)
Definition: md5.c:290
#define VNET_REWRITE_FOR_SW_INTERFACE_ADDRESS_BROADCAST
Definition: rewrite.h:264
icmp6_router_solicitation_or_advertisement_next_t
u32 n_solicitations_rcvd
Definition: ip6_neighbor.c:153
static void unset_random_neighbor_entry(void)
Definition: ip6_neighbor.c:272
static void ip6_neighbor_syslog(vlib_main_t *vm, int priority, char *fmt,...)
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
#define ICMP6_ROUTER_DISCOVERY_FLAG_OTHER_CONFIG_VIA_DHCP
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
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:684
a
Definition: bitmap.h:516
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
format_function_t format_ip6_address
Definition: format.h:95
static void ip6_nbr_probe(ip_adjacency_t *adj)
Definition: ip6_neighbor.c:333
static clib_error_t * ip6_neighbor_init(vlib_main_t *vm)
f64 last_radv_time
Definition: ip6_neighbor.c:142
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
ip_interface_address_t * if_address_pool
Pool of addresses that are assigned to interfaces.
Definition: lookup.h:375
An indication that the rewrite is complete, i.e.
Definition: adj_nbr.h:98
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
u8 * va_format(u8 *s, const char *fmt, va_list *va)
Definition: format.c:386
adj_index_t all_nodes_adj_index
Definition: ip6_neighbor.c:119
static char * log_level_strings[]
static void ip6_nd_mk_complete(adj_index_t ai, ip6_neighbor_t *nbr)
Definition: ip6_neighbor.c:401
mhash_t neighbor_index_by_key
Definition: ip6_neighbor.c:190
u32 free_list_index
Buffer free list that this buffer was allocated from and will be freed to.
Definition: buffer.h:108
#define PREDICT_TRUE(x)
Definition: clib.h:98
u8 as_u8[16]
Definition: ip6_packet.h:48
u64 as_u64[2]
Definition: ip6_packet.h:51
int send_unicast
Definition: ip6_neighbor.c:111
ip6_address_t prefix
Definition: ip6_neighbor.c:42
static void vlib_error_count(vlib_main_t *vm, uword node_index, uword counter, uword increment)
Definition: error_funcs.h:55
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:275
static uword ip6_address_is_local_unicast(ip6_address_t *a)
Definition: ip6_packet.h:299
f64 last_multicast_time
Definition: ip6_neighbor.c:143
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
adj_index_t adj_rewrite_add_and_lock(fib_protocol_t nh_proto, vnet_link_t link_type, u32 sw_if_index, u8 *rewrite)
adj_rewrite_add_and_lock
Definition: adj_rewrite.c:25
void md5_init(md5_context_t *c)
Definition: md5.c:211
vnet_link_t adj_get_link_type(adj_index_t ai)
Return the link type of the adjacency.
Definition: adj.c:262
#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
u32 vlib_buffer_alloc_from_free_list(vlib_main_t *vm, u32 *buffers, u32 n_buffers, u32 free_list_index)
Allocate buffers from specific freelist into supplied array.
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:182
ip6_radv_prefix_t * adv_prefixes_pool
Definition: ip6_neighbor.c:95
IP unicast adjacency.
Definition: lookup.h:188
#define ethernet_buffer_header_size(b)
Determine the size of the Ethernet headers of the current frame in the buffer.
Definition: ethernet.h:387
u8 src_address[6]
Definition: packet.h:54
static uword ip6_address_is_global_unicast(ip6_address_t *a)
Definition: ip6_packet.h:306
ip6_neighbor_t * ip6_neighbors_entries(u32 sw_if_index)
Definition: ip6_neighbor.c:715
pending_resolution_t * pending_resolutions
Definition: ip6_neighbor.c:180
static vlib_cli_command_t set_ip6_neighbor_command
(constructor) VLIB_CLI_COMMAND (set_ip6_neighbor_command)
Definition: ip6_neighbor.c:844
#define ETHER_MAC_ADDR_LEN
Definition: ip6_neighbor.c:36
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
word vnet_sw_interface_compare(vnet_main_t *vnm, uword sw_if_index0, uword sw_if_index1)
Definition: interface.c:1109
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:424
static int logmask
#define IP6_NEIGHBOR_FLAG_DYNAMIC
Definition: ip6_neighbor.h:37
struct _vlib_node_registration vlib_node_registration_t
#define STRUCT_OFFSET_OF(t, f)
Definition: clib.h:62
u32 adv_pref_lifetime_in_secs
Definition: ip6_neighbor.c:47
#define DEF_ADV_PREF_LIFETIME
Definition: ip6_neighbor.c:60
static vnet_sw_interface_t * vnet_get_sw_interface(vnet_main_t *vnm, u32 sw_if_index)
format_function_t format_vlib_cpu_time
Definition: node_funcs.h:1107
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:84
vlib_error_t * errors
Definition: node.h:419
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:200
ip6_address_t src_address
Definition: ip6_packet.h:337
format_function_t format_vnet_sw_if_index_name
union ip_adjacency_t_::@175 sub_type
void * data_callback
Definition: arp.c:65
clib_error_t * disable_ip6_interface(vlib_main_t *vm, u32 sw_if_index)
u32 vlib_register_node(vlib_main_t *vm, vlib_node_registration_t *r)
Definition: node.c:451
static uword ip6_neighbor_process_timer_event(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
vlib_packet_template_t discover_neighbor_packet_template
Definition: ip6.h:161
ethernet_main_t ethernet_main
Definition: ethernet.h:270
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
#define VNET_BUFFER_LOCALLY_ORIGINATED
Definition: buffer.h:71
fib_node_index_t ip6_fib_table_lookup_exact_match(u32 fib_index, const ip6_address_t *addr, u32 len)
Definition: ip6_fib.c:292
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:117
#define static_always_inline
Definition: clib.h:85
u8 * format_ethernet_address(u8 *s, va_list *args)
Definition: format.c:44
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:348
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
u32 local_interface_sw_if_index
Definition: vnet.h:55
VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION(ip6_neighbor_sw_interface_up_down)
u8 link_layer_addr_len
Definition: ip6_neighbor.c:92
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:194
#define ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE
u8 dst_address[6]
Definition: packet.h:53
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:206
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:735
#define DEF_ADV_VALID_LIFETIME
Definition: ip6_neighbor.c:59
mhash_t address_to_mldp_index
Definition: ip6_neighbor.c:104
#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:145
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:64
void vl_api_rpc_call_main_thread(void *fp, u8 *data, u32 data_length)
Definition: memory_vlib.c:1268
static void unformat_free(unformat_input_t *i)
Definition: format.h:161
#define clib_warning(format, args...)
Definition: error.h:59
unsigned long u64
Definition: types.h:89
adj_index_t all_routers_adj_index
Definition: ip6_neighbor.c:120
void adj_unlock(adj_index_t adj_index)
Release a reference counting lock on the adjacency.
Definition: adj.c:209
f64 max_radv_interval
Definition: ip6_neighbor.c:136
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:977
static clib_error_t * set_ip6_neighbor(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: ip6_neighbor.c:790
u32 * neighbor_input_next_index_by_hw_if_index
Definition: ip6_neighbor.c:186
u16 fp_len
The mask length.
Definition: fib_types.h:149
u32 ip6_fib_table_get_index_for_sw_if_index(u32 sw_if_index)
Definition: ip6_fib.c:445
#define MAX_DELAY_BETWEEN_RAS
Definition: ip6_neighbor.c:133
Definition: fib_entry.h:216
f64 max_delay_between_radv
Definition: ip6_neighbor.c:139
u32 adv_time_in_msec_between_retransmitted_neighbor_solicitations
Definition: ip6_neighbor.c:85
vnet_api_error_t api_errno
Definition: vnet.h:77
Definition: fib_entry.h:221
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:369
vlib_main_t * vlib_main
Definition: vnet.h:79
f64 min_radv_interval
Definition: ip6_neighbor.c:137
void vnet_register_ip6_neighbor_resolution_event(vnet_main_t *vnm, void *address_arg, uword node_index, uword type_opaque, uword data)
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:82
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:931
Adjacency source.
Definition: fib_entry.h:88
ip46_address_t fp_addr
The address type is not deriveable from the fp_addr member.
Definition: fib_types.h:168
uword type_opaque
Definition: arp.c:62
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:646
int all_routers_mcast
Definition: ip6_neighbor.c:115
static clib_error_t * enable_ip6_interface_cmd(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
uword os_get_cpu_number(void)
Definition: unix-misc.c:224
#define DEF_MAX_RADV_INTERVAL
Definition: ip6_neighbor.c:124
#define IP6_MLDP_ALERT_TYPE
u8 link_layer_address[8]
Definition: ip6_neighbor.c:91
f64 next_multicast_time
Definition: ip6_neighbor.c:144
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:214
#define foreach_log_level
enum icmp6_neighbor_discovery_option_type icmp6_neighbor_discovery_option_type_t
#define ELOG_DATA(em, f)
Definition: elog.h:392
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, u8 shg)
#define unformat_parse_error(input)
Definition: format.h:267
int ip6_address_compare(ip6_address_t *a1, ip6_address_t *a2)
Definition: ip46_cli.c:58
#define PREDICT_FALSE(x)
Definition: clib.h:97
vnet_main_t vnet_main
Definition: misc.c:43
#define VLIB_FRAME_SIZE
Definition: node.h:328
int adv_other_flag
Definition: ip6_neighbor.c:82
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:196
mhash_t address_to_prefix_index
Definition: ip6_neighbor.c:98
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:221
#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:216
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:350
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:576
ip6_add_del_interface_address_callback_t * add_del_interface_address_callbacks
Definition: ip6.h:158
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:121
void ip6_link_local_address_from_ethernet_mac_address(ip6_address_t *ip, u8 *mac)
Definition: ip6_forward.c:2988
unformat_function_t unformat_ip6_address
Definition: format.h:94
int failed_device_check
Definition: ip6_neighbor.c:114
vlib_node_registration_t ip6_icmp_input_node
(constructor) VLIB_REGISTER_NODE (ip6_icmp_input_node)
Definition: icmp6.c:240
ip6_mldp_group_t * mldp_group_pool
Definition: ip6_neighbor.c:101
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)
Definition: ip6_neighbor.c:860
clib_error_t * enable_ip6_interface(vlib_main_t *vm, u32 sw_if_index)
icmp6_neighbor_solicitation_or_advertisement_next_t
Definition: ip6_neighbor.c:852
int adv_managed_flag
Definition: ip6_neighbor.c:81
static uword icmp6_neighbor_advertisement(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
u32 n_solicitations_dropped
Definition: ip6_neighbor.c:154
void mhash_init(mhash_t *h, uword n_value_bytes, uword n_key_bytes)
Definition: mhash.c:168
static void set_unset_ip6_neighbor_rpc(vlib_main_t *vm, u32 sw_if_index, ip6_address_t *a, u8 *link_layer_addreess, int is_add, int is_static)
Definition: ip6_neighbor.c:315
u16 n_vectors
Definition: node.h:344
static ip6_address_t ip6a_zero
Definition: ip6_neighbor.c:203
#define IP6_NEIGHBOR_FLAG_STATIC
Definition: ip6_neighbor.h:36
void fib_table_entry_delete_index(fib_node_index_t fib_entry_index, fib_source_t source)
Delete a FIB entry.
Definition: fib_table.c:831
ip6_address_t mcast_address
Definition: ip6_neighbor.c:70
log_level_t
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
u8 curr_hop_limit
Definition: ip6_neighbor.c:80
struct ip_adjacency_t_::@175::@176 nbr
IP_LOOKUP_NEXT_ARP/IP_LOOKUP_NEXT_REWRITE.
ip6_address_t * mcast_source_address_pool
Definition: ip6_neighbor.c:72
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:88
#define clib_memcpy(a, b, c)
Definition: string.h:69
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:207
#define DEF_CURR_HOP_LIMIT
Definition: ip6_neighbor.c:126
elog_main_t elog_main
Definition: main.h:141
int adv_link_layer_address
Definition: ip6_neighbor.c:112
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:28
static vlib_cli_command_t show_ip6_neighbors_command
(constructor) VLIB_CLI_COMMAND (show_ip6_neighbors_command)
Definition: ip6_neighbor.c:782
fib_node_index_t fib_entry_index
Definition: ip6_neighbor.h:39
u32 adj_index_t
An index for adjacencies.
Definition: adj_types.h:30
uword * mac_by_ip6
Definition: l2_bd.h:84
#define ELOG_TYPE_DECLARE(f)
Definition: elog.h:350
This packet matches an "incomplete adjacency" and packets need to be passed to ARP to find rewrite st...
Definition: lookup.h:73
void md5_add(md5_context_t *c, void *data, int data_bytes)
Definition: md5.c:235
u64 cpu_time_last_updated
Definition: ip6_neighbor.h:38
static void * ip6_next_header(ip6_header_t *i)
Definition: ip6_packet.h:341
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
adj_index_t all_mldv2_routers_adj_index
Definition: ip6_neighbor.c:121
#define VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX
Definition: buffer.h:310
u32 initial_adverts_count
Definition: ip6_neighbor.c:147
u32 * if_address_pool_index_by_sw_if_index
Head of doubly linked list of interface addresses for each software interface.
Definition: lookup.h:382
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:1141
ip6_add_del_interface_address_function_t * function
Definition: ip6.h:89
#define MAX_INITIAL_RTR_ADVERTISEMENTS
Definition: ip6_neighbor.c:131
u16 cached_next_index
Definition: node.h:463
ip6_address_t link_local_address
Definition: ip6_neighbor.c:157
#define VNET_SW_INTERFACE_FLAG_ADMIN_UP
Definition: interface.h:528
u32 max_l3_packet_bytes[VLIB_N_RX_TX]
Definition: interface.h:449
uword unformat_ethernet_address(unformat_input_t *input, va_list *args)
Definition: format.c:245
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
int prefix_option
Definition: ip6_neighbor.c:113
static uword * mhash_get(mhash_t *h, const void *key)
Definition: mhash.h:110
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
#define vnet_buffer(b)
Definition: buffer.h:361
ip6_address_t ip6_address
Definition: ip6_neighbor.h:26
ip6_main_t ip6_main
Definition: ip6_forward.c:2828
ip_lookup_main_t lookup_main
Definition: ip6.h:135
u32 n_advertisements_sent
Definition: ip6_neighbor.c:152
static clib_error_t * show_ip6_interface_cmd(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
f64 min_delay_between_radv
Definition: ip6_neighbor.c:138
#define DEF_MIN_RADV_INTERVAL
Definition: ip6_neighbor.c:125
static_always_inline uword icmp6_router_solicitation(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
static int ip6_neighbor_sort(void *a1, void *a2)
Definition: ip6_neighbor.c:702
u32 vlib_buffer_add_data(vlib_main_t *vm, u32 free_list_index, u32 buffer_index, void *data, u32 n_data_bytes)
u32 * if_radv_pool_index_by_sw_if_index
Definition: ip6_neighbor.c:192
u16 adv_router_lifetime_in_sec
Definition: ip6_neighbor.c:83
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:259
Route added as a result of interface configuration.
Definition: fib_entry.h:50
mhash_t pending_resolutions_by_address
Definition: ip6_neighbor.c:179
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:461
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:95
static uword vnet_sw_interface_is_admin_up(vnet_main_t *vnm, u32 sw_if_index)
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
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)
Definition: ip6_neighbor.c:509
u32 ip_version_traffic_class_and_flow_label
Definition: ip6_packet.h:324
vlib_node_t * vlib_get_node_by_name(vlib_main_t *vm, u8 *name)
Definition: node.c:45
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)
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:87
vlib_node_registration_t ip6_icmp_neighbor_discovery_event_node
u16 payload_length
Definition: ip6_packet.h:328
static void * vlib_process_get_event_data(vlib_main_t *vm, uword *return_event_type_opaque)
Definition: node_funcs.h:473
static void ip6_neighbor_set_unset_rpc_callback(ip6_neighbor_set_unset_rpc_args_t *a)
Definition: ip6_neighbor.c:690
ethernet_interface_t * ethernet_get_interface(ethernet_main_t *em, u32 hw_if_index)
Definition: interface.c:563
static void ip6_set_solicited_node_multicast_address(ip6_address_t *a, u32 id)
Definition: ip6_packet.h:164
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:29
ip6_neighbor_key_t key
Definition: ip6_neighbor.h:33
static uword ip6_address_is_link_local_unicast(ip6_address_t *a)
Definition: ip6_packet.h:292
u32 elog_string(elog_main_t *em, char *fmt,...)
Definition: elog.c:525
void icmp6_register_type(vlib_main_t *vm, icmp6_type_t type, u32 node_index)
Definition: icmp6.c:803
#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
Definition: lookup.h:199
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:920
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)
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:253
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:59
l2_bridge_domain_t * bd_configs
Definition: l2_input.h:69
#define ICMP6_ROUTER_DISCOVERY_FLAG_ADDRESS_CONFIG_VIA_DHCP
clib_error_t * set_ip6_link_local_address(vlib_main_t *vm, u32 sw_if_index, ip6_address_t *address, u8 address_length)
#define hash_get_mem(h, key)
Definition: hash.h:268
static u32 ip6_neighbor_sw_interface_add_del(vnet_main_t *vnm, u32 sw_if_index, u32 is_add)
static vlib_node_registration_t ip6_icmp_neighbor_advertisement_node
(constructor) VLIB_REGISTER_NODE (ip6_icmp_neighbor_advertisement_node)
void * vlib_packet_template_get_packet(vlib_main_t *vm, vlib_packet_template_t *t, u32 *bi_result)
static clib_error_t * ip6_neighbor_sw_interface_up_down(vnet_main_t *vnm, u32 sw_if_index, u32 flags)
Definition: ip6_neighbor.c:237
f64 initial_adverts_interval
Definition: ip6_neighbor.c:148
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
static u32 random_u32(u32 *seed)
32-bit random number generator
Definition: random.h:69
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
vnet_sw_interface_type_t type
Definition: interface.h:523
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
uword node_index
Definition: arp.c:61
This packet is to be rewritten and forwarded to the next processing node.
Definition: lookup.h:83
#define vec_foreach(var, vec)
Vector iterator.
static uword ip6_address_is_unspecified(ip6_address_t *a)
Definition: ip6_packet.h:273
void ip6_ethernet_update_adjacency(vnet_main_t *vnm, u32 sw_if_index, u32 ai)
Definition: ip6_neighbor.c:469
u32 adv_valid_lifetime_in_secs
Definition: ip6_neighbor.c:46
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:445
vhost_vring_addr_t addr
Definition: vhost-user.h:81
#define clib_error_return(e, args...)
Definition: error.h:111
struct _unformat_input_t unformat_input_t
u32 initial_adverts_sent
Definition: ip6_neighbor.c:149
static void * ip_interface_address_get_address(ip_lookup_main_t *lm, ip_interface_address_t *a)
Definition: lookup.h:453
static ip6_neighbor_t * ip6_nd_find(u32 sw_if_index, const ip6_address_t *addr)
Definition: ip6_neighbor.c:432
mhash_t mac_changes_by_address
Definition: ip6_neighbor.c:183
static void ip6_link_local_address_from_ethernet_address(ip6_address_t *a, u8 *ethernet_address)
Definition: ip6_packet.h:176
static adj_walk_rc_t ip6_nd_mk_complete_walk(adj_index_t ai, void *ctx)
Definition: ip6_neighbor.c:451
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:187
#define MAX_INITIAL_RTR_ADVERT_INTERVAL
Definition: ip6_neighbor.c:130
u32 flags
Definition: vhost-user.h:75
#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:445
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:85
clib_error_t * ip6_neighbor_cmd(vlib_main_t *vm, unformat_input_t *main_input, vlib_cli_command_t *cmd)
f64 max_rtr_default_lifetime
Definition: ip6_neighbor.c:140
unformat_function_t unformat_line_input
Definition: format.h:281
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:188
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:252
u32 * fib_index_by_sw_if_index
Definition: ip6.h:144
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:34
static_always_inline uword icmp6_router_advertisement(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
#define MAX_DEF_RTR_LIFETIME
Definition: ip6_neighbor.c:128
u32 adv_link_mtu
Definition: ip6_neighbor.c:88
Definition: defs.h:46
static ip6_neighbor_main_t ip6_neighbor_main
Definition: ip6_neighbor.c:202
pending_resolution_t * mac_changes
Definition: ip6_neighbor.c:184
ip6_address_t dst_address
Definition: ip6_packet.h:337
int ip6_interface_enabled(vlib_main_t *vm, u32 sw_if_index)
static void ip6_set_reserved_multicast_address(ip6_address_t *a, ip6_multicast_address_scope_t scope, u16 id)
Definition: ip6_packet.h:154
static ip_adjacency_t * ip_get_adjacency(ip_lookup_main_t *lm, u32 adj_index)
Definition: lookup.h:415
clib_error_t * ip6_set_neighbor_limit(u32 neighbor_limit)
format_function_t format_icmp6_input_trace
Definition: icmp6.h:68
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:605
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:109