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