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;
118 } dhcpv6_duid_ll_string_t;
120 static dhcpv6_duid_ll_string_t client_duid;
121 #define CLIENT_DUID_LENGTH sizeof (client_duid)
122 #define DHCPV6_CLIENT_IAID 1
125 signal_report (report_t * r)
127 vlib_main_t *vm = vlib_get_main ();
128 dhcp6_pd_client_main_t *cm = &dhcp6_pd_client_main;
129 uword ni = cm->publisher_node;
130 uword et = cm->publisher_et;
132 if (ni == (uword) ~ 0)
134 report_t *q = vlib_process_signal_event_data (vm, ni, et, 1, sizeof *q);
140 publish_report (report_t * r)
142 void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
143 vl_api_rpc_call_main_thread (signal_report, (u8 *) r, sizeof *r);
148 dhcp6_pd_set_publisher_node (uword node_index, uword event_type)
150 dhcp6_pd_client_main_t *cm = &dhcp6_pd_client_main;
151 cm->publisher_node = node_index;
152 cm->publisher_et = event_type;
155 #define foreach_dhcpv6_pd_client \
156 _(DROP, "error-drop") \
157 _(LOOKUP, "ip6-lookup")
161 #define _(sym,str) DHCPV6_PD_CLIENT_NEXT_##sym,
162 foreach_dhcpv6_pd_client
164 DHCPV6_PD_CLIENT_N_NEXT,
165 } dhcpv6_pd_client_next_t;
168 * per-packet trace data
170 typedef struct dhcpv6_pd_client_trace_t_
172 } dhcpv6_pd_client_trace_t;
175 format_dhcpv6_pd_client_trace (u8 * s, va_list * args)
177 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
178 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
179 //dhcpv6_pd_client_trace_t *t = va_arg (*args, dhcpv6_pd_client_trace_t *);
181 s = format (s, "nothing");
187 server_index_get_or_create (u8 * data, u16 len)
189 dhcp6_pd_client_main_t *cm = &dhcp6_pd_client_main;
194 for (i = 0; i < vec_len (cm->server_ids); i++)
196 se = &cm->server_ids[i];
197 if (se->len == len && 0 == memcmp (se->data, data, len))
203 vec_validate (new_se.data, len - 1);
204 memcpy (new_se.data, data, len);
206 vec_add1 (cm->server_ids, new_se);
208 return vec_len (cm->server_ids) - 1;
212 stop_sending_client_message (vlib_main_t * vm,
213 dhcp6_pd_client_state_t * client_state)
217 client_state->keep_sending_client_message = 0;
218 vec_free (client_state->params.prefixes);
219 if (client_state->buffer)
221 bi0 = vlib_get_buffer_index (vm, client_state->buffer);
222 vlib_buffer_free (vm, &bi0, 1);
223 client_state->buffer = 0;
224 adj_unlock (client_state->adj_index);
225 client_state->adj_index = ~0;
230 dhcpv6_pd_client_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
231 vlib_frame_t * frame)
233 dhcp6_pd_client_main_t *cm = &dhcp6_pd_client_main;
235 dhcpv6_pd_client_next_t next_index;
236 u32 n_left_from, *from, *to_next;
238 n_left_from = frame->n_vectors;
239 from = vlib_frame_vector_args (frame);
241 while (n_left_from > 0)
245 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
247 while (n_left_from > 0 && n_left_to_next > 0)
251 dhcpv6_header_t *dhcpv60;
252 dhcpv6_option_t *option;
255 u32 next0 = DHCPV6_PD_CLIENT_NEXT_DROP;
260 u8 client_id_present = 0;
263 dhcp6_pd_client_state_t *client_state = NULL;
272 b0 = vlib_get_buffer (vm, bi0);
274 dhcpv60 = vlib_buffer_get_current (b0);
275 ip0 = (void *) (b0->data + vnet_buffer (b0)->l3_hdr_offset);
276 u32 dhcpv6_ip6_palyoad_offset =
277 (u8 *) dhcpv60 - ((u8 *) ip0 + sizeof (*ip0));
279 ntohs (ip0->payload_length) - dhcpv6_ip6_palyoad_offset -
282 memset (&report, 0, sizeof (report));
284 sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
285 if (sw_if_index >= vec_len (cm->client_state_by_sw_if_index))
288 client_state = &cm->client_state_by_sw_if_index[sw_if_index];
291 (dhcpv60->xid[0] << 16) + (dhcpv60->xid[1] << 8) +
293 if (!client_state || client_state->transaction_id != xid)
296 ("Received DHCPv6 message with wrong Transaction ID");
300 report.sw_if_index = sw_if_index;
301 report.msg_type = dhcpv60->msg_type;
302 report.server_index = ~0;
304 switch (dhcpv60->msg_type)
306 case DHCPV6_MSG_ADVERTISE:
307 case DHCPV6_MSG_REPLY:
308 option = (dhcpv6_option_t *) (dhcpv60 + 1);
309 while (options_length > 0)
312 ntohs (option->length) + sizeof (*option))
315 ("remaining payload length < option length (%d < %d)",
317 ntohs (option->length) + sizeof (*option));
320 u16 oo = ntohs (option->option);
321 if (oo == DHCPV6_OPTION_IA_PD)
323 u8 discard_ia_pd = 0;
324 dhcpv6_ia_header_t *ia_header = (void *) option;
325 iaid = ntohl (ia_header->iaid);
326 u32 T1 = ntohl (ia_header->t1);
327 u32 T2 = ntohl (ia_header->t2);
328 if (iaid != DHCPV6_CLIENT_IAID)
330 if (T1 != 0 && T2 != 0 && T1 > T2)
337 dhcpv6_option_t *inner_option =
338 (void *) ia_header->data;
339 u16 inner_options_length =
340 ntohs (option->length) - (sizeof (*ia_header) -
341 sizeof (dhcpv6_option_t));
342 while (inner_options_length > 0)
344 u16 inner_oo = ntohs (inner_option->option);
347 else if (inner_oo == DHCPV6_OPTION_IAPREFIX)
349 dhcpv6_ia_opt_pd_t *iaprefix =
350 (void *) inner_option;
351 vec_validate (report.prefixes,
353 prefix_info_t *prefix_info =
354 &report.prefixes[report.n_prefixes];
356 prefix_info->preferred_time =
357 ntohl (iaprefix->preferred);
358 prefix_info->valid_time =
359 ntohl (iaprefix->valid);
360 prefix_info->prefix_length = iaprefix->prefix;
361 prefix_info->prefix = iaprefix->addr;
363 else if (inner_oo == DHCPV6_OPTION_STATUS_CODE)
365 dhcpv6_status_code_t *sc =
366 (void *) inner_option;
367 report.inner_status_code =
368 ntohs (sc->status_code);
370 inner_options_length -=
371 sizeof (*inner_option) +
372 ntohs (inner_option->length);
374 (void *) ((u8 *) inner_option +
375 sizeof (*inner_option) +
376 ntohs (inner_option->length));
379 else if (oo == DHCPV6_OPTION_CLIENTID)
381 if (client_id_present)
384 ("Duplicate Client ID in received DHVPv6 message");
389 u16 len = ntohs (option->length);
390 client_id_present = 1;
391 if (len != CLIENT_DUID_LENGTH ||
392 0 != memcmp (option->data,
393 client_duid.bin_string,
397 ("Unrecognized client DUID inside received DHVPv6 message");
402 else if (oo == DHCPV6_OPTION_SERVERID)
404 if (report.server_index != ~0)
407 ("Duplicate Server ID in received DHVPv6 message");
412 u16 ol = ntohs (option->length);
413 if (ol - 2 /* 2 byte DUID type code */ > 128)
416 ("Server DUID (without type code) is longer than 128 octets");
421 report.server_index =
422 server_index_get_or_create (option->data, ol);
426 else if (oo == DHCPV6_OPTION_PREFERENCE)
428 report.preference = option->data[0];
430 else if (oo == DHCPV6_OPTION_STATUS_CODE)
432 dhcpv6_status_code_t *sc = (void *) option;
433 report.status_code = ntohs (sc->status_code);
435 options_length -= sizeof (*option) + ntohs (option->length);
437 (void *) ((u8 *) option + sizeof (*option) +
438 ntohs (option->length));
441 if (!client_id_present)
444 ("Missing Client ID in received DHVPv6 message");
447 if (report.server_index == ~0)
450 ("Missing Server ID in received DHVPv6 message");
455 publish_report (&report);
457 vec_free (report.prefixes);
464 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
466 dhcpv6_pd_client_trace_t *t =
467 vlib_add_trace (vm, node, b0, sizeof (*t));
470 /* verify speculative enqueue, maybe switch current next frame */
471 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
472 to_next, n_left_to_next,
476 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
479 return frame->n_vectors;
483 VLIB_REGISTER_NODE (dhcpv6_pd_client_node, static) = {
484 .function = dhcpv6_pd_client_node_fn,
485 .name = "dhcpv6-pd-client",
486 .vector_size = sizeof (u32),
490 .n_next_nodes = DHCPV6_PD_CLIENT_N_NEXT,
492 #define _(s,n) [DHCPV6_PD_CLIENT_NEXT_##s] = n,
493 foreach_dhcpv6_pd_client
497 .format_trace = format_dhcpv6_pd_client_trace,
501 static_always_inline f64
502 random_f64_from_to (f64 from, f64 to)
505 static u8 seed_set = 0;
508 seed = random_default_seed ();
511 return random_f64 (&seed) * (to - from) + from;
514 static const ip6_address_t all_dhcp6_relay_agents_and_servers = {
516 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
517 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02}
520 static vlib_buffer_t *
521 create_buffer_for_client_message (vlib_main_t * vm,
523 dhcp6_pd_client_state_t
524 * client_state, u32 type)
526 dhcp6_pd_client_main_t *dm = &dhcp6_pd_client_main;
527 vnet_main_t *vnm = vnet_get_main ();
533 dhcpv6_header_t *dhcp;
534 ip6_address_t src_addr;
535 u32 dhcp_opt_len = 0;
536 client_state->transaction_start = vlib_time_now (vm);
540 vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
541 vnet_sw_interface_t *sup_sw = vnet_get_sup_sw_interface (vnm, sw_if_index);
542 vnet_sw_interface_t *sw = vnet_get_sw_interface (vnm, sw_if_index);
544 /* Interface(s) down? */
545 if ((hw->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) == 0)
547 if ((sup_sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
549 if ((sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
552 /* Get a link-local address */
553 src_addr = ip6_neighbor_get_link_local_address (sw_if_index);
555 if (src_addr.as_u8[0] != 0xfe)
557 clib_warning ("Could not find source address to send DHCPv6 packet");
561 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
563 clib_warning ("Buffer allocation failed");
567 b = vlib_get_buffer (vm, bi);
568 vnet_buffer (b)->sw_if_index[VLIB_RX] = sw_if_index;
569 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
570 client_state->adj_index = adj_mcast_add_or_lock (FIB_PROTOCOL_IP6,
573 vnet_buffer (b)->ip.adj_index[VLIB_TX] = client_state->adj_index;
574 b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
576 ip = (ip6_header_t *) vlib_buffer_get_current (b);
577 udp = (udp_header_t *) (ip + 1);
578 dhcp = (dhcpv6_header_t *) (udp + 1);
580 ip->src_address = src_addr;
582 ip->ip_version_traffic_class_and_flow_label =
583 clib_host_to_net_u32 (0x6 << 28);
584 ip->payload_length = 0;
585 ip->protocol = IP_PROTOCOL_UDP;
587 udp->src_port = clib_host_to_net_u16 (DHCPV6_CLIENT_PORT);
588 udp->dst_port = clib_host_to_net_u16 (DHCPV6_SERVER_PORT);
592 dhcp->msg_type = type;
593 dhcp->xid[0] = (client_state->transaction_id & 0x00ff0000) >> 16;
594 dhcp->xid[1] = (client_state->transaction_id & 0x0000ff00) >> 8;
595 dhcp->xid[2] = (client_state->transaction_id & 0x000000ff) >> 0;
597 void *d = (void *) dhcp->data;
598 dhcpv6_option_t *duid;
599 dhcpv6_elapsed_t *elapsed;
600 dhcpv6_ia_header_t *ia_hdr;
601 dhcpv6_ia_opt_pd_t *opt_pd;
602 if (type == DHCPV6_MSG_SOLICIT || type == DHCPV6_MSG_REQUEST ||
603 type == DHCPV6_MSG_RENEW || type == DHCPV6_MSG_REBIND ||
604 type == DHCPV6_MSG_RELEASE)
606 duid = (dhcpv6_option_t *) d;
607 duid->option = clib_host_to_net_u16 (DHCPV6_OPTION_CLIENTID);
608 duid->length = clib_host_to_net_u16 (CLIENT_DUID_LENGTH);
609 clib_memcpy (duid + 1, client_duid.bin_string, CLIENT_DUID_LENGTH);
610 d += sizeof (*duid) + CLIENT_DUID_LENGTH;
612 if (client_state->params.server_index != ~0)
615 &dm->server_ids[client_state->params.server_index];
617 duid = (dhcpv6_option_t *) d;
618 duid->option = clib_host_to_net_u16 (DHCPV6_OPTION_SERVERID);
619 duid->length = clib_host_to_net_u16 (se->len);
620 clib_memcpy (duid + 1, se->data, se->len);
621 d += sizeof (*duid) + se->len;
624 elapsed = (dhcpv6_elapsed_t *) d;
625 elapsed->opt.option = clib_host_to_net_u16 (DHCPV6_OPTION_ELAPSED_TIME);
626 elapsed->opt.length =
627 clib_host_to_net_u16 (sizeof (*elapsed) - sizeof (elapsed->opt));
628 elapsed->elapsed_10ms = 0;
629 client_state->elapsed_pos =
630 (char *) &elapsed->elapsed_10ms -
631 (char *) vlib_buffer_get_current (b);
632 d += sizeof (*elapsed);
634 ia_hdr = (dhcpv6_ia_header_t *) d;
635 ia_hdr->opt.option = clib_host_to_net_u16 (DHCPV6_OPTION_IA_PD);
636 ia_hdr->iaid = clib_host_to_net_u32 (DHCPV6_CLIENT_IAID);
637 ia_hdr->t1 = clib_host_to_net_u32 (client_state->params.T1);
638 ia_hdr->t2 = clib_host_to_net_u32 (client_state->params.T2);
639 d += sizeof (*ia_hdr);
641 n_prefixes = vec_len (client_state->params.prefixes);
644 clib_host_to_net_u16 (sizeof (*ia_hdr) +
645 n_prefixes * sizeof (*opt_pd) -
646 sizeof (ia_hdr->opt));
648 for (i = 0; i < n_prefixes; i++)
650 dhcp6_pd_send_client_message_params_prefix_t *pref =
651 &client_state->params.prefixes[i];
652 opt_pd = (dhcpv6_ia_opt_pd_t *) d;
653 opt_pd->opt.option = clib_host_to_net_u16 (DHCPV6_OPTION_IAPREFIX);
655 clib_host_to_net_u16 (sizeof (*opt_pd) - sizeof (opt_pd->opt));
656 opt_pd->addr = pref->prefix;
657 opt_pd->prefix = pref->prefix_length;
658 opt_pd->valid = clib_host_to_net_u32 (pref->valid_lt);
659 opt_pd->preferred = clib_host_to_net_u32 (pref->preferred_lt);
660 d += sizeof (*opt_pd);
665 clib_warning ("State not implemented");
668 dhcp_opt_len = ((u8 *) d) - dhcp->data;
670 clib_host_to_net_u16 (sizeof (*udp) + sizeof (*dhcp) + dhcp_opt_len);
671 ip->payload_length = udp->length;
673 sizeof (*ip) + sizeof (*udp) + sizeof (*dhcp) + dhcp_opt_len;
675 ip->dst_address = all_dhcp6_relay_agents_and_servers;
681 check_pd_send_client_message (vlib_main_t * vm,
682 dhcp6_pd_client_state_t * client_state,
683 f64 current_time, f64 * due_time)
693 int bogus_length = 0;
695 dhcp6_pd_send_client_message_params_t *params;
697 f64 now = vlib_time_now (vm);
699 if (!client_state->keep_sending_client_message)
702 params = &client_state->params;
704 if (client_state->due_time > current_time)
706 *due_time = client_state->due_time;
710 p0 = client_state->buffer;
712 next_index = ip6_rewrite_mcast_node.index;
714 c0 = vlib_buffer_copy (vm, p0);
715 ci0 = vlib_get_buffer_index (vm, c0);
717 ip = (ip6_header_t *) vlib_buffer_get_current (c0);
718 udp = (udp_header_t *) (ip + 1);
720 u16 *elapsed_field = (u16 *) ((void *) ip + client_state->elapsed_pos);
722 clib_host_to_net_u16 ((u16)
723 ((now - client_state->transaction_start) * 100));
727 ip6_tcp_udp_icmp_compute_checksum (vm, 0, ip, &bogus_length);
729 f = vlib_get_frame_to_node (vm, next_index);
730 to_next = vlib_frame_vector_args (f);
733 vlib_put_frame_to_node (vm, next_index, f);
735 if (params->mrc != 0 && --client_state->n_left == 0)
736 stop_sending_client_message (vm, client_state);
739 client_state->sleep_interval =
740 (2 + random_f64_from_to (-0.1, 0.1)) * client_state->sleep_interval;
741 if (client_state->sleep_interval > params->mrt)
742 client_state->sleep_interval =
743 (1 + random_f64_from_to (-0.1, 0.1)) * params->mrt;
745 client_state->due_time = current_time + client_state->sleep_interval;
748 && current_time > client_state->start_time + params->mrd)
749 stop_sending_client_message (vm, client_state);
751 *due_time = client_state->due_time;
754 return client_state->keep_sending_client_message;
758 send_dhcp6_pd_client_message_process (vlib_main_t * vm,
759 vlib_node_runtime_t * rt,
762 dhcp6_pd_client_main_t *cm = &dhcp6_pd_client_main;
763 dhcp6_pd_client_state_t *client_state;
764 uword *event_data = 0;
765 f64 sleep_time = 1e9;
773 vlib_process_wait_for_event_or_clock (vm, sleep_time);
774 vlib_process_get_events (vm, &event_data);
775 vec_reset_length (event_data);
777 current_time = vlib_time_now (vm);
780 due_time = current_time + 1e9;
781 for (i = 0; i < vec_len (cm->client_state_by_sw_if_index); i++)
783 client_state = &cm->client_state_by_sw_if_index[i];
784 if (!client_state->entry_valid)
786 if (check_pd_send_client_message
787 (vm, client_state, current_time, &dt) && (dt < due_time))
790 current_time = vlib_time_now (vm);
792 while (due_time < current_time);
794 sleep_time = due_time - current_time;
801 VLIB_REGISTER_NODE (send_dhcp6_pd_client_message_process_node) = {
802 .function = send_dhcp6_pd_client_message_process,
803 .type = VLIB_NODE_TYPE_PROCESS,
804 .name = "send-dhcp6-pd-client-message-process",
809 dhcp6_pd_send_client_message (vlib_main_t * vm, u32 sw_if_index, u8 stop,
810 dhcp6_pd_send_client_message_params_t * params)
812 dhcp6_pd_client_main_t *cm = &dhcp6_pd_client_main;
813 dhcp6_pd_client_state_t *client_state = 0;
814 dhcp6_pd_client_state_t empty_state = {
818 ASSERT (~0 != sw_if_index);
820 vec_validate_init_empty (cm->client_state_by_sw_if_index, sw_if_index,
822 client_state = &cm->client_state_by_sw_if_index[sw_if_index];
823 if (!client_state->entry_valid)
825 client_state->entry_valid = 1;
826 client_state->adj_index = ~0;
829 stop_sending_client_message (vm, client_state);
833 client_state->keep_sending_client_message = 1;
834 vec_free (client_state->params.prefixes);
835 client_state->params = *params;
836 client_state->params.prefixes = vec_dup (params->prefixes);
837 client_state->n_left = params->mrc;
838 client_state->start_time = vlib_time_now (vm);
839 client_state->sleep_interval =
840 (1 + random_f64_from_to (-0.1, 0.1)) * params->irt;
841 client_state->due_time = 0; /* send first packet ASAP */
842 client_state->transaction_id = random_u32 (&cm->seed) & 0x00ffffff;
843 client_state->buffer =
844 create_buffer_for_client_message (vm, sw_if_index, client_state,
846 if (!client_state->buffer)
847 client_state->keep_sending_client_message = 0;
849 vlib_process_signal_event (vm,
850 send_dhcp6_pd_client_message_process_node.index,
856 vl_api_dhcp6_pd_send_client_message_t_handler
857 (vl_api_dhcp6_pd_send_client_message_t * mp)
859 vl_api_dhcp6_pd_send_client_message_reply_t *rmp;
860 dhcp6_pd_send_client_message_params_t params;
861 vlib_main_t *vm = vlib_get_main ();
866 VALIDATE_SW_IF_INDEX (mp);
868 BAD_SW_IF_INDEX_LABEL;
869 REPLY_MACRO (VL_API_DHCP6_PD_SEND_CLIENT_MESSAGE_REPLY);
874 params.sw_if_index = ntohl (mp->sw_if_index);
875 params.server_index = ntohl (mp->server_index);
876 params.irt = ntohl (mp->irt);
877 params.mrt = ntohl (mp->mrt);
878 params.mrc = ntohl (mp->mrc);
879 params.mrd = ntohl (mp->mrd);
880 params.msg_type = mp->msg_type;
881 params.T1 = ntohl (mp->T1);
882 params.T2 = ntohl (mp->T2);
883 n_prefixes = ntohl (mp->n_prefixes);
886 vec_validate (params.prefixes, n_prefixes - 1);
887 for (i = 0; i < n_prefixes; i++)
889 vl_api_dhcp6_pd_prefix_info_t *pi = &mp->prefixes[i];
890 dhcp6_pd_send_client_message_params_prefix_t *pref =
892 pref->preferred_lt = ntohl (pi->preferred_time);
893 pref->valid_lt = ntohl (pi->valid_time);
894 memcpy (pref->prefix.as_u8, pi->prefix, 16);
895 pref->prefix_length = pi->prefix_length;
898 dhcp6_pd_send_client_message (vm, ntohl (mp->sw_if_index), mp->stop,
902 static clib_error_t *
903 call_dhcp6_pd_reply_event_callbacks (void *data,
904 _vnet_dhcp6_pd_reply_event_function_list_elt_t
907 clib_error_t *error = 0;
911 error = elt->fp (data);
914 elt = elt->next_dhcp6_pd_reply_event_function;
921 dhcp6_pd_reply_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
924 /* These cross the longjmp boundry (vlib_process_wait_for_event)
925 * and need to be volatile - to prevent them from being optimized into
926 * a register - which could change during suspension */
930 vlib_process_wait_for_event (vm);
931 uword event_type = DHCP6_PD_DP_REPLY_REPORT;
932 void *event_data = vlib_process_get_event_data (vm, &event_type);
935 if (event_type == DHCP6_PD_DP_REPLY_REPORT)
937 report_t *events = event_data;
938 for (i = 0; i < vec_len (events); i++)
941 sizeof (vl_api_dhcp6_pd_reply_event_t) +
942 vec_len (events[i].prefixes) *
943 sizeof (vl_api_dhcp6_pd_prefix_info_t);
944 vl_api_dhcp6_pd_reply_event_t *event =
945 clib_mem_alloc (event_size);
946 memset (event, 0, event_size);
948 event->sw_if_index = htonl (events[i].sw_if_index);
949 event->server_index = htonl (events[i].server_index);
950 event->msg_type = events[i].msg_type;
951 event->T1 = htonl (events[i].T1);
952 event->T2 = htonl (events[i].T2);
953 event->inner_status_code = htons (events[i].inner_status_code);
954 event->status_code = htons (events[i].status_code);
955 event->preference = events[i].preference;
957 event->n_prefixes = htonl (vec_len (events[i].prefixes));
958 vl_api_dhcp6_pd_prefix_info_t *prefix =
959 (typeof (prefix)) event->prefixes;
961 for (j = 0; j < vec_len (events[i].prefixes); j++)
963 prefix_info_t *info = &events[i].prefixes[j];
964 memcpy (prefix->prefix, &info->prefix, 16);
965 prefix->prefix_length = info->prefix_length;
966 prefix->valid_time = htonl (info->valid_time);
967 prefix->preferred_time = htonl (info->preferred_time);
971 dhcp6_pd_client_public_main_t *dpcpm =
972 &dhcp6_pd_client_public_main;
973 call_dhcp6_pd_reply_event_callbacks (event, dpcpm->functions);
975 vpe_client_registration_t *reg;
977 pool_foreach(reg, vpe_api_main.dhcp6_pd_reply_events_registrations,
979 vl_api_registration_t *vl_reg;
981 vl_api_client_index_to_registration (reg->client_index);
982 if (vl_reg && vl_api_can_send_msg (vl_reg))
984 vl_api_dhcp6_pd_reply_event_t *msg =
985 vl_msg_api_alloc (event_size);
986 clib_memcpy (msg, event, event_size);
987 msg->_vl_msg_id = htons (VL_API_DHCP6_PD_REPLY_EVENT);
988 msg->client_index = reg->client_index;
989 msg->pid = reg->client_pid;
990 vl_api_send_msg (vl_reg, (u8 *) msg);
995 clib_mem_free (event);
998 vlib_process_put_event_data (vm, event_data);
1005 VLIB_REGISTER_NODE (dhcp6_pd_reply_process_node, ) = {
1006 .function = dhcp6_pd_reply_process,
1007 .type = VLIB_NODE_TYPE_PROCESS,
1008 .name = "dhcp6-pd-reply-publisher-process",
1013 vl_api_want_dhcp6_pd_reply_events_t_handler
1014 (vl_api_want_dhcp6_pd_reply_events_t * mp)
1016 vpe_api_main_t *am = &vpe_api_main;
1017 vl_api_want_dhcp6_pd_reply_events_reply_t *rmp;
1021 hash_get (am->dhcp6_pd_reply_events_registration_hash, mp->client_index);
1022 vpe_client_registration_t *rp;
1025 if (mp->enable_disable)
1027 clib_warning ("pid %d: already enabled...", ntohl (mp->pid));
1028 rv = VNET_API_ERROR_INVALID_REGISTRATION;
1034 pool_elt_at_index (am->dhcp6_pd_reply_events_registrations, p[0]);
1035 pool_put (am->dhcp6_pd_reply_events_registrations, rp);
1036 hash_unset (am->dhcp6_pd_reply_events_registration_hash,
1038 if (pool_elts (am->dhcp6_pd_reply_events_registrations) == 0)
1039 dhcp6_pd_set_publisher_node (~0, REPORT_MAX);
1043 if (mp->enable_disable == 0)
1045 clib_warning ("pid %d: already disabled...", ntohl (mp->pid));
1046 rv = VNET_API_ERROR_INVALID_REGISTRATION;
1049 pool_get (am->dhcp6_pd_reply_events_registrations, rp);
1050 rp->client_index = mp->client_index;
1051 rp->client_pid = ntohl (mp->pid);
1052 hash_set (am->dhcp6_pd_reply_events_registration_hash, rp->client_index,
1053 rp - am->dhcp6_pd_reply_events_registrations);
1054 dhcp6_pd_set_publisher_node (dhcp6_pd_reply_process_node.index,
1055 DHCP6_PD_DP_REPLY_REPORT);
1058 REPLY_MACRO (VL_API_WANT_DHCP6_PD_REPLY_EVENTS_REPLY);
1062 vl_api_dhcp6_duid_ll_set_t_handler (vl_api_dhcp6_duid_ll_set_t * mp)
1064 vl_api_dhcp6_duid_ll_set_reply_t *rmp;
1065 dhcpv6_duid_ll_string_t *duid;
1068 duid = (dhcpv6_duid_ll_string_t *) mp->duid_ll;
1069 if (duid->duid_type != htonl (DHCPV6_DUID_LL))
1071 rv = VNET_API_ERROR_INVALID_VALUE;
1074 clib_memcpy (&client_duid, &duid, sizeof (client_duid));
1077 REPLY_MACRO (VL_API_DHCP6_DUID_LL_SET_REPLY);
1081 generate_client_duid (void)
1083 client_duid.duid_type = htons (DHCPV6_DUID_LL);
1084 client_duid.hardware_type = htons (1);
1086 vnet_main_t *vnm = vnet_get_main ();
1087 vnet_interface_main_t *im = &vnm->interface_main;
1088 vnet_hw_interface_t *hi;
1089 ethernet_interface_t *eth_if = 0;
1092 pool_foreach (hi, im->hw_interfaces,
1094 eth_if = ethernet_get_interface (ðernet_main, hi->hw_if_index);
1101 clib_memcpy (client_duid.lla, eth_if->address, 6);
1104 clib_warning ("Failed to find any Ethernet interface, "
1105 "setting DHCPv6 DUID link-layer address to random value");
1106 u32 seed = random_default_seed ();
1108 client_duid.lla[0] = 0xc2; /* locally administered unicast */
1109 client_duid.lla[1] = 0x18;
1110 client_duid.lla[2] = 0x44;
1111 client_duid.lla[3] = random_u32 (&seed);
1112 client_duid.lla[4] = random_u32 (&seed);
1113 client_duid.lla[5] = random_u32 (&seed);
1118 dhcp6_clients_enable_disable (u8 enable)
1120 vlib_main_t *vm = vlib_get_main ();
1124 if (client_duid.duid_type == 0)
1125 generate_client_duid ();
1126 udp_register_dst_port (vm, UDP_DST_PORT_dhcpv6_to_client,
1127 dhcpv6_pd_client_node.index, 0 /* is_ip6 */ );
1130 udp_unregister_dst_port (vm, UDP_DST_PORT_dhcpv6_to_client,
1135 vl_api_dhcp6_clients_enable_disable_t_handler
1136 (vl_api_dhcp6_clients_enable_disable_t * mp)
1138 vl_api_dhcp6_clients_enable_disable_reply_t *rmp;
1141 dhcp6_clients_enable_disable (mp->enable);
1143 REPLY_MACRO (VL_API_WANT_DHCP6_PD_REPLY_EVENTS_REPLY);
1146 static clib_error_t *
1147 dhcp6_pd_client_init (vlib_main_t * vm)
1149 dhcp6_pd_client_main_t *cm = &dhcp6_pd_client_main;
1152 cm->vnet_main = vnet_get_main ();
1154 cm->publisher_node = ~0;
1156 cm->seed = 0xdeaddabe;
1161 VLIB_INIT_FUNCTION (dhcp6_pd_client_init);
1164 * fd.io coding-style-patch-verification: ON
1167 * eval: (c-set-style "gnu")