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