Implement DHCPv6 PD client (VPP-718, VPP-1050)
[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 = (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   ip6_address_info_t *address_info;
875   u32 prefix_group_index;
876   u32 n;
877
878   if (prefix_group != 0 && prefix_group[0] != '\0')
879     {
880       if (strnlen ((const char *) prefix_group, 64) == 64)
881         return VNET_API_ERROR_INVALID_VALUE;
882
883       prefix_group_index = prefix_group_find_or_create (prefix_group, 1);
884     }
885   else
886     prefix_group_index = ~0;
887
888   n = vec_len (apm->addresses);
889
890   vec_foreach (address_info, apm->addresses)
891   {
892     if (address_info->sw_if_index == sw_if_index &&
893         address_info->prefix_group_index == prefix_group_index &&
894         address_info->prefix_length == prefix_length &&
895         0 == memcmp (&address_info->address, &address, 16))
896       {
897         if (is_add)
898           return VNET_API_ERROR_DUPLICATE_IF_ADDRESS;
899         cp_ip6_address_add_del_now (address_info, 0 /* del */ );
900         *address_info = apm->addresses[n - 1];
901         _vec_len (apm->addresses) = n - 1;
902         return 0;
903       }
904   }
905
906   if (!is_add)
907     return VNET_API_ERROR_ADDRESS_NOT_FOUND_FOR_INTERFACE;
908
909   vec_validate (apm->addresses, n);
910   address_info = &apm->addresses[n];
911   address_info->sw_if_index = sw_if_index;
912   address_info->prefix_group_index = prefix_group_index;
913   address_info->address = address;
914   address_info->prefix_length = prefix_length;
915   cp_ip6_address_add_del_now (address_info, 1 /* add */ );
916
917   return 0;
918 }
919
920 static void
921   vl_api_ip6_add_del_address_using_prefix_t_handler
922   (vl_api_ip6_add_del_address_using_prefix_t * mp)
923 {
924   vl_api_ip6_add_del_address_using_prefix_reply_t *rmp;
925   u32 sw_if_index;
926   ip6_address_t address;
927   u8 prefix_length;
928   int rv = 0;
929
930   sw_if_index = ntohl (mp->sw_if_index);
931   if (!vnet_sw_if_index_is_api_valid (sw_if_index))
932     {
933       rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
934       goto bad_sw_if_index;
935     }
936
937   memcpy (address.as_u8, mp->address, 16);
938   prefix_length = mp->prefix_length;
939
940   rv =
941     cp_ip6_address_add_del (sw_if_index, mp->prefix_group, address,
942                             prefix_length, mp->is_add);
943
944   BAD_SW_IF_INDEX_LABEL;
945
946   REPLY_MACRO (VL_API_SW_INTERFACE_SET_TABLE_REPLY);
947 }
948
949 static clib_error_t *
950 cp_ip6_address_add_del_command_function (vlib_main_t * vm,
951                                          unformat_input_t * input,
952                                          vlib_cli_command_t * cmd)
953 {
954   vnet_main_t *vnm = vnet_get_main ();
955   clib_error_t *error = 0;
956   u32 sw_if_index = ~0;
957   u8 *prefix_group = 0;
958   ip6_address_t address;
959   u32 prefix_length;
960   u8 address_set = 0;
961   u8 add = 1;
962
963   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
964     {
965       if (unformat
966           (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index));
967       else if (unformat (input, "prefix group %s", &prefix_group));
968       else
969         if (unformat
970             (input, "%U/%d", unformat_ip6_address, &address, &prefix_length))
971         address_set = 1;
972       else if (unformat (input, "del"))
973         add = 0;
974       else
975         {
976           error = clib_error_return (0, "unexpected input `%U'",
977                                      format_unformat_error, input);
978           goto done;
979         }
980     }
981
982   if (sw_if_index == ~0)
983     error = clib_error_return (0, "Missing sw_if_index");
984   else if (address_set == 0)
985     error = clib_error_return (0, "Missing address");
986   else
987     {
988       if (cp_ip6_address_add_del
989           (sw_if_index, prefix_group, address, prefix_length, add) != 0)
990         error = clib_error_return (0, "Error adding or removing address");
991     }
992
993 done:
994   return error;
995 }
996
997 /*?
998  * This command is used to add/delete IPv6 address
999  * potentially using available prefix from specified prefix group
1000  *
1001  * @cliexpar
1002  * @parblock
1003  * Example of how to add IPv6 address:
1004  * @cliexcmd{set ip6 address GigabitEthernet2/0/0
1005  *           prefix group my-prefix-group ::7/64}
1006  * Example of how to delete IPv6 address:
1007  * @cliexcmd{set ip6 address GigabitEthernet2/0/0
1008  *           prefix group my-prefix-group ::7/64 del}
1009  * @endparblock
1010 ?*/
1011 /* *INDENT-OFF* */
1012 VLIB_CLI_COMMAND (ip6_address_add_del_command, static) = {
1013   .path = "set ip6 address",
1014   .short_help = "set ip6 address <interface> [prefix group <string>] "
1015                 "<address> [del]",
1016   .function = cp_ip6_address_add_del_command_function,
1017 };
1018 /* *INDENT-ON* */
1019
1020 static clib_error_t *
1021 cp_ip6_addresses_show_command_function (vlib_main_t * vm,
1022                                         unformat_input_t * input,
1023                                         vlib_cli_command_t * cmd)
1024 {
1025   ip6_address_with_prefix_main_t *apm = &ip6_address_with_prefix_main;
1026   ip6_prefix_main_t *pm = &ip6_prefix_main;
1027   ip6_address_info_t *address_info;
1028   const u8 *prefix_group;
1029   clib_error_t *error = 0;
1030   int i;
1031
1032   for (i = 0; i < vec_len (apm->addresses); i++)
1033     {
1034       address_info = &apm->addresses[i];
1035       if (address_info->prefix_group_index == ~0)
1036         prefix_group = (const u8 *) "NONE";
1037       else
1038         prefix_group =
1039           pm->prefix_group_name_by_index[address_info->prefix_group_index];
1040       vlib_cli_output (vm,
1041                        "sw_if_index: %u, prefix_group: %s, address: %U/%d",
1042                        address_info->sw_if_index, prefix_group,
1043                        format_ip6_address, &address_info->address,
1044                        address_info->prefix_length);
1045     }
1046
1047   return error;
1048 }
1049
1050 /* *INDENT-OFF* */
1051 VLIB_CLI_COMMAND (ip6_addresses_show_command, static) = {
1052   .path = "show ip6 addresses",
1053   .short_help = "show ip6 addresses",
1054   .function = cp_ip6_addresses_show_command_function,
1055 };
1056 /* *INDENT-ON* */
1057
1058 static clib_error_t *
1059 cp_ip6_prefixes_show_command_function (vlib_main_t * vm,
1060                                        unformat_input_t * input,
1061                                        vlib_cli_command_t * cmd)
1062 {
1063   ip6_prefix_main_t *pm = &ip6_prefix_main;
1064   clib_error_t *error = 0;
1065   prefix_info_t *prefix_info;
1066   const u8 *prefix_group;
1067   f64 current_time = vlib_time_now (vm);
1068
1069   /* *INDENT-OFF* */
1070   pool_foreach (prefix_info, pm->prefix_pool,
1071   ({
1072     prefix_group =
1073       pm->prefix_group_name_by_index[prefix_info->prefix_group_index];
1074     vlib_cli_output (vm, "opaque_data: %lu, prefix: %U/%d, prefix group: %s, "
1075                      "preferred lifetime: %u, valid lifetime: %u "
1076                      "(%f remaining)",
1077                      prefix_info->opaque_data, format_ip6_address,
1078                      &prefix_info->prefix, prefix_info->prefix_length,
1079                      prefix_group,
1080                      prefix_info->preferred_lt, prefix_info->valid_lt,
1081                      prefix_info->due_time - current_time);
1082   }));
1083   /* *INDENT-ON* */
1084
1085   return error;
1086 }
1087
1088 /* *INDENT-OFF* */
1089 VLIB_CLI_COMMAND (ip6_prefixes_show_command, static) = {
1090   .path = "show ip6 prefixes",
1091   .short_help = "show ip6 prefixes",
1092   .function = cp_ip6_prefixes_show_command_function,
1093 };
1094 /* *INDENT-ON* */
1095
1096 static clib_error_t *
1097 ip6_pd_clients_show_command_function (vlib_main_t * vm,
1098                                       unformat_input_t * input,
1099                                       vlib_cli_command_t * cmd)
1100 {
1101   dhcp6_pd_client_cp_main_t *rm = &dhcp6_pd_client_cp_main;
1102   ip6_prefix_main_t *pm = &ip6_prefix_main;
1103   clib_error_t *error = 0;
1104   client_state_t *cs;
1105   f64 current_time = vlib_time_now (vm);
1106   const u8 *prefix_group;
1107   char buf1[256];
1108   char buf2[256];
1109   const char *rebinding;
1110   u32 i;
1111
1112   for (i = 0; i < vec_len (rm->client_state_by_sw_if_index); i++)
1113     {
1114       cs = &rm->client_state_by_sw_if_index[i];
1115       if (cs->enabled)
1116         {
1117           if (cs->T1_due_time != DBL_MAX && cs->T1_due_time > current_time)
1118             {
1119               sprintf (buf1, "%u remaining",
1120                        (u32) round (cs->T1_due_time - current_time));
1121             }
1122           else
1123             sprintf (buf1, "timeout");
1124           if (cs->T2_due_time != DBL_MAX && cs->T2_due_time > current_time)
1125             sprintf (buf2, "%u remaining",
1126                      (u32) round (cs->T2_due_time - current_time));
1127           else
1128             sprintf (buf2, "timeout");
1129           if (cs->rebinding)
1130             rebinding = ", REBINDING";
1131           else
1132             rebinding = "";
1133           prefix_group =
1134             pm->prefix_group_name_by_index[cs->prefix_group_index];
1135           if (cs->T1)
1136             vlib_cli_output (vm,
1137                              "sw_if_index: %u, prefix group: %s, T1: %u (%s), "
1138                              "T2: %u (%s), server index: %d%s", i,
1139                              prefix_group, cs->T1, buf1, cs->T2, buf2,
1140                              cs->server_index, rebinding);
1141           else
1142             vlib_cli_output (vm, "sw_if_index: %u, prefix group: %s%s", i,
1143                              prefix_group, rebinding);
1144         }
1145     }
1146
1147   return error;
1148 }
1149
1150 /* *INDENT-OFF* */
1151 VLIB_CLI_COMMAND (ip6_pd_clients_show_command, static) = {
1152   .path = "show ip6 pd clients",
1153   .short_help = "show ip6 pd clients",
1154   .function = ip6_pd_clients_show_command_function,
1155 };
1156 /* *INDENT-ON* */
1157
1158 static int
1159 dhcp6_pd_client_enable_disable (u32 sw_if_index, const u8 * prefix_group,
1160                                 u8 enable)
1161 {
1162   dhcp6_pd_client_cp_main_t *rm = &dhcp6_pd_client_cp_main;
1163   ip6_prefix_main_t *pm = &ip6_prefix_main;
1164   vnet_main_t *vnm = rm->vnet_main;
1165   client_state_t *client_state;
1166   static client_state_t empty_config = {
1167     0
1168   };
1169   prefix_info_t *prefix_info;
1170   prefix_info_t *prefix_list = 0;
1171   u32 prefix_group_index;
1172
1173   if (!vnet_sw_interface_is_api_valid (vnm, sw_if_index))
1174     {
1175       clib_warning ("Invalid sw_if_index");
1176       return VNET_API_ERROR_INVALID_VALUE;
1177     }
1178
1179   vec_validate_init_empty (rm->client_state_by_sw_if_index, sw_if_index,
1180                            empty_config);
1181   client_state = &rm->client_state_by_sw_if_index[sw_if_index];
1182
1183   u8 old_enabled = client_state->enabled;
1184
1185   if (enable)
1186     {
1187       if (strnlen ((const char *) prefix_group, 64) == 64
1188           || prefix_group[0] == '\0')
1189         return VNET_API_ERROR_INVALID_VALUE;
1190       prefix_group_index =
1191         prefix_group_find_or_create (prefix_group, !old_enabled);
1192       if (old_enabled
1193           && prefix_group_index != client_state->prefix_group_index)
1194         return VNET_API_ERROR_INVALID_VALUE;
1195     }
1196
1197   if (!old_enabled && enable)
1198     {
1199       client_state->enabled = 1;
1200       client_state->prefix_group_index = prefix_group_index;
1201       ASSERT (client_state->prefix_group_index != ~0);
1202       client_state->server_index = ~0;
1203
1204       rm->n_clients++;
1205       if (rm->n_clients == 1)
1206         {
1207           enable_process ();
1208           dhcp6_clients_enable_disable (1);
1209         }
1210
1211       ip6_enable (sw_if_index);
1212       send_client_message_start_stop (sw_if_index, ~0, DHCPV6_MSG_SOLICIT,
1213                                       0, 1);
1214     }
1215   else if (old_enabled && !enable)
1216     {
1217       send_client_message_start_stop (sw_if_index, ~0, ~0, 0, 0);
1218
1219       rm->n_clients--;
1220       if (rm->n_clients == 0)
1221         {
1222           dhcp6_clients_enable_disable (0);
1223           disable_process ();
1224         }
1225
1226       vec_validate (prefix_list, 0);
1227
1228       /* *INDENT-OFF* */
1229       pool_foreach (prefix_info, pm->prefix_pool,
1230       ({
1231         if (is_dhcpv6_pd_prefix (prefix_info) &&
1232             prefix_info->opaque_data == sw_if_index)
1233           {
1234             ASSERT (sw_if_index < vec_len (rm->client_state_by_sw_if_index) &&
1235                     rm->client_state_by_sw_if_index[sw_if_index].enabled);
1236             client_state_t *client_state =
1237               &rm->client_state_by_sw_if_index[sw_if_index];
1238             prefix_list[0] = *prefix_info;
1239             send_client_message_start_stop (sw_if_index,
1240                                             client_state->server_index,
1241                                             DHCPV6_MSG_RELEASE, prefix_list,
1242                                             1);
1243             u32 prefix_index = prefix_info - pm->prefix_pool;
1244             notify_prefix_add_del (prefix_index, 0);
1245             set_is_dhcpv6_pd_prefix (prefix_info, 0);
1246             pool_put (pm->prefix_pool, prefix_info);
1247           }
1248       }));
1249       /* *INDENT-ON* */
1250
1251       vec_free (prefix_list);
1252
1253       memset (client_state, 0, sizeof (*client_state));
1254     }
1255
1256   return 0;
1257 }
1258
1259 static clib_error_t *
1260 dhcp6_pd_client_enable_disable_command_fn (vlib_main_t *
1261                                            vm,
1262                                            unformat_input_t
1263                                            * input, vlib_cli_command_t * cmd)
1264 {
1265   dhcp6_pd_client_cp_main_t *rm = &dhcp6_pd_client_cp_main;
1266   vnet_main_t *vnm = rm->vnet_main;
1267   clib_error_t *error = 0;
1268   u8 *prefix_group = 0;
1269   u32 sw_if_index = ~0;
1270   u8 enable = 1;
1271
1272   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1273     {
1274       if (unformat
1275           (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
1276         ;
1277       else if (unformat (input, "prefix group %s", &prefix_group));
1278       else if (unformat (input, "disable"))
1279         enable = 0;
1280       else
1281         {
1282           error = clib_error_return (0, "unexpected input `%U'",
1283                                      format_unformat_error, input);
1284           goto done;
1285         }
1286     }
1287
1288   if (prefix_group == 0 && enable)
1289     error = clib_error_return (0, "Prefix group must be set when enabling");
1290   else if (sw_if_index != ~0)
1291     {
1292       if (dhcp6_pd_client_enable_disable (sw_if_index, prefix_group, enable)
1293           != 0)
1294         error = clib_error_return (0, "Invalid sw_if_index or prefix group");
1295     }
1296   else
1297     error = clib_error_return (0, "Missing sw_if_index");
1298
1299 done:
1300   vec_free (prefix_group);
1301
1302   return error;
1303 }
1304
1305 /*?
1306  * This command is used to enable/disable DHCPv6 PD client
1307  * on particular interface.
1308  *
1309  * @cliexpar
1310  * @parblock
1311  * Example of how to enable DHCPv6 PD client:
1312  * @cliexcmd{dhcp6 pd client GigabitEthernet2/0/0 prefix group my-pd-group}
1313  * Example of how to disable DHCPv6 PD client:
1314  * @cliexcmd{dhcp6 pd client GigabitEthernet2/0/0 disable}
1315  * @endparblock
1316 ?*/
1317 /* *INDENT-OFF* */
1318 VLIB_CLI_COMMAND (dhcp6_pd_client_enable_disable_command, static) = {
1319   .path = "dhcp6 pd client",
1320   .short_help = "dhcp6 pd client <interface> (prefix group <string> | disable)",
1321   .function = dhcp6_pd_client_enable_disable_command_fn,
1322 };
1323 /* *INDENT-ON* */
1324
1325 static void
1326   vl_api_dhcp6_pd_client_enable_disable_t_handler
1327   (vl_api_dhcp6_pd_client_enable_disable_t * mp)
1328 {
1329   vl_api_dhcp6_pd_client_enable_disable_reply_t *rmp;
1330   u32 sw_if_index;
1331   int rv = 0;
1332
1333   VALIDATE_SW_IF_INDEX (mp);
1334
1335   sw_if_index = ntohl (mp->sw_if_index);
1336
1337   rv =
1338     dhcp6_pd_client_enable_disable (sw_if_index, mp->prefix_group,
1339                                     mp->enable);
1340
1341   BAD_SW_IF_INDEX_LABEL;
1342
1343   REPLY_MACRO (VL_API_SW_INTERFACE_SET_TABLE_REPLY);
1344 }
1345
1346 #define vl_msg_name_crc_list
1347 #include <vnet/dhcp/dhcp6_pd_client_cp.api.h>
1348 #undef vl_msg_name_crc_list
1349
1350 static void
1351 setup_message_id_table (api_main_t * am)
1352 {
1353 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
1354   foreach_vl_msg_name_crc_dhcp6_pd_client_cp;
1355 #undef _
1356 }
1357
1358 static clib_error_t *
1359 dhcp_pd_client_cp_init (vlib_main_t * vm)
1360 {
1361   dhcp6_pd_client_cp_main_t *rm = &dhcp6_pd_client_cp_main;
1362   api_main_t *am = &api_main;
1363
1364   rm->vlib_main = vm;
1365   rm->vnet_main = vnet_get_main ();
1366   rm->api_main = am;
1367   rm->node_index = dhcp6_pd_client_cp_process_node.index;
1368
1369 #define _(N,n)                                                  \
1370     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
1371                            vl_api_##n##_t_handler,              \
1372                            vl_noop_handler,                     \
1373                            vl_api_##n##_t_endian,               \
1374                            vl_api_##n##_t_print,                \
1375                            sizeof(vl_api_##n##_t), 0/* do NOT trace! */);
1376   foreach_dhcp6_pd_client_cp_msg;
1377 #undef _
1378
1379   /*
1380    * Set up the (msg_name, crc, message-id) table
1381    */
1382   setup_message_id_table (am);
1383
1384   return 0;
1385 }
1386
1387 VLIB_INIT_FUNCTION (dhcp_pd_client_cp_init);
1388
1389 /*
1390  * fd.io coding-style-patch-verification: ON
1391  *
1392  * Local Variables:
1393  * eval: (c-set-style "gnu")
1394  * End:
1395  */