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 <dhcp/dhcp6_packet.h>
18 #include <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 <dhcp/dhcp6_pd_client_dp.h>
25 #include <dhcp/dhcp6_client_common_dp.h>
26 #include <vnet/ip/ip_types_api.h>
28 dhcp6_pd_client_main_t dhcp6_pd_client_main;
29 dhcp6_pd_client_public_main_t dhcp6_pd_client_public_main;
32 signal_report (prefix_report_t * r)
34 vlib_main_t *vm = vlib_get_main ();
35 dhcp6_pd_client_main_t *cm = &dhcp6_pd_client_main;
36 uword ni = cm->publisher_node;
37 uword et = cm->publisher_et;
39 if (ni == (uword) ~ 0)
42 vlib_process_signal_event_data (vm, ni, et, 1, sizeof *q);
48 dhcp6_pd_publish_report (prefix_report_t * r)
50 void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
51 vl_api_rpc_call_main_thread (signal_report, (u8 *) r, sizeof *r);
56 dhcp6_pd_set_publisher_node (uword node_index, uword event_type)
58 dhcp6_pd_client_main_t *cm = &dhcp6_pd_client_main;
59 cm->publisher_node = node_index;
60 cm->publisher_et = event_type;
64 stop_sending_client_message (vlib_main_t * vm,
65 dhcp6_pd_client_state_t * client_state)
69 client_state->keep_sending_client_message = 0;
70 vec_free (client_state->params.prefixes);
71 if (client_state->buffer)
73 bi0 = vlib_get_buffer_index (vm, client_state->buffer);
74 vlib_buffer_free (vm, &bi0, 1);
75 client_state->buffer = 0;
76 adj_unlock (client_state->adj_index);
77 client_state->adj_index = ~0;
81 static vlib_buffer_t *
82 create_buffer_for_client_message (vlib_main_t * vm,
84 dhcp6_pd_client_state_t
85 * client_state, u32 type)
87 dhcp6_client_common_main_t *ccm = &dhcp6_client_common_main;
88 vnet_main_t *vnm = vnet_get_main ();
94 dhcpv6_header_t *dhcp;
95 ip6_address_t src_addr;
97 client_state->transaction_start = vlib_time_now (vm);
101 vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
102 vnet_sw_interface_t *sup_sw = vnet_get_sup_sw_interface (vnm, sw_if_index);
103 vnet_sw_interface_t *sw = vnet_get_sw_interface (vnm, sw_if_index);
105 /* Interface(s) down? */
106 if ((hw->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) == 0)
108 if ((sup_sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
110 if ((sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
113 /* Get a link-local address */
114 src_addr = ip6_neighbor_get_link_local_address (sw_if_index);
116 if (src_addr.as_u8[0] != 0xfe)
118 clib_warning ("Could not find source address to send DHCPv6 packet");
122 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
124 clib_warning ("Buffer allocation failed");
128 b = vlib_get_buffer (vm, bi);
129 vnet_buffer (b)->sw_if_index[VLIB_RX] = sw_if_index;
130 vnet_buffer (b)->sw_if_index[VLIB_TX] = sw_if_index;
131 client_state->adj_index = adj_mcast_add_or_lock (FIB_PROTOCOL_IP6,
134 vnet_buffer (b)->ip.adj_index[VLIB_TX] = client_state->adj_index;
135 b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
137 ip = (ip6_header_t *) vlib_buffer_get_current (b);
138 udp = (udp_header_t *) (ip + 1);
139 dhcp = (dhcpv6_header_t *) (udp + 1);
141 ip->src_address = src_addr;
143 ip->ip_version_traffic_class_and_flow_label =
144 clib_host_to_net_u32 (0x6 << 28);
145 ip->payload_length = 0;
146 ip->protocol = IP_PROTOCOL_UDP;
148 udp->src_port = clib_host_to_net_u16 (DHCPV6_CLIENT_PORT);
149 udp->dst_port = clib_host_to_net_u16 (DHCPV6_SERVER_PORT);
153 dhcp->msg_type = type;
154 dhcp->xid[0] = (client_state->transaction_id & 0x00ff0000) >> 16;
155 dhcp->xid[1] = (client_state->transaction_id & 0x0000ff00) >> 8;
156 dhcp->xid[2] = (client_state->transaction_id & 0x000000ff) >> 0;
158 void *d = (void *) dhcp->data;
159 dhcpv6_option_t *duid;
160 dhcpv6_elapsed_t *elapsed;
161 dhcpv6_ia_header_t *ia_hdr;
162 dhcpv6_ia_opt_pd_t *opt_pd;
163 if (type == DHCPV6_MSG_SOLICIT || type == DHCPV6_MSG_REQUEST ||
164 type == DHCPV6_MSG_RENEW || type == DHCPV6_MSG_REBIND ||
165 type == DHCPV6_MSG_RELEASE)
167 duid = (dhcpv6_option_t *) d;
168 duid->option = clib_host_to_net_u16 (DHCPV6_OPTION_CLIENTID);
169 duid->length = clib_host_to_net_u16 (CLIENT_DUID_LENGTH);
170 clib_memcpy (duid + 1, client_duid.bin_string, CLIENT_DUID_LENGTH);
171 d += sizeof (*duid) + CLIENT_DUID_LENGTH;
173 if (client_state->params.server_index != ~0)
176 &ccm->server_ids[client_state->params.server_index];
178 duid = (dhcpv6_option_t *) d;
179 duid->option = clib_host_to_net_u16 (DHCPV6_OPTION_SERVERID);
180 duid->length = clib_host_to_net_u16 (se->len);
181 clib_memcpy (duid + 1, se->data, se->len);
182 d += sizeof (*duid) + se->len;
185 elapsed = (dhcpv6_elapsed_t *) d;
186 elapsed->opt.option = clib_host_to_net_u16 (DHCPV6_OPTION_ELAPSED_TIME);
187 elapsed->opt.length =
188 clib_host_to_net_u16 (sizeof (*elapsed) - sizeof (elapsed->opt));
189 elapsed->elapsed_10ms = 0;
190 client_state->elapsed_pos =
191 (char *) &elapsed->elapsed_10ms -
192 (char *) vlib_buffer_get_current (b);
193 d += sizeof (*elapsed);
195 ia_hdr = (dhcpv6_ia_header_t *) d;
196 ia_hdr->opt.option = clib_host_to_net_u16 (DHCPV6_OPTION_IA_PD);
197 ia_hdr->iaid = clib_host_to_net_u32 (DHCPV6_CLIENT_IAID);
198 ia_hdr->t1 = clib_host_to_net_u32 (client_state->params.T1);
199 ia_hdr->t2 = clib_host_to_net_u32 (client_state->params.T2);
200 d += sizeof (*ia_hdr);
202 n_prefixes = vec_len (client_state->params.prefixes);
205 clib_host_to_net_u16 (sizeof (*ia_hdr) +
206 n_prefixes * sizeof (*opt_pd) -
207 sizeof (ia_hdr->opt));
209 for (i = 0; i < n_prefixes; i++)
211 dhcp6_pd_send_client_message_params_prefix_t *pref =
212 &client_state->params.prefixes[i];
213 opt_pd = (dhcpv6_ia_opt_pd_t *) d;
214 opt_pd->opt.option = clib_host_to_net_u16 (DHCPV6_OPTION_IAPREFIX);
216 clib_host_to_net_u16 (sizeof (*opt_pd) - sizeof (opt_pd->opt));
217 opt_pd->addr = pref->prefix;
218 opt_pd->prefix = pref->prefix_length;
219 opt_pd->valid = clib_host_to_net_u32 (pref->valid_lt);
220 opt_pd->preferred = clib_host_to_net_u32 (pref->preferred_lt);
221 d += sizeof (*opt_pd);
226 clib_warning ("State not implemented");
229 dhcp_opt_len = ((u8 *) d) - dhcp->data;
231 clib_host_to_net_u16 (sizeof (*udp) + sizeof (*dhcp) + dhcp_opt_len);
232 ip->payload_length = udp->length;
234 sizeof (*ip) + sizeof (*udp) + sizeof (*dhcp) + dhcp_opt_len;
236 ip->dst_address = all_dhcp6_relay_agents_and_servers;
242 check_pd_send_client_message (vlib_main_t * vm,
243 dhcp6_pd_client_state_t * client_state,
244 f64 current_time, f64 * due_time)
254 int bogus_length = 0;
256 dhcp6_pd_send_client_message_params_t *params;
258 f64 now = vlib_time_now (vm);
260 if (!client_state->keep_sending_client_message)
263 params = &client_state->params;
265 if (client_state->due_time > current_time)
267 *due_time = client_state->due_time;
271 p0 = client_state->buffer;
273 next_index = ip6_rewrite_mcast_node.index;
275 c0 = vlib_buffer_copy (vm, p0);
276 ci0 = vlib_get_buffer_index (vm, c0);
278 ip = (ip6_header_t *) vlib_buffer_get_current (c0);
279 udp = (udp_header_t *) (ip + 1);
281 u16 *elapsed_field = (u16 *) ((void *) ip + client_state->elapsed_pos);
283 clib_host_to_net_u16 ((u16)
284 ((now - client_state->transaction_start) * 100));
288 ip6_tcp_udp_icmp_compute_checksum (vm, 0, ip, &bogus_length);
290 f = vlib_get_frame_to_node (vm, next_index);
291 to_next = vlib_frame_vector_args (f);
294 vlib_put_frame_to_node (vm, next_index, f);
296 if (params->mrc != 0 && --client_state->n_left == 0)
297 stop_sending_client_message (vm, client_state);
300 client_state->sleep_interval =
301 (2 + random_f64_from_to (-0.1, 0.1)) * client_state->sleep_interval;
302 if (client_state->sleep_interval > params->mrt)
303 client_state->sleep_interval =
304 (1 + random_f64_from_to (-0.1, 0.1)) * params->mrt;
306 client_state->due_time = current_time + client_state->sleep_interval;
309 && current_time > client_state->start_time + params->mrd)
310 stop_sending_client_message (vm, client_state);
312 *due_time = client_state->due_time;
315 return client_state->keep_sending_client_message;
319 send_dhcp6_pd_client_message_process (vlib_main_t * vm,
320 vlib_node_runtime_t * rt,
323 dhcp6_pd_client_main_t *cm = &dhcp6_pd_client_main;
324 dhcp6_pd_client_state_t *client_state;
325 uword *event_data = 0;
326 f64 sleep_time = 1e9;
334 vlib_process_wait_for_event_or_clock (vm, sleep_time);
335 vlib_process_get_events (vm, &event_data);
336 vec_reset_length (event_data);
338 current_time = vlib_time_now (vm);
341 due_time = current_time + 1e9;
342 for (i = 0; i < vec_len (cm->client_state_by_sw_if_index); i++)
344 client_state = &cm->client_state_by_sw_if_index[i];
345 if (!client_state->entry_valid)
347 if (check_pd_send_client_message
348 (vm, client_state, current_time, &dt) && (dt < due_time))
351 current_time = vlib_time_now (vm);
353 while (due_time < current_time);
355 sleep_time = due_time - current_time;
362 VLIB_REGISTER_NODE (send_dhcp6_pd_client_message_process_node, static) = {
363 .function = send_dhcp6_pd_client_message_process,
364 .type = VLIB_NODE_TYPE_PROCESS,
365 .name = "send-dhcp6-pd-client-message-process",
370 dhcp6_pd_send_client_message (vlib_main_t * vm, u32 sw_if_index, u8 stop,
371 dhcp6_pd_send_client_message_params_t * params)
373 dhcp6_pd_client_main_t *cm = &dhcp6_pd_client_main;
374 dhcp6_pd_client_state_t *client_state = 0;
375 dhcp6_pd_client_state_t empty_state = {
379 ASSERT (~0 != sw_if_index);
381 vec_validate_init_empty (cm->client_state_by_sw_if_index, sw_if_index,
383 client_state = &cm->client_state_by_sw_if_index[sw_if_index];
384 if (!client_state->entry_valid)
386 client_state->entry_valid = 1;
387 client_state->adj_index = ~0;
390 stop_sending_client_message (vm, client_state);
394 client_state->keep_sending_client_message = 1;
395 vec_free (client_state->params.prefixes);
396 client_state->params = *params;
397 client_state->params.prefixes = vec_dup (params->prefixes);
398 client_state->n_left = params->mrc;
399 client_state->start_time = vlib_time_now (vm);
400 client_state->sleep_interval =
401 (1 + random_f64_from_to (-0.1, 0.1)) * params->irt;
402 client_state->due_time = 0; /* send first packet ASAP */
403 client_state->transaction_id = random_u32 (&cm->seed) & 0x00ffffff;
404 client_state->buffer =
405 create_buffer_for_client_message (vm, sw_if_index, client_state,
407 if (!client_state->buffer)
408 client_state->keep_sending_client_message = 0;
410 vlib_process_signal_event (vm,
411 send_dhcp6_pd_client_message_process_node.index,
416 static clib_error_t *
417 dhcp6_pd_client_init (vlib_main_t * vm)
419 dhcp6_pd_client_main_t *cm = &dhcp6_pd_client_main;
422 cm->vnet_main = vnet_get_main ();
423 cm->publisher_node = ~0;
424 cm->seed = (u32) clib_cpu_time_now ();
429 VLIB_INIT_FUNCTION (dhcp6_pd_client_init);
432 * fd.io coding-style-patch-verification: ON
435 * eval: (c-set-style "gnu")