LCOV - code coverage report
Current view: top level - plugins/dhcp - dhcp6_pd_client_cp.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 403 611 66.0 %
Date: 2023-07-05 22:20:52 Functions: 37 43 86.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2018 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #include <vnet/vnet.h>
      17             : #include <vlibmemory/api.h>
      18             : #include <dhcp/dhcp6_packet.h>
      19             : #include <dhcp/dhcp6_pd_client_dp.h>
      20             : #include <vnet/ip/ip.h>
      21             : #include <vnet/ip/ip6.h>
      22             : #include <vnet/ip/ip6_link.h>
      23             : #include <vnet/ip6-nd/ip6_ra.h>
      24             : #include <float.h>
      25             : #include <math.h>
      26             : #include <string.h>
      27             : #include <vnet/ip/ip_types_api.h>
      28             : 
      29             : typedef struct
      30             : {
      31             :   u32 prefix_group_index;
      32             :   uword opaque_data;            // used by prefix publisher
      33             :   ip6_address_t prefix;
      34             :   u8 prefix_length;
      35             :   u32 preferred_lt;
      36             :   u32 valid_lt;
      37             :   f64 due_time;
      38             : } prefix_info_t;
      39             : 
      40             : typedef struct
      41             : {
      42             :   u8 enabled;
      43             :   u32 prefix_group_index;
      44             :   u32 server_index;
      45             :   u32 T1;
      46             :   u32 T2;
      47             :   f64 T1_due_time;
      48             :   f64 T2_due_time;
      49             :   u32 prefix_count;
      50             :   u8 rebinding;
      51             : } client_state_t;
      52             : 
      53             : typedef struct
      54             : {
      55             :   client_state_t *client_state_by_sw_if_index;
      56             :   clib_bitmap_t *prefix_ownership_bitmap;
      57             :   u32 n_clients;
      58             :   f64 max_valid_due_time;
      59             : 
      60             :   /* convenience */
      61             :   vlib_main_t *vlib_main;
      62             :   vnet_main_t *vnet_main;
      63             :   api_main_t *api_main;
      64             :   u32 node_index;
      65             : } dhcp6_pd_client_cp_main_t;
      66             : 
      67             : static dhcp6_pd_client_cp_main_t dhcp6_pd_client_cp_main;
      68             : 
      69             : typedef struct
      70             : {
      71             :   prefix_info_t *prefix_pool;
      72             :   const u8 **prefix_group_name_by_index;
      73             :   /* vector of active prefix pool indicies, prep-H for pool_foreach(..) */
      74             :   u32 *indices;
      75             : } ip6_prefix_main_t;
      76             : 
      77             : static ip6_prefix_main_t ip6_prefix_main;
      78             : 
      79             : typedef struct
      80             : {
      81             :   /* config */
      82             :   u32 sw_if_index;
      83             :   u32 prefix_group_index;
      84             :   ip6_address_t address;
      85             :   u8 prefix_length;
      86             : 
      87             :   /* state */
      88             :   u8 configured_in_data_plane;
      89             : } ip6_address_info_t;
      90             : 
      91             : typedef struct
      92             : {
      93             :   ip6_address_info_t *addresses;
      94             :   u32 *active_prefix_index_by_prefix_group_index;
      95             : } ip6_address_with_prefix_main_t;
      96             : 
      97             : static ip6_address_with_prefix_main_t ip6_address_with_prefix_main;
      98             : 
      99             : enum
     100             : {
     101             :   DHCPV6_PD_EVENT_INTERRUPT,
     102             :   DHCPV6_PD_EVENT_DISABLE,
     103             : };
     104             : 
     105             : static_always_inline u32
     106          16 : active_prefix_index_by_prefix_group_index_get (u32 prefix_group_index)
     107             : {
     108          16 :   ip6_address_with_prefix_main_t *apm = &ip6_address_with_prefix_main;
     109             : 
     110          16 :   if (prefix_group_index >=
     111          16 :       vec_len (apm->active_prefix_index_by_prefix_group_index))
     112           6 :     return ~0;
     113             : 
     114          10 :   return apm->active_prefix_index_by_prefix_group_index[prefix_group_index];
     115             : }
     116             : 
     117             : static_always_inline void
     118           2 : active_prefix_index_by_prefix_group_index_set (u32 prefix_group_index,
     119             :                                                u32 prefix_index)
     120             : {
     121           2 :   ip6_address_with_prefix_main_t *apm = &ip6_address_with_prefix_main;
     122             :   static const u32 empty = ~0;
     123             : 
     124           2 :   ASSERT (prefix_group_index != ~0);
     125             : 
     126           2 :   if (prefix_index == ~0
     127           1 :       && prefix_group_index >=
     128           1 :       vec_len (apm->active_prefix_index_by_prefix_group_index))
     129           0 :     return;
     130             : 
     131           3 :   vec_validate_init_empty (apm->active_prefix_index_by_prefix_group_index,
     132             :                            prefix_group_index, empty);
     133           2 :   apm->active_prefix_index_by_prefix_group_index[prefix_group_index] =
     134             :     prefix_index;
     135             : }
     136             : 
     137             : static_always_inline u8
     138           4 : is_dhcpv6_pd_prefix (prefix_info_t * prefix_info)
     139             : {
     140           4 :   dhcp6_pd_client_cp_main_t *rm = &dhcp6_pd_client_cp_main;
     141           4 :   ip6_prefix_main_t *pm = &ip6_prefix_main;
     142             :   u32 prefix_index;
     143             : 
     144           4 :   prefix_index = prefix_info - pm->prefix_pool;
     145           4 :   return clib_bitmap_get (rm->prefix_ownership_bitmap, prefix_index);
     146             : }
     147             : 
     148             : static_always_inline void
     149           2 : set_is_dhcpv6_pd_prefix (prefix_info_t * prefix_info, u8 value)
     150             : {
     151           2 :   dhcp6_pd_client_cp_main_t *rm = &dhcp6_pd_client_cp_main;
     152           2 :   ip6_prefix_main_t *pm = &ip6_prefix_main;
     153             :   u32 prefix_index;
     154             : 
     155           2 :   prefix_index = prefix_info - pm->prefix_pool;
     156           2 :   rm->prefix_ownership_bitmap =
     157           2 :     clib_bitmap_set (rm->prefix_ownership_bitmap, prefix_index, value);
     158           2 : }
     159             : 
     160             : static void
     161             : cp_ip6_address_prefix_add_del_handler (u32 prefix_index, u8 is_add);
     162             : 
     163             : static void
     164           2 : notify_prefix_add_del (u32 prefix_index, u8 is_add)
     165             : {
     166             :   // TODO: use registries
     167           2 :   cp_ip6_address_prefix_add_del_handler (prefix_index, is_add);
     168           2 : }
     169             : 
     170             : static void
     171          29 : send_client_message_start_stop (u32 sw_if_index, u32 server_index,
     172             :                                 u8 msg_type, prefix_info_t * prefix_list,
     173             :                                 u8 start)
     174             : {
     175          29 :   dhcp6_pd_client_cp_main_t *rm = &dhcp6_pd_client_cp_main;
     176          29 :   dhcp6_pd_send_client_message_params_t params = { 0, };
     177          29 :   dhcp6_pd_send_client_message_params_prefix_t *prefixes = 0, *pref;
     178             :   u32 i;
     179             : 
     180          29 :   ASSERT (sw_if_index < vec_len (rm->client_state_by_sw_if_index) &&
     181             :           rm->client_state_by_sw_if_index[sw_if_index].enabled);
     182          29 :   client_state_t *client_state =
     183          29 :     &rm->client_state_by_sw_if_index[sw_if_index];
     184             : 
     185          29 :   params.sw_if_index = sw_if_index;
     186          29 :   params.server_index = server_index;
     187          29 :   params.msg_type = msg_type;
     188          29 :   if (start)
     189             :     {
     190          17 :       if (msg_type == DHCPV6_MSG_SOLICIT)
     191             :         {
     192           8 :           params.irt = 1;
     193           8 :           params.mrt = 120;
     194             :         }
     195           9 :       else if (msg_type == DHCPV6_MSG_REQUEST)
     196             :         {
     197           5 :           params.irt = 1;
     198           5 :           params.mrt = 30;
     199           5 :           params.mrc = 10;
     200             :         }
     201           4 :       else if (msg_type == DHCPV6_MSG_RENEW)
     202             :         {
     203           2 :           params.irt = 10;
     204           2 :           params.mrt = 600;
     205           2 :           f64 current_time = vlib_time_now (rm->vlib_main);
     206           2 :           i32 diff_time = client_state->T2 - current_time;
     207           2 :           if (diff_time < 0)
     208           1 :             diff_time = 0;
     209           2 :           params.mrd = diff_time;
     210             :         }
     211           2 :       else if (msg_type == DHCPV6_MSG_REBIND)
     212             :         {
     213           2 :           params.irt = 10;
     214           2 :           params.mrt = 600;
     215           2 :           f64 current_time = vlib_time_now (rm->vlib_main);
     216           2 :           i32 diff_time = rm->max_valid_due_time - current_time;
     217           2 :           if (diff_time < 0)
     218           2 :             diff_time = 0;
     219           2 :           params.mrd = diff_time;
     220             :         }
     221           0 :       else if (msg_type == DHCPV6_MSG_RELEASE)
     222             :         {
     223           0 :           params.mrc = 1;
     224             :         }
     225             :     }
     226             : 
     227          29 :   params.T1 = 0;
     228          29 :   params.T2 = 0;
     229          29 :   if (vec_len (prefix_list) != 0)
     230           1 :     vec_validate (prefixes, vec_len (prefix_list) - 1);
     231          30 :   for (i = 0; i < vec_len (prefix_list); i++)
     232             :     {
     233           1 :       prefix_info_t *prefix = &prefix_list[i];
     234           1 :       pref = &prefixes[i];
     235           1 :       pref->valid_lt = prefix->valid_lt;
     236           1 :       pref->preferred_lt = prefix->preferred_lt;
     237           1 :       pref->prefix = prefix->prefix;
     238           1 :       pref->prefix_length = prefix->prefix_length;
     239             :     }
     240          29 :   params.prefixes = prefixes;
     241             : 
     242          29 :   dhcp6_pd_send_client_message (rm->vlib_main, sw_if_index, !start, &params);
     243             : 
     244          29 :   vec_free (params.prefixes);
     245          29 : }
     246             : 
     247             : static void interrupt_process (void);
     248             : 
     249             : static u8
     250           0 : ip6_prefixes_equal (ip6_address_t * prefix1, ip6_address_t * prefix2, u8 len)
     251             : {
     252           0 :   if (len >= 64)
     253             :     {
     254           0 :       if (prefix1->as_u64[0] != prefix2->as_u64[0])
     255           0 :         return 0;
     256           0 :       if (len == 64)
     257           0 :         return 1;
     258           0 :       return clib_net_to_host_u64 (prefix1->as_u64[1]) >> (128 - len) ==
     259           0 :         clib_net_to_host_u64 (prefix2->as_u64[1]) >> (128 - len);
     260             :     }
     261           0 :   return clib_net_to_host_u64 (prefix1->as_u64[0]) >> (64 - len) ==
     262           0 :     clib_net_to_host_u64 (prefix2->as_u64[0]) >> (64 - len);
     263             : }
     264             : 
     265             : static clib_error_t *
     266          14 : dhcp6_pd_reply_event_handler (vl_api_dhcp6_pd_reply_event_t * mp)
     267             : {
     268          14 :   dhcp6_pd_client_cp_main_t *rm = &dhcp6_pd_client_cp_main;
     269          14 :   ip6_prefix_main_t *pm = &ip6_prefix_main;
     270          14 :   vlib_main_t *vm = rm->vlib_main;
     271             :   client_state_t *client_state;
     272             :   ip6_address_t *prefix;
     273             :   u32 sw_if_index;
     274             :   u32 n_prefixes;
     275             :   vl_api_dhcp6_pd_prefix_info_t *api_prefix;
     276             :   u32 inner_status_code;
     277             :   u32 status_code;
     278             :   u32 server_index;
     279             :   f64 current_time;
     280          14 :   clib_error_t *error = 0;
     281             :   u32 i;
     282             :   prefix_info_t *prefix_info;
     283             : 
     284          14 :   current_time = vlib_time_now (vm);
     285             : 
     286          14 :   sw_if_index = ntohl (mp->sw_if_index);
     287             : 
     288          14 :   if (sw_if_index >= vec_len (rm->client_state_by_sw_if_index))
     289           1 :     return 0;
     290             : 
     291          13 :   client_state = &rm->client_state_by_sw_if_index[sw_if_index];
     292             : 
     293          13 :   if (!client_state->enabled)
     294           0 :     return 0;
     295             : 
     296          13 :   server_index = ntohl (mp->server_index);
     297             : 
     298          13 :   n_prefixes = ntohl (mp->n_prefixes);
     299             : 
     300          13 :   inner_status_code = ntohs (mp->inner_status_code);
     301          13 :   status_code = ntohs (mp->status_code);
     302             : 
     303          13 :   if (mp->msg_type == DHCPV6_MSG_API_ADVERTISE
     304           7 :       && client_state->server_index == ~0)
     305             :     {
     306           6 :       prefix_info_t *prefix_list = 0, *prefix_info;
     307             :       u8 prefix_length;
     308             : 
     309           6 :       if (inner_status_code == DHCPV6_STATUS_NOPREFIX_AVAIL)
     310             :         {
     311           1 :           clib_warning
     312             :             ("Advertise message arrived with NoPrefixAvail status code");
     313           1 :           return 0;
     314             :         }
     315             : 
     316           5 :       if (n_prefixes > 0)
     317           1 :         vec_validate (prefix_list, n_prefixes - 1);
     318           6 :       for (i = 0; i < n_prefixes; i++)
     319             :         {
     320           1 :           api_prefix = &mp->prefixes[i];
     321           1 :           prefix = (ip6_address_t *) api_prefix->prefix.address;
     322           1 :           prefix_length = api_prefix->prefix.len;
     323             : 
     324           1 :           prefix_info = &prefix_list[i];
     325           1 :           prefix_info->prefix = *prefix;
     326           1 :           prefix_info->prefix_length = prefix_length;
     327           1 :           prefix_info->preferred_lt = 0;
     328           1 :           prefix_info->valid_lt = 0;
     329             :         }
     330             : 
     331           5 :       client_state->server_index = server_index;
     332             : 
     333           5 :       send_client_message_start_stop (sw_if_index, server_index,
     334             :                                       DHCPV6_MSG_REQUEST, prefix_list, 1);
     335           5 :       vec_free (prefix_list);
     336             :     }
     337             : 
     338          12 :   if (mp->msg_type != DHCPV6_MSG_API_REPLY)
     339           6 :     return 0;
     340             : 
     341           6 :   if (!client_state->rebinding && client_state->server_index != server_index)
     342             :     {
     343           1 :       clib_warning ("Reply message arrived with Server ID different "
     344             :                     "from that in Request or Renew message");
     345           1 :       return 0;
     346             :     }
     347             : 
     348           5 :   if (inner_status_code == DHCPV6_STATUS_NOPREFIX_AVAIL)
     349             :     {
     350           0 :       clib_warning ("Reply message arrived with NoPrefixAvail status code");
     351           0 :       if (n_prefixes > 0)
     352             :         {
     353           0 :           clib_warning
     354             :             ("Invalid Reply message arrived: It contains NoPrefixAvail "
     355             :              "status code but also contains prefixes");
     356           0 :           return 0;
     357             :         }
     358             :     }
     359             : 
     360           5 :   if (status_code == DHCPV6_STATUS_UNSPEC_FAIL)
     361             :     {
     362           0 :       clib_warning ("Reply message arrived with UnspecFail status code");
     363           0 :       return 0;
     364             :     }
     365             : 
     366           5 :   send_client_message_start_stop (sw_if_index, server_index,
     367           5 :                                   mp->msg_type, 0, 0);
     368             : 
     369           5 :   vec_reset_length (pm->indices);
     370             :   /*
     371             :    * We're going to loop through the pool multiple times,
     372             :    * so collect active indices.
     373             :    */
     374             :   /* *INDENT-OFF* */
     375           5 :   pool_foreach (prefix_info, pm->prefix_pool)
     376             :    {
     377           0 :     vec_add1 (pm->indices, prefix_info - pm->prefix_pool);
     378             :   }
     379             :   /* *INDENT-ON* */
     380             : 
     381           7 :   for (i = 0; i < n_prefixes; i++)
     382             :     {
     383             :       u8 prefix_length;
     384             :       u32 valid_time;
     385             :       u32 preferred_time;
     386             :       int j;
     387             : 
     388           2 :       prefix_info = 0;
     389           2 :       api_prefix = &mp->prefixes[i];
     390             : 
     391           2 :       prefix = (ip6_address_t *) api_prefix->prefix.address;
     392           2 :       prefix_length = api_prefix->prefix.len;
     393             : 
     394           2 :       if (ip6_address_is_link_local_unicast (prefix))
     395           0 :         continue;
     396             : 
     397           2 :       valid_time = ntohl (api_prefix->valid_time);
     398           2 :       preferred_time = ntohl (api_prefix->preferred_time);
     399           2 :       prefix_length = api_prefix->prefix.len;
     400             : 
     401           2 :       if (preferred_time > valid_time)
     402           1 :         continue;
     403             : 
     404           1 :       u8 address_prefix_present = 0;
     405             : 
     406             :       /* Look for a matching prefix_info */
     407           1 :       for (j = 0; j < vec_len (pm->indices); j++)
     408             :         {
     409           0 :           prefix_info = pool_elt_at_index (pm->prefix_pool, pm->indices[j]);
     410             : 
     411           0 :           if (is_dhcpv6_pd_prefix (prefix_info) &&
     412           0 :               prefix_info->opaque_data == sw_if_index &&
     413           0 :               prefix_info->prefix_length == prefix_length &&
     414           0 :               ip6_prefixes_equal (&prefix_info->prefix, prefix,
     415             :                                   prefix_length))
     416             :             {
     417           0 :               address_prefix_present = 1;
     418           0 :               break;
     419             :             }
     420             :         }
     421             : 
     422           1 :       if (address_prefix_present)
     423             :         {
     424             :           /* Found the (primary) prefix, update prefix timers */
     425           0 :           prefix_info->preferred_lt = preferred_time;
     426           0 :           prefix_info->valid_lt = valid_time;
     427           0 :           prefix_info->due_time = current_time + valid_time;
     428           0 :           if (prefix_info->due_time > rm->max_valid_due_time)
     429           0 :             rm->max_valid_due_time = prefix_info->due_time;
     430             : 
     431             :           /*
     432             :            * Tell the RA code to update any secondary per-interface
     433             :            * timers that it might be hoarding.
     434             :            */
     435           0 :           ip6_ra_update_secondary_radv_info
     436             :             (prefix, prefix_length,
     437           0 :              prefix_info->opaque_data /* sw_if_index */ ,
     438             :              valid_time, preferred_time);
     439           0 :           continue;
     440             :         }
     441             : 
     442           1 :       if (valid_time == 0)
     443           0 :         continue;
     444             : 
     445           1 :       pool_get (pm->prefix_pool, prefix_info);
     446           1 :       vec_add1 (pm->indices, prefix_info - pm->prefix_pool);
     447           1 :       prefix_info->prefix_group_index = client_state->prefix_group_index;
     448           1 :       set_is_dhcpv6_pd_prefix (prefix_info, 1);
     449           1 :       prefix_info->opaque_data = sw_if_index;
     450           1 :       prefix_info->prefix_length = prefix_length;
     451           1 :       prefix_info->prefix = *prefix;
     452           1 :       prefix_info->preferred_lt = preferred_time;
     453           1 :       prefix_info->valid_lt = valid_time;
     454           1 :       prefix_info->due_time = current_time + valid_time;
     455           1 :       if (prefix_info->due_time > rm->max_valid_due_time)
     456           1 :         rm->max_valid_due_time = prefix_info->due_time;
     457           1 :       rm->client_state_by_sw_if_index[sw_if_index].prefix_count++;
     458             : 
     459           1 :       u32 prefix_index = prefix_info - pm->prefix_pool;
     460           1 :       notify_prefix_add_del (prefix_index, 1);
     461             :     }
     462             : 
     463           5 :   client_state->server_index = server_index;
     464           5 :   client_state->T1 = ntohl (mp->T1);
     465           5 :   client_state->T2 = ntohl (mp->T2);
     466           5 :   if (client_state->T1 != 0)
     467           4 :     client_state->T1_due_time = current_time + client_state->T1;
     468           5 :   if (client_state->T2 != 0)
     469           4 :     client_state->T2_due_time = current_time + client_state->T2;
     470           5 :   client_state->rebinding = 0;
     471             : 
     472           5 :   interrupt_process ();
     473             : 
     474           5 :   return error;
     475             : }
     476             : 
     477             : static prefix_info_t *
     478           4 : create_prefix_list (u32 sw_if_index)
     479             : {
     480           4 :   ip6_prefix_main_t *pm = &ip6_prefix_main;
     481           4 :   prefix_info_t *prefix_info, *prefix_list = 0;;
     482             : 
     483             :   /* *INDENT-OFF* */
     484           4 :   pool_foreach (prefix_info, pm->prefix_pool)
     485             :    {
     486           0 :     if (is_dhcpv6_pd_prefix (prefix_info) &&
     487           0 :         prefix_info->opaque_data == sw_if_index)
     488             :       {
     489           0 :         u32 pos = vec_len (prefix_list);
     490           0 :         vec_validate (prefix_list, pos);
     491           0 :         clib_memcpy (&prefix_list[pos], prefix_info, sizeof (*prefix_info));
     492             :       }
     493             :   }
     494             :   /* *INDENT-ON* */
     495             : 
     496           4 :   return prefix_list;
     497             : }
     498             : 
     499        1119 : VNET_DHCP6_PD_REPLY_EVENT_FUNCTION (dhcp6_pd_reply_event_handler);
     500             : 
     501             : static uword
     502         566 : dhcp6_pd_client_cp_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
     503             :                             vlib_frame_t * f)
     504             : {
     505         566 :   dhcp6_pd_client_cp_main_t *rm = &dhcp6_pd_client_cp_main;
     506         566 :   ip6_prefix_main_t *pm = &ip6_prefix_main;
     507             :   prefix_info_t *prefix_info;
     508             :   client_state_t *client_state;
     509         566 :   f64 sleep_time = 1e9;
     510             :   f64 current_time;
     511             :   f64 due_time;
     512             :   uword event_type;
     513         566 :   uword *event_data = 0;
     514             :   int i;
     515             : 
     516             :   while (1)
     517             :     {
     518         590 :       vlib_process_wait_for_event_or_clock (vm, sleep_time);
     519          24 :       event_type = vlib_process_get_events (vm, &event_data);
     520          24 :       vec_reset_length (event_data);
     521             : 
     522          24 :       if (event_type == DHCPV6_PD_EVENT_DISABLE)
     523             :         {
     524           7 :           vlib_node_set_state (vm, rm->node_index, VLIB_NODE_STATE_DISABLED);
     525           7 :           sleep_time = 1e9;
     526           7 :           continue;
     527             :         }
     528             : 
     529          17 :       current_time = vlib_time_now (vm);
     530             :       do
     531             :         {
     532          18 :           due_time = current_time + 1e9;
     533             :           /* *INDENT-OFF* */
     534          22 :           pool_foreach (prefix_info, pm->prefix_pool)
     535             :            {
     536           4 :             if (is_dhcpv6_pd_prefix (prefix_info))
     537             :               {
     538           4 :                 if (prefix_info->due_time > current_time)
     539             :                   {
     540           3 :                     if (prefix_info->due_time < due_time)
     541           3 :                       due_time = prefix_info->due_time;
     542             :                   }
     543             :                 else
     544             :                   {
     545           1 :                     u32 prefix_index = prefix_info - pm->prefix_pool;
     546           1 :                     notify_prefix_add_del (prefix_index, 0);
     547           1 :                     u32 sw_if_index = prefix_info->opaque_data;
     548           1 :                     set_is_dhcpv6_pd_prefix (prefix_info, 0);
     549           1 :                     pool_put (pm->prefix_pool, prefix_info);
     550           1 :                     client_state = &rm->client_state_by_sw_if_index[sw_if_index];
     551           1 :                     if (--client_state->prefix_count == 0)
     552             :                       {
     553           1 :                         client_state->rebinding = 0;
     554           1 :                         client_state->server_index = ~0;
     555           1 :                         send_client_message_start_stop (sw_if_index, ~0,
     556             :                                                         DHCPV6_MSG_SOLICIT,
     557             :                                                         0, 1);
     558             :                       }
     559             :                   }
     560             :               }
     561             :           }
     562             :           /* *INDENT-ON* */
     563          54 :           for (i = 0; i < vec_len (rm->client_state_by_sw_if_index); i++)
     564             :             {
     565          36 :               client_state_t *cs = &rm->client_state_by_sw_if_index[i];
     566          36 :               if (cs->enabled && cs->server_index != ~0)
     567             :                 {
     568          17 :                   if (cs->T2_due_time > current_time)
     569             :                     {
     570          15 :                       if (cs->T2_due_time < due_time)
     571          12 :                         due_time = cs->T2_due_time;
     572          15 :                       if (cs->T1_due_time > current_time)
     573             :                         {
     574          13 :                           if (cs->T1_due_time < due_time)
     575           4 :                             due_time = cs->T1_due_time;
     576             :                         }
     577             :                       else
     578             :                         {
     579           2 :                           cs->T1_due_time = DBL_MAX;
     580             :                           prefix_info_t *prefix_list;
     581           2 :                           prefix_list = create_prefix_list (i);
     582           2 :                           send_client_message_start_stop (i, cs->server_index,
     583             :                                                           DHCPV6_MSG_RENEW,
     584             :                                                           prefix_list, 1);
     585           2 :                           vec_free (prefix_list);
     586             :                         }
     587             :                     }
     588             :                   else
     589             :                     {
     590           2 :                       cs->T2_due_time = DBL_MAX;
     591             :                       prefix_info_t *prefix_list;
     592           2 :                       prefix_list = create_prefix_list (i);
     593           2 :                       cs->rebinding = 1;
     594           2 :                       send_client_message_start_stop (i, ~0,
     595             :                                                       DHCPV6_MSG_REBIND,
     596             :                                                       prefix_list, 1);
     597           2 :                       vec_free (prefix_list);
     598             :                     }
     599             :                 }
     600             :             }
     601          18 :           current_time = vlib_time_now (vm);
     602             :         }
     603          18 :       while (due_time < current_time);
     604             : 
     605          17 :       sleep_time = due_time - current_time;
     606             :     }
     607             : 
     608             :   return 0;
     609             : }
     610             : 
     611             : /* *INDENT-OFF* */
     612      149000 : VLIB_REGISTER_NODE (dhcp6_pd_client_cp_process_node) = {
     613             :     .function = dhcp6_pd_client_cp_process,
     614             :     .type = VLIB_NODE_TYPE_PROCESS,
     615             :     .name = "dhcp6-pd-client-cp-process",
     616             : };
     617             : /* *INDENT-ON* */
     618             : 
     619             : static void
     620           5 : interrupt_process (void)
     621             : {
     622           5 :   dhcp6_pd_client_cp_main_t *rm = &dhcp6_pd_client_cp_main;
     623           5 :   vlib_main_t *vm = rm->vlib_main;
     624             : 
     625           5 :   vlib_process_signal_event (vm, dhcp6_pd_client_cp_process_node.index,
     626             :                              DHCPV6_PD_EVENT_INTERRUPT, 0);
     627           5 : }
     628             : 
     629             : static void
     630           7 : disable_process (void)
     631             : {
     632           7 :   dhcp6_pd_client_cp_main_t *rm = &dhcp6_pd_client_cp_main;
     633           7 :   vlib_main_t *vm = rm->vlib_main;
     634             : 
     635           7 :   vlib_process_signal_event (vm, dhcp6_pd_client_cp_process_node.index,
     636             :                              DHCPV6_PD_EVENT_DISABLE, 0);
     637           7 : }
     638             : 
     639             : static void
     640           7 : enable_process (void)
     641             : {
     642           7 :   dhcp6_pd_client_cp_main_t *rm = &dhcp6_pd_client_cp_main;
     643           7 :   vlib_main_t *vm = rm->vlib_main;
     644             :   vlib_node_t *node;
     645             : 
     646           7 :   node = vec_elt (vm->node_main.nodes, rm->node_index);
     647             : 
     648           7 :   vlib_node_set_state (vm, rm->node_index, VLIB_NODE_STATE_POLLING);
     649           7 :   vlib_start_process (vm, node->runtime_index);
     650           7 : }
     651             : 
     652             : static u32
     653           7 : cp_ip6_construct_address (ip6_address_info_t * address_info, u32 prefix_index,
     654             :                           ip6_address_t * r_addr)
     655             : {
     656           7 :   ip6_prefix_main_t *pm = &ip6_prefix_main;
     657             :   prefix_info_t *prefix;
     658             :   u64 mask, addr0, pref;
     659             : 
     660           7 :   addr0 = clib_net_to_host_u64 (address_info->address.as_u64[0]);
     661           7 :   prefix = &pm->prefix_pool[prefix_index];
     662           7 :   if (prefix->prefix_length > 64)
     663             :     {
     664           0 :       clib_warning ("Prefix length is bigger that 64 bits");
     665           0 :       return 1;
     666             :     }
     667           7 :   mask = ((u64) 1 << (64 - prefix->prefix_length)) - 1;
     668           7 :   addr0 &= mask;
     669           7 :   pref = clib_host_to_net_u64 (prefix->prefix.as_u64[0]);
     670           7 :   pref &= ~mask;
     671           7 :   addr0 |= pref;
     672           7 :   r_addr->as_u64[0] = clib_host_to_net_u64 (addr0);
     673           7 :   r_addr->as_u64[1] = address_info->address.as_u64[1];
     674             : 
     675           7 :   return 0;
     676             : }
     677             : 
     678             : static void
     679          11 : cp_ip6_address_add_del_now (ip6_address_info_t * address_info, u8 is_add)
     680             : {
     681          11 :   vlib_main_t *vm = vlib_get_main ();
     682             :   u32 prefix_index;
     683             :   ip6_address_t addr;
     684             :   clib_error_t *error;
     685             : 
     686          11 :   if (address_info->prefix_group_index != ~0)
     687             :     prefix_index =
     688          11 :       active_prefix_index_by_prefix_group_index_get
     689             :       (address_info->prefix_group_index);
     690             :   else
     691           0 :     prefix_index = ~0;
     692             : 
     693          11 :   if (is_add && !address_info->configured_in_data_plane)
     694             :     {
     695           5 :       if (prefix_index != ~0)
     696             :         {
     697           2 :           if (cp_ip6_construct_address (address_info, prefix_index, &addr) !=
     698             :               0)
     699           0 :             return;
     700             :           error =
     701           2 :             ip6_add_del_interface_address (vm, address_info->sw_if_index,
     702           2 :                                            &addr, address_info->prefix_length,
     703             :                                            0 /* add */ );
     704           2 :           if (error)
     705           0 :             clib_warning ("Failed adding IPv6 address: %U",
     706             :                           format_clib_error, error);
     707             :           else
     708             :             {
     709             :               if (CLIB_DEBUG > 0)
     710           2 :                 clib_warning ("Add address %U on %U",
     711             :                               format_ip6_address_and_length,
     712             :                               &addr, address_info->prefix_length,
     713             :                               format_vnet_sw_if_index_name,
     714             :                               vnet_get_main (), address_info->sw_if_index);
     715             : 
     716           2 :               address_info->configured_in_data_plane = 1;
     717             :             }
     718             :         }
     719             :       else
     720             :         {
     721           3 :           if (address_info->prefix_group_index == ~0)
     722             :             {
     723             :               error =
     724           0 :                 ip6_add_del_interface_address (vm, address_info->sw_if_index,
     725             :                                                &address_info->address,
     726           0 :                                                address_info->prefix_length,
     727             :                                                0 /* add */ );
     728           0 :               if (error)
     729           0 :                 clib_warning ("Failed adding IPv6 address: %U",
     730             :                               format_clib_error, error);
     731             :               else
     732             :                 {
     733             :                   if (CLIB_DEBUG > 0)
     734           0 :                     clib_warning ("Add address %U on %U",
     735             :                                   format_ip6_address_and_length,
     736             :                                   &addr, address_info->prefix_length,
     737             :                                   format_vnet_sw_if_index_name,
     738             :                                   vnet_get_main (),
     739             :                                   address_info->sw_if_index);
     740             : 
     741           0 :                   address_info->configured_in_data_plane = 1;
     742             :                 }
     743             :             }
     744             :         }
     745             :     }
     746           6 :   else if (!is_add && address_info->configured_in_data_plane)
     747             :     {
     748           2 :       if (prefix_index == ~0)
     749             :         {
     750           0 :           if (address_info->prefix_group_index == ~0)
     751             :             {
     752             :               error =
     753           0 :                 ip6_add_del_interface_address (vm, address_info->sw_if_index,
     754             :                                                &address_info->address,
     755           0 :                                                address_info->prefix_length,
     756             :                                                1 /* del */ );
     757           0 :               if (error)
     758           0 :                 clib_warning ("Failed deleting IPv6 address: %U",
     759             :                               format_clib_error, error);
     760           0 :               address_info->configured_in_data_plane = 0;
     761             :             }
     762             :           else
     763           0 :             clib_warning ("Deleting address with prefix "
     764             :                           "but active prefix index is not set");
     765             :         }
     766             :       else
     767             :         {
     768           2 :           if (cp_ip6_construct_address (address_info, prefix_index, &addr) !=
     769             :               0)
     770           0 :             return;
     771             :           error =
     772           2 :             ip6_add_del_interface_address (vm, address_info->sw_if_index,
     773           2 :                                            &addr, address_info->prefix_length,
     774             :                                            1 /* del */ );
     775           2 :           if (error)
     776           0 :             clib_warning ("Failed deleting IPv6 address: %U",
     777             :                           format_clib_error, error);
     778           2 :           address_info->configured_in_data_plane = 0;
     779             :         }
     780             :     }
     781             : }
     782             : 
     783             : static u32
     784           1 : cp_ip6_address_find_new_active_prefix (u32 prefix_group_index,
     785             :                                        u32 ignore_prefix_index)
     786             : {
     787           1 :   ip6_prefix_main_t *pm = &ip6_prefix_main;
     788             :   prefix_info_t *prefix_info;
     789             : 
     790             :   /* *INDENT-OFF* */
     791           2 :   pool_foreach (prefix_info, pm->prefix_pool)
     792             :    {
     793           1 :     if (prefix_info->prefix_group_index == prefix_group_index &&
     794           1 :         prefix_info - pm->prefix_pool != ignore_prefix_index)
     795           0 :         return prefix_info - pm->prefix_pool;
     796             :   }
     797             :   /* *INDENT-ON* */
     798           1 :   return ~0;
     799             : }
     800             : 
     801             : static void
     802           3 : cp_ip6_advertise_prefix (prefix_info_t * prefix_info,
     803             :                          ip6_address_info_t * address_info, int enable)
     804             : {
     805           3 :   vlib_main_t *vm = vlib_get_main ();
     806           3 :   ip6_main_t *im = &ip6_main;
     807             :   u32 prefix_index;
     808             :   ip6_address_t addr;
     809             :   int rv;
     810             : 
     811             :   prefix_index =
     812           3 :     active_prefix_index_by_prefix_group_index_get
     813             :     (address_info->prefix_group_index);
     814             : 
     815           3 :   if (cp_ip6_construct_address (address_info, prefix_index, &addr) != 0)
     816             :     {
     817           0 :       clib_warning ("address construction FAIL");
     818           1 :       return;
     819             :     }
     820             : 
     821             :   /* The RA code assumes that host bits are zero, so clear them */
     822           3 :   addr.as_u64[0] &= im->fib_masks[address_info->prefix_length].as_u64[0];
     823           3 :   addr.as_u64[1] &= im->fib_masks[address_info->prefix_length].as_u64[1];
     824             : 
     825           3 :   rv = ip6_ra_prefix (vm, address_info->sw_if_index,
     826           3 :                       &addr, address_info->prefix_length,
     827             :                       0 /* use_default */ ,
     828             :                       prefix_info->valid_lt,
     829             :                       prefix_info->preferred_lt, 0 /* no_advertise */ ,
     830             :                       0 /* off_link */ ,
     831             :                       0 /* no_autoconfig */ ,
     832             :                       0 /* no_onlink */ ,
     833             :                       enable == 0 /* is_no */ );
     834           3 :   if (rv != 0)
     835             :     {
     836           1 :       clib_warning ("ip6_neighbor_ra_prefix returned %d", rv);
     837           1 :       return;
     838             :     }
     839             : 
     840             :   if (CLIB_DEBUG > 0)
     841           2 :     clib_warning ("Advertise prefix %U valid lt %u preferred lt %u",
     842             :                   format_ip6_address_and_length, &addr,
     843             :                   address_info->prefix_length, prefix_info->valid_lt,
     844             :                   prefix_info->preferred_lt);
     845             : }
     846             : 
     847             : 
     848             : static void
     849           2 : cp_ip6_address_prefix_add_del_handler (u32 prefix_index, u8 is_add)
     850             : {
     851           2 :   ip6_address_with_prefix_main_t *apm = &ip6_address_with_prefix_main;
     852           2 :   ip6_prefix_main_t *pm = &ip6_prefix_main;
     853             :   ip6_address_info_t *address_info;
     854             :   prefix_info_t *prefix;
     855             :   u32 new_prefix_index;
     856             :   u32 prefix_group_index;
     857             :   u32 i;
     858             : 
     859           2 :   prefix = &pm->prefix_pool[prefix_index];
     860           2 :   prefix_group_index = prefix->prefix_group_index;
     861             : 
     862           2 :   if (is_add)
     863             :     {
     864           1 :       if (active_prefix_index_by_prefix_group_index_get
     865             :           (prefix_group_index) == ~0)
     866             :         {
     867           1 :           active_prefix_index_by_prefix_group_index_set
     868             :             (prefix_group_index, prefix_index);
     869           2 :           for (i = 0; i < vec_len (apm->addresses); i++)
     870             :             {
     871           1 :               address_info = &apm->addresses[i];
     872           1 :               if (address_info->prefix_group_index == prefix_group_index)
     873             :                 {
     874             :                   /* Add the prefix to the interface */
     875           1 :                   cp_ip6_address_add_del_now (address_info, 1 /* add */ );
     876             :                   /* And advertise the prefix on the interface */
     877           1 :                   cp_ip6_advertise_prefix (prefix, address_info,
     878             :                                            1 /* enable */ );
     879             :                 }
     880             :             }
     881             :         }
     882             :     }
     883             :   else
     884             :     {
     885           1 :       if (active_prefix_index_by_prefix_group_index_get
     886             :           (prefix_group_index) == prefix_index)
     887             :         {
     888           3 :           for (i = 0; i < vec_len (apm->addresses); i++)
     889             :             {
     890           2 :               address_info = &apm->addresses[i];
     891           2 :               if (address_info->prefix_group_index == prefix_group_index)
     892             :                 {
     893           2 :                   cp_ip6_advertise_prefix (prefix, address_info,
     894             :                                            0 /* enable */ );
     895           2 :                   cp_ip6_address_add_del_now (address_info, 0 /* del */ );
     896             :                 }
     897             :             }
     898           1 :           active_prefix_index_by_prefix_group_index_set
     899             :             (prefix_group_index, ~0);
     900             :           new_prefix_index =
     901           1 :             cp_ip6_address_find_new_active_prefix (prefix_group_index,
     902             :                                                    prefix_index);
     903           1 :           if (new_prefix_index != ~0)
     904             :             {
     905           0 :               active_prefix_index_by_prefix_group_index_set
     906             :                 (prefix_group_index, new_prefix_index);
     907           0 :               for (i = 0; i < vec_len (apm->addresses); i++)
     908             :                 {
     909           0 :                   address_info = &apm->addresses[i];
     910           0 :                   if (address_info->prefix_group_index == prefix_group_index)
     911             :                     {
     912           0 :                       cp_ip6_address_add_del_now (address_info, 1 /* add */ );
     913           0 :                       cp_ip6_advertise_prefix (prefix, address_info,
     914             :                                                1 /* enable */ );
     915             :                     }
     916             :                 }
     917             :             }
     918             :         }
     919             :     }
     920           2 : }
     921             : 
     922             : static u32
     923          15 : prefix_group_find_or_create (const u8 * name, u8 create)
     924             : {
     925          15 :   ip6_prefix_main_t *pm = &ip6_prefix_main;
     926          15 :   u32 free_index = ~0;
     927             :   u8 *name_dup;
     928             :   u32 i;
     929             : 
     930          15 :   for (i = 0; i < vec_len (pm->prefix_group_name_by_index); i++)
     931             :     {
     932          14 :       if (pm->prefix_group_name_by_index[i] == 0)
     933           0 :         free_index = i;
     934          14 :       else if (0 ==
     935          14 :                strcmp ((const char *) pm->prefix_group_name_by_index[i],
     936             :                        (const char *) name))
     937          14 :         return i;
     938             :     }
     939           1 :   if (!create)
     940           0 :     return ~0;
     941           1 :   name_dup = (u8 *) strdup ((const char *) name);
     942           1 :   if (free_index != ~0)
     943             :     {
     944           0 :       pm->prefix_group_name_by_index[free_index] = name_dup;
     945           0 :       return free_index;
     946             :     }
     947             :   else
     948             :     {
     949           1 :       vec_add1 (pm->prefix_group_name_by_index, name_dup);
     950           1 :       return vec_len (pm->prefix_group_name_by_index) - 1;
     951             :     }
     952             : }
     953             : 
     954             : int
     955           8 : dhcp6_cp_ip6_address_add_del (u32 sw_if_index, const u8 * prefix_group,
     956             :                               ip6_address_t address, u8 prefix_length,
     957             :                               u8 is_add)
     958             : {
     959             : 
     960           8 :   ip6_address_with_prefix_main_t *apm = &ip6_address_with_prefix_main;
     961           8 :   vnet_main_t *vnm = vnet_get_main ();
     962             :   ip6_address_info_t *address_info;
     963             :   u32 prefix_group_index;
     964             :   u32 n;
     965             : 
     966           8 :   if (!vnet_sw_interface_is_api_valid (vnm, sw_if_index))
     967             :     {
     968           0 :       clib_warning ("Invalid sw_if_index");
     969           0 :       return VNET_API_ERROR_INVALID_VALUE;
     970             :     }
     971             : 
     972           8 :   if (prefix_group != 0 && prefix_group[0] != '\0')
     973             :     {
     974           8 :       if (strnlen ((const char *) prefix_group, 64) == 64)
     975           0 :         return VNET_API_ERROR_INVALID_VALUE;
     976             : 
     977           8 :       prefix_group_index = prefix_group_find_or_create (prefix_group, 1);
     978             :     }
     979             :   else
     980           0 :     prefix_group_index = ~0;
     981             : 
     982           8 :   n = vec_len (apm->addresses);
     983             : 
     984           9 :   vec_foreach (address_info, apm->addresses)
     985             :   {
     986           5 :     if (address_info->sw_if_index == sw_if_index &&
     987           5 :         address_info->prefix_group_index == prefix_group_index &&
     988           5 :         address_info->prefix_length == prefix_length &&
     989           4 :         0 == memcmp (&address_info->address, &address, 16))
     990             :       {
     991           4 :         if (is_add)
     992           0 :           return VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
     993           4 :         cp_ip6_address_add_del_now (address_info, 0 /* del */ );
     994           4 :         *address_info = apm->addresses[n - 1];
     995           4 :         vec_set_len (apm->addresses, n - 1);
     996           4 :         return 0;
     997             :       }
     998             :   }
     999             : 
    1000           4 :   if (!is_add)
    1001           0 :     return VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
    1002             : 
    1003           4 :   vec_validate (apm->addresses, n);
    1004           4 :   address_info = &apm->addresses[n];
    1005           4 :   address_info->sw_if_index = sw_if_index;
    1006           4 :   address_info->prefix_group_index = prefix_group_index;
    1007           4 :   address_info->address = address;
    1008           4 :   address_info->prefix_length = prefix_length;
    1009           4 :   cp_ip6_address_add_del_now (address_info, 1 /* add */ );
    1010             : 
    1011           4 :   return 0;
    1012             : }
    1013             : 
    1014             : static clib_error_t *
    1015           0 : cp_ip6_address_add_del_command_function (vlib_main_t * vm,
    1016             :                                          unformat_input_t * input,
    1017             :                                          vlib_cli_command_t * cmd)
    1018             : {
    1019           0 :   vnet_main_t *vnm = vnet_get_main ();
    1020           0 :   clib_error_t *error = 0;
    1021           0 :   u32 sw_if_index = ~0;
    1022           0 :   u8 *prefix_group = 0;
    1023             :   ip6_address_t address;
    1024             :   u32 prefix_length;
    1025           0 :   u8 address_set = 0;
    1026           0 :   u8 add = 1;
    1027           0 :   unformat_input_t _line_input, *line_input = &_line_input;
    1028             : 
    1029           0 :   if (!unformat_user (input, unformat_line_input, line_input))
    1030           0 :     return 0;
    1031             : 
    1032           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
    1033             :     {
    1034           0 :       if (unformat
    1035             :           (line_input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index));
    1036           0 :       else if (unformat (line_input, "prefix group %s", &prefix_group));
    1037             :       else
    1038           0 :         if (unformat (line_input, "%U/%d", unformat_ip6_address,
    1039             :                       &address, &prefix_length))
    1040           0 :         address_set = 1;
    1041           0 :       else if (unformat (line_input, "del"))
    1042           0 :         add = 0;
    1043             :       else
    1044             :         {
    1045           0 :           error = clib_error_return (0, "unexpected input `%U'",
    1046             :                                      format_unformat_error, line_input);
    1047           0 :           unformat_free (line_input);
    1048           0 :           goto done;
    1049             :         }
    1050             :     }
    1051             : 
    1052           0 :   unformat_free (line_input);
    1053             : 
    1054           0 :   if (sw_if_index == ~0)
    1055           0 :     error = clib_error_return (0, "Missing sw_if_index");
    1056           0 :   else if (address_set == 0)
    1057           0 :     error = clib_error_return (0, "Missing address");
    1058             :   else
    1059             :     {
    1060           0 :       if (dhcp6_cp_ip6_address_add_del
    1061             :           (sw_if_index, prefix_group, address, prefix_length, add) != 0)
    1062           0 :         error = clib_error_return (0, "Error adding or removing address");
    1063             :     }
    1064             : 
    1065           0 : done:
    1066           0 :   return error;
    1067             : }
    1068             : 
    1069             : /*?
    1070             :  * This command is used to add/delete IPv6 address
    1071             :  * potentially using available prefix from specified prefix group
    1072             :  *
    1073             :  * @cliexpar
    1074             :  * @parblock
    1075             :  * Example of how to add IPv6 address:
    1076             :  * @cliexcmd{set ip6 address GigabitEthernet2/0/0
    1077             :  *           prefix group my-prefix-group ::7/64}
    1078             :  * Example of how to delete IPv6 address:
    1079             :  * @cliexcmd{set ip6 address GigabitEthernet2/0/0
    1080             :  *           prefix group my-prefix-group ::7/64 del}
    1081             :  * @endparblock
    1082             : ?*/
    1083             : /* *INDENT-OFF* */
    1084      224727 : VLIB_CLI_COMMAND (ip6_address_add_del_command, static) = {
    1085             :   .path = "set ip6 address",
    1086             :   .short_help = "set ip6 address <interface> [prefix group <string>] "
    1087             :                 "<address> [del]",
    1088             :   .function = cp_ip6_address_add_del_command_function,
    1089             : };
    1090             : /* *INDENT-ON* */
    1091             : 
    1092             : static clib_error_t *
    1093           0 : cp_ip6_addresses_show_command_function (vlib_main_t * vm,
    1094             :                                         unformat_input_t * input,
    1095             :                                         vlib_cli_command_t * cmd)
    1096             : {
    1097           0 :   ip6_address_with_prefix_main_t *apm = &ip6_address_with_prefix_main;
    1098           0 :   ip6_prefix_main_t *pm = &ip6_prefix_main;
    1099             :   ip6_address_info_t *address_info;
    1100             :   const u8 *prefix_group;
    1101           0 :   clib_error_t *error = 0;
    1102             :   int i;
    1103             : 
    1104           0 :   for (i = 0; i < vec_len (apm->addresses); i++)
    1105             :     {
    1106           0 :       address_info = &apm->addresses[i];
    1107           0 :       if (address_info->prefix_group_index == ~0)
    1108           0 :         prefix_group = (const u8 *) "NONE";
    1109             :       else
    1110           0 :         prefix_group =
    1111           0 :           pm->prefix_group_name_by_index[address_info->prefix_group_index];
    1112           0 :       vlib_cli_output (vm,
    1113             :                        "sw_if_index: %u, prefix_group: %s, address: %U/%d",
    1114             :                        address_info->sw_if_index, prefix_group,
    1115             :                        format_ip6_address, &address_info->address,
    1116           0 :                        address_info->prefix_length);
    1117             :     }
    1118             : 
    1119           0 :   return error;
    1120             : }
    1121             : 
    1122             : /* *INDENT-OFF* */
    1123      224727 : VLIB_CLI_COMMAND (ip6_addresses_show_command, static) = {
    1124             :   .path = "show ip6 addresses",
    1125             :   .short_help = "show ip6 addresses",
    1126             :   .function = cp_ip6_addresses_show_command_function,
    1127             : };
    1128             : /* *INDENT-ON* */
    1129             : 
    1130             : static clib_error_t *
    1131           0 : cp_ip6_prefixes_show_command_function (vlib_main_t * vm,
    1132             :                                        unformat_input_t * input,
    1133             :                                        vlib_cli_command_t * cmd)
    1134             : {
    1135           0 :   ip6_prefix_main_t *pm = &ip6_prefix_main;
    1136           0 :   clib_error_t *error = 0;
    1137             :   prefix_info_t *prefix_info;
    1138             :   const u8 *prefix_group;
    1139           0 :   f64 current_time = vlib_time_now (vm);
    1140             : 
    1141             :   /* *INDENT-OFF* */
    1142           0 :   pool_foreach (prefix_info, pm->prefix_pool)
    1143             :    {
    1144           0 :     prefix_group =
    1145           0 :       pm->prefix_group_name_by_index[prefix_info->prefix_group_index];
    1146           0 :     vlib_cli_output (vm, "opaque_data: %lu, prefix: %U/%d, prefix group: %s, "
    1147             :                      "preferred lifetime: %u, valid lifetime: %u "
    1148             :                      "(%f remaining)",
    1149             :                      prefix_info->opaque_data, format_ip6_address,
    1150           0 :                      &prefix_info->prefix, prefix_info->prefix_length,
    1151             :                      prefix_group,
    1152             :                      prefix_info->preferred_lt, prefix_info->valid_lt,
    1153           0 :                      prefix_info->due_time - current_time);
    1154             :   }
    1155             :   /* *INDENT-ON* */
    1156             : 
    1157           0 :   return error;
    1158             : }
    1159             : 
    1160             : /* *INDENT-OFF* */
    1161      224727 : VLIB_CLI_COMMAND (ip6_prefixes_show_command, static) = {
    1162             :   .path = "show ip6 prefixes",
    1163             :   .short_help = "show ip6 prefixes",
    1164             :   .function = cp_ip6_prefixes_show_command_function,
    1165             : };
    1166             : /* *INDENT-ON* */
    1167             : 
    1168             : static clib_error_t *
    1169           0 : ip6_pd_clients_show_command_function (vlib_main_t * vm,
    1170             :                                       unformat_input_t * input,
    1171             :                                       vlib_cli_command_t * cmd)
    1172             : {
    1173           0 :   dhcp6_pd_client_cp_main_t *rm = &dhcp6_pd_client_cp_main;
    1174           0 :   ip6_prefix_main_t *pm = &ip6_prefix_main;
    1175           0 :   clib_error_t *error = 0;
    1176             :   client_state_t *cs;
    1177           0 :   f64 current_time = vlib_time_now (vm);
    1178             :   const u8 *prefix_group;
    1179           0 :   u8 *buf1 = 0;
    1180           0 :   u8 *buf2 = 0;
    1181             :   const char *rebinding;
    1182             :   u32 i;
    1183             : 
    1184           0 :   for (i = 0; i < vec_len (rm->client_state_by_sw_if_index); i++)
    1185             :     {
    1186           0 :       cs = &rm->client_state_by_sw_if_index[i];
    1187           0 :       if (cs->enabled)
    1188             :         {
    1189           0 :           vec_reset_length (buf1);
    1190           0 :           vec_reset_length (buf2);
    1191           0 :           if (cs->T1_due_time != DBL_MAX && cs->T1_due_time > current_time)
    1192             :             {
    1193           0 :               buf1 = format (buf1, "%u remaining",
    1194           0 :                              (u32) round (cs->T1_due_time - current_time));
    1195             :             }
    1196             :           else
    1197           0 :             buf1 = format (buf1, "timeout");
    1198           0 :           if (cs->T2_due_time != DBL_MAX && cs->T2_due_time > current_time)
    1199           0 :             buf2 = format (buf2, "%u remaining",
    1200           0 :                            (u32) round (cs->T2_due_time - current_time));
    1201             :           else
    1202           0 :             buf2 = format (buf2, "timeout");
    1203           0 :           if (cs->rebinding)
    1204           0 :             rebinding = ", REBINDING";
    1205             :           else
    1206           0 :             rebinding = "";
    1207           0 :           prefix_group =
    1208           0 :             pm->prefix_group_name_by_index[cs->prefix_group_index];
    1209           0 :           if (cs->T1)
    1210           0 :             vlib_cli_output (vm,
    1211             :                              "sw_if_index: %u, prefix group: %s, T1: %u (%v), "
    1212             :                              "T2: %u (%v), server index: %d%s", i,
    1213             :                              prefix_group, cs->T1, buf1, cs->T2, buf2,
    1214             :                              cs->server_index, rebinding);
    1215             :           else
    1216           0 :             vlib_cli_output (vm, "sw_if_index: %u, prefix group: %s%s", i,
    1217             :                              prefix_group, rebinding);
    1218             :         }
    1219             :     }
    1220             : 
    1221           0 :   vec_free (buf1);
    1222           0 :   vec_free (buf2);
    1223             : 
    1224           0 :   return error;
    1225             : }
    1226             : 
    1227             : /* *INDENT-OFF* */
    1228      224727 : VLIB_CLI_COMMAND (ip6_pd_clients_show_command, static) = {
    1229             :   .path = "show ip6 pd clients",
    1230             :   .short_help = "show ip6 pd clients",
    1231             :   .function = ip6_pd_clients_show_command_function,
    1232             : };
    1233             : /* *INDENT-ON* */
    1234             : 
    1235             : 
    1236             : 
    1237             : int
    1238          14 : dhcp6_pd_client_enable_disable (u32 sw_if_index,
    1239             :                                 const u8 * prefix_group, u8 enable)
    1240             : {
    1241          14 :   dhcp6_pd_client_cp_main_t *rm = &dhcp6_pd_client_cp_main;
    1242          14 :   ip6_prefix_main_t *pm = &ip6_prefix_main;
    1243          14 :   vnet_main_t *vnm = rm->vnet_main;
    1244             :   client_state_t *client_state;
    1245             :   static client_state_t empty_config = {
    1246             :     0
    1247             :   };
    1248             :   prefix_info_t *prefix_info;
    1249          14 :   prefix_info_t *prefix_list = 0;
    1250             :   u32 prefix_group_index;
    1251             : 
    1252          14 :   if (!vnet_sw_interface_is_api_valid (vnm, sw_if_index))
    1253             :     {
    1254           0 :       clib_warning ("Invalid sw_if_index");
    1255           0 :       return VNET_API_ERROR_INVALID_VALUE;
    1256             :     }
    1257             : 
    1258          16 :   vec_validate_init_empty (rm->client_state_by_sw_if_index, sw_if_index,
    1259             :                            empty_config);
    1260          14 :   client_state = &rm->client_state_by_sw_if_index[sw_if_index];
    1261             : 
    1262          14 :   u8 old_enabled = client_state->enabled;
    1263             : 
    1264          14 :   if (enable)
    1265             :     {
    1266           7 :       if (strnlen ((const char *) prefix_group, 64) == 64
    1267           7 :           || prefix_group[0] == '\0')
    1268           0 :         return VNET_API_ERROR_INVALID_VALUE;
    1269             :       prefix_group_index =
    1270           7 :         prefix_group_find_or_create (prefix_group, !old_enabled);
    1271           7 :       if (old_enabled
    1272           0 :           && prefix_group_index != client_state->prefix_group_index)
    1273           0 :         return VNET_API_ERROR_INVALID_VALUE;
    1274             :     }
    1275             : 
    1276          14 :   if (!old_enabled && enable)
    1277             :     {
    1278           7 :       client_state->enabled = 1;
    1279           7 :       client_state->prefix_group_index = prefix_group_index;
    1280           7 :       ASSERT (client_state->prefix_group_index != ~0);
    1281           7 :       client_state->server_index = ~0;
    1282             : 
    1283           7 :       rm->n_clients++;
    1284           7 :       if (rm->n_clients == 1)
    1285             :         {
    1286           7 :           enable_process ();
    1287           7 :           dhcp6_clients_enable_disable (1);
    1288             :         }
    1289             : 
    1290           7 :       ip6_link_enable (sw_if_index, NULL);
    1291           7 :       send_client_message_start_stop (sw_if_index, ~0, DHCPV6_MSG_SOLICIT,
    1292             :                                       0, 1);
    1293             :     }
    1294           7 :   else if (old_enabled && !enable)
    1295             :     {
    1296           7 :       send_client_message_start_stop (sw_if_index, ~0, ~0, 0, 0);
    1297             : 
    1298           7 :       rm->n_clients--;
    1299           7 :       if (rm->n_clients == 0)
    1300             :         {
    1301           7 :           dhcp6_clients_enable_disable (0);
    1302           7 :           disable_process ();
    1303             :         }
    1304             : 
    1305           7 :       vec_validate (prefix_list, 0);
    1306             : 
    1307             :       /* *INDENT-OFF* */
    1308           7 :       pool_foreach (prefix_info, pm->prefix_pool)
    1309             :        {
    1310           0 :         if (is_dhcpv6_pd_prefix (prefix_info) &&
    1311           0 :             prefix_info->opaque_data == sw_if_index)
    1312             :           {
    1313           0 :             ASSERT (sw_if_index < vec_len (rm->client_state_by_sw_if_index) &&
    1314             :                     rm->client_state_by_sw_if_index[sw_if_index].enabled);
    1315           0 :             client_state_t *client_state =
    1316           0 :               &rm->client_state_by_sw_if_index[sw_if_index];
    1317           0 :             prefix_list[0] = *prefix_info;
    1318           0 :             send_client_message_start_stop (sw_if_index,
    1319             :                                             client_state->server_index,
    1320             :                                             DHCPV6_MSG_RELEASE, prefix_list,
    1321             :                                             1);
    1322           0 :             u32 prefix_index = prefix_info - pm->prefix_pool;
    1323           0 :             notify_prefix_add_del (prefix_index, 0);
    1324           0 :             set_is_dhcpv6_pd_prefix (prefix_info, 0);
    1325           0 :             pool_put (pm->prefix_pool, prefix_info);
    1326             :           }
    1327             :       }
    1328             :       /* *INDENT-ON* */
    1329             : 
    1330           7 :       vec_free (prefix_list);
    1331             : 
    1332           7 :       clib_memset (client_state, 0, sizeof (*client_state));
    1333             :     }
    1334             : 
    1335          14 :   return 0;
    1336             : }
    1337             : 
    1338             : static clib_error_t *
    1339           0 : dhcp6_pd_client_enable_disable_command_fn (vlib_main_t *
    1340             :                                            vm,
    1341             :                                            unformat_input_t
    1342             :                                            * input, vlib_cli_command_t * cmd)
    1343             : {
    1344           0 :   dhcp6_pd_client_cp_main_t *rm = &dhcp6_pd_client_cp_main;
    1345           0 :   vnet_main_t *vnm = rm->vnet_main;
    1346           0 :   clib_error_t *error = 0;
    1347           0 :   u8 *prefix_group = 0;
    1348           0 :   u32 sw_if_index = ~0;
    1349           0 :   u8 enable = 1;
    1350           0 :   unformat_input_t _line_input, *line_input = &_line_input;
    1351             : 
    1352           0 :   if (!unformat_user (input, unformat_line_input, line_input))
    1353           0 :     return 0;
    1354             : 
    1355           0 :   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
    1356             :     {
    1357           0 :       if (unformat
    1358             :           (line_input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
    1359             :         ;
    1360           0 :       else if (unformat (line_input, "prefix group %s", &prefix_group));
    1361           0 :       else if (unformat (line_input, "disable"))
    1362           0 :         enable = 0;
    1363             :       else
    1364             :         {
    1365           0 :           error = clib_error_return (0, "unexpected input `%U'",
    1366             :                                      format_unformat_error, line_input);
    1367           0 :           goto done;
    1368             :         }
    1369             :     }
    1370             : 
    1371           0 :   if (prefix_group == 0 && enable)
    1372           0 :     error = clib_error_return (0, "Prefix group must be set when enabling");
    1373           0 :   else if (sw_if_index != ~0)
    1374             :     {
    1375           0 :       if (dhcp6_pd_client_enable_disable (sw_if_index, prefix_group, enable)
    1376             :           != 0)
    1377           0 :         error = clib_error_return (0, "Invalid sw_if_index or prefix group");
    1378             :     }
    1379             :   else
    1380           0 :     error = clib_error_return (0, "Missing sw_if_index");
    1381             : 
    1382           0 : done:
    1383           0 :   vec_free (prefix_group);
    1384           0 :   unformat_free (line_input);
    1385             : 
    1386           0 :   return error;
    1387             : }
    1388             : 
    1389             : /*?
    1390             :  * This command is used to enable/disable DHCPv6 PD client
    1391             :  * on particular interface.
    1392             :  *
    1393             :  * @cliexpar
    1394             :  * @parblock
    1395             :  * Example of how to enable DHCPv6 PD client:
    1396             :  * @cliexcmd{dhcp6 pd client GigabitEthernet2/0/0 prefix group my-pd-group}
    1397             :  * Example of how to disable DHCPv6 PD client:
    1398             :  * @cliexcmd{dhcp6 pd client GigabitEthernet2/0/0 disable}
    1399             :  * @endparblock
    1400             : ?*/
    1401             : /* *INDENT-OFF* */
    1402      224727 : VLIB_CLI_COMMAND (dhcp6_pd_client_enable_disable_command, static) = {
    1403             :   .path = "dhcp6 pd client",
    1404             :   .short_help = "dhcp6 pd client <interface> (prefix group <string> | disable)",
    1405             :   .function = dhcp6_pd_client_enable_disable_command_fn,
    1406             : };
    1407             : /* *INDENT-ON* */
    1408             : 
    1409             : #include <vlib/unix/plugin.h>
    1410             : 
    1411             : static clib_error_t *
    1412         559 : dhcp_pd_client_cp_init (vlib_main_t * vm)
    1413             : {
    1414         559 :   dhcp6_pd_client_cp_main_t *rm = &dhcp6_pd_client_cp_main;
    1415             : 
    1416         559 :   rm->vlib_main = vm;
    1417         559 :   rm->vnet_main = vnet_get_main ();
    1418         559 :   rm->api_main = vlibapi_get_main ();
    1419         559 :   rm->node_index = dhcp6_pd_client_cp_process_node.index;
    1420             : 
    1421         559 :   return (NULL);
    1422             : }
    1423             : 
    1424        3359 : VLIB_INIT_FUNCTION (dhcp_pd_client_cp_init);
    1425             : 
    1426             : /*
    1427             :  * fd.io coding-style-patch-verification: ON
    1428             :  *
    1429             :  * Local Variables:
    1430             :  * eval: (c-set-style "gnu")
    1431             :  * End:
    1432             :  */

Generated by: LCOV version 1.14