LCOV - code coverage report
Current view: top level - vnet/ip6-nd - ip6_ra.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 592 852 69.5 %
Date: 2023-07-05 22:20:52 Functions: 36 41 87.8 %

          Line data    Source code
       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/ip6-nd/ip6_ra.h>
      19             : 
      20             : #include <vnet/ip/ip.h>
      21             : #include <vnet/ip-neighbor/ip_neighbor_dp.h>
      22             : 
      23             : #include <vnet/fib/ip6_fib.h>
      24             : #include <vnet/ip/ip6_link.h>
      25             : 
      26             : /**
      27             :  * @file
      28             :  * @brief IPv6 Router Advertisements.
      29             :  *
      30             :  * The files contains the API and CLI code for managing IPv6 RAs
      31             :  */
      32             : 
      33             : /* *INDENT-OFF* */
      34             : /* Router solicitation packet format for ethernet. */
      35             : typedef CLIB_PACKED (struct
      36             : {
      37             :     ip6_header_t ip;
      38             :     icmp6_neighbor_discovery_header_t neighbor;
      39             :     icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
      40             :     link_layer_option;
      41             : }) icmp6_router_solicitation_header_t;
      42             : 
      43             : /* router advertisement packet format for ethernet. */
      44             : typedef CLIB_PACKED (struct
      45             : {
      46             :   ip6_header_t ip;
      47             :   icmp6_router_advertisement_header_t router;
      48             :   icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
      49             :   link_layer_option;
      50             :   icmp6_neighbor_discovery_mtu_option_t mtu_option;
      51             :   icmp6_neighbor_discovery_prefix_information_option_t
      52             :   prefix[0];
      53             : }) icmp6_router_advertisement_packet_t;
      54             : /* *INDENT-ON* */
      55             : 
      56             : #define DEF_MAX_RADV_INTERVAL 200
      57             : #define DEF_MIN_RADV_INTERVAL .75 * DEF_MAX_RADV_INTERVAL
      58             : #define DEF_CURR_HOP_LIMIT  64
      59             : #define DEF_DEF_RTR_LIFETIME   3 * DEF_MAX_RADV_INTERVAL
      60             : #define MAX_DEF_RTR_LIFETIME   9000
      61             : 
      62             : #define MAX_INITIAL_RTR_ADVERT_INTERVAL   16    /* seconds */
      63             : #define MAX_INITIAL_RTR_ADVERTISEMENTS        3 /*transmissions */
      64             : #define MIN_DELAY_BETWEEN_RAS                              3    /* seconds */
      65             : #define MAX_DELAY_BETWEEN_RAS                    1800   /* seconds */
      66             : #define MAX_RA_DELAY_TIME                                          .5   /* seconds */
      67             : 
      68             : static ip6_link_delegate_id_t ip6_ra_delegate_id;
      69             : static ip6_ra_t *ip6_ra_pool;
      70             : 
      71             : 
      72             : /* vector of registered RA report listeners */
      73             : static ip6_ra_report_notify_t *ip6_ra_listeners;
      74             : 
      75             : static int ip6_ra_publish (ip6_ra_report_t * r);
      76             : 
      77             : void
      78         560 : ip6_ra_report_register (ip6_ra_report_notify_t fn)
      79             : {
      80             :   ip6_ra_report_notify_t *listener;
      81         561 :   vec_foreach (listener, ip6_ra_listeners)
      82             :   {
      83           1 :     if (*listener == fn)
      84           0 :       return;
      85             :   }
      86             : 
      87         560 :   vec_add1 (ip6_ra_listeners, fn);
      88             : }
      89             : 
      90             : void
      91           0 : ip6_ra_report_unregister (ip6_ra_report_notify_t fn)
      92             : {
      93             :   u32 ii;
      94             : 
      95           0 :   vec_foreach_index (ii, ip6_ra_listeners)
      96             :   {
      97           0 :     if (ip6_ra_listeners[ii] == fn)
      98             :       {
      99           0 :         vec_del1 (ip6_ra_listeners, ii);
     100           0 :         break;
     101             :       }
     102             :   }
     103           0 : }
     104             : 
     105             : ip6_ra_t *
     106        1948 : ip6_ra_get_itf (u32 sw_if_index)
     107             : {
     108             :   index_t rai;
     109             : 
     110        1948 :   rai = ip6_link_delegate_get (sw_if_index, ip6_ra_delegate_id);
     111             : 
     112        1948 :   if (INDEX_INVALID != rai)
     113        1946 :     return (pool_elt_at_index (ip6_ra_pool, rai));
     114             : 
     115           2 :   return (NULL);
     116             : }
     117             : 
     118             : u8
     119        1638 : ip6_ra_adv_enabled (u32 sw_if_index)
     120             : {
     121             :   ip6_ra_t *ra;
     122             : 
     123        1638 :   ra = ip6_ra_get_itf (sw_if_index);
     124             : 
     125        1638 :   return ((ra != NULL) && (ra->send_radv != 0));
     126             : }
     127             : 
     128             : void
     129           1 : ip6_ra_itf_walk (ip6_ra_itf_walk_fn_t fn, void *ctx)
     130             : {
     131             :   ip6_ra_t *radv_info;
     132             : 
     133           6 :   pool_foreach (radv_info, ip6_ra_pool)
     134             :     {
     135           5 :       if (WALK_STOP == fn (radv_info->sw_if_index, ctx))
     136           0 :         break;
     137             :     }
     138           1 : }
     139             : 
     140             : /* for "syslogging" - use elog for now */
     141             : #define foreach_log_level            \
     142             :   _ (DEBUG, "DEBUG")                 \
     143             :   _ (INFO, "INFORMATION")          \
     144             :   _ (NOTICE, "NOTICE")                     \
     145             :   _ (WARNING, "WARNING")             \
     146             :   _ (ERR, "ERROR")                 \
     147             :   _ (CRIT, "CRITICAL")               \
     148             :   _ (ALERT, "ALERT")                 \
     149             :   _ (EMERG,  "EMERGENCY")
     150             : 
     151             : typedef enum
     152             : {
     153             : #define _(f,s) LOG_##f,
     154             :   foreach_log_level
     155             : #undef _
     156             : } log_level_t;
     157             : 
     158             : static char *log_level_strings[] = {
     159             : #define _(f,s) s,
     160             :   foreach_log_level
     161             : #undef _
     162             : };
     163             : 
     164             : static int logmask = 1 << LOG_DEBUG;
     165             : 
     166             : static void
     167           0 : ip6_neighbor_syslog (vlib_main_t * vm, int priority, char *fmt, ...)
     168             : {
     169             :   /* just use elog for now */
     170             :   u8 *what;
     171             :   va_list va;
     172             : 
     173           0 :   if ((priority > LOG_EMERG) || !(logmask & (1 << priority)))
     174           0 :     return;
     175             : 
     176           0 :   va_start (va, fmt);
     177           0 :   if (fmt)
     178             :     {
     179           0 :       what = va_format (0, fmt, &va);
     180             : 
     181             :       ELOG_TYPE_DECLARE (e) =
     182             :       {
     183             :       .format = "ip6 nd:  (%s): %s",.format_args = "T4T4",};
     184             :       struct
     185             :       {
     186             :         u32 s[2];
     187             :       } *ed;
     188           0 :       ed = ELOG_DATA (vlib_get_elog_main (), e);
     189           0 :       ed->s[0] =
     190           0 :         elog_string (vlib_get_elog_main (), log_level_strings[priority]);
     191           0 :       ed->s[1] = elog_string (vlib_get_elog_main (), (char *) what);
     192             :     }
     193           0 :   va_end (va);
     194           0 :   return;
     195             : }
     196             : 
     197             : /* ipv6 neighbor discovery - router advertisements */
     198             : typedef enum
     199             : {
     200             :   ICMP6_ROUTER_SOLICITATION_NEXT_DROP,
     201             :   ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW,
     202             :   ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX,
     203             :   ICMP6_ROUTER_SOLICITATION_N_NEXT,
     204             : } icmp6_router_solicitation_or_advertisement_next_t;
     205             : 
     206             : /*
     207             :  * Note: Both periodic RAs and solicited RS come through here.
     208             :  */
     209             : static_always_inline uword
     210         110 : icmp6_router_solicitation (vlib_main_t * vm,
     211             :                            vlib_node_runtime_t * node, vlib_frame_t * frame)
     212             : {
     213         110 :   vnet_main_t *vnm = vnet_get_main ();
     214         110 :   ip6_main_t *im = &ip6_main;
     215         110 :   uword n_packets = frame->n_vectors;
     216             :   u32 *from, *to_next;
     217             :   u32 n_left_from, n_left_to_next, next_index;
     218         110 :   u32 n_advertisements_sent = 0;
     219             :   int bogus_length;
     220             : 
     221             :   icmp6_neighbor_discovery_option_type_t option_type;
     222             : 
     223             :   vlib_node_runtime_t *error_node =
     224         110 :     vlib_node_get_runtime (vm, ip6_icmp_input_node.index);
     225             : 
     226         110 :   from = vlib_frame_vector_args (frame);
     227         110 :   n_left_from = n_packets;
     228         110 :   next_index = node->cached_next_index;
     229             : 
     230         110 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
     231          17 :     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
     232             :                                    /* stride */ 1,
     233             :                                    sizeof (icmp6_input_trace_t));
     234             : 
     235             :   /* source may append his LL address */
     236         110 :   option_type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
     237             : 
     238         220 :   while (n_left_from > 0)
     239             :     {
     240         110 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     241             : 
     242         220 :       while (n_left_from > 0 && n_left_to_next > 0)
     243             :         {
     244             :           vlib_buffer_t *p0;
     245             :           ip6_header_t *ip0;
     246         110 :           ip6_ra_t *radv_info = NULL;
     247             : 
     248             :           icmp6_neighbor_discovery_header_t *h0;
     249             :           icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *o0;
     250             : 
     251             :           u32 bi0, options_len0, sw_if_index0, next0, error0;
     252         110 :           u32 is_solicitation = 1, is_dropped = 0;
     253             :           u32 is_unspecified, is_link_local;
     254             : 
     255         110 :           bi0 = to_next[0] = from[0];
     256             : 
     257         110 :           from += 1;
     258         110 :           to_next += 1;
     259         110 :           n_left_from -= 1;
     260         110 :           n_left_to_next -= 1;
     261             : 
     262         110 :           p0 = vlib_get_buffer (vm, bi0);
     263         110 :           ip0 = vlib_buffer_get_current (p0);
     264         110 :           h0 = ip6_next_header (ip0);
     265         110 :           options_len0 =
     266         110 :             clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
     267         110 :           is_unspecified = ip6_address_is_unspecified (&ip0->src_address);
     268         110 :           is_link_local =
     269         110 :             ip6_address_is_link_local_unicast (&ip0->src_address);
     270             : 
     271         110 :           error0 = ICMP6_ERROR_NONE;
     272         110 :           sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
     273             : 
     274             :           /* check if solicitation  (not from nd_timer node) */
     275         110 :           if (ip6_address_is_unspecified (&ip0->dst_address))
     276           3 :             is_solicitation = 0;
     277             : 
     278             :           /* Check that source address is unspecified, link-local or else on-link. */
     279         110 :           if (!is_unspecified && !is_link_local)
     280             :             {
     281           4 :               u32 src_adj_index0 = ip6_src_lookup_for_packet (im, p0, ip0);
     282             : 
     283           4 :               if (ADJ_INDEX_INVALID != src_adj_index0)
     284             :                 {
     285           3 :                   ip_adjacency_t *adj0 = adj_get (src_adj_index0);
     286             : 
     287           3 :                   error0 = (adj0->rewrite_header.sw_if_index != sw_if_index0
     288             :                             ?
     289             :                             ICMP6_ERROR_ROUTER_SOLICITATION_SOURCE_NOT_ON_LINK
     290           3 :                             : error0);
     291             :                 }
     292             :               else
     293             :                 {
     294           1 :                   error0 = ICMP6_ERROR_ROUTER_SOLICITATION_SOURCE_NOT_ON_LINK;
     295             :                 }
     296             :             }
     297             : 
     298             :           /* check for source LL option and process */
     299         110 :           o0 = (void *) (h0 + 1);
     300         110 :           o0 = ((options_len0 == 8
     301          79 :                  && o0->header.type == option_type
     302         189 :                  && o0->header.n_data_u64s == 1) ? o0 : 0);
     303             : 
     304             :           /* if src address unspecified IGNORE any options */
     305         110 :           if (PREDICT_TRUE (error0 == ICMP6_ERROR_NONE && o0 != 0 &&
     306             :                             !is_unspecified && !is_link_local))
     307             :             {
     308             :               /* *INDENT-OFF* */
     309           0 :               ip_neighbor_learn_t learn = {
     310             :                 .sw_if_index = sw_if_index0,
     311             :                 .ip = {
     312             :                   .ip.ip6 = ip0->src_address,
     313             :                   .version = AF_IP6,
     314             :                 },
     315             :               };
     316             :               /* *INDENT-ON* */
     317           0 :               memcpy (&learn.mac, o0->ethernet_address, sizeof (learn.mac));
     318           0 :               ip_neighbor_learn_dp (&learn);
     319             :             }
     320             : 
     321             :           /* default is to drop */
     322         110 :           next0 = ICMP6_ROUTER_SOLICITATION_NEXT_DROP;
     323             : 
     324         110 :           if (error0 == ICMP6_ERROR_NONE)
     325             :             {
     326             :               vnet_sw_interface_t *sw_if0;
     327             :               ethernet_interface_t *eth_if0;
     328             :               u32 adj_index0;
     329             : 
     330         109 :               sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
     331         109 :               ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
     332             :               eth_if0 =
     333         109 :                 ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
     334             : 
     335             :               /* only support ethernet interface type for now */
     336         109 :               error0 =
     337             :                 (!eth_if0) ? ICMP6_ERROR_ROUTER_SOLICITATION_UNSUPPORTED_INTF
     338         109 :                 : error0;
     339             : 
     340         109 :               if (error0 == ICMP6_ERROR_NONE)
     341             :                 {
     342             :                   /* adjust the sizeof the buffer to just include the ipv6 header */
     343          95 :                   p0->current_length -=
     344             :                     (options_len0 +
     345             :                      sizeof (icmp6_neighbor_discovery_header_t));
     346             : 
     347          95 :                   radv_info = ip6_ra_get_itf (sw_if_index0);
     348             : 
     349          95 :                   error0 = ((!radv_info || 0 == radv_info->send_radv) ?
     350         190 :                               ICMP6_ERROR_ROUTER_SOLICITATION_RADV_NOT_CONFIG :
     351             :                               error0);
     352          95 :                   if (error0 == ICMP6_ERROR_NONE)
     353             :                     {
     354          18 :                       f64 now = vlib_time_now (vm);
     355             : 
     356             :                       /* for solicited adverts - need to rate limit */
     357          18 :                       if (is_solicitation)
     358             :                         {
     359          15 :                           if (0 != radv_info->last_radv_time &&
     360           1 :                               (now - radv_info->last_radv_time) <
     361             :                               MIN_DELAY_BETWEEN_RAS)
     362           1 :                             is_dropped = 1;
     363             :                           else
     364          14 :                             radv_info->last_radv_time = now;
     365             :                         }
     366             : 
     367             :                       /* send now  */
     368             :                       icmp6_router_advertisement_header_t rh;
     369             : 
     370          18 :                       rh.icmp.type = ICMP6_router_advertisement;
     371          18 :                       rh.icmp.code = 0;
     372          18 :                       rh.icmp.checksum = 0;
     373             : 
     374          18 :                       rh.current_hop_limit = radv_info->curr_hop_limit;
     375          18 :                       rh.router_lifetime_in_sec =
     376          18 :                         clib_host_to_net_u16
     377          18 :                         (radv_info->adv_router_lifetime_in_sec);
     378             :                       rh.
     379             :                         time_in_msec_between_retransmitted_neighbor_solicitations
     380          18 :                         =
     381          18 :                         clib_host_to_net_u32 (radv_info->
     382             :                                               adv_time_in_msec_between_retransmitted_neighbor_solicitations);
     383          18 :                       rh.neighbor_reachable_time_in_msec =
     384          18 :                         clib_host_to_net_u32 (radv_info->
     385             :                                               adv_neighbor_reachable_time_in_msec);
     386             : 
     387          18 :                       rh.flags =
     388          18 :                         (radv_info->adv_managed_flag) ?
     389             :                         ICMP6_ROUTER_DISCOVERY_FLAG_ADDRESS_CONFIG_VIA_DHCP :
     390             :                         0;
     391          18 :                       rh.flags |=
     392          18 :                         ((radv_info->adv_other_flag) ?
     393             :                          ICMP6_ROUTER_DISCOVERY_FLAG_OTHER_CONFIG_VIA_DHCP :
     394             :                          0);
     395             : 
     396             : 
     397          18 :                       u16 payload_length =
     398             :                         sizeof (icmp6_router_advertisement_header_t);
     399             : 
     400          18 :                       if (vlib_buffer_add_data
     401             :                           (vm, &bi0, (void *) &rh,
     402             :                            sizeof (icmp6_router_advertisement_header_t)))
     403             :                         {
     404             :                           /* buffer allocation failed, drop the pkt */
     405           0 :                           error0 = ICMP6_ERROR_ALLOC_FAILURE;
     406           0 :                           goto drop0;
     407             :                         }
     408             : 
     409          18 :                       if (radv_info->adv_link_layer_address)
     410             :                         {
     411             :                           icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
     412             :                             h;
     413             : 
     414          18 :                           h.header.type =
     415             :                             ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
     416          18 :                           h.header.n_data_u64s = 1;
     417             : 
     418             :                           /* copy ll address */
     419          18 :                           clib_memcpy (&h.ethernet_address[0],
     420             :                                        &eth_if0->address, 6);
     421             : 
     422          18 :                           if (vlib_buffer_add_data
     423             :                               (vm, &bi0, (void *) &h,
     424             :                                sizeof
     425             :                                (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t)))
     426             :                             {
     427           0 :                               error0 = ICMP6_ERROR_ALLOC_FAILURE;
     428           0 :                               goto drop0;
     429             :                             }
     430             : 
     431          18 :                           payload_length +=
     432             :                             sizeof
     433             :                             (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t);
     434             :                         }
     435             : 
     436             :                       /* add MTU option */
     437          18 :                       if (radv_info->adv_link_mtu)
     438             :                         {
     439             :                           icmp6_neighbor_discovery_mtu_option_t h;
     440             : 
     441          18 :                           h.unused = 0;
     442          18 :                           h.mtu =
     443          18 :                             clib_host_to_net_u32 (radv_info->adv_link_mtu);
     444          18 :                           h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_mtu;
     445          18 :                           h.header.n_data_u64s = 1;
     446             : 
     447          18 :                           payload_length +=
     448             :                             sizeof (icmp6_neighbor_discovery_mtu_option_t);
     449             : 
     450          18 :                           if (vlib_buffer_add_data
     451             :                               (vm, &bi0, (void *) &h,
     452             :                                sizeof
     453             :                                (icmp6_neighbor_discovery_mtu_option_t)))
     454             :                             {
     455           0 :                               error0 = ICMP6_ERROR_ALLOC_FAILURE;
     456           0 :                               goto drop0;
     457             :                             }
     458             :                         }
     459             : 
     460             :                       /* add advertised prefix options  */
     461             :                       ip6_radv_prefix_t *pr_info;
     462             : 
     463             :                       /* *INDENT-OFF* */
     464          29 :                       pool_foreach (pr_info, radv_info->adv_prefixes_pool)
     465             :                        {
     466          11 :                         if(pr_info->enabled &&
     467          11 :                            (!pr_info->decrement_lifetime_flag
     468           0 :                             || (pr_info->pref_lifetime_expires >0)))
     469             :                           {
     470             :                             /* advertise this prefix */
     471             :                             icmp6_neighbor_discovery_prefix_information_option_t h;
     472             : 
     473          11 :                             h.header.type = ICMP6_NEIGHBOR_DISCOVERY_OPTION_prefix_information;
     474          11 :                             h.header.n_data_u64s  =  (sizeof(icmp6_neighbor_discovery_prefix_information_option_t) >> 3);
     475             : 
     476          11 :                             h.dst_address_length  = pr_info->prefix_len;
     477             : 
     478          11 :                             h.flags  = (pr_info->adv_on_link_flag) ? ICMP6_NEIGHBOR_DISCOVERY_PREFIX_INFORMATION_FLAG_ON_LINK : 0;
     479          11 :                             h.flags |= (pr_info->adv_autonomous_flag) ?  ICMP6_NEIGHBOR_DISCOVERY_PREFIX_INFORMATION_AUTO :  0;
     480             : 
     481          11 :                             if(radv_info->cease_radv && pr_info->deprecated_prefix_flag)
     482             :                               {
     483           0 :                                 h.valid_time = clib_host_to_net_u32(MIN_ADV_VALID_LIFETIME);
     484           0 :                                 h.preferred_time  = 0;
     485             :                               }
     486             :                             else
     487             :                               {
     488          11 :                                 if(pr_info->decrement_lifetime_flag)
     489             :                                   {
     490           0 :                                     pr_info->adv_valid_lifetime_in_secs = ((pr_info->valid_lifetime_expires  > now)) ?
     491           0 :                                       (pr_info->valid_lifetime_expires  - now) : 0;
     492             : 
     493           0 :                                     pr_info->adv_pref_lifetime_in_secs = ((pr_info->pref_lifetime_expires  > now)) ?
     494           0 :                                       (pr_info->pref_lifetime_expires  - now) : 0;
     495             :                                   }
     496             : 
     497          11 :                                 h.valid_time = clib_host_to_net_u32(pr_info->adv_valid_lifetime_in_secs);
     498          11 :                                 h.preferred_time  = clib_host_to_net_u32(pr_info->adv_pref_lifetime_in_secs) ;
     499             :                               }
     500          11 :                             h.unused  = 0;
     501             : 
     502             :                             /* Handy for debugging, but too noisy... */
     503             :                             if (0 && CLIB_DEBUG > 0)
     504             :                               clib_warning
     505             :                                 ("send RA for prefix %U/%d "
     506             :                                  "sw_if_index %d valid %u preferred %u",
     507             :                                  format_ip6_address, &pr_info->prefix,
     508             :                                  pr_info->prefix_len, sw_if_index0,
     509             :                                  clib_net_to_host_u32 (h.valid_time),
     510             :                                  clib_net_to_host_u32 (h.preferred_time));
     511             : 
     512          11 :                             if (h.valid_time == 0)
     513           0 :                               clib_warning ("BUG: send RA with valid_time 0");
     514             : 
     515          11 :                             clib_memcpy(&h.dst_address, &pr_info->prefix,  sizeof(ip6_address_t));
     516             : 
     517          11 :                             payload_length += sizeof( icmp6_neighbor_discovery_prefix_information_option_t);
     518             : 
     519          11 :                             if (vlib_buffer_add_data
     520             :                                 (vm, &bi0, (void *)&h,
     521             :                                  sizeof(icmp6_neighbor_discovery_prefix_information_option_t)))
     522             :                               {
     523           0 :                                 error0 = ICMP6_ERROR_ALLOC_FAILURE;
     524           0 :                                 goto drop0;
     525             :                               }
     526             : 
     527             :                           }
     528             :                       }
     529             :                       /* *INDENT-ON* */
     530             : 
     531             :                       /* add additional options before here */
     532             : 
     533             :                       /* finish building the router advertisement... */
     534          18 :                       if (!is_unspecified && radv_info->send_unicast)
     535             :                         {
     536          14 :                           ip0->dst_address = ip0->src_address;
     537             :                         }
     538             :                       else
     539             :                         {
     540             :                           /* target address is all-nodes mcast addr */
     541           4 :                           ip6_set_reserved_multicast_address
     542             :                             (&ip0->dst_address,
     543             :                              IP6_MULTICAST_SCOPE_link_local,
     544             :                              IP6_MULTICAST_GROUP_ID_all_hosts);
     545             :                         }
     546             : 
     547             :                       /* source address MUST be the link-local address */
     548          18 :                       ip6_address_copy (&ip0->src_address,
     549             :                                         ip6_get_link_local_address
     550             :                                         (radv_info->sw_if_index));
     551             : 
     552          18 :                       ip0->hop_limit = 255;
     553          18 :                       ip0->payload_length =
     554          18 :                         clib_host_to_net_u16 (payload_length);
     555             : 
     556          18 :                       icmp6_router_advertisement_header_t *rh0 =
     557             :                         (icmp6_router_advertisement_header_t *) (ip0 + 1);
     558          18 :                       rh0->icmp.checksum =
     559          18 :                         ip6_tcp_udp_icmp_compute_checksum (vm, p0, ip0,
     560             :                                                            &bogus_length);
     561          18 :                       ASSERT (bogus_length == 0);
     562             : 
     563             :                       /* setup output if and adjacency */
     564          18 :                       vnet_buffer (p0)->sw_if_index[VLIB_RX] =
     565          18 :                         vnet_main.local_interface_sw_if_index;
     566             : 
     567          18 :                       if (is_solicitation)
     568             :                         {
     569             :                           ethernet_header_t *eth0;
     570             :                           /* Reuse current MAC header, copy SMAC to DMAC and
     571             :                            * interface MAC to SMAC */
     572          15 :                           vlib_buffer_reset (p0);
     573          15 :                           vlib_buffer_advance (
     574          15 :                             p0, vnet_buffer (p0)->l2_hdr_offset);
     575          15 :                           eth0 = vlib_buffer_get_current (p0);
     576          15 :                           clib_memcpy (eth0->dst_address, eth0->src_address,
     577             :                                        6);
     578          15 :                           clib_memcpy (eth0->src_address, &eth_if0->address,
     579             :                                        6);
     580          15 :                           next0 =
     581          15 :                             is_dropped ? next0 :
     582             :                             ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX;
     583          15 :                           vnet_buffer (p0)->sw_if_index[VLIB_TX] =
     584             :                             sw_if_index0;
     585             :                         }
     586             :                       else
     587             :                         {
     588           3 :                           adj_index0 = ip6_link_get_mcast_adj (sw_if_index0);
     589           3 :                           if (adj_index0 == INDEX_INVALID)
     590           0 :                             error0 = ICMP6_ERROR_DST_LOOKUP_MISS;
     591             :                           else
     592             :                             {
     593           3 :                               next0 =
     594           3 :                                 is_dropped ? next0 :
     595             :                                 ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW;
     596           3 :                               vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
     597             :                                 adj_index0;
     598             :                             }
     599             :                         }
     600          18 :                       p0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
     601             : 
     602          18 :                       radv_info->n_solicitations_dropped += is_dropped;
     603          18 :                       radv_info->n_solicitations_rcvd += is_solicitation;
     604             : 
     605          18 :                       if ((error0 == ICMP6_ERROR_NONE) && !is_dropped)
     606             :                         {
     607          17 :                           radv_info->n_advertisements_sent++;
     608          17 :                           n_advertisements_sent++;
     609             :                         }
     610             :                     }
     611             :                 }
     612             :             }
     613             : 
     614          92 :         drop0:
     615         110 :           p0->error = error_node->errors[error0];
     616             : 
     617         110 :           if (error0 != ICMP6_ERROR_NONE)
     618          92 :             vlib_error_count (vm, error_node->node_index, error0, 1);
     619             : 
     620         110 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     621             :                                            to_next, n_left_to_next,
     622             :                                            bi0, next0);
     623             : 
     624             :         }
     625             : 
     626         110 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     627             :     }
     628             : 
     629             :   /* Account for router advertisements sent. */
     630         110 :   vlib_error_count (vm, error_node->node_index,
     631             :                     ICMP6_ERROR_ROUTER_ADVERTISEMENTS_TX,
     632             :                     n_advertisements_sent);
     633             : 
     634         110 :   return frame->n_vectors;
     635             : }
     636             : 
     637             : /* *INDENT-OFF* */
     638      178120 : VLIB_REGISTER_NODE (ip6_icmp_router_solicitation_node,static) =
     639             : {
     640             :   .function = icmp6_router_solicitation,
     641             :   .name = "icmp6-router-solicitation",
     642             : 
     643             :   .vector_size = sizeof (u32),
     644             : 
     645             :   .format_trace = format_icmp6_input_trace,
     646             : 
     647             :   .n_next_nodes = ICMP6_ROUTER_SOLICITATION_N_NEXT,
     648             :   .next_nodes = {
     649             :     [ICMP6_ROUTER_SOLICITATION_NEXT_DROP] = "ip6-drop",
     650             :     [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_RW] = "ip6-rewrite-mcast",
     651             :     [ICMP6_ROUTER_SOLICITATION_NEXT_REPLY_TX] = "interface-output",
     652             :   },
     653             : };
     654             : /* *INDENT-ON* */
     655             : 
     656             :  /* validate advertised info for consistancy (see RFC-4861 section 6.2.7) - log any inconsistencies, packet will always  be dropped  */
     657             : static_always_inline uword
     658           5 : icmp6_router_advertisement (vlib_main_t * vm,
     659             :                             vlib_node_runtime_t * node, vlib_frame_t * frame)
     660             : {
     661           5 :   vnet_main_t *vnm = vnet_get_main ();
     662           5 :   uword n_packets = frame->n_vectors;
     663             :   u32 *from, *to_next;
     664             :   u32 n_left_from, n_left_to_next, next_index;
     665           5 :   u32 n_advertisements_rcvd = 0;
     666             : 
     667             :   vlib_node_runtime_t *error_node =
     668           5 :     vlib_node_get_runtime (vm, ip6_icmp_input_node.index);
     669             : 
     670           5 :   from = vlib_frame_vector_args (frame);
     671           5 :   n_left_from = n_packets;
     672           5 :   next_index = node->cached_next_index;
     673             : 
     674           5 :   if (node->flags & VLIB_NODE_FLAG_TRACE)
     675           5 :     vlib_trace_frame_buffers_only (vm, node, from, frame->n_vectors,
     676             :                                    /* stride */ 1,
     677             :                                    sizeof (icmp6_input_trace_t));
     678             : 
     679          10 :   while (n_left_from > 0)
     680             :     {
     681           5 :       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
     682             : 
     683          10 :       while (n_left_from > 0 && n_left_to_next > 0)
     684             :         {
     685             :           vlib_buffer_t *p0;
     686             :           ip6_header_t *ip0;
     687           5 :           ip6_ra_t *radv_info = 0;
     688             :           icmp6_router_advertisement_header_t *h0;
     689             :           u32 bi0, options_len0, sw_if_index0, next0, error0;
     690             : 
     691           5 :           bi0 = to_next[0] = from[0];
     692             : 
     693           5 :           from += 1;
     694           5 :           to_next += 1;
     695           5 :           n_left_from -= 1;
     696           5 :           n_left_to_next -= 1;
     697             : 
     698           5 :           p0 = vlib_get_buffer (vm, bi0);
     699           5 :           ip0 = vlib_buffer_get_current (p0);
     700           5 :           h0 = ip6_next_header (ip0);
     701           5 :           options_len0 =
     702           5 :             clib_net_to_host_u16 (ip0->payload_length) - sizeof (h0[0]);
     703             : 
     704           5 :           error0 = ICMP6_ERROR_NONE;
     705           5 :           sw_if_index0 = vnet_buffer (p0)->sw_if_index[VLIB_RX];
     706             : 
     707             :           /* Check that source address is link-local */
     708           5 :           error0 = (!ip6_address_is_link_local_unicast (&ip0->src_address)) ?
     709           5 :             ICMP6_ERROR_ROUTER_ADVERTISEMENT_SOURCE_NOT_LINK_LOCAL : error0;
     710             : 
     711             :           /* default is to drop */
     712           5 :           next0 = ICMP6_ROUTER_SOLICITATION_NEXT_DROP;
     713             : 
     714           5 :           n_advertisements_rcvd++;
     715             : 
     716           5 :           if (error0 == ICMP6_ERROR_NONE)
     717             :             {
     718             :               vnet_sw_interface_t *sw_if0;
     719             :               ethernet_interface_t *eth_if0;
     720             : 
     721           5 :               sw_if0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
     722           5 :               ASSERT (sw_if0->type == VNET_SW_INTERFACE_TYPE_HARDWARE);
     723             :               eth_if0 =
     724           5 :                 ethernet_get_interface (&ethernet_main, sw_if0->hw_if_index);
     725             : 
     726             :               /* only support ethernet interface type for now */
     727           5 :               error0 =
     728             :                 (!eth_if0) ? ICMP6_ERROR_ROUTER_SOLICITATION_UNSUPPORTED_INTF
     729           5 :                 : error0;
     730             : 
     731           5 :               if (error0 == ICMP6_ERROR_NONE)
     732             :                 {
     733             :                   /* look up the radv_t information for this interface */
     734           5 :                   radv_info = ip6_ra_get_itf (sw_if_index0);
     735             : 
     736           5 :                   error0 = ((!radv_info) ?
     737           5 :                             ICMP6_ERROR_ROUTER_SOLICITATION_RADV_NOT_CONFIG :
     738             :                             error0);
     739             : 
     740           5 :                   if (error0 == ICMP6_ERROR_NONE)
     741             :                     {
     742           5 :                       radv_info->keep_sending_rs = 0;
     743             : 
     744             :                       ip6_ra_report_t r;
     745             : 
     746           5 :                       r.sw_if_index = sw_if_index0;
     747           5 :                       memcpy (&r.router_address, &ip0->src_address, 16);
     748           5 :                       r.current_hop_limit = h0->current_hop_limit;
     749           5 :                       r.flags = h0->flags;
     750           5 :                       r.router_lifetime_in_sec =
     751           5 :                         clib_net_to_host_u16 (h0->router_lifetime_in_sec);
     752           5 :                       r.neighbor_reachable_time_in_msec =
     753           5 :                         clib_net_to_host_u32
     754             :                         (h0->neighbor_reachable_time_in_msec);
     755           5 :                       r.time_in_msec_between_retransmitted_neighbor_solicitations = clib_net_to_host_u32 (h0->time_in_msec_between_retransmitted_neighbor_solicitations);
     756           5 :                       r.prefixes = 0;
     757             : 
     758             :                       /* validate advertised information */
     759           5 :                       if ((h0->current_hop_limit && radv_info->curr_hop_limit)
     760           0 :                           && (h0->current_hop_limit !=
     761           0 :                               radv_info->curr_hop_limit))
     762             :                         {
     763           0 :                           ip6_neighbor_syslog (vm, LOG_WARNING,
     764             :                                                "our AdvCurHopLimit on %U doesn't agree with %U",
     765             :                                                format_vnet_sw_if_index_name,
     766             :                                                vnm, sw_if_index0,
     767             :                                                format_ip6_address,
     768             :                                                &ip0->src_address);
     769             :                         }
     770             : 
     771           5 :                       if ((h0->flags &
     772             :                            ICMP6_ROUTER_DISCOVERY_FLAG_ADDRESS_CONFIG_VIA_DHCP)
     773           5 :                           != radv_info->adv_managed_flag)
     774             :                         {
     775           0 :                           ip6_neighbor_syslog (vm, LOG_WARNING,
     776             :                                                "our AdvManagedFlag on %U doesn't agree with %U",
     777             :                                                format_vnet_sw_if_index_name,
     778             :                                                vnm, sw_if_index0,
     779             :                                                format_ip6_address,
     780             :                                                &ip0->src_address);
     781             :                         }
     782             : 
     783           5 :                       if ((h0->flags &
     784             :                            ICMP6_ROUTER_DISCOVERY_FLAG_OTHER_CONFIG_VIA_DHCP)
     785           5 :                           != radv_info->adv_other_flag)
     786             :                         {
     787           0 :                           ip6_neighbor_syslog (vm, LOG_WARNING,
     788             :                                                "our AdvOtherConfigFlag on %U doesn't agree with %U",
     789             :                                                format_vnet_sw_if_index_name,
     790             :                                                vnm, sw_if_index0,
     791             :                                                format_ip6_address,
     792             :                                                &ip0->src_address);
     793             :                         }
     794             : 
     795           5 :                       if ((h0->
     796             :                            time_in_msec_between_retransmitted_neighbor_solicitations
     797           0 :                            && radv_info->
     798             :                            adv_time_in_msec_between_retransmitted_neighbor_solicitations)
     799           0 :                           && (h0->
     800             :                               time_in_msec_between_retransmitted_neighbor_solicitations
     801             :                               !=
     802           0 :                               clib_host_to_net_u32 (radv_info->
     803             :                                                     adv_time_in_msec_between_retransmitted_neighbor_solicitations)))
     804             :                         {
     805           0 :                           ip6_neighbor_syslog (vm, LOG_WARNING,
     806             :                                                "our AdvRetransTimer on %U doesn't agree with %U",
     807             :                                                format_vnet_sw_if_index_name,
     808             :                                                vnm, sw_if_index0,
     809             :                                                format_ip6_address,
     810             :                                                &ip0->src_address);
     811             :                         }
     812             : 
     813           5 :                       if ((h0->neighbor_reachable_time_in_msec &&
     814           0 :                            radv_info->adv_neighbor_reachable_time_in_msec) &&
     815           0 :                           (h0->neighbor_reachable_time_in_msec !=
     816           0 :                            clib_host_to_net_u32
     817             :                            (radv_info->adv_neighbor_reachable_time_in_msec)))
     818             :                         {
     819           0 :                           ip6_neighbor_syslog (vm, LOG_WARNING,
     820             :                                                "our AdvReachableTime on %U doesn't agree with %U",
     821             :                                                format_vnet_sw_if_index_name,
     822             :                                                vnm, sw_if_index0,
     823             :                                                format_ip6_address,
     824             :                                                &ip0->src_address);
     825             :                         }
     826             : 
     827             :                       /* check for MTU or prefix options or .. */
     828           5 :                       u8 *opt_hdr = (u8 *) (h0 + 1);
     829           9 :                       while (options_len0 > 0)
     830             :                         {
     831           4 :                           icmp6_neighbor_discovery_option_header_t *o0 =
     832             :                             (icmp6_neighbor_discovery_option_header_t *)
     833             :                             opt_hdr;
     834           4 :                           int opt_len = o0->n_data_u64s << 3;
     835           4 :                           icmp6_neighbor_discovery_option_type_t option_type =
     836           4 :                             o0->type;
     837             : 
     838           4 :                           if (options_len0 < 2)
     839             :                             {
     840           0 :                               ip6_neighbor_syslog (vm, LOG_ERR,
     841             :                                                    "malformed RA packet on %U from %U",
     842             :                                                    format_vnet_sw_if_index_name,
     843             :                                                    vnm, sw_if_index0,
     844             :                                                    format_ip6_address,
     845             :                                                    &ip0->src_address);
     846           0 :                               break;
     847             :                             }
     848             : 
     849           4 :                           if (opt_len == 0)
     850             :                             {
     851           0 :                               ip6_neighbor_syslog (vm, LOG_ERR,
     852             :                                                    " zero length option in RA on %U from %U",
     853             :                                                    format_vnet_sw_if_index_name,
     854             :                                                    vnm, sw_if_index0,
     855             :                                                    format_ip6_address,
     856             :                                                    &ip0->src_address);
     857           0 :                               break;
     858             :                             }
     859           4 :                           else if (opt_len > options_len0)
     860             :                             {
     861           0 :                               ip6_neighbor_syslog (vm, LOG_ERR,
     862             :                                                    "option length in RA packet  greater than total length on %U from %U",
     863             :                                                    format_vnet_sw_if_index_name,
     864             :                                                    vnm, sw_if_index0,
     865             :                                                    format_ip6_address,
     866             :                                                    &ip0->src_address);
     867           0 :                               break;
     868             :                             }
     869             : 
     870           4 :                           options_len0 -= opt_len;
     871           4 :                           opt_hdr += opt_len;
     872             : 
     873           4 :                           switch (option_type)
     874             :                             {
     875           0 :                             case ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address:
     876             :                               {
     877             :                                 icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
     878           0 :                                   * h =
     879             :                                   (icmp6_neighbor_discovery_ethernet_link_layer_address_option_t
     880             :                                    *) (o0);
     881             : 
     882           0 :                                 if (opt_len < sizeof (*h))
     883           0 :                                   break;
     884             : 
     885           0 :                                 memcpy (r.slla, h->ethernet_address, 6);
     886             :                               }
     887           0 :                               break;
     888             : 
     889           0 :                             case ICMP6_NEIGHBOR_DISCOVERY_OPTION_mtu:
     890             :                               {
     891           0 :                                 icmp6_neighbor_discovery_mtu_option_t *h =
     892             :                                   (icmp6_neighbor_discovery_mtu_option_t
     893             :                                    *) (o0);
     894             : 
     895           0 :                                 if (opt_len < sizeof (*h))
     896           0 :                                   break;
     897             : 
     898           0 :                                 r.mtu = clib_net_to_host_u32 (h->mtu);
     899             : 
     900           0 :                                 if ((h->mtu && radv_info->adv_link_mtu) &&
     901           0 :                                     (h->mtu !=
     902           0 :                                      clib_host_to_net_u32
     903             :                                      (radv_info->adv_link_mtu)))
     904             :                                   {
     905           0 :                                     ip6_neighbor_syslog (vm, LOG_WARNING,
     906             :                                                          "our AdvLinkMTU on %U doesn't agree with %U",
     907             :                                                          format_vnet_sw_if_index_name,
     908             :                                                          vnm, sw_if_index0,
     909             :                                                          format_ip6_address,
     910             :                                                          &ip0->src_address);
     911             :                                   }
     912             :                               }
     913           0 :                               break;
     914             : 
     915           4 :                             case ICMP6_NEIGHBOR_DISCOVERY_OPTION_prefix_information:
     916             :                               {
     917             :                                 icmp6_neighbor_discovery_prefix_information_option_t
     918           4 :                                   * h =
     919             :                                   (icmp6_neighbor_discovery_prefix_information_option_t
     920             :                                    *) (o0);
     921             : 
     922             :                                 /* validate advertised prefix options  */
     923             :                                 ip6_radv_prefix_t *pr_info;
     924             :                                 u32 preferred, valid;
     925             : 
     926           4 :                                 if (opt_len < sizeof (*h))
     927           0 :                                   break;
     928             : 
     929           4 :                                 vec_validate (r.prefixes,
     930             :                                               vec_len (r.prefixes));
     931           4 :                                 ra_report_prefix_info_t *prefix =
     932           4 :                                   vec_elt_at_index (r.prefixes,
     933             :                                                     vec_len (r.prefixes) - 1);
     934             : 
     935             :                                 preferred =
     936           4 :                                   clib_net_to_host_u32 (h->preferred_time);
     937           4 :                                 valid = clib_net_to_host_u32 (h->valid_time);
     938             : 
     939           4 :                                 prefix->preferred_time = preferred;
     940           4 :                                 prefix->valid_time = valid;
     941           4 :                                 prefix->flags = h->flags & 0xc0;
     942           4 :                                 prefix->prefix.fp_len = h->dst_address_length;
     943           4 :                                 prefix->prefix.fp_addr.ip6 = h->dst_address;
     944           4 :                                 prefix->prefix.fp_proto = FIB_PROTOCOL_IP6;
     945             : 
     946             :                                 /* look for matching prefix - if we our advertising it, it better be consistant */
     947             :                                 /* *INDENT-OFF* */
     948           4 :                                 pool_foreach (pr_info, radv_info->adv_prefixes_pool)
     949             :                                  {
     950             : 
     951             :                                   ip6_address_t mask;
     952           0 :                                   ip6_address_mask_from_width(&mask, pr_info->prefix_len);
     953             : 
     954           0 :                                   if(pr_info->enabled &&
     955           0 :                                      (pr_info->prefix_len == h->dst_address_length) &&
     956           0 :                                      ip6_address_is_equal_masked (&pr_info->prefix,  &h->dst_address, &mask))
     957             :                                     {
     958             :                                       /* found it */
     959           0 :                                       if(!pr_info->decrement_lifetime_flag &&
     960           0 :                                          valid != pr_info->adv_valid_lifetime_in_secs)
     961             :                                         {
     962           0 :                                           ip6_neighbor_syslog(vm,  LOG_WARNING,
     963             :                                                               "our ADV validlifetime on  %U for %U does not  agree with %U",
     964             :                                                               format_vnet_sw_if_index_name, vnm, sw_if_index0,format_ip6_address, &pr_info->prefix,
     965             :                                                               format_ip6_address, &h->dst_address);
     966             :                                         }
     967           0 :                                       if(!pr_info->decrement_lifetime_flag &&
     968           0 :                                          preferred != pr_info->adv_pref_lifetime_in_secs)
     969             :                                         {
     970           0 :                                           ip6_neighbor_syslog(vm,  LOG_WARNING,
     971             :                                                               "our ADV preferredlifetime on  %U for %U does not  agree with %U",
     972             :                                                               format_vnet_sw_if_index_name, vnm, sw_if_index0,format_ip6_address, &pr_info->prefix,
     973             :                                                               format_ip6_address, &h->dst_address);
     974             :                                         }
     975             :                                     }
     976           0 :                                   break;
     977             :                                 }
     978             :                                 /* *INDENT-ON* */
     979           4 :                                 break;
     980             :                               }
     981           0 :                             default:
     982             :                               /* skip this one */
     983           0 :                               break;
     984             :                             }
     985             :                         }
     986           5 :                       ip6_ra_publish (&r);
     987             :                     }
     988             :                 }
     989             :             }
     990             : 
     991           5 :           p0->error = error_node->errors[error0];
     992             : 
     993           5 :           if (error0 != ICMP6_ERROR_NONE)
     994           0 :             vlib_error_count (vm, error_node->node_index, error0, 1);
     995             : 
     996           5 :           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
     997             :                                            to_next, n_left_to_next,
     998             :                                            bi0, next0);
     999             :         }
    1000             : 
    1001           5 :       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
    1002             :     }
    1003             : 
    1004             :   /* Account for router advertisements received. */
    1005           5 :   vlib_error_count (vm, error_node->node_index,
    1006             :                     ICMP6_ERROR_ROUTER_ADVERTISEMENTS_RX,
    1007             :                     n_advertisements_rcvd);
    1008             : 
    1009           5 :   return frame->n_vectors;
    1010             : }
    1011             : 
    1012             : /* *INDENT-OFF* */
    1013      178120 : VLIB_REGISTER_NODE (ip6_icmp_router_advertisement_node,static) =
    1014             : {
    1015             :   .function = icmp6_router_advertisement,
    1016             :   .name = "icmp6-router-advertisement",
    1017             : 
    1018             :   .vector_size = sizeof (u32),
    1019             : 
    1020             :   .format_trace = format_icmp6_input_trace,
    1021             : 
    1022             :   .n_next_nodes = 1,
    1023             :   .next_nodes = {
    1024             :     [0] = "ip6-drop",
    1025             :   },
    1026             : };
    1027             : /* *INDENT-ON* */
    1028             : 
    1029             : static inline f64
    1030           4 : random_f64_from_to (f64 from, f64 to)
    1031             : {
    1032             :   static u32 seed = 0;
    1033             :   static u8 seed_set = 0;
    1034           4 :   if (!seed_set)
    1035             :     {
    1036           2 :       seed = random_default_seed ();
    1037           2 :       seed_set = 1;
    1038             :     }
    1039           4 :   return random_f64 (&seed) * (to - from) + from;
    1040             : }
    1041             : 
    1042             : static inline u8
    1043           2 : get_mac_address (u32 sw_if_index, u8 * address)
    1044             : {
    1045           2 :   vnet_main_t *vnm = vnet_get_main ();
    1046           2 :   vnet_hw_interface_t *hw_if = vnet_get_sup_hw_interface (vnm, sw_if_index);
    1047           2 :   if (!hw_if->hw_address)
    1048           0 :     return 1;
    1049           2 :   clib_memcpy (address, hw_if->hw_address, 6);
    1050           2 :   return 0;
    1051             : }
    1052             : 
    1053             : static inline vlib_buffer_t *
    1054           2 : create_buffer_for_rs (vlib_main_t * vm, ip6_ra_t * radv_info)
    1055             : {
    1056             :   u32 bi0;
    1057             :   vlib_buffer_t *p0;
    1058             :   icmp6_router_solicitation_header_t *rh;
    1059             :   u16 payload_length;
    1060             :   int bogus_length;
    1061             :   u32 sw_if_index;
    1062             : 
    1063           2 :   sw_if_index = radv_info->sw_if_index;
    1064             : 
    1065           2 :   if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
    1066             :     {
    1067           0 :       clib_warning ("buffer allocation failure");
    1068           0 :       return 0;
    1069             :     }
    1070             : 
    1071           2 :   p0 = vlib_get_buffer (vm, bi0);
    1072           2 :   p0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
    1073             : 
    1074           2 :   vnet_buffer (p0)->sw_if_index[VLIB_RX] = sw_if_index;
    1075           2 :   vnet_buffer (p0)->sw_if_index[VLIB_TX] = sw_if_index;
    1076             : 
    1077           4 :   vnet_buffer (p0)->ip.adj_index[VLIB_TX] =
    1078           2 :     ip6_link_get_mcast_adj (sw_if_index);
    1079             : 
    1080           2 :   rh = vlib_buffer_get_current (p0);
    1081           2 :   p0->current_length = sizeof (*rh);
    1082             : 
    1083           2 :   rh->neighbor.icmp.type = ICMP6_router_solicitation;
    1084           2 :   rh->neighbor.icmp.code = 0;
    1085           2 :   rh->neighbor.icmp.checksum = 0;
    1086           2 :   rh->neighbor.reserved_must_be_zero = 0;
    1087             : 
    1088           2 :   rh->link_layer_option.header.type =
    1089             :     ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address;
    1090           2 :   if (0 != get_mac_address (sw_if_index,
    1091           2 :                             rh->link_layer_option.ethernet_address))
    1092             :     {
    1093           0 :       clib_warning ("interface with sw_if_index %u has no mac address",
    1094             :                     sw_if_index);
    1095           0 :       vlib_buffer_free (vm, &bi0, 1);
    1096           0 :       return 0;
    1097             :     }
    1098           2 :   rh->link_layer_option.header.n_data_u64s = 1;
    1099             : 
    1100           2 :   payload_length = sizeof (rh->neighbor) + sizeof (u64);
    1101             : 
    1102           2 :   rh->ip.ip_version_traffic_class_and_flow_label =
    1103           2 :     clib_host_to_net_u32 (0x6 << 28);
    1104           2 :   rh->ip.payload_length = clib_host_to_net_u16 (payload_length);
    1105           2 :   rh->ip.protocol = IP_PROTOCOL_ICMP6;
    1106           2 :   rh->ip.hop_limit = 255;
    1107           2 :   ip6_address_copy (&rh->ip.src_address,
    1108             :                     ip6_get_link_local_address (radv_info->sw_if_index));
    1109             :   /* set address ff02::2 */
    1110           2 :   rh->ip.dst_address.as_u64[0] = clib_host_to_net_u64 (0xff02ULL << 48);
    1111           2 :   rh->ip.dst_address.as_u64[1] = clib_host_to_net_u64 (2);
    1112             : 
    1113           2 :   rh->neighbor.icmp.checksum = ip6_tcp_udp_icmp_compute_checksum (vm, p0,
    1114             :                                                                   &rh->ip,
    1115             :                                                                   &bogus_length);
    1116             : 
    1117           2 :   return p0;
    1118             : }
    1119             : 
    1120             : static inline void
    1121           3 : stop_sending_rs (vlib_main_t * vm, ip6_ra_t * ra)
    1122             : {
    1123             :   u32 bi0;
    1124             : 
    1125           3 :   ra->keep_sending_rs = 0;
    1126           3 :   if (ra->buffer)
    1127             :     {
    1128           1 :       bi0 = vlib_get_buffer_index (vm, ra->buffer);
    1129           1 :       vlib_buffer_free (vm, &bi0, 1);
    1130           1 :       ra->buffer = 0;
    1131             :     }
    1132           3 : }
    1133             : 
    1134             : static inline bool
    1135           8 : check_send_rs (vlib_main_t * vm, ip6_ra_t * radv_info, f64 current_time,
    1136             :                f64 * due_time)
    1137             : {
    1138             :   vlib_buffer_t *p0;
    1139             :   vlib_frame_t *f;
    1140             :   u32 *to_next;
    1141             :   u32 next_index;
    1142             :   vlib_buffer_t *c0;
    1143             :   u32 ci0;
    1144             : 
    1145             :   icmp6_send_router_solicitation_params_t *params;
    1146             : 
    1147           8 :   if (!radv_info->keep_sending_rs)
    1148           4 :     return false;
    1149             : 
    1150           4 :   params = &radv_info->params;
    1151             : 
    1152           4 :   if (radv_info->due_time > current_time)
    1153             :     {
    1154           1 :       *due_time = radv_info->due_time;
    1155           1 :       return true;
    1156             :     }
    1157             : 
    1158           3 :   p0 = radv_info->buffer;
    1159             : 
    1160           3 :   next_index = ip6_rewrite_mcast_node.index;
    1161             : 
    1162           3 :   c0 = vlib_buffer_copy (vm, p0);
    1163           3 :   if (c0 == NULL)
    1164           0 :     return radv_info->keep_sending_rs;
    1165             : 
    1166           3 :   ci0 = vlib_get_buffer_index (vm, c0);
    1167             : 
    1168           3 :   f = vlib_get_frame_to_node (vm, next_index);
    1169           3 :   to_next = vlib_frame_vector_args (f);
    1170           3 :   to_next[0] = ci0;
    1171           3 :   f->n_vectors = 1;
    1172           3 :   vlib_put_frame_to_node (vm, next_index, f);
    1173             : 
    1174           3 :   if (params->mrc != 0 && --radv_info->n_left == 0)
    1175           1 :     stop_sending_rs (vm, radv_info);
    1176             :   else
    1177             :     {
    1178           2 :       radv_info->sleep_interval =
    1179           2 :         (2 + random_f64_from_to (-0.1, 0.1)) * radv_info->sleep_interval;
    1180           2 :       if (radv_info->sleep_interval > params->mrt)
    1181           0 :         radv_info->sleep_interval =
    1182           0 :           (1 + random_f64_from_to (-0.1, 0.1)) * params->mrt;
    1183             : 
    1184           2 :       radv_info->due_time = current_time + radv_info->sleep_interval;
    1185             : 
    1186           2 :       if (params->mrd != 0
    1187           0 :           && current_time > radv_info->start_time + params->mrd)
    1188           0 :         stop_sending_rs (vm, radv_info);
    1189             :       else
    1190           2 :         *due_time = radv_info->due_time;
    1191             :     }
    1192             : 
    1193           3 :   return radv_info->keep_sending_rs;
    1194             : }
    1195             : 
    1196             : static uword
    1197         559 : send_rs_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
    1198             :                  vlib_frame_t * f0)
    1199             : {
    1200         559 :   uword *event_data = NULL;
    1201         559 :   f64 sleep_time = 1e9;
    1202             :   ip6_ra_t *radv_info;
    1203             :   f64 current_time;
    1204             :   f64 due_time;
    1205         559 :   f64 dt = 0;
    1206             : 
    1207             :   while (true)
    1208             :     {
    1209         564 :       vlib_process_wait_for_event_or_clock (vm, sleep_time);
    1210           5 :       vlib_process_get_events (vm, &event_data);
    1211           5 :       vec_reset_length (event_data);
    1212             : 
    1213           5 :       current_time = vlib_time_now (vm);
    1214             :       do
    1215             :         {
    1216           5 :           due_time = current_time + 1e9;
    1217             :         /* *INDENT-OFF* */
    1218          13 :         pool_foreach (radv_info, ip6_ra_pool)
    1219             :          {
    1220           8 :             if (check_send_rs (vm, radv_info, current_time, &dt)
    1221           3 :                 && (dt < due_time))
    1222           3 :               due_time = dt;
    1223             :         }
    1224             :         /* *INDENT-ON* */
    1225           5 :           current_time = vlib_time_now (vm);
    1226             :         }
    1227           5 :       while (due_time < current_time);
    1228             : 
    1229           5 :       sleep_time = due_time - current_time;
    1230             :     }
    1231             : 
    1232             :   return 0;
    1233             : }
    1234             : 
    1235             : /* *INDENT-OFF* */
    1236      178120 : VLIB_REGISTER_NODE (ip6_rs_process_node) = {
    1237             :     .function = send_rs_process,
    1238             :     .type = VLIB_NODE_TYPE_PROCESS,
    1239             :     .name = "ip6-rs-process",
    1240             : };
    1241             : /* *INDENT-ON* */
    1242             : 
    1243             : void
    1244           2 : icmp6_send_router_solicitation (vlib_main_t * vm, u32 sw_if_index, u8 stop,
    1245             :                                 const icmp6_send_router_solicitation_params_t
    1246             :                                 * params)
    1247             : {
    1248             :   ip6_ra_t *ra;
    1249             : 
    1250           2 :   ASSERT (~0 != sw_if_index);
    1251             : 
    1252           2 :   ra = ip6_ra_get_itf (sw_if_index);
    1253             : 
    1254           2 :   if (!ra)
    1255           0 :     return;
    1256             : 
    1257           2 :   stop_sending_rs (vm, ra);
    1258             : 
    1259           2 :   if (!stop)
    1260             :     {
    1261           2 :       ra->keep_sending_rs = 1;
    1262           2 :       ra->params = *params;
    1263           2 :       ra->n_left = params->mrc;
    1264           2 :       ra->start_time = vlib_time_now (vm);
    1265           2 :       ra->sleep_interval = (1 + random_f64_from_to (-0.1, 0.1)) * params->irt;
    1266           2 :       ra->due_time = 0;              /* send first packet ASAP */
    1267           2 :       ra->buffer = create_buffer_for_rs (vm, ra);
    1268           2 :       if (!ra->buffer)
    1269           0 :         ra->keep_sending_rs = 0;
    1270             :       else
    1271           2 :         vlib_process_signal_event (vm, ip6_rs_process_node.index, 1, 0);
    1272             :     }
    1273             : }
    1274             : 
    1275             : static const ethernet_interface_t *
    1276        2046 : ip6_ra_get_eth_itf (u32 sw_if_index)
    1277             : {
    1278             :   const vnet_sw_interface_t *sw;
    1279             : 
    1280             :   /* lookup radv container  - ethernet interfaces only */
    1281        2046 :   sw = vnet_get_sup_sw_interface (vnet_get_main (), sw_if_index);
    1282        2046 :   if (sw->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
    1283        2046 :     return (ethernet_get_interface (&ethernet_main, sw->hw_if_index));
    1284             : 
    1285           0 :   return (NULL);
    1286             : }
    1287             : 
    1288             : /**
    1289             :  * @brief called when IP6 is enabled on an interface
    1290             :  *create and initialize router advertisement parameters with default
    1291             :  * values for this intfc
    1292             :  */
    1293             : static void
    1294        2046 : ip6_ra_link_enable (u32 sw_if_index)
    1295             : {
    1296             :   const ethernet_interface_t *eth;
    1297             :   ip6_ra_t *radv_info;
    1298             : 
    1299        2046 :   eth = ip6_ra_get_eth_itf (sw_if_index);
    1300             : 
    1301        2046 :   if (NULL == eth)
    1302         155 :     return;
    1303             : 
    1304        1891 :   ASSERT (INDEX_INVALID == ip6_link_delegate_get (sw_if_index,
    1305             :                                                   ip6_ra_delegate_id));
    1306             : 
    1307        1891 :   pool_get_zero (ip6_ra_pool, radv_info);
    1308             : 
    1309        1891 :   radv_info->seed = (u32) clib_cpu_time_now ();
    1310        1891 :   random_u32 (&radv_info->seed);
    1311             : 
    1312        1891 :   radv_info->sw_if_index = sw_if_index;
    1313        1891 :   radv_info->max_radv_interval = DEF_MAX_RADV_INTERVAL;
    1314        1891 :   radv_info->min_radv_interval = DEF_MIN_RADV_INTERVAL;
    1315        1891 :   radv_info->curr_hop_limit = DEF_CURR_HOP_LIMIT;
    1316        1891 :   radv_info->adv_router_lifetime_in_sec = DEF_DEF_RTR_LIFETIME;
    1317             : 
    1318             :   /* send ll address source address option */
    1319        1891 :   radv_info->adv_link_layer_address = 1;
    1320             : 
    1321        1891 :   radv_info->min_delay_between_radv = MIN_DELAY_BETWEEN_RAS;
    1322        1891 :   radv_info->max_delay_between_radv = MAX_DELAY_BETWEEN_RAS;
    1323        1891 :   radv_info->max_rtr_default_lifetime = MAX_DEF_RTR_LIFETIME;
    1324             : 
    1325        1891 :   radv_info->initial_adverts_count = MAX_INITIAL_RTR_ADVERTISEMENTS;
    1326        1891 :   radv_info->initial_adverts_sent = radv_info->initial_adverts_count - 1;
    1327        1891 :   radv_info->initial_adverts_interval = MAX_INITIAL_RTR_ADVERT_INTERVAL;
    1328             : 
    1329             :   /* fill in delegate for this interface that will be needed later */
    1330        3782 :   radv_info->adv_link_mtu =
    1331        1891 :     vnet_sw_interface_get_mtu (vnet_get_main (), sw_if_index, VNET_MTU_IP6);
    1332             : 
    1333        1891 :   mhash_init (&radv_info->address_to_prefix_index, sizeof (uword),
    1334             :               sizeof (ip6_address_t));
    1335             : 
    1336        1891 :   ip6_link_delegate_update (sw_if_index, ip6_ra_delegate_id,
    1337        1891 :                             radv_info - ip6_ra_pool);
    1338             : }
    1339             : 
    1340             : static void
    1341        1718 : ip6_ra_delegate_disable (index_t rai)
    1342             : {
    1343             :   ip6_radv_prefix_t *p;
    1344             :   ip6_ra_t *radv_info;
    1345             : 
    1346        1718 :   radv_info = pool_elt_at_index (ip6_ra_pool, rai);
    1347             : 
    1348             :   /* clean up prefix and MDP pools */
    1349             :   /* *INDENT-OFF* */
    1350        1718 :   pool_flush(p, radv_info->adv_prefixes_pool,
    1351             :   ({
    1352             :     mhash_unset (&radv_info->address_to_prefix_index, &p->prefix, 0);
    1353             :   }));
    1354             :   /* *INDENT-ON* */
    1355             : 
    1356        1718 :   pool_free (radv_info->adv_prefixes_pool);
    1357             : 
    1358        1718 :   mhash_free (&radv_info->address_to_prefix_index);
    1359             : 
    1360        1718 :   pool_put (ip6_ra_pool, radv_info);
    1361        1718 : }
    1362             : 
    1363             : void
    1364           0 : ip6_ra_update_secondary_radv_info (ip6_address_t * address, u8 prefix_len,
    1365             :                                    u32 primary_sw_if_index,
    1366             :                                    u32 valid_time, u32 preferred_time)
    1367             : {
    1368           0 :   vlib_main_t *vm = vlib_get_main ();
    1369             :   static u32 *radv_indices;
    1370             :   ip6_ra_t *radv_info;
    1371             :   int i;
    1372             :   ip6_address_t mask;
    1373           0 :   ip6_address_mask_from_width (&mask, prefix_len);
    1374             : 
    1375           0 :   vec_reset_length (radv_indices);
    1376             :   /* *INDENT-OFF* */
    1377           0 :   pool_foreach (radv_info, ip6_ra_pool)
    1378             :    {
    1379           0 :     vec_add1 (radv_indices, radv_info - ip6_ra_pool);
    1380             :   }
    1381             :   /* *INDENT-ON* */
    1382             : 
    1383             :   /*
    1384             :    * If we have another customer for this prefix,
    1385             :    * tell the RA code about it...
    1386             :    */
    1387           0 :   for (i = 0; i < vec_len (radv_indices); i++)
    1388             :     {
    1389             :       ip6_radv_prefix_t *this_prefix;
    1390           0 :       radv_info = pool_elt_at_index (ip6_ra_pool, radv_indices[i]);
    1391             : 
    1392             :       /* We already took care of these timers... */
    1393           0 :       if (radv_info->sw_if_index == primary_sw_if_index)
    1394           0 :         continue;
    1395             : 
    1396             :       /* *INDENT-OFF* */
    1397           0 :       pool_foreach (this_prefix, radv_info->adv_prefixes_pool)
    1398             :        {
    1399           0 :         if (this_prefix->prefix_len == prefix_len
    1400           0 :             && ip6_address_is_equal_masked (&this_prefix->prefix, address,
    1401             :                                             &mask))
    1402             :           {
    1403           0 :             int rv = ip6_ra_prefix (vm,
    1404             :                                     radv_info->sw_if_index,
    1405             :                                     address,
    1406             :                                     prefix_len,
    1407             :                                     0 /* use_default */,
    1408             :                                     valid_time,
    1409             :                                     preferred_time,
    1410             :                                     0 /* no_advertise */,
    1411             :                                     0 /* off_link */,
    1412             :                                     0 /* no_autoconfig */,
    1413             :                                     0 /* no_onlink */,
    1414             :                                     0 /* is_no */);
    1415           0 :             if (rv != 0)
    1416           0 :               clib_warning ("ip6_neighbor_ra_prefix returned %d", rv);
    1417             :           }
    1418             :       }
    1419             :       /* *INDENT-ON*/
    1420             :     }
    1421           0 : }
    1422             : 
    1423             : /* send a RA or update the timer info etc.. */
    1424             : static uword
    1425        6920 : ip6_ra_process_timer_event (vlib_main_t * vm,
    1426             :                             vlib_node_runtime_t * node, vlib_frame_t * frame)
    1427             : {
    1428        6920 :   vnet_main_t *vnm = vnet_get_main ();
    1429             :   ip6_ra_t *radv_info;
    1430        6920 :   vlib_frame_t *f = 0;
    1431        6920 :   u32 n_this_frame = 0;
    1432        6920 :   u32 n_left_to_next = 0;
    1433        6920 :   u32 *to_next = 0;
    1434             :   u32 bo0;
    1435             :   icmp6_router_solicitation_header_t *h0;
    1436             :   vlib_buffer_t *b0;
    1437        6920 :   f64 now = vlib_time_now (vm);
    1438             : 
    1439             :   /* Interface ip6 radv info list */
    1440             :   /* *INDENT-OFF* */
    1441       18580 :   pool_foreach (radv_info, ip6_ra_pool)
    1442             :    {
    1443       11660 :     if( !vnet_sw_interface_is_admin_up (vnm, radv_info->sw_if_index))
    1444             :       {
    1445          54 :         radv_info->initial_adverts_sent = radv_info->initial_adverts_count-1;
    1446          54 :         radv_info->next_multicast_time = now;
    1447          54 :         radv_info->last_multicast_time = now;
    1448          54 :         radv_info->last_radv_time = 0;
    1449          54 :         continue;
    1450             :       }
    1451             : 
    1452             :     /* is it time to send a multicast  RA on this interface? */
    1453       11606 :     if(radv_info->send_radv && (now >=  radv_info->next_multicast_time))
    1454             :       {
    1455           3 :         u32 n_to_alloc = 1;
    1456             :         u32 n_allocated;
    1457             : 
    1458           6 :         f64 rfn = (radv_info->max_radv_interval - radv_info->min_radv_interval) *
    1459           3 :           random_f64 (&radv_info->seed) + radv_info->min_radv_interval;
    1460             : 
    1461             :         /* multicast send - compute next multicast send time */
    1462           3 :         if( radv_info->initial_adverts_sent > 0)
    1463             :           {
    1464           3 :             radv_info->initial_adverts_sent--;
    1465           3 :             if(rfn > radv_info->initial_adverts_interval)
    1466           3 :               rfn =  radv_info->initial_adverts_interval;
    1467             : 
    1468             :             /* check to see if we are ceasing to send */
    1469           3 :             if( radv_info->initial_adverts_sent  == 0)
    1470           0 :               if(radv_info->cease_radv)
    1471           0 :                 radv_info->send_radv = 0;
    1472             :           }
    1473             : 
    1474           3 :         radv_info->next_multicast_time =  rfn + now;
    1475           3 :         radv_info->last_multicast_time = now;
    1476             : 
    1477             :         /* send advert now - build a "solicted" router advert with unspecified source address */
    1478           3 :         n_allocated = vlib_buffer_alloc (vm, &bo0, n_to_alloc);
    1479             : 
    1480           3 :         if (PREDICT_FALSE(n_allocated == 0))
    1481             :           {
    1482           0 :             clib_warning ("buffer allocation failure");
    1483           0 :             continue;
    1484             :           }
    1485           3 :         b0 = vlib_get_buffer (vm, bo0);
    1486           3 :         b0->current_length = sizeof( icmp6_router_solicitation_header_t);
    1487           3 :         b0->error = ICMP6_ERROR_NONE;
    1488           3 :         vnet_buffer (b0)->sw_if_index[VLIB_RX] = radv_info->sw_if_index;
    1489             : 
    1490           3 :         h0 =  vlib_buffer_get_current (b0);
    1491             : 
    1492           3 :         clib_memset (h0, 0, sizeof (icmp6_router_solicitation_header_t));
    1493             : 
    1494           3 :         h0->ip.ip_version_traffic_class_and_flow_label = clib_host_to_net_u32 (0x6 << 28);
    1495           3 :         h0->ip.payload_length = clib_host_to_net_u16 (sizeof (icmp6_router_solicitation_header_t)
    1496             :                                                       - STRUCT_OFFSET_OF (icmp6_router_solicitation_header_t, neighbor));
    1497           3 :         h0->ip.protocol = IP_PROTOCOL_ICMP6;
    1498           3 :         h0->ip.hop_limit = 255;
    1499             : 
    1500             :         /* set src/dst address as "unspecified" this marks this packet as internally generated rather than recieved */
    1501           3 :         h0->ip.src_address.as_u64[0] = 0;
    1502           3 :         h0->ip.src_address.as_u64[1] = 0;
    1503             : 
    1504           3 :         h0->ip.dst_address.as_u64[0] = 0;
    1505           3 :         h0->ip.dst_address.as_u64[1] = 0;
    1506             : 
    1507           3 :         h0->neighbor.icmp.type = ICMP6_router_solicitation;
    1508             : 
    1509           3 :         if (PREDICT_FALSE(f == 0))
    1510             :           {
    1511           3 :             f = vlib_get_frame_to_node (vm, ip6_icmp_router_solicitation_node.index);
    1512           3 :             to_next = vlib_frame_vector_args (f);
    1513           3 :             n_left_to_next = VLIB_FRAME_SIZE;
    1514           3 :             n_this_frame = 0;
    1515             :           }
    1516             : 
    1517           3 :         n_this_frame++;
    1518           3 :         n_left_to_next--;
    1519           3 :         to_next[0] = bo0;
    1520           3 :         to_next += 1;
    1521             : 
    1522           3 :         if (PREDICT_FALSE(n_left_to_next == 0))
    1523             :           {
    1524           0 :             f->n_vectors = n_this_frame;
    1525           0 :             vlib_put_frame_to_node (vm, ip6_icmp_router_solicitation_node.index, f);
    1526           0 :             f = 0;
    1527             :           }
    1528             :       }
    1529             :   }
    1530             :   /* *INDENT-ON* */
    1531             : 
    1532        6920 :   if (f)
    1533             :     {
    1534           3 :       ASSERT (n_this_frame);
    1535           3 :       f->n_vectors = n_this_frame;
    1536           3 :       vlib_put_frame_to_node (vm, ip6_icmp_router_solicitation_node.index, f);
    1537             :     }
    1538        6920 :   return 0;
    1539             : }
    1540             : 
    1541             : static void
    1542           5 : ip6_ra_handle_report (ip6_ra_report_t * rap)
    1543             : {
    1544             :   u32 ii;
    1545             : 
    1546          11 :   vec_foreach_index (ii, ip6_ra_listeners) ip6_ra_listeners[ii] (rap);
    1547           5 :   vec_free (rap->prefixes);
    1548           5 :   clib_mem_free (rap);
    1549           5 : }
    1550             : 
    1551             : static uword
    1552         559 : ip6_ra_event_process (vlib_main_t * vm,
    1553             :                       vlib_node_runtime_t * node, vlib_frame_t * frame)
    1554             : {
    1555             :   ip6_ra_report_t *r;
    1556             :   uword event_type;
    1557         559 :   uword *event_data = 0;
    1558             :   int i;
    1559             : 
    1560             :   /* init code here */
    1561             : 
    1562             :   while (1)
    1563             :     {
    1564        7484 :       vlib_process_wait_for_event_or_clock (vm, 1. /* seconds */ );
    1565             : 
    1566        6925 :       event_type = vlib_process_get_events (vm, &event_data);
    1567             : 
    1568        6925 :       if (event_type == ~0)
    1569             :         {
    1570             :           /* No events found: timer expired. */
    1571             :           /* process interface list and send RAs as appropriate, update timer info */
    1572        6920 :           ip6_ra_process_timer_event (vm, node, frame);
    1573             :         }
    1574             :       else
    1575             :         {
    1576          10 :           for (i = 0; i < vec_len (event_data); i++)
    1577             :             {
    1578           5 :               r = (void *) (event_data[i]);
    1579           5 :               ip6_ra_handle_report (r);
    1580             :             }
    1581           5 :           vec_reset_length (event_data);
    1582             :         }
    1583             :     }
    1584             :   return frame->n_vectors;
    1585             : }
    1586             : 
    1587             : /* *INDENT-OFF* */
    1588      178120 : VLIB_REGISTER_NODE (ip6_ra_process_node) =
    1589             : {
    1590             :  .function = ip6_ra_event_process,
    1591             :  .name = "ip6-ra-process",
    1592             :  .type = VLIB_NODE_TYPE_PROCESS,
    1593             : };
    1594             : /* *INDENT-ON* */
    1595             : 
    1596             : static void
    1597           5 : ip6_ra_signal_report (ip6_ra_report_t * r)
    1598             : {
    1599           5 :   vlib_main_t *vm = vlib_get_main ();
    1600             :   ip6_ra_report_t *q;
    1601             : 
    1602           5 :   if (!vec_len (ip6_ra_listeners))
    1603           0 :     return;
    1604             : 
    1605           5 :   q = clib_mem_alloc (sizeof (*q));
    1606           5 :   *q = *r;
    1607             : 
    1608           5 :   vlib_process_signal_event (vm, ip6_ra_process_node.index, 0, (uword) q);
    1609             : }
    1610             : 
    1611             : static int
    1612           5 : ip6_ra_publish (ip6_ra_report_t * r)
    1613             : {
    1614             :   void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
    1615           5 :   vl_api_rpc_call_main_thread (ip6_ra_signal_report, (u8 *) r, sizeof *r);
    1616           5 :   return 0;
    1617             : }
    1618             : 
    1619             : /* API support functions */
    1620             : int
    1621         185 : ip6_ra_config (vlib_main_t * vm, u32 sw_if_index,
    1622             :                u8 suppress, u8 managed, u8 other,
    1623             :                u8 ll_option, u8 send_unicast, u8 cease,
    1624             :                u8 use_lifetime, u32 lifetime,
    1625             :                u32 initial_count, u32 initial_interval,
    1626             :                u32 max_interval, u32 min_interval, u8 is_no)
    1627             : {
    1628             :   ip6_ra_t *radv_info;
    1629             : 
    1630             :   /* look up the radv_t  information for this interface */
    1631         185 :   radv_info = ip6_ra_get_itf (sw_if_index);
    1632             : 
    1633         185 :   if (!radv_info)
    1634           0 :     return (VNET_API_ERROR_IP6_NOT_ENABLED);
    1635             : 
    1636             :   /* Start off believing that we're going to send radv's */
    1637         185 :   radv_info->send_radv = 1;
    1638             : 
    1639         185 :   if ((max_interval != 0) && (min_interval == 0))
    1640           0 :     min_interval = .75 * max_interval;
    1641             : 
    1642         185 :   max_interval =
    1643             :     (max_interval !=
    1644             :      0) ? ((is_no) ? DEF_MAX_RADV_INTERVAL : max_interval) :
    1645         185 :     radv_info->max_radv_interval;
    1646         185 :   min_interval =
    1647             :     (min_interval !=
    1648             :      0) ? ((is_no) ? DEF_MIN_RADV_INTERVAL : min_interval) :
    1649         185 :     radv_info->min_radv_interval;
    1650         185 :   lifetime =
    1651             :     (use_lifetime !=
    1652         185 :      0) ? ((is_no) ? DEF_DEF_RTR_LIFETIME : lifetime) :
    1653         185 :     radv_info->adv_router_lifetime_in_sec;
    1654             : 
    1655         185 :   if (lifetime)
    1656             :     {
    1657         185 :       if (lifetime > MAX_DEF_RTR_LIFETIME)
    1658           0 :         lifetime = MAX_DEF_RTR_LIFETIME;
    1659             : 
    1660         185 :       if (lifetime <= max_interval)
    1661           0 :         return VNET_API_ERROR_INVALID_VALUE;
    1662             :     }
    1663             : 
    1664         185 :   if (min_interval != 0)
    1665             :     {
    1666         185 :       if ((min_interval > .75 * max_interval) || (min_interval < 3))
    1667           0 :         return VNET_API_ERROR_INVALID_VALUE;
    1668             :     }
    1669             : 
    1670         185 :   if ((initial_count > MAX_INITIAL_RTR_ADVERTISEMENTS) ||
    1671             :       (initial_interval > MAX_INITIAL_RTR_ADVERT_INTERVAL))
    1672           0 :     return VNET_API_ERROR_INVALID_VALUE;
    1673             : 
    1674             :   /*
    1675             :      if "flag" is set and is_no is true then restore default value else set value corresponding to "flag"
    1676             :      if "flag" is clear  don't change corresponding value
    1677             :    */
    1678         185 :   radv_info->send_radv =
    1679         185 :     (suppress != 0) ? ((is_no != 0) ? 1 : 0) : radv_info->send_radv;
    1680         185 :   radv_info->adv_managed_flag =
    1681         185 :     (managed != 0) ? ((is_no) ? 0 : 1) : radv_info->adv_managed_flag;
    1682         185 :   radv_info->adv_other_flag =
    1683         185 :     (other != 0) ? ((is_no) ? 0 : 1) : radv_info->adv_other_flag;
    1684         185 :   radv_info->adv_link_layer_address =
    1685         185 :     (ll_option != 0) ? ((is_no) ? 1 : 0) : radv_info->adv_link_layer_address;
    1686         185 :   radv_info->send_unicast =
    1687         185 :     (send_unicast != 0) ? ((is_no) ? 0 : 1) : radv_info->send_unicast;
    1688         185 :   radv_info->cease_radv =
    1689         185 :     (cease != 0) ? ((is_no) ? 0 : 1) : radv_info->cease_radv;
    1690             : 
    1691         185 :   radv_info->min_radv_interval = min_interval;
    1692         185 :   radv_info->max_radv_interval = max_interval;
    1693         185 :   radv_info->adv_router_lifetime_in_sec = lifetime;
    1694             : 
    1695         185 :   radv_info->initial_adverts_count =
    1696             :     (initial_count !=
    1697         185 :      0) ? ((is_no) ? MAX_INITIAL_RTR_ADVERTISEMENTS : initial_count) :
    1698             :     radv_info->initial_adverts_count;
    1699         185 :   radv_info->initial_adverts_interval =
    1700             :     (initial_interval !=
    1701         185 :      0) ? ((is_no) ? MAX_INITIAL_RTR_ADVERT_INTERVAL : initial_interval) :
    1702             :     radv_info->initial_adverts_interval;
    1703             : 
    1704             :   /* restart */
    1705         185 :   if ((cease != 0) && (is_no))
    1706           0 :     radv_info->send_radv = 1;
    1707             : 
    1708         185 :   radv_info->initial_adverts_sent = radv_info->initial_adverts_count - 1;
    1709         185 :   radv_info->next_multicast_time = vlib_time_now (vm);
    1710         185 :   radv_info->last_multicast_time = vlib_time_now (vm);
    1711         185 :   radv_info->last_radv_time = 0;
    1712             : 
    1713         185 :   return (0);
    1714             : }
    1715             : 
    1716             : 
    1717             : int
    1718          16 : ip6_ra_prefix (vlib_main_t * vm, u32 sw_if_index,
    1719             :                ip6_address_t * prefix_addr, u8 prefix_len,
    1720             :                u8 use_default, u32 val_lifetime, u32 pref_lifetime,
    1721             :                u8 no_advertise, u8 off_link, u8 no_autoconfig,
    1722             :                u8 no_onlink, u8 is_no)
    1723             : {
    1724             :   ip6_ra_t *radv_info;
    1725             : 
    1726             :   /* look up the radv_t  information for this interface */
    1727          16 :   radv_info = ip6_ra_get_itf (sw_if_index);
    1728             : 
    1729          16 :   if (!radv_info)
    1730           0 :     return (VNET_API_ERROR_IP6_NOT_ENABLED);
    1731             : 
    1732          16 :   f64 now = vlib_time_now (vm);
    1733             : 
    1734             :   /* prefix info add, delete or update */
    1735             :   ip6_radv_prefix_t *prefix;
    1736             : 
    1737             :   /* lookup  prefix info for this  address on this interface */
    1738          16 :   uword *p = mhash_get (&radv_info->address_to_prefix_index, prefix_addr);
    1739             : 
    1740          16 :   prefix = p ? pool_elt_at_index (radv_info->adv_prefixes_pool, p[0]) : 0;
    1741             : 
    1742          16 :   if (is_no)
    1743             :     {
    1744             :       /* delete */
    1745           6 :       if (!prefix)
    1746           1 :         return VNET_API_ERROR_INVALID_VALUE;    /* invalid prefix */
    1747             : 
    1748           5 :       if (prefix->prefix_len != prefix_len)
    1749           0 :         return VNET_API_ERROR_INVALID_VALUE_2;
    1750             : 
    1751             :       /* FIXME - Should the DP do this or the CP ? */
    1752             :       /* do specific delete processing here before returning */
    1753             :       /* try to remove from routing table */
    1754             : 
    1755           5 :       mhash_unset (&radv_info->address_to_prefix_index, prefix_addr,
    1756             :                    /* old_value */ 0);
    1757           5 :       pool_put (radv_info->adv_prefixes_pool, prefix);
    1758             : 
    1759           5 :       radv_info->initial_adverts_sent = radv_info->initial_adverts_count - 1;
    1760           5 :       radv_info->next_multicast_time = vlib_time_now (vm);
    1761           5 :       radv_info->last_multicast_time = vlib_time_now (vm);
    1762           5 :       radv_info->last_radv_time = 0;
    1763           5 :       return (0);
    1764             :     }
    1765             : 
    1766             :   /* adding or changing */
    1767          10 :   if (!prefix)
    1768             :     {
    1769             :       /* add */
    1770             :       u32 pi;
    1771           5 :       pool_get_zero (radv_info->adv_prefixes_pool, prefix);
    1772           5 :       pi = prefix - radv_info->adv_prefixes_pool;
    1773           5 :       mhash_set (&radv_info->address_to_prefix_index, prefix_addr, pi,
    1774             :                  /* old_value */ 0);
    1775             : 
    1776           5 :       clib_memset (prefix, 0x0, sizeof (ip6_radv_prefix_t));
    1777             : 
    1778           5 :       prefix->prefix_len = prefix_len;
    1779           5 :       clib_memcpy (&prefix->prefix, prefix_addr, sizeof (ip6_address_t));
    1780             : 
    1781             :       /* initialize default values */
    1782           5 :       prefix->adv_on_link_flag = 1;  /* L bit set */
    1783           5 :       prefix->adv_autonomous_flag = 1;       /* A bit set */
    1784           5 :       prefix->adv_valid_lifetime_in_secs = DEF_ADV_VALID_LIFETIME;
    1785           5 :       prefix->adv_pref_lifetime_in_secs = DEF_ADV_PREF_LIFETIME;
    1786           5 :       prefix->enabled = 1;
    1787           5 :       prefix->decrement_lifetime_flag = 1;
    1788           5 :       prefix->deprecated_prefix_flag = 1;
    1789             : 
    1790             :       if (off_link == 0)
    1791             :         {
    1792             :           /* FIXME - Should the DP do this or the CP ? */
    1793             :           /* insert prefix into routing table as a connected prefix */
    1794             :         }
    1795             : 
    1796           5 :       if (use_default)
    1797           0 :         goto restart;
    1798             :     }
    1799             :   else
    1800             :     {
    1801             : 
    1802           5 :       if (prefix->prefix_len != prefix_len)
    1803           0 :         return VNET_API_ERROR_INVALID_VALUE_2;
    1804             : 
    1805             :       if (off_link != 0)
    1806             :         {
    1807             :           /* FIXME - Should the DP do this or the CP ? */
    1808             :           /* remove from routing table if already there */
    1809             :         }
    1810             :     }
    1811             : 
    1812          10 :   if ((val_lifetime == ~0) || (pref_lifetime == ~0))
    1813             :     {
    1814           9 :       prefix->adv_valid_lifetime_in_secs = ~0;
    1815           9 :       prefix->adv_pref_lifetime_in_secs = ~0;
    1816           9 :       prefix->decrement_lifetime_flag = 0;
    1817             :     }
    1818             :   else
    1819             :     {
    1820           1 :       prefix->adv_valid_lifetime_in_secs = val_lifetime;;
    1821           1 :       prefix->adv_pref_lifetime_in_secs = pref_lifetime;
    1822             :     }
    1823             : 
    1824             :   /* copy  remaining */
    1825          10 :   prefix->enabled = !(no_advertise != 0);
    1826          10 :   prefix->adv_on_link_flag = !((off_link != 0) || (no_onlink != 0));
    1827          10 :   prefix->adv_autonomous_flag = !(no_autoconfig != 0);
    1828             : 
    1829          10 : restart:
    1830             :   /* restart */
    1831             :   /* fill in the expiration times  */
    1832          10 :   prefix->valid_lifetime_expires = now + prefix->adv_valid_lifetime_in_secs;
    1833          10 :   prefix->pref_lifetime_expires = now + prefix->adv_pref_lifetime_in_secs;
    1834             : 
    1835          10 :   radv_info->initial_adverts_sent = radv_info->initial_adverts_count - 1;
    1836          10 :   radv_info->next_multicast_time = vlib_time_now (vm);
    1837          10 :   radv_info->last_multicast_time = vlib_time_now (vm);
    1838          10 :   radv_info->last_radv_time = 0;
    1839             : 
    1840          10 :   return (0);
    1841             : }
    1842             : 
    1843             : clib_error_t *
    1844           0 : ip6_ra_cmd (vlib_main_t * vm,
    1845             :             unformat_input_t * main_input, vlib_cli_command_t * cmd)
    1846             : {
    1847           0 :   vnet_main_t *vnm = vnet_get_main ();
    1848           0 :   clib_error_t *error = 0;
    1849           0 :   u8 is_no = 0;
    1850           0 :   u8 suppress = 0, managed = 0, other = 0;
    1851           0 :   u8 suppress_ll_option = 0, send_unicast = 0, cease = 0;
    1852           0 :   u8 use_lifetime = 0;
    1853           0 :   u32 sw_if_index, ra_lifetime = 0, ra_initial_count =
    1854           0 :     0, ra_initial_interval = 0;
    1855           0 :   u32 ra_max_interval = 0, ra_min_interval = 0;
    1856             : 
    1857           0 :   unformat_input_t _line_input, *line_input = &_line_input;
    1858             : 
    1859           0 :   int add_radv_info = 1;
    1860             :   ip6_address_t ip6_addr;
    1861             :   u32 addr_len;
    1862             : 
    1863             : 
    1864             :   /* Get a line of input. */
    1865           0 :   if (!unformat_user (main_input, unformat_line_input, line_input))
    1866           0 :     return 0;
    1867             : 
    1868             :   /* get basic radv info for this interface */
    1869           0 :   if (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
    1870             :     {
    1871             : 
    1872           0 :       if (unformat_user (line_input,
    1873             :                          unformat_vnet_sw_interface, vnm, &sw_if_index))
    1874             :         {
    1875           0 :           if (!ip6_ra_get_eth_itf (sw_if_index))
    1876             :             {
    1877             :               error =
    1878           0 :                 clib_error_return (0, "Interface must be of ethernet type");
    1879           0 :               goto done;
    1880             :             }
    1881             : 
    1882           0 :           if (!ip6_link_is_enabled (sw_if_index))
    1883             :             {
    1884           0 :               error = clib_error_return (0, "IP6 nt enabler interface %U'",
    1885             :                                          format_unformat_error, line_input);
    1886           0 :               goto done;
    1887             :             }
    1888             :         }
    1889             :       else
    1890             :         {
    1891           0 :           error = clib_error_return (0, "invalid interface name %U'",
    1892             :                                      format_unformat_error, line_input);
    1893           0 :           goto done;
    1894             :         }
    1895             :     }
    1896             : 
    1897             :   /* get the rest of the command */
    1898           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
    1899             :     {
    1900           0 :       if (unformat (line_input, "no"))
    1901           0 :         is_no = 1;
    1902           0 :       else if (unformat (line_input, "prefix %U/%d",
    1903             :                          unformat_ip6_address, &ip6_addr, &addr_len))
    1904             :         {
    1905           0 :           add_radv_info = 0;
    1906             :         }
    1907           0 :       else if (unformat (line_input, "ra-managed-config-flag"))
    1908             :         {
    1909           0 :           managed = 1;
    1910             :         }
    1911           0 :       else if (unformat (line_input, "ra-other-config-flag"))
    1912             :         {
    1913           0 :           other = 1;
    1914             :         }
    1915           0 :       else if (unformat (line_input, "ra-suppress") ||
    1916           0 :                unformat (line_input, "ra-surpress"))
    1917             :         {
    1918           0 :           suppress = 1;
    1919             :         }
    1920           0 :       else if (unformat (line_input, "ra-suppress-link-layer") ||
    1921           0 :                unformat (line_input, "ra-surpress-link-layer"))
    1922             :         {
    1923           0 :           suppress_ll_option = 1;
    1924             :         }
    1925           0 :       else if (unformat (line_input, "ra-send-unicast"))
    1926             :         {
    1927           0 :           send_unicast = 1;
    1928             :         }
    1929           0 :       else if (unformat (line_input, "ra-lifetime"))
    1930             :         {
    1931           0 :           if (!unformat (line_input, "%d", &ra_lifetime))
    1932             :             {
    1933           0 :               error = unformat_parse_error (line_input);
    1934           0 :               goto done;
    1935             :             }
    1936           0 :           use_lifetime = 1;
    1937             :         }
    1938           0 :       else if (unformat (line_input, "ra-initial"))
    1939             :         {
    1940           0 :           if (!unformat
    1941             :               (line_input, "%d %d", &ra_initial_count, &ra_initial_interval))
    1942             :             {
    1943           0 :               error = unformat_parse_error (line_input);
    1944           0 :               goto done;
    1945             :             }
    1946             :         }
    1947           0 :       else if (unformat (line_input, "ra-interval"))
    1948             :         {
    1949           0 :           if (!unformat (line_input, "%d", &ra_max_interval))
    1950             :             {
    1951           0 :               error = unformat_parse_error (line_input);
    1952           0 :               goto done;
    1953             :             }
    1954             : 
    1955           0 :           if (!unformat (line_input, "%d", &ra_min_interval))
    1956           0 :             ra_min_interval = 0;
    1957             :         }
    1958           0 :       else if (unformat (line_input, "ra-cease"))
    1959             :         {
    1960           0 :           cease = 1;
    1961             :         }
    1962             :       else
    1963             :         {
    1964           0 :           break;
    1965             :         }
    1966             :     }
    1967             : 
    1968           0 :   if (add_radv_info)
    1969             :     {
    1970           0 :       ip6_ra_config (vm, sw_if_index,
    1971             :                      suppress, managed, other,
    1972             :                      suppress_ll_option, send_unicast, cease,
    1973             :                      use_lifetime, ra_lifetime,
    1974             :                      ra_initial_count, ra_initial_interval,
    1975             :                      ra_max_interval, ra_min_interval, is_no);
    1976             :     }
    1977             :   else
    1978             :     {
    1979           0 :       u32 valid_lifetime_in_secs = 0;
    1980           0 :       u32 pref_lifetime_in_secs = 0;
    1981           0 :       u8 use_prefix_default_values = 0;
    1982           0 :       u8 no_advertise = 0;
    1983           0 :       u8 off_link = 0;
    1984           0 :       u8 no_autoconfig = 0;
    1985           0 :       u8 no_onlink = 0;
    1986             : 
    1987             :       /* get the rest of the command */
    1988           0 :       while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
    1989             :         {
    1990           0 :           if (unformat (line_input, "default"))
    1991             :             {
    1992           0 :               use_prefix_default_values = 1;
    1993           0 :               break;
    1994             :             }
    1995           0 :           else if (unformat (line_input, "infinite"))
    1996             :             {
    1997           0 :               valid_lifetime_in_secs = ~0;
    1998           0 :               pref_lifetime_in_secs = ~0;
    1999           0 :               break;
    2000             :             }
    2001           0 :           else if (unformat (line_input, "%d %d", &valid_lifetime_in_secs,
    2002             :                              &pref_lifetime_in_secs))
    2003           0 :             break;
    2004             :           else
    2005           0 :             break;
    2006             :         }
    2007             : 
    2008             : 
    2009             :       /* get the rest of the command */
    2010           0 :       while (!use_prefix_default_values &&
    2011           0 :              unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
    2012             :         {
    2013           0 :           if (unformat (line_input, "no-advertise"))
    2014           0 :             no_advertise = 1;
    2015           0 :           else if (unformat (line_input, "off-link"))
    2016           0 :             off_link = 1;
    2017           0 :           else if (unformat (line_input, "no-autoconfig"))
    2018           0 :             no_autoconfig = 1;
    2019           0 :           else if (unformat (line_input, "no-onlink"))
    2020           0 :             no_onlink = 1;
    2021             :           else
    2022             :             {
    2023           0 :               error = unformat_parse_error (line_input);
    2024           0 :               goto done;
    2025             :             }
    2026             :         }
    2027             : 
    2028           0 :       ip6_ra_prefix (vm, sw_if_index,
    2029             :                      &ip6_addr, addr_len,
    2030             :                      use_prefix_default_values,
    2031             :                      valid_lifetime_in_secs,
    2032             :                      pref_lifetime_in_secs,
    2033             :                      no_advertise, off_link, no_autoconfig, no_onlink, is_no);
    2034             :     }
    2035             : 
    2036           0 : done:
    2037           0 :   unformat_free (line_input);
    2038             : 
    2039           0 :   return error;
    2040             : }
    2041             : 
    2042             : static u8 *
    2043           0 : format_ip6_ra (u8 * s, va_list * args)
    2044             : {
    2045           0 :   index_t rai = va_arg (*args, index_t);
    2046           0 :   u32 indent = va_arg (*args, u32);
    2047             :   ip6_radv_prefix_t *p;
    2048             :   ip6_ra_t *radv_info;
    2049             : 
    2050           0 :   radv_info = pool_elt_at_index (ip6_ra_pool, rai);
    2051             : 
    2052           0 :   s = format (s, "%UAdvertised Prefixes:\n", format_white_space, indent);
    2053             : 
    2054           0 :   indent += 2;
    2055             : 
    2056             :   /* *INDENT-OFF* */
    2057           0 :   pool_foreach (p, radv_info->adv_prefixes_pool)
    2058             :    {
    2059           0 :     s = format (s, "%Uprefix %U, length %d\n",
    2060             :                 format_white_space, indent+2,
    2061           0 :                 format_ip6_address, &p->prefix, p->prefix_len);
    2062             :   }
    2063             :   /* *INDENT-ON* */
    2064             : 
    2065           0 :   s = format (s, "%UMTU is %d\n",
    2066             :               format_white_space, indent, radv_info->adv_link_mtu);
    2067           0 :   s = format (s, "%UICMP error messages are unlimited\n",
    2068             :               format_white_space, indent);
    2069           0 :   s = format (s, "%UICMP redirects are disabled\n",
    2070             :               format_white_space, indent);
    2071           0 :   s = format (s, "%UICMP unreachables are not sent\n",
    2072             :               format_white_space, indent);
    2073           0 :   s = format (s, "%UND DAD is disabled\n", format_white_space, indent);
    2074             :   //s = format (s, "%UND reachable time is %d milliseconds\n",);
    2075           0 :   s = format (s, "%UND advertised reachable time is %d\n",
    2076             :               format_white_space, indent,
    2077             :               radv_info->adv_neighbor_reachable_time_in_msec);
    2078           0 :   s = format (s,
    2079             :               "%UND advertised retransmit interval is %d (msec)\n",
    2080             :               format_white_space, indent,
    2081             :               radv_info->
    2082             :               adv_time_in_msec_between_retransmitted_neighbor_solicitations);
    2083             :   s =
    2084           0 :     format (s,
    2085             :             "%UND router advertisements are sent every %0.1f seconds (min interval is %0.1f)\n",
    2086             :             format_white_space, indent, radv_info->max_radv_interval,
    2087             :             radv_info->min_radv_interval);
    2088             :   s =
    2089           0 :     format (s, "%UND router advertisements live for %d seconds\n",
    2090             :             format_white_space, indent,
    2091           0 :             radv_info->adv_router_lifetime_in_sec);
    2092             :   s =
    2093           0 :     format (s, "%UHosts %s stateless autoconfig for addresses\n",
    2094             :             format_white_space, indent,
    2095           0 :             (radv_info->adv_managed_flag) ? "use" : " don't use");
    2096             :   s =
    2097           0 :     format (s, "%UND router advertisements sent %d\n", format_white_space,
    2098             :             indent, radv_info->n_advertisements_sent);
    2099             :   s =
    2100           0 :     format (s, "%UND router solicitations received %d\n", format_white_space,
    2101             :             indent, radv_info->n_solicitations_rcvd);
    2102             :   s =
    2103           0 :     format (s, "%UND router solicitations dropped %d\n", format_white_space,
    2104             :             indent, radv_info->n_solicitations_dropped);
    2105             : 
    2106           0 :   return (s);
    2107             : }
    2108             : 
    2109             : /*?
    2110             :  * This command is used to configure the neighbor discovery
    2111             :  * parameters on a given interface. Use the '<em>show ip6 interface</em>'
    2112             :  * command to display some of the current neighbor discovery parameters
    2113             :  * on a given interface. This command has three formats:
    2114             :  *
    2115             :  *
    2116             :  * <b>Format 1 - Router Advertisement Options:</b> (Only one can be entered in
    2117             :  * a single command)
    2118             :  *
    2119             :  * @clistart
    2120             :  * ip6 nd <interface> [no] [ra-managed-config-flag] |
    2121             :  *   [ra-other-config-flag] | [ra-suppress] | [ra-suppress-link-layer] |
    2122             :  *   [ra-send-unicast] | [ra-lifetime <lifetime>] |
    2123             :  *   [ra-initial <cnt> <interval>] |
    2124             :  *   [ra-interval <max-interval> [<min-interval>]] | [ra-cease]
    2125             :  * @cliend
    2126             :  *
    2127             :  * Where:
    2128             :  *
    2129             :  * <em>[no] ra-managed-config-flag</em> - Advertises in ICMPv6
    2130             :  * router-advertisement messages to use stateful address
    2131             :  * auto-configuration to obtain address information (sets the M-bit).
    2132             :  * Default is the M-bit is not set and the '<em>no</em>' option
    2133             :  * returns it to this default state.
    2134             :  *
    2135             :  * <em>[no] ra-other-config-flag</em> - Indicates in ICMPv6
    2136             :  * router-advertisement messages that hosts use stateful auto
    2137             :  * configuration to obtain nonaddress related information (sets
    2138             :  * the O-bit). Default is the O-bit is not set and the '<em>no</em>'
    2139             :  * option returns it to this default state.
    2140             :  *
    2141             :  * <em>[no] ra-suppress</em> - Disables sending ICMPv6 router-advertisement
    2142             :  * messages. The '<em>no</em>' option implies to enable sending ICMPv6
    2143             :  * router-advertisement messages.
    2144             :  *
    2145             :  * <em>[no] ra-suppress-link-layer</em> - Indicates not to include the
    2146             :  * optional source link-layer address in the ICMPv6 router-advertisement
    2147             :  * messages. Default is to include the optional source link-layer address
    2148             :  * and the '<em>no</em>' option returns it to this default state.
    2149             :  *
    2150             :  * <em>[no] ra-send-unicast</em> - Use the source address of the
    2151             :  * router-solicitation message if available. The default is to use
    2152             :  * multicast address of all nodes, and the '<em>no</em>' option returns
    2153             :  * it to this default state.
    2154             :  *
    2155             :  * <em>[no] ra-lifetime <lifetime></em> - Advertises the lifetime of a
    2156             :  * default router in ICMPv6 router-advertisement messages. The range is
    2157             :  * from 0 to 9000 seconds. '<em><lifetime></em>' must be greater than
    2158             :  * '<em><max-interval></em>'. The default value is 600 seconds and the
    2159             :  * '<em>no</em>' option returns it to this default value.
    2160             :  *
    2161             :  * <em>[no] ra-initial <cnt> <interval></em> - Number of initial ICMPv6
    2162             :  * router-advertisement messages sent and the interval between each
    2163             :  * message. Range for count is 1 - 3 and default is 3. Range for interval
    2164             :  * is 1 to 16 seconds, and default is 16 seconds. The '<em>no</em>' option
    2165             :  * returns both to their default value.
    2166             :  *
    2167             :  * <em>[no] ra-interval <max-interval> [<min-interval>]</em> - Configures the
    2168             :  * interval between sending ICMPv6 router-advertisement messages. The
    2169             :  * range for max-interval is from 4 to 200 seconds. min-interval can not
    2170             :  * be more than 75% of max-interval. If not set, min-interval will be
    2171             :  * set to 75% of max-interval. The range for min-interval is from 3 to
    2172             :  * 150 seconds.  The '<em>no</em>' option returns both to their default
    2173             :  * value.
    2174             :  *
    2175             :  * <em>[no] ra-cease</em> - Cease sending ICMPv6 router-advertisement messages.
    2176             :  * The '<em>no</em>' options implies to start (or restart) sending
    2177             :  * ICMPv6 router-advertisement messages.
    2178             :  *
    2179             :  *
    2180             :  * <b>Format 2 - Prefix Options:</b>
    2181             :  *
    2182             :  * @clistart
    2183             :  * ip6 nd <interface> [no] prefix <ip6-address>/<width>
    2184             :  *   [<valid-lifetime> <pref-lifetime> | infinite] [no-advertise] [off-link]
    2185             :  *   [no-autoconfig] [no-onlink]
    2186             :  * @cliend
    2187             :  *
    2188             :  * Where:
    2189             :  *
    2190             :  * <em>no</em> - All additional flags are ignored and the prefix is deleted.
    2191             :  *
    2192             :  * <em><valid-lifetime> <pref-lifetime></em> - '<em><valid-lifetime></em>' is
    2193             :  * the length of time in seconds during what the prefix is valid for the
    2194             :  * purpose of on-link determination. Range is 7203 to 2592000 seconds and
    2195             :  * default is 2592000 seconds (30 days). '<em><pref-lifetime></em>' is the
    2196             :  * preferred-lifetime and is the length of time in seconds during what
    2197             :  * addresses generated from the prefix remain preferred. Range is 0 to 604800
    2198             :  * seconds and default is 604800 seconds (7 days).
    2199             :  *
    2200             :  * <em>infinite</em> - Both '<em><valid-lifetime></em>' and
    2201             :  * '<em><pref-lifetime></em>' are infinite, no timeout.
    2202             :  *
    2203             :  * <em>no-advertise</em> - Do not send full router address in prefix
    2204             :  * advertisement. Default is to advertise (i.e. - This flag is off by default).
    2205             :  *
    2206             :  * <em>off-link</em> - Prefix is off-link, clear L-bit in packet. Default is
    2207             :  * on-link (i.e. - This flag is off and L-bit in packet is set by default
    2208             :  * and this prefix can be used for on-link determination). '<em>no-onlink</em>'
    2209             :  * also controls the L-bit.
    2210             :  *
    2211             :  * <em>no-autoconfig</em> - Do not use prefix for autoconfiguration, clear
    2212             :  * A-bit in packet. Default is autoconfig (i.e. - This flag is off and A-bit
    2213             :  * in packet is set by default.
    2214             :  *
    2215             :  * <em>no-onlink</em> - Do not use prefix for onlink determination, clear L-bit
    2216             :  * in packet. Default is on-link (i.e. - This flag is off and L-bit in packet
    2217             :  * is set by default and this prefix can be used for on-link determination).
    2218             :  * '<em>off-link</em>' also controls the L-bit.
    2219             :  *
    2220             :  *
    2221             :  * <b>Format 3: - Default of Prefix:</b>
    2222             :  *
    2223             :  * @cliexcmd{ip6 nd <interface> [no] prefix <ip6-address>/<width> default}
    2224             :  *
    2225             :  * When a new prefix is added (or existing one is being overwritten)
    2226             :  * <em>default</em> uses default values for the prefix. If <em>no</em> is
    2227             :  * used, the <em>default</em> is ignored and the prefix is deleted.
    2228             :  *
    2229             :  *
    2230             :  * @cliexpar
    2231             :  * Example of how set a router advertisement option:
    2232             :  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 ra-interval 100 20}
    2233             :  * Example of how to add a prefix:
    2234             :  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 prefix fe80::fe:28ff:fe9c:75b3/64
    2235             :  * infinite no-advertise}
    2236             :  * Example of how to delete a prefix:
    2237             :  * @cliexcmd{ip6 nd GigabitEthernet2/0/0 no prefix fe80::fe:28ff:fe9c:75b3/64}
    2238             : ?*/
    2239             : /* *INDENT-OFF* */
    2240      272887 : VLIB_CLI_COMMAND (ip6_nd_command, static) =
    2241             : {
    2242             :   .path = "ip6 nd",
    2243             :   .short_help = "ip6 nd <interface> ...",
    2244             :   .function = ip6_ra_cmd,
    2245             : };
    2246             : /* *INDENT-ON* */
    2247             : 
    2248             : /**
    2249             :  * VFT for registering as a delegate to an IP6 link
    2250             :  */
    2251             : const static ip6_link_delegate_vft_t ip6_ra_delegate_vft = {
    2252             :   .ildv_disable = ip6_ra_delegate_disable,
    2253             :   .ildv_enable = ip6_ra_link_enable,
    2254             :   .ildv_format = format_ip6_ra,
    2255             : };
    2256             : 
    2257             : static clib_error_t *
    2258         559 : ip6_ra_init (vlib_main_t * vm)
    2259             : {
    2260         559 :   vlib_call_init_function (vm, icmp6_init);
    2261             : 
    2262         559 :   icmp6_register_type (vm, ICMP6_router_solicitation,
    2263             :                        ip6_icmp_router_solicitation_node.index);
    2264         559 :   icmp6_register_type (vm, ICMP6_router_advertisement,
    2265             :                        ip6_icmp_router_advertisement_node.index);
    2266             : 
    2267         559 :   ip6_ra_delegate_id = ip6_link_delegate_register (&ip6_ra_delegate_vft);
    2268             : 
    2269         559 :   return (NULL);
    2270             : }
    2271             : 
    2272             : /* *INDENT-OFF* */
    2273       96319 : VLIB_INIT_FUNCTION (ip6_ra_init) =
    2274             : {
    2275             :   .runs_after = VLIB_INITS("icmp6_init"),
    2276             : };
    2277             : /* *INDENT-ON* */
    2278             : 
    2279             : /*
    2280             :  * fd.io coding-style-patch-verification: ON
    2281             :  *
    2282             :  * Local Variables:
    2283             :  * eval: (c-set-style "gnu")
    2284             :  * End:
    2285             :  */

Generated by: LCOV version 1.14