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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include <vlib/vlib.h>
17 #include <vnet/dhcp/dhcp6_packet.h>
18 #include <vnet/dhcp/dhcp_proxy.h>
19 #include <vnet/mfib/mfib_table.h>
20 #include <vnet/mfib/ip6_mfib.h>
21 #include <vnet/fib/fib.h>
22 #include <vnet/adj/adj_mcast.h>
23 #include <vnet/ip/ip6_neighbor.h>
24 #include <vlibapi/api_common.h>
25 #include <vlibmemory/api.h>
26 #include <vnet/dhcp/dhcp6_pd_client_dp.h>
28 #include <vnet/vnet_msg_enum.h>
30 #define vl_typedefs /* define message structures */
31 #include <vnet/vnet_all_api_h.h>
34 #define vl_endianfun /* define message structures */
35 #include <vnet/vnet_all_api_h.h>
38 /* instantiate all the print functions we know about */
39 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
41 #include <vnet/vnet_all_api_h.h>
44 #include <vlibapi/api_helper_macros.h>
49 u8 keep_sending_client_message; /* when true then next fields are valid */
50 dhcp6_pd_send_client_message_params_t params;
51 f64 transaction_start;
57 vlib_buffer_t *buffer;
60 } dhcp6_pd_client_state_t;
70 dhcp6_pd_client_state_t *client_state_by_sw_if_index;
71 server_id_t *server_ids;
79 vlib_main_t *vlib_main;
80 vnet_main_t *vnet_main;
81 } dhcp6_pd_client_main_t;
83 static dhcp6_pd_client_main_t dhcp6_pd_client_main;
84 dhcp6_pd_client_public_main_t dhcp6_pd_client_public_main;
102 u16 inner_status_code;
106 prefix_info_t *prefixes;
119 } dhcpv6_duid_string_t;
121 static dhcpv6_duid_string_t client_duid;
122 #define CLIENT_DUID_LENGTH sizeof (client_duid)
123 #define DHCPV6_CLIENT_IAID 1
126 signal_report (report_t * r)
128 vlib_main_t *vm = vlib_get_main ();
129 dhcp6_pd_client_main_t *cm = &dhcp6_pd_client_main;
130 uword ni = cm->publisher_node;
131 uword et = cm->publisher_et;
133 if (ni == (uword) ~ 0)
135 report_t *q = vlib_process_signal_event_data (vm, ni, et, 1, sizeof *q);
141 publish_report (report_t * r)
143 void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
144 vl_api_rpc_call_main_thread (signal_report, (u8 *) r, sizeof *r);
149 dhcp6_pd_set_publisher_node (uword node_index, uword event_type)
151 dhcp6_pd_client_main_t *cm = &dhcp6_pd_client_main;
152 cm->publisher_node = node_index;
153 cm->publisher_et = event_type;
156 #define foreach_dhcpv6_pd_client \
157 _(DROP, "error-drop") \
158 _(LOOKUP, "ip6-lookup")
162 #define _(sym,str) DHCPV6_PD_CLIENT_NEXT_##sym,
163 foreach_dhcpv6_pd_client
165 DHCPV6_PD_CLIENT_N_NEXT,
166 } dhcpv6_pd_client_next_t;
169 * per-packet trace data
171 typedef struct dhcpv6_pd_client_trace_t_
173 } dhcpv6_pd_client_trace_t;
176 format_dhcpv6_pd_client_trace (u8 * s, va_list * args)
178 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
179 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
180 //dhcpv6_pd_client_trace_t *t = va_arg (*args, dhcpv6_pd_client_trace_t *);
182 s = format (s, "nothing");
188 server_index_get_or_create (u8 * data, u16 len)
190 dhcp6_pd_client_main_t *cm = &dhcp6_pd_client_main;
195 for (i = 0; i < vec_len (cm->server_ids); i++)
197 se = &cm->server_ids[i];
198 if (se->len == len && 0 == memcmp (se->data, data, len))
204 vec_validate (new_se.data, len - 1);
205 memcpy (new_se.data, data, len);
207 vec_add1 (cm->server_ids, new_se);
209 return vec_len (cm->server_ids) - 1;
213 stop_sending_client_message (vlib_main_t * vm,
214 dhcp6_pd_client_state_t * client_state)
218 client_state->keep_sending_client_message = 0;
219 vec_free (client_state->params.prefixes);
220 if (client_state->buffer)
222 bi0 = vlib_get_buffer_index (vm, client_state->buffer);
223 vlib_buffer_free (vm, &bi0, 1);
224 client_state->buffer = 0;
225 adj_unlock (client_state->adj_index);
226 client_state->adj_index = ~0;
231 dhcpv6_pd_client_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
232 vlib_frame_t * frame)
234 dhcp6_pd_client_main_t *cm = &dhcp6_pd_client_main;
236 dhcpv6_pd_client_next_t next_index;
237 u32 n_left_from, *from, *to_next;
239 n_left_from = frame->n_vectors;
240 from = vlib_frame_vector_args (frame);
242 while (n_left_from > 0)
246 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
248 while (n_left_from > 0 && n_left_to_next > 0)
252 dhcpv6_header_t *dhcpv60;
253 dhcpv6_option_t *option;
256 u32 next0 = DHCPV6_PD_CLIENT_NEXT_DROP;
261 u8 client_id_present = 0;
264 dhcp6_pd_client_state_t *client_state = NULL;
273 b0 = vlib_get_buffer (vm, bi0);
275 dhcpv60 = vlib_buffer_get_current (b0);
276 ip0 = (void *) (b0->data + vnet_buffer (b0)->l3_hdr_offset);
277 u32 dhcpv6_ip6_palyoad_offset =
278 (u8 *) dhcpv60 - ((u8 *) ip0 + sizeof (*ip0));
280 ntohs (ip0->payload_length) - dhcpv6_ip6_palyoad_offset -
283 memset (&report, 0, sizeof (report));
285 sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
286 if (sw_if_index >= vec_len (cm->client_state_by_sw_if_index))
289 client_state = &cm->client_state_by_sw_if_index[sw_if_index];
292 (dhcpv60->xid[0] << 16) + (dhcpv60->xid[1] << 8) +
294 if (!client_state || client_state->transaction_id != xid)
297 ("Received DHCPv6 message with wrong Transaction ID");
301 report.sw_if_index = sw_if_index;
302 report.msg_type = dhcpv60->msg_type;
303 report.server_index = ~0;
305 switch (dhcpv60->msg_type)
307 case DHCPV6_MSG_ADVERTISE:
308 case DHCPV6_MSG_REPLY:
309 option = (dhcpv6_option_t *) (dhcpv60 + 1);
310 while (options_length > 0)
313 ntohs (option->length) + sizeof (*option))
316 ("remaining payload length < option length (%d < %d)",
318 ntohs (option->length) + sizeof (*option));
321 u16 oo = ntohs (option->option);
322 if (oo == DHCPV6_OPTION_IA_PD)
324 u8 discard_ia_pd = 0;
325 dhcpv6_ia_header_t *ia_header = (void *) option;
326 iaid = ntohl (ia_header->iaid);
327 u32 T1 = ntohl (ia_header->t1);
328 u32 T2 = ntohl (ia_header->t2);
329 if (iaid != DHCPV6_CLIENT_IAID)
331 if (T1 != 0 && T2 != 0 && T1 > T2)
338 dhcpv6_option_t *inner_option =
339 (void *) ia_header->data;
340 u16 inner_options_length =
341 ntohs (option->length) - (sizeof (*ia_header) -
342 sizeof (dhcpv6_option_t));
343 while (inner_options_length > 0)
345 u16 inner_oo = ntohs (inner_option->option);
348 else if (inner_oo == DHCPV6_OPTION_IAPREFIX)
350 dhcpv6_ia_opt_pd_t *iaprefix =
351 (void *) inner_option;
352 vec_validate (report.prefixes,
354 prefix_info_t *prefix_info =
355 &report.prefixes[report.n_prefixes];
357 prefix_info->preferred_time =
358 ntohl (iaprefix->preferred);
359 prefix_info->valid_time =
360 ntohl (iaprefix->valid);
361 prefix_info->prefix_length = iaprefix->prefix;
362 prefix_info->prefix = iaprefix->addr;
364 else if (inner_oo == DHCPV6_OPTION_STATUS_CODE)
366 dhcpv6_status_code_t *sc =
367 (void *) inner_option;
368 report.inner_status_code =
369 ntohs (sc->status_code);
371 inner_options_length -=
372 sizeof (*inner_option) +
373 ntohs (inner_option->length);
375 (void *) ((u8 *) inner_option +
376 sizeof (*inner_option) +
377 ntohs (inner_option->length));
380 else if (oo == DHCPV6_OPTION_CLIENTID)
382 if (client_id_present)
385 ("Duplicate Client ID in received DHVPv6 message");
390 u16 len = ntohs (option->length);
391 client_id_present = 1;
392 if (len != CLIENT_DUID_LENGTH ||
393 0 != memcmp (option->data,
394 client_duid.bin_string,
398 ("Unrecognized client DUID inside received DHVPv6 message");
403 else if (oo == DHCPV6_OPTION_SERVERID)
405 if (report.server_index != ~0)
408 ("Duplicate Server ID in received DHVPv6 message");
412 report.server_index =
413 server_index_get_or_create (option->data,
414 ntohs (option->length));
416 else if (oo == DHCPV6_OPTION_PREFERENCE)
418 report.preference = option->data[0];
420 else if (oo == DHCPV6_OPTION_STATUS_CODE)
422 dhcpv6_status_code_t *sc = (void *) option;
423 report.status_code = ntohs (sc->status_code);
425 options_length -= sizeof (*option) + ntohs (option->length);
427 (void *) ((u8 *) option + sizeof (*option) +
428 ntohs (option->length));
431 if (!client_id_present)
434 ("Missing Client ID in received DHVPv6 message");
437 if (report.server_index == ~0)
440 ("Missing Server ID in received DHVPv6 message");
445 publish_report (&report);
447 vec_free (report.prefixes);
454 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
456 dhcpv6_pd_client_trace_t *t =
457 vlib_add_trace (vm, node, b0, sizeof (*t));
460 /* verify speculative enqueue, maybe switch current next frame */
461 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
462 to_next, n_left_to_next,
466 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
469 return frame->n_vectors;
473 VLIB_REGISTER_NODE (dhcpv6_pd_client_node, static) = {
474 .function = dhcpv6_pd_client_node_fn,
475 .name = "dhcpv6-pd-client",
476 .vector_size = sizeof (u32),
480 .n_next_nodes = DHCPV6_PD_CLIENT_N_NEXT,
482 #define _(s,n) [DHCPV6_PD_CLIENT_NEXT_##s] = n,
483 foreach_dhcpv6_pd_client
487 .format_trace = format_dhcpv6_pd_client_trace,
491 static_always_inline f64
492 random_f64_from_to (f64 from, f64 to)
495 static u8 seed_set = 0;
498 seed = random_default_seed ();
501 return random_f64 (&seed) * (to - from) + from;
504 static const ip6_address_t all_dhcp6_relay_agents_and_servers = {
506 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
507 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02}
510 static vlib_buffer_t *
511 create_buffer_for_client_message (vlib_main_t * vm,
513 dhcp6_pd_client_state_t
514 * client_state, u32 type)
516 dhcp6_pd_client_main_t *dm = &dhcp6_pd_client_main;
517 vnet_main_t *vnm = vnet_get_main ();
523 dhcpv6_header_t *dhcp;
524 ip6_address_t src_addr;
525 u32 dhcp_opt_len = 0;
526 client_state->transaction_start = vlib_time_now (vm);
530 vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
531 vnet_sw_interface_t *sup_sw = vnet_get_sup_sw_interface (vnm, sw_if_index);
532 vnet_sw_interface_t *sw = vnet_get_sw_interface (vnm, sw_if_index);
534 /* Interface(s) down? */
535 if ((hw->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) == 0)
537 if ((sup_sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
539 if ((sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
542 /* Get a link-local address */
543 src_addr = ip6_neighbor_get_link_local_address (sw_if_index);
545 if (src_addr.as_u8[0] != 0xfe)
547 clib_warning ("Could not find source address to send DHCPv6 packet");
551 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
553 clib_warning ("Buffer allocation failed");
557 b = vlib_get_buffer (vm, bi);
558 vnet_buffer (b)->sw_if_index[VLIB_RX] = sw_if_index;
559 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
560 client_state->adj_index = adj_mcast_add_or_lock (FIB_PROTOCOL_IP6,
563 vnet_buffer (b)->ip.adj_index[VLIB_TX] = client_state->adj_index;
564 b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
566 ip = (ip6_header_t *) vlib_buffer_get_current (b);
567 udp = (udp_header_t *) (ip + 1);
568 dhcp = (dhcpv6_header_t *) (udp + 1);
570 ip->src_address = src_addr;
572 ip->ip_version_traffic_class_and_flow_label =
573 clib_host_to_net_u32 (0x6 << 28);
574 ip->payload_length = 0;
575 ip->protocol = IP_PROTOCOL_UDP;
577 udp->src_port = clib_host_to_net_u16 (DHCPV6_CLIENT_PORT);
578 udp->dst_port = clib_host_to_net_u16 (DHCPV6_SERVER_PORT);
582 dhcp->msg_type = type;
583 dhcp->xid[0] = (client_state->transaction_id & 0x00ff0000) >> 16;
584 dhcp->xid[1] = (client_state->transaction_id & 0x0000ff00) >> 8;
585 dhcp->xid[2] = (client_state->transaction_id & 0x000000ff) >> 0;
587 void *d = (void *) dhcp->data;
588 dhcpv6_option_t *duid;
589 dhcpv6_elapsed_t *elapsed;
590 dhcpv6_ia_header_t *ia_hdr;
591 dhcpv6_ia_opt_pd_t *opt_pd;
592 if (type == DHCPV6_MSG_SOLICIT || type == DHCPV6_MSG_REQUEST ||
593 type == DHCPV6_MSG_RENEW || type == DHCPV6_MSG_REBIND ||
594 type == DHCPV6_MSG_RELEASE)
596 duid = (dhcpv6_option_t *) d;
597 duid->option = clib_host_to_net_u16 (DHCPV6_OPTION_CLIENTID);
598 duid->length = clib_host_to_net_u16 (CLIENT_DUID_LENGTH);
599 clib_memcpy (duid + 1, client_duid.bin_string, CLIENT_DUID_LENGTH);
600 d += sizeof (*duid) + CLIENT_DUID_LENGTH;
602 if (client_state->params.server_index != ~0)
605 &dm->server_ids[client_state->params.server_index];
607 duid = (dhcpv6_option_t *) d;
608 duid->option = clib_host_to_net_u16 (DHCPV6_OPTION_SERVERID);
609 duid->length = clib_host_to_net_u16 (se->len);
610 clib_memcpy (duid + 1, se->data, se->len);
611 d += sizeof (*duid) + se->len;
614 elapsed = (dhcpv6_elapsed_t *) d;
615 elapsed->opt.option = clib_host_to_net_u16 (DHCPV6_OPTION_ELAPSED_TIME);
616 elapsed->opt.length =
617 clib_host_to_net_u16 (sizeof (*elapsed) - sizeof (elapsed->opt));
618 elapsed->elapsed_10ms = 0;
619 client_state->elapsed_pos =
620 (char *) &elapsed->elapsed_10ms -
621 (char *) vlib_buffer_get_current (b);
622 d += sizeof (*elapsed);
624 ia_hdr = (dhcpv6_ia_header_t *) d;
625 ia_hdr->opt.option = clib_host_to_net_u16 (DHCPV6_OPTION_IA_PD);
626 ia_hdr->iaid = clib_host_to_net_u32 (DHCPV6_CLIENT_IAID);
627 ia_hdr->t1 = clib_host_to_net_u32 (client_state->params.T1);
628 ia_hdr->t2 = clib_host_to_net_u32 (client_state->params.T2);
629 d += sizeof (*ia_hdr);
631 n_prefixes = vec_len (client_state->params.prefixes);
634 clib_host_to_net_u16 (sizeof (*ia_hdr) +
635 n_prefixes * sizeof (*opt_pd) -
636 sizeof (ia_hdr->opt));
638 for (i = 0; i < n_prefixes; i++)
640 dhcp6_pd_send_client_message_params_prefix_t *pref =
641 &client_state->params.prefixes[i];
642 opt_pd = (dhcpv6_ia_opt_pd_t *) d;
643 opt_pd->opt.option = clib_host_to_net_u16 (DHCPV6_OPTION_IAPREFIX);
645 clib_host_to_net_u16 (sizeof (*opt_pd) - sizeof (opt_pd->opt));
646 opt_pd->addr = pref->prefix;
647 opt_pd->prefix = pref->prefix_length;
648 opt_pd->valid = clib_host_to_net_u32 (pref->valid_lt);
649 opt_pd->preferred = clib_host_to_net_u32 (pref->preferred_lt);
650 d += sizeof (*opt_pd);
655 clib_warning ("State not implemented");
658 dhcp_opt_len = ((u8 *) d) - dhcp->data;
660 clib_host_to_net_u16 (sizeof (*udp) + sizeof (*dhcp) + dhcp_opt_len);
661 ip->payload_length = udp->length;
663 sizeof (*ip) + sizeof (*udp) + sizeof (*dhcp) + dhcp_opt_len;
665 ip->dst_address = all_dhcp6_relay_agents_and_servers;
671 check_pd_send_client_message (vlib_main_t * vm,
672 dhcp6_pd_client_state_t * client_state,
673 f64 current_time, f64 * due_time)
683 int bogus_length = 0;
685 dhcp6_pd_send_client_message_params_t *params;
687 f64 now = vlib_time_now (vm);
689 if (!client_state->keep_sending_client_message)
692 params = &client_state->params;
694 if (client_state->due_time > current_time)
696 *due_time = client_state->due_time;
700 p0 = client_state->buffer;
702 next_index = ip6_rewrite_mcast_node.index;
704 c0 = vlib_buffer_copy (vm, p0);
705 ci0 = vlib_get_buffer_index (vm, c0);
707 ip = (ip6_header_t *) vlib_buffer_get_current (c0);
708 udp = (udp_header_t *) (ip + 1);
710 u16 *elapsed_field = (u16 *) ((void *) ip + client_state->elapsed_pos);
712 clib_host_to_net_u16 ((u16)
713 ((now - client_state->transaction_start) * 100));
717 ip6_tcp_udp_icmp_compute_checksum (vm, 0, ip, &bogus_length);
719 f = vlib_get_frame_to_node (vm, next_index);
720 to_next = vlib_frame_vector_args (f);
723 vlib_put_frame_to_node (vm, next_index, f);
725 if (params->mrc != 0 && --client_state->n_left == 0)
726 stop_sending_client_message (vm, client_state);
729 client_state->sleep_interval =
730 (2 + random_f64_from_to (-0.1, 0.1)) * client_state->sleep_interval;
731 if (client_state->sleep_interval > params->mrt)
732 client_state->sleep_interval =
733 (1 + random_f64_from_to (-0.1, 0.1)) * params->mrt;
735 client_state->due_time = current_time + client_state->sleep_interval;
738 && current_time > client_state->start_time + params->mrd)
739 stop_sending_client_message (vm, client_state);
741 *due_time = client_state->due_time;
744 return client_state->keep_sending_client_message;
748 send_dhcp6_pd_client_message_process (vlib_main_t * vm,
749 vlib_node_runtime_t * rt,
752 dhcp6_pd_client_main_t *cm = &dhcp6_pd_client_main;
753 dhcp6_pd_client_state_t *client_state;
754 uword *event_data = 0;
755 f64 sleep_time = 1e9;
763 vlib_process_wait_for_event_or_clock (vm, sleep_time);
764 vlib_process_get_events (vm, &event_data);
765 vec_reset_length (event_data);
767 current_time = vlib_time_now (vm);
770 due_time = current_time + 1e9;
771 for (i = 0; i < vec_len (cm->client_state_by_sw_if_index); i++)
773 client_state = &cm->client_state_by_sw_if_index[i];
774 if (!client_state->entry_valid)
776 if (check_pd_send_client_message
777 (vm, client_state, current_time, &dt) && (dt < due_time))
780 current_time = vlib_time_now (vm);
782 while (due_time < current_time);
784 sleep_time = due_time - current_time;
791 VLIB_REGISTER_NODE (send_dhcp6_pd_client_message_process_node) = {
792 .function = send_dhcp6_pd_client_message_process,
793 .type = VLIB_NODE_TYPE_PROCESS,
794 .name = "send-dhcp6-pd-client-message-process",
799 dhcp6_pd_send_client_message (vlib_main_t * vm, u32 sw_if_index, u8 stop,
800 dhcp6_pd_send_client_message_params_t * params)
802 dhcp6_pd_client_main_t *cm = &dhcp6_pd_client_main;
803 dhcp6_pd_client_state_t *client_state = 0;
804 dhcp6_pd_client_state_t empty_state = {
808 ASSERT (~0 != sw_if_index);
810 vec_validate_init_empty (cm->client_state_by_sw_if_index, sw_if_index,
812 client_state = &cm->client_state_by_sw_if_index[sw_if_index];
813 if (!client_state->entry_valid)
815 client_state->entry_valid = 1;
816 client_state->adj_index = ~0;
819 stop_sending_client_message (vm, client_state);
823 client_state->keep_sending_client_message = 1;
824 vec_free (client_state->params.prefixes);
825 client_state->params = *params;
826 client_state->params.prefixes = vec_dup (params->prefixes);
827 client_state->n_left = params->mrc;
828 client_state->start_time = vlib_time_now (vm);
829 client_state->sleep_interval =
830 (1 + random_f64_from_to (-0.1, 0.1)) * params->irt;
831 client_state->due_time = 0; /* send first packet ASAP */
832 client_state->transaction_id = random_u32 (&cm->seed) & 0x00ffffff;
833 client_state->buffer =
834 create_buffer_for_client_message (vm, sw_if_index, client_state,
836 if (!client_state->buffer)
837 client_state->keep_sending_client_message = 0;
839 vlib_process_signal_event (vm,
840 send_dhcp6_pd_client_message_process_node.index,
846 vl_api_dhcp6_pd_send_client_message_t_handler
847 (vl_api_dhcp6_pd_send_client_message_t * mp)
849 vl_api_dhcp6_pd_send_client_message_reply_t *rmp;
850 dhcp6_pd_send_client_message_params_t params;
851 vlib_main_t *vm = vlib_get_main ();
856 VALIDATE_SW_IF_INDEX (mp);
858 BAD_SW_IF_INDEX_LABEL;
859 REPLY_MACRO (VL_API_DHCP6_PD_SEND_CLIENT_MESSAGE_REPLY);
864 params.sw_if_index = ntohl (mp->sw_if_index);
865 params.server_index = ntohl (mp->server_index);
866 params.irt = ntohl (mp->irt);
867 params.mrt = ntohl (mp->mrt);
868 params.mrc = ntohl (mp->mrc);
869 params.mrd = ntohl (mp->mrd);
870 params.msg_type = mp->msg_type;
871 params.T1 = ntohl (mp->T1);
872 params.T2 = ntohl (mp->T2);
873 n_prefixes = ntohl (mp->n_prefixes);
876 vec_validate (params.prefixes, n_prefixes - 1);
877 for (i = 0; i < n_prefixes; i++)
879 vl_api_dhcp6_pd_prefix_info_t *pi = &mp->prefixes[i];
880 dhcp6_pd_send_client_message_params_prefix_t *pref =
882 pref->preferred_lt = ntohl (pi->preferred_time);
883 pref->valid_lt = ntohl (pi->valid_time);
884 memcpy (pref->prefix.as_u8, pi->prefix, 16);
885 pref->prefix_length = pi->prefix_length;
888 dhcp6_pd_send_client_message (vm, ntohl (mp->sw_if_index), mp->stop,
892 static clib_error_t *
893 call_dhcp6_pd_reply_event_callbacks (void *data,
894 _vnet_dhcp6_pd_reply_event_function_list_elt_t
897 clib_error_t *error = 0;
901 error = elt->fp (data);
904 elt = elt->next_dhcp6_pd_reply_event_function;
911 dhcp6_pd_reply_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
914 /* These cross the longjmp boundry (vlib_process_wait_for_event)
915 * and need to be volatile - to prevent them from being optimized into
916 * a register - which could change during suspension */
920 vlib_process_wait_for_event (vm);
921 uword event_type = DHCP6_PD_DP_REPLY_REPORT;
922 void *event_data = vlib_process_get_event_data (vm, &event_type);
925 if (event_type == DHCP6_PD_DP_REPLY_REPORT)
927 report_t *events = event_data;
928 for (i = 0; i < vec_len (events); i++)
931 sizeof (vl_api_dhcp6_pd_reply_event_t) +
932 vec_len (events[i].prefixes) *
933 sizeof (vl_api_dhcp6_pd_prefix_info_t);
934 vl_api_dhcp6_pd_reply_event_t *event =
935 clib_mem_alloc (event_size);
936 memset (event, 0, event_size);
938 event->sw_if_index = htonl (events[i].sw_if_index);
939 event->server_index = htonl (events[i].server_index);
940 event->msg_type = events[i].msg_type;
941 event->T1 = htonl (events[i].T1);
942 event->T2 = htonl (events[i].T2);
943 event->inner_status_code = htons (events[i].inner_status_code);
944 event->status_code = htons (events[i].status_code);
945 event->preference = events[i].preference;
947 event->n_prefixes = htonl (vec_len (events[i].prefixes));
948 vl_api_dhcp6_pd_prefix_info_t *prefix =
949 (typeof (prefix)) event->prefixes;
951 for (j = 0; j < vec_len (events[i].prefixes); j++)
953 prefix_info_t *info = &events[i].prefixes[j];
954 memcpy (prefix->prefix, &info->prefix, 16);
955 prefix->prefix_length = info->prefix_length;
956 prefix->valid_time = htonl (info->valid_time);
957 prefix->preferred_time = htonl (info->preferred_time);
961 dhcp6_pd_client_public_main_t *dpcpm =
962 &dhcp6_pd_client_public_main;
963 call_dhcp6_pd_reply_event_callbacks (event, dpcpm->functions);
965 vpe_client_registration_t *reg;
967 pool_foreach(reg, vpe_api_main.dhcp6_pd_reply_events_registrations,
969 vl_api_registration_t *vl_reg;
971 vl_api_client_index_to_registration (reg->client_index);
972 if (vl_reg && vl_api_can_send_msg (vl_reg))
974 vl_api_dhcp6_pd_reply_event_t *msg =
975 vl_msg_api_alloc (event_size);
976 clib_memcpy (msg, event, event_size);
977 msg->_vl_msg_id = htons (VL_API_DHCP6_PD_REPLY_EVENT);
978 msg->client_index = reg->client_index;
979 msg->pid = reg->client_pid;
980 vl_api_send_msg (vl_reg, (u8 *) msg);
985 clib_mem_free (event);
988 vlib_process_put_event_data (vm, event_data);
995 VLIB_REGISTER_NODE (dhcp6_pd_reply_process_node, ) = {
996 .function = dhcp6_pd_reply_process,
997 .type = VLIB_NODE_TYPE_PROCESS,
998 .name = "dhcp6-pd-reply-publisher-process",
1003 vl_api_want_dhcp6_pd_reply_events_t_handler
1004 (vl_api_want_dhcp6_pd_reply_events_t * mp)
1006 vpe_api_main_t *am = &vpe_api_main;
1007 vl_api_want_dhcp6_pd_reply_events_reply_t *rmp;
1011 hash_get (am->dhcp6_pd_reply_events_registration_hash, mp->client_index);
1012 vpe_client_registration_t *rp;
1015 if (mp->enable_disable)
1017 clib_warning ("pid %d: already enabled...", ntohl (mp->pid));
1018 rv = VNET_API_ERROR_INVALID_REGISTRATION;
1024 pool_elt_at_index (am->dhcp6_pd_reply_events_registrations, p[0]);
1025 pool_put (am->dhcp6_pd_reply_events_registrations, rp);
1026 hash_unset (am->dhcp6_pd_reply_events_registration_hash,
1028 if (pool_elts (am->dhcp6_pd_reply_events_registrations) == 0)
1029 dhcp6_pd_set_publisher_node (~0, REPORT_MAX);
1033 if (mp->enable_disable == 0)
1035 clib_warning ("pid %d: already disabled...", ntohl (mp->pid));
1036 rv = VNET_API_ERROR_INVALID_REGISTRATION;
1039 pool_get (am->dhcp6_pd_reply_events_registrations, rp);
1040 rp->client_index = mp->client_index;
1041 rp->client_pid = ntohl (mp->pid);
1042 hash_set (am->dhcp6_pd_reply_events_registration_hash, rp->client_index,
1043 rp - am->dhcp6_pd_reply_events_registrations);
1044 dhcp6_pd_set_publisher_node (dhcp6_pd_reply_process_node.index,
1045 DHCP6_PD_DP_REPLY_REPORT);
1048 REPLY_MACRO (VL_API_WANT_DHCP6_PD_REPLY_EVENTS_REPLY);
1052 dhcp6_clients_enable_disable (u8 enable)
1054 vlib_main_t *vm = vlib_get_main ();
1057 udp_register_dst_port (vm, UDP_DST_PORT_dhcpv6_to_client,
1058 dhcpv6_pd_client_node.index, 0 /* is_ip6 */ );
1060 udp_unregister_dst_port (vm, UDP_DST_PORT_dhcpv6_to_client,
1065 vl_api_dhcp6_clients_enable_disable_t_handler
1066 (vl_api_dhcp6_clients_enable_disable_t * mp)
1068 vl_api_dhcp6_clients_enable_disable_reply_t *rmp;
1071 dhcp6_clients_enable_disable (mp->enable);
1073 REPLY_MACRO (VL_API_WANT_DHCP6_PD_REPLY_EVENTS_REPLY);
1077 genereate_client_duid (void)
1079 client_duid.duid_type = htons (DHCPV6_DUID_LLT);
1080 client_duid.hardware_type = htons (1);
1081 u32 time_since_2000 = (u32) time (0) - 946684800;
1082 client_duid.time = htonl (time_since_2000);
1084 vnet_main_t *vnm = vnet_get_main ();
1085 vnet_interface_main_t *im = &vnm->interface_main;
1086 vnet_hw_interface_t *hi;
1087 ethernet_interface_t *eth_if = 0;
1090 pool_foreach (hi, im->hw_interfaces,
1092 eth_if = ethernet_get_interface (ðernet_main, hi->hw_if_index);
1099 clib_memcpy (client_duid.lla, eth_if->address, 6);
1102 clib_warning ("Failed to find any Ethernet interface, "
1103 "setting DHCPv6 DUID link-layer address to random value");
1104 u32 seed = random_default_seed ();
1106 client_duid.lla[0] = 0xc2; /* locally administered unicast */
1107 client_duid.lla[1] = 0x18;
1108 client_duid.lla[2] = 0x44;
1109 client_duid.lla[3] = random_u32 (&seed);
1110 client_duid.lla[4] = random_u32 (&seed);
1111 client_duid.lla[5] = random_u32 (&seed);
1115 static clib_error_t *
1116 dhcp6_pd_client_init (vlib_main_t * vm)
1118 dhcp6_pd_client_main_t *cm = &dhcp6_pd_client_main;
1121 cm->vnet_main = vnet_get_main ();
1123 cm->publisher_node = ~0;
1125 cm->seed = 0xdeaddabe;
1127 // TODO: should be stored in non-volatile memory
1128 genereate_client_duid ();
1133 VLIB_INIT_FUNCTION (dhcp6_pd_client_init);
1136 * fd.io coding-style-patch-verification: ON
1139 * eval: (c-set-style "gnu")