2 * Copyright (c) 2015 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.
15 #include <vlib/vlib.h>
16 #include <vnet/dhcp/client.h>
17 #include <vnet/dhcp/dhcp_proxy.h>
18 #include <vnet/fib/fib_table.h>
20 dhcp_client_main_t dhcp_client_main;
21 static u8 *format_dhcp_client_state (u8 * s, va_list * va);
22 static vlib_node_registration_t dhcp_client_process_node;
25 dhcp_client_acquire_address (dhcp_client_main_t * dcm, dhcp_client_t * c)
28 * Install any/all info gleaned from dhcp, right here
30 ip4_add_del_interface_address (dcm->vlib_main, c->sw_if_index,
31 (void *) &c->leased_address,
32 c->subnet_mask_width, 0 /*is_del */ );
36 dhcp_client_release_address (dhcp_client_main_t * dcm, dhcp_client_t * c)
39 * Remove any/all info gleaned from dhcp, right here. Caller(s)
40 * have not wiped out the info yet.
43 ip4_add_del_interface_address (dcm->vlib_main, c->sw_if_index,
44 (void *) &c->leased_address,
45 c->subnet_mask_width, 1 /*is_del */ );
49 set_l2_rewrite (dhcp_client_main_t * dcm, dhcp_client_t * c)
51 /* Acquire the L2 rewrite string for the indicated sw_if_index */
52 c->l2_rewrite = vnet_build_rewrite_for_sw_interface (dcm->vnet_main,
58 void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
61 dhcp_client_proc_callback (uword * client_index)
63 vlib_main_t *vm = vlib_get_main ();
64 ASSERT (vlib_get_thread_index () == 0);
65 vlib_process_signal_event (vm, dhcp_client_process_node.index,
66 EVENT_DHCP_CLIENT_WAKEUP, *client_index);
70 * dhcp_client_for_us - server-to-client callback.
71 * Called from proxy_node.c:dhcp_proxy_to_client_input().
72 * This function first decides that the packet in question is
73 * actually for the dhcp client code in case we're also acting as
74 * a dhcp proxy. Ay caramba, what a folly!
77 dhcp_client_for_us (u32 bi, vlib_buffer_t * b,
79 udp_header_t * udp, dhcp_header_t * dhcp)
81 dhcp_client_main_t *dcm = &dhcp_client_main;
82 vlib_main_t *vm = dcm->vlib_main;
85 f64 now = vlib_time_now (dcm->vlib_main);
86 u8 dhcp_message_type = 0;
90 * Doing dhcp client on this interface?
91 * Presumably we will always receive dhcp clnt for-us pkts on
92 * the interface that's asking for an address.
94 p = hash_get (dcm->client_by_sw_if_index,
95 vnet_buffer (b)->sw_if_index[VLIB_RX]);
99 c = pool_elt_at_index (dcm->clients, p[0]);
101 /* Mixing dhcp relay and dhcp proxy? DGMS... */
102 if (c->state == DHCP_BOUND && c->retry_count == 0)
105 /* parse through the packet, learn what we can */
106 if (dhcp->your_ip_address.as_u32)
107 c->leased_address.as_u32 = dhcp->your_ip_address.as_u32;
109 c->dhcp_server.as_u32 = dhcp->server_ip_address.as_u32;
111 o = (dhcp_option_t *) dhcp->options;
113 while (o->option != 0xFF /* end of options */ &&
114 (u8 *) o < (b->data + b->current_data + b->current_length))
118 case 53: /* dhcp message type */
119 dhcp_message_type = o->data[0];
122 case 51: /* lease time */
124 u32 lease_time_in_seconds =
125 clib_host_to_net_u32 (o->data_as_u32[0]);
126 c->lease_expires = now + (f64) lease_time_in_seconds;
127 c->lease_lifetime = lease_time_in_seconds;
128 /* Set a sensible default, in case we don't get opt 58 */
129 c->lease_renewal_interval = lease_time_in_seconds / 2;
133 case 58: /* lease renew time in seconds */
135 u32 lease_renew_time_in_seconds =
136 clib_host_to_net_u32 (o->data_as_u32[0]);
137 c->lease_renewal_interval = lease_renew_time_in_seconds;
141 case 54: /* dhcp server address */
142 c->dhcp_server.as_u32 = o->data_as_u32[0];
145 case 1: /* subnet mask */
147 u32 subnet_mask = clib_host_to_net_u32 (o->data_as_u32[0]);
148 c->subnet_mask_width = count_set_bits (subnet_mask);
151 case 3: /* router address */
153 u32 router_address = o->data_as_u32[0];
154 c->router_address.as_u32 = router_address;
158 case 12: /* hostname */
160 /* Replace the existing hostname if necessary */
161 vec_free (c->hostname);
162 vec_validate (c->hostname, o->length - 1);
163 clib_memcpy (c->hostname, o->data, o->length);
167 /* $$$$ Your message in this space, parse more options */
172 o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
178 if (dhcp_message_type != DHCP_PACKET_OFFER)
180 clib_warning ("sw_if_index %d state %U message type %d",
181 c->sw_if_index, format_dhcp_client_state,
182 c->state, dhcp_message_type);
183 c->next_transmit = now + 5.0;
187 /* Received an offer, go send a request */
188 c->state = DHCP_REQUEST;
190 c->next_transmit = 0; /* send right now... */
191 /* Poke the client process, which will send the request */
192 uword client_id = c - dcm->clients;
193 vl_api_rpc_call_main_thread (dhcp_client_proc_callback,
194 (u8 *) & client_id, sizeof (uword));
199 if (dhcp_message_type != DHCP_PACKET_ACK)
201 clib_warning ("sw_if_index %d state %U message type %d",
202 c->sw_if_index, format_dhcp_client_state,
203 c->state, dhcp_message_type);
204 c->next_transmit = now + 5.0;
207 /* OK, we own the address (etc), add to the routing table(s) */
208 if (c->state == DHCP_REQUEST)
210 void (*fp) (u32, u32, u8 *, u8, u8, u8 *, u8 *, u8 *) =
213 /* add the advertised subnet and disable the feature */
214 dhcp_client_acquire_address (dcm, c);
215 vnet_feature_enable_disable ("ip4-unicast",
216 "ip4-dhcp-client-detect",
217 c->sw_if_index, 0, 0, 0);
220 * Configure default IP route:
222 if (c->router_address.as_u32)
224 fib_prefix_t all_0s = {
226 .fp_addr.ip4.as_u32 = 0x0,
227 .fp_proto = FIB_PROTOCOL_IP4,
229 ip46_address_t nh = {
230 .ip4 = c->router_address,
234 fib_table_entry_path_add (
235 fib_table_get_index_for_sw_if_index (
243 ~0, 1, NULL, // no label stack
244 FIB_ROUTE_PATH_FLAG_NONE);
249 * Call the user's event callback to report DHCP information
252 (*fp) (c->client_index, /* clinet index */
253 c->pid, c->hostname, c->subnet_mask_width, 0, /* is_ipv6 */
254 (u8 *) & c->leased_address, /* host IP address */
255 (u8 *) & c->router_address, /* router IP address */
256 (u8 *) (c->l2_rewrite + 6)); /* host MAC address */
259 c->state = DHCP_BOUND;
261 c->next_transmit = now + (f64) c->lease_renewal_interval;
262 c->lease_expires = now + (f64) c->lease_lifetime;
266 clib_warning ("client %d bogus state %d", c - dcm->clients, c->state);
270 /* drop the pkt, return 1 */
271 vlib_buffer_free (vm, &bi, 1);
276 send_dhcp_pkt (dhcp_client_main_t * dcm, dhcp_client_t * c,
277 dhcp_packet_type_t type, int is_broadcast)
279 vlib_main_t *vm = dcm->vlib_main;
280 vnet_main_t *vnm = dcm->vnet_main;
281 vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, c->sw_if_index);
282 vnet_sw_interface_t *sup_sw
283 = vnet_get_sup_sw_interface (vnm, c->sw_if_index);
284 vnet_sw_interface_t *sw = vnet_get_sw_interface (vnm, c->sw_if_index);
293 u16 udp_length, ip_length;
295 /* Interface(s) down? */
296 if ((hw->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) == 0)
298 if ((sup_sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
300 if ((sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
303 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
305 clib_warning ("buffer allocation failure");
306 c->next_transmit = 0;
310 /* Build a dhcpv4 pkt from whole cloth */
311 b = vlib_get_buffer (vm, bi);
313 ASSERT (b->current_data == 0);
315 vnet_buffer (b)->sw_if_index[VLIB_RX] = c->sw_if_index;
318 f = vlib_get_frame_to_node (vm, hw->output_node_index);
319 vnet_buffer (b)->sw_if_index[VLIB_TX] = c->sw_if_index;
320 clib_memcpy (b->data, c->l2_rewrite, vec_len (c->l2_rewrite));
322 (((u8 *) vlib_buffer_get_current (b)) + vec_len (c->l2_rewrite));
326 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
327 vnet_buffer (b)->sw_if_index[VLIB_TX] = ~0; /* use interface VRF */
328 ip = vlib_buffer_get_current (b);
331 /* Enqueue the packet right now */
332 to_next = vlib_frame_vector_args (f);
337 vlib_put_frame_to_node (vm, hw->output_node_index, f);
339 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
341 udp = (udp_header_t *) (ip + 1);
342 dhcp = (dhcp_header_t *) (udp + 1);
344 /* $$$ optimize, maybe */
345 memset (ip, 0, sizeof (*ip) + sizeof (*udp) + sizeof (*dhcp));
347 ip->ip_version_and_header_length = 0x45;
349 ip->protocol = IP_PROTOCOL_UDP;
353 /* src = 0.0.0.0, dst = 255.255.255.255 */
354 ip->dst_address.as_u32 = ~0;
358 /* Renewing an active lease, plain old ip4 src/dst */
359 ip->src_address.as_u32 = c->leased_address.as_u32;
360 ip->dst_address.as_u32 = c->dhcp_server.as_u32;
363 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client);
364 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_server);
366 /* Send the interface MAC address */
367 clib_memcpy (dhcp->client_hardware_address, c->l2_rewrite + 6, 6);
369 /* Lease renewal, set up client_ip_address */
370 if (is_broadcast == 0)
371 dhcp->client_ip_address.as_u32 = c->leased_address.as_u32;
373 dhcp->opcode = 1; /* request, all we send */
374 dhcp->hardware_type = 1; /* ethernet */
375 dhcp->hardware_address_length = 6;
376 dhcp->transaction_identifier = c->transaction_id;
378 clib_host_to_net_u16 (is_broadcast && c->set_broadcast_flag ?
379 DHCP_FLAG_BROADCAST : 0);
380 dhcp->magic_cookie.as_u32 = DHCP_MAGIC;
382 o = (dhcp_option_t *) dhcp->options;
384 /* Send option 53, the DHCP message type */
385 o->option = DHCP_PACKET_OPTION_MSG_TYPE;
388 o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
390 /* Send option 57, max msg length */
391 if (0 /* not needed, apparently */ )
396 u16 *o2 = (u16 *) o->data;
397 *o2 = clib_host_to_net_u16 (1152);
398 o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
403 * If server ip address is available with non-zero value,
404 * option 54 (DHCP Server Identifier) is sent.
406 if (c->dhcp_server.as_u32)
410 clib_memcpy (o->data, &c->dhcp_server.as_u32, 4);
411 o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
414 /* send option 50, requested IP address */
415 if (c->leased_address.as_u32)
419 clib_memcpy (o->data, &c->leased_address.as_u32, 4);
420 o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
423 /* send option 12, host name */
424 if (vec_len (c->hostname))
427 o->length = vec_len (c->hostname);
428 clib_memcpy (o->data, c->hostname, vec_len (c->hostname));
429 o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
432 /* send option 61, client_id */
433 if (vec_len (c->client_identifier))
436 o->length = vec_len (c->client_identifier);
437 clib_memcpy (o->data, c->client_identifier,
438 vec_len (c->client_identifier));
439 o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
442 /* $$ maybe send the client s/w version if anyone cares */
445 * send option 55, parameter request list
446 * The current list - see below, matches the Linux dhcp client's list
447 * Any specific dhcp server config and/or dhcp server may or may
448 * not yield specific options.
451 o->length = vec_len (c->option_55_data);
452 clib_memcpy (o->data, c->option_55_data, vec_len (c->option_55_data));
453 o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
460 b->current_length = ((u8 *) o) - b->data;
462 /* fix ip length, checksum and udp length */
463 ip_length = vlib_buffer_length_in_chain (vm, b);
465 ip_length -= vec_len (c->l2_rewrite);
467 ip->length = clib_host_to_net_u16 (ip_length);
468 ip->checksum = ip4_header_checksum (ip);
470 udp_length = ip_length - (sizeof (*ip));
471 udp->length = clib_host_to_net_u16 (udp_length);
475 dhcp_discover_state (dhcp_client_main_t * dcm, dhcp_client_t * c, f64 now)
478 * State machine "DISCOVER" state. Send a dhcp discover packet,
479 * eventually back off the retry rate.
481 send_dhcp_pkt (dcm, c, DHCP_PACKET_DISCOVER, 1 /* is_broadcast */ );
484 if (c->retry_count > 10)
485 c->next_transmit = now + 5.0;
487 c->next_transmit = now + 1.0;
492 dhcp_request_state (dhcp_client_main_t * dcm, dhcp_client_t * c, f64 now)
495 * State machine "REQUEST" state. Send a dhcp request packet,
496 * eventually drop back to the discover state.
498 send_dhcp_pkt (dcm, c, DHCP_PACKET_REQUEST, 1 /* is_broadcast */ );
501 if (c->retry_count > 7 /* lucky you */ )
503 c->state = DHCP_DISCOVER;
504 c->next_transmit = now;
508 c->next_transmit = now + 1.0;
513 dhcp_bound_state (dhcp_client_main_t * dcm, dhcp_client_t * c, f64 now)
516 * State machine "BOUND" state. Send a dhcp request packet,
517 * eventually, when the lease expires, forget the dhcp data
518 * and go back to the stone age.
520 send_dhcp_pkt (dcm, c, DHCP_PACKET_REQUEST, 0 /* is_broadcast */ );
523 if (c->retry_count > 10)
524 c->next_transmit = now + 5.0;
526 c->next_transmit = now + 1.0;
528 if (now > c->lease_expires)
530 if (c->router_address.as_u32)
532 fib_prefix_t all_0s = {
534 .fp_addr.ip4.as_u32 = 0x0,
535 .fp_proto = FIB_PROTOCOL_IP4,
537 ip46_address_t nh = {
538 .ip4 = c->router_address,
541 fib_table_entry_path_remove (fib_table_get_index_for_sw_if_index
542 (FIB_PROTOCOL_IP4, c->sw_if_index),
543 &all_0s, FIB_SOURCE_DHCP,
544 DPO_PROTO_IP4, &nh, c->sw_if_index, ~0,
545 1, FIB_ROUTE_PATH_FLAG_NONE);
548 dhcp_client_release_address (dcm, c);
549 c->state = DHCP_DISCOVER;
550 c->next_transmit = now;
552 /* Wipe out any memory of the address we had... */
553 c->leased_address.as_u32 = 0;
554 c->subnet_mask_width = 0;
555 c->router_address.as_u32 = 0;
556 c->lease_renewal_interval = 0;
557 c->dhcp_server.as_u32 = 0;
564 dhcp_client_sm (f64 now, f64 timeout, uword pool_index)
566 dhcp_client_main_t *dcm = &dhcp_client_main;
569 /* deleted, pooched, yadda yadda yadda */
570 if (pool_is_free_index (dcm->clients, pool_index))
573 c = pool_elt_at_index (dcm->clients, pool_index);
575 /* Time for us to do something with this client? */
576 if (now < c->next_transmit)
582 case DHCP_DISCOVER: /* send a discover */
583 if (dhcp_discover_state (dcm, c, now))
587 case DHCP_REQUEST: /* send a request */
588 if (dhcp_request_state (dcm, c, now))
592 case DHCP_BOUND: /* bound, renew needed? */
593 if (dhcp_bound_state (dcm, c, now))
598 clib_warning ("dhcp client %d bogus state %d",
599 c - dcm->clients, c->state);
603 if (c->next_transmit < now + timeout)
604 return c->next_transmit - now;
610 dhcp_client_process (vlib_main_t * vm,
611 vlib_node_runtime_t * rt, vlib_frame_t * f)
616 uword *event_data = 0;
617 dhcp_client_main_t *dcm = &dhcp_client_main;
623 vlib_process_wait_for_event_or_clock (vm, timeout);
625 event_type = vlib_process_get_events (vm, &event_data);
627 now = vlib_time_now (vm);
631 case EVENT_DHCP_CLIENT_WAKEUP:
632 for (i = 0; i < vec_len (event_data); i++)
633 timeout = dhcp_client_sm (now, timeout, event_data[i]);
638 pool_foreach (c, dcm->clients,
640 timeout = dhcp_client_sm (now, timeout,
641 (uword) (c - dcm->clients));
644 if (pool_elts (dcm->clients) == 0)
649 vec_reset_length (event_data);
657 VLIB_REGISTER_NODE (dhcp_client_process_node,static) = {
658 .function = dhcp_client_process,
659 .type = VLIB_NODE_TYPE_PROCESS,
660 .name = "dhcp-client-process",
661 .process_log2_n_stack_bytes = 16,
666 format_dhcp_client_state (u8 * s, va_list * va)
668 dhcp_client_state_t state = va_arg (*va, dhcp_client_state_t);
669 char *str = "BOGUS!";
677 foreach_dhcp_client_state;
683 s = format (s, "%s", str);
688 format_dhcp_client (u8 * s, va_list * va)
690 dhcp_client_main_t *dcm = va_arg (*va, dhcp_client_main_t *);
691 dhcp_client_t *c = va_arg (*va, dhcp_client_t *);
692 int verbose = va_arg (*va, int);
694 s = format (s, "[%d] %U state %U ", c - dcm->clients,
695 format_vnet_sw_if_index_name, dcm->vnet_main, c->sw_if_index,
696 format_dhcp_client_state, c->state);
698 if (c->leased_address.as_u32)
699 s = format (s, "addr %U/%d gw %U\n",
700 format_ip4_address, &c->leased_address,
701 c->subnet_mask_width, format_ip4_address, &c->router_address);
703 s = format (s, "no address\n");
707 s = format (s, "retry count %d, next xmt %.2f",
708 c->retry_count, c->next_transmit);
713 static clib_error_t *
714 show_dhcp_client_command_fn (vlib_main_t * vm,
715 unformat_input_t * input,
716 vlib_cli_command_t * cmd)
718 dhcp_client_main_t *dcm = &dhcp_client_main;
721 u32 sw_if_index = ~0;
724 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
726 if (unformat (input, "intfc %U",
727 unformat_vnet_sw_interface, dcm->vnet_main, &sw_if_index))
729 else if (unformat (input, "verbose"))
735 if (sw_if_index != ~0)
737 p = hash_get (dcm->client_by_sw_if_index, sw_if_index);
739 return clib_error_return (0, "dhcp client not configured");
740 c = pool_elt_at_index (dcm->clients, p[0]);
741 vlib_cli_output (vm, "%U", format_dhcp_client, dcm, c, verbose);
746 pool_foreach (c, dcm->clients,
748 vlib_cli_output (vm, "%U",
749 format_dhcp_client, dcm,
758 VLIB_CLI_COMMAND (show_dhcp_client_command, static) = {
759 .path = "show dhcp client",
760 .short_help = "show dhcp client [intfc <intfc>][verbose]",
761 .function = show_dhcp_client_command_fn,
767 dhcp_client_add_del (dhcp_client_add_del_args_t * a)
769 dhcp_client_main_t *dcm = &dhcp_client_main;
770 vlib_main_t *vm = dcm->vlib_main;
773 fib_prefix_t all_0s = {
775 .fp_addr.ip4.as_u32 = 0x0,
776 .fp_proto = FIB_PROTOCOL_IP4,
779 p = hash_get (dcm->client_by_sw_if_index, a->sw_if_index);
781 if ((p && a->is_add) || (!p && a->is_add == 0))
782 return VNET_API_ERROR_INVALID_VALUE;
786 pool_get (dcm->clients, c);
787 memset (c, 0, sizeof (*c));
788 c->state = DHCP_DISCOVER;
789 c->sw_if_index = a->sw_if_index;
790 c->client_index = a->client_index;
792 c->event_callback = a->event_callback;
793 c->option_55_data = a->option_55_data;
794 c->hostname = a->hostname;
795 c->client_identifier = a->client_identifier;
796 c->set_broadcast_flag = a->set_broadcast_flag;
799 c->transaction_id = random_u32 (&dcm->seed);
801 while (c->transaction_id == 0);
802 set_l2_rewrite (dcm, c);
803 hash_set (dcm->client_by_sw_if_index, a->sw_if_index, c - dcm->clients);
806 * In order to accept any OFFER, whether broadcasted or unicasted, we
807 * need to configure the dhcp-client-detect feature as an input feature
808 * so the DHCP OFFER is sent to the ip4-local node. Without this a
809 * broadcasted OFFER hits the 255.255.255.255/32 address and a unicast
810 * hits 0.0.0.0/0 both of which default to drop and the latter may forward
811 * of box - not what we want. Nor to we want to change these route for
812 * all interfaces in this table
814 vnet_feature_enable_disable ("ip4-unicast",
815 "ip4-dhcp-client-detect",
816 c->sw_if_index, 1, 0, 0);
818 vlib_process_signal_event (vm, dhcp_client_process_node.index,
819 EVENT_DHCP_CLIENT_WAKEUP, c - dcm->clients);
823 c = pool_elt_at_index (dcm->clients, p[0]);
825 if (c->router_address.as_u32)
827 ip46_address_t nh = {
828 .ip4 = c->router_address,
831 fib_table_entry_path_remove (fib_table_get_index_for_sw_if_index
832 (FIB_PROTOCOL_IP4, c->sw_if_index),
833 &all_0s, FIB_SOURCE_DHCP,
834 DPO_PROTO_IP4, &nh, c->sw_if_index, ~0,
835 1, FIB_ROUTE_PATH_FLAG_NONE);
837 dhcp_client_release_address (dcm, c);
839 vec_free (c->option_55_data);
840 vec_free (c->hostname);
841 vec_free (c->client_identifier);
842 vec_free (c->l2_rewrite);
843 hash_unset (dcm->client_by_sw_if_index, c->sw_if_index);
844 pool_put (dcm->clients, c);
850 dhcp_client_config (vlib_main_t * vm,
856 void *event_callback, u8 set_broadcast_flag, u32 pid)
858 dhcp_client_add_del_args_t _a, *a = &_a;
861 memset (a, 0, sizeof (*a));
863 a->sw_if_index = sw_if_index;
864 a->client_index = client_index;
866 a->event_callback = event_callback;
867 a->set_broadcast_flag = set_broadcast_flag;
868 vec_validate (a->hostname, strlen ((char *) hostname) - 1);
869 strncpy ((char *) a->hostname, (char *) hostname, vec_len (a->hostname));
870 vec_validate (a->client_identifier, strlen ((char *) client_id) - 1);
871 strncpy ((char *) a->client_identifier, (char *) client_id,
872 vec_len (a->client_identifier));
875 * Option 55 request list. These data precisely match
876 * the Ubuntu dhcp client. YMMV.
880 vec_add1 (a->option_55_data, 1);
881 /* Broadcast address */
882 vec_add1 (a->option_55_data, 28);
884 vec_add1 (a->option_55_data, 2);
886 vec_add1 (a->option_55_data, 3);
888 vec_add1 (a->option_55_data, 15);
890 vec_add1 (a->option_55_data, 6);
892 vec_add1 (a->option_55_data, 119);
894 vec_add1 (a->option_55_data, 12);
895 /* NetBIOS name server */
896 vec_add1 (a->option_55_data, 44);
898 vec_add1 (a->option_55_data, 47);
900 vec_add1 (a->option_55_data, 26);
901 /* Classless static route */
902 vec_add1 (a->option_55_data, 121);
904 vec_add1 (a->option_55_data, 42);
906 rv = dhcp_client_add_del (a);
913 case VNET_API_ERROR_INVALID_VALUE:
915 vec_free (a->hostname);
916 vec_free (a->client_identifier);
917 vec_free (a->option_55_data);
920 clib_warning ("dhcp client already enabled on intf_idx %d",
923 clib_warning ("dhcp client not enabled on on intf_idx %d",
928 clib_warning ("dhcp_client_add_del returned %d", rv);
934 static clib_error_t *
935 dhcp_client_set_command_fn (vlib_main_t * vm,
936 unformat_input_t * input,
937 vlib_cli_command_t * cmd)
940 dhcp_client_main_t *dcm = &dhcp_client_main;
943 u8 sw_if_index_set = 0;
944 u8 set_broadcast_flag = 1;
946 dhcp_client_add_del_args_t _a, *a = &_a;
949 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
951 if (unformat (input, "intfc %U",
952 unformat_vnet_sw_interface, dcm->vnet_main, &sw_if_index))
954 else if (unformat (input, "hostname %v", &hostname))
956 else if (unformat (input, "del"))
958 else if (unformat (input, "broadcast", &set_broadcast_flag))
964 if (sw_if_index_set == 0)
965 return clib_error_return (0, "interface not specified");
967 memset (a, 0, sizeof (*a));
969 a->sw_if_index = sw_if_index;
970 a->hostname = hostname;
971 a->client_identifier = format (0, "vpe 1.0%c", 0);
972 a->set_broadcast_flag = set_broadcast_flag;
975 * Option 55 request list. These data precisely match
976 * the Ubuntu dhcp client. YMMV.
980 vec_add1 (a->option_55_data, 1);
981 /* Broadcast address */
982 vec_add1 (a->option_55_data, 28);
984 vec_add1 (a->option_55_data, 2);
986 vec_add1 (a->option_55_data, 3);
988 vec_add1 (a->option_55_data, 15);
990 vec_add1 (a->option_55_data, 6);
992 vec_add1 (a->option_55_data, 119);
994 vec_add1 (a->option_55_data, 12);
995 /* NetBIOS name server */
996 vec_add1 (a->option_55_data, 44);
998 vec_add1 (a->option_55_data, 47);
1000 vec_add1 (a->option_55_data, 26);
1001 /* Classless static route */
1002 vec_add1 (a->option_55_data, 121);
1004 vec_add1 (a->option_55_data, 42);
1006 rv = dhcp_client_add_del (a);
1013 case VNET_API_ERROR_INVALID_VALUE:
1015 vec_free (a->hostname);
1016 vec_free (a->client_identifier);
1017 vec_free (a->option_55_data);
1019 return clib_error_return (0, "dhcp client already enabled on %U",
1020 format_vnet_sw_if_index_name,
1021 dcm->vnet_main, sw_if_index);
1023 return clib_error_return (0, "dhcp client not enabled on %U",
1024 format_vnet_sw_if_index_name,
1025 dcm->vnet_main, sw_if_index);
1029 vlib_cli_output (vm, "dhcp_client_add_del returned %d", rv);
1036 VLIB_CLI_COMMAND (dhcp_client_set_command, static) = {
1037 .path = "set dhcp client",
1038 .short_help = "set dhcp client [del] intfc <interface> [hostname <name>]",
1039 .function = dhcp_client_set_command_fn,
1043 static clib_error_t *
1044 dhcp_client_init (vlib_main_t * vm)
1046 dhcp_client_main_t *dcm = &dhcp_client_main;
1048 dcm->vlib_main = vm;
1049 dcm->vnet_main = vnet_get_main ();
1050 dcm->seed = 0xdeaddabe;
1054 VLIB_INIT_FUNCTION (dhcp_client_init);
1057 * fd.io coding-style-patch-verification: ON
1060 * eval: (c-set-style "gnu")