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