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_add_rx_address (dhcp_client_main_t * dcm, dhcp_client_t * c)
27 /* Install a local entry for the offered address */
31 .fp_addr.ip4 = c->leased_address,
32 .fp_proto = FIB_PROTOCOL_IP4,
35 fib_table_entry_special_add(fib_table_get_index_for_sw_if_index(
40 (FIB_ENTRY_FLAG_LOCAL));
42 /* And add the server's address as uRPF exempt so we can accept
43 * local packets from it */
47 .fp_addr.ip4 = c->dhcp_server,
48 .fp_proto = FIB_PROTOCOL_IP4,
51 fib_table_entry_special_add(fib_table_get_index_for_sw_if_index(
55 FIB_SOURCE_URPF_EXEMPT,
56 (FIB_ENTRY_FLAG_DROP));
60 dhcp_client_remove_rx_address (dhcp_client_main_t * dcm, dhcp_client_t * c)
65 .fp_addr.ip4 = c->leased_address,
66 .fp_proto = FIB_PROTOCOL_IP4,
69 fib_table_entry_special_remove(fib_table_get_index_for_sw_if_index(
77 .fp_addr.ip4 = c->dhcp_server,
78 .fp_proto = FIB_PROTOCOL_IP4,
81 fib_table_entry_special_remove(fib_table_get_index_for_sw_if_index(
85 FIB_SOURCE_URPF_EXEMPT);
89 dhcp_client_acquire_address (dhcp_client_main_t * dcm, dhcp_client_t * c)
92 * Install any/all info gleaned from dhcp, right here
94 ip4_add_del_interface_address (dcm->vlib_main, c->sw_if_index,
95 (void *) &c->leased_address,
96 c->subnet_mask_width, 0 /*is_del*/);
100 dhcp_client_release_address (dhcp_client_main_t * dcm, dhcp_client_t * c)
103 * Remove any/all info gleaned from dhcp, right here. Caller(s)
104 * have not wiped out the info yet.
107 ip4_add_del_interface_address (dcm->vlib_main, c->sw_if_index,
108 (void *) &c->leased_address,
109 c->subnet_mask_width, 1 /*is_del*/);
113 set_l2_rewrite (dhcp_client_main_t * dcm, dhcp_client_t * c)
115 /* Acquire the L2 rewrite string for the indicated sw_if_index */
116 c->l2_rewrite = vnet_build_rewrite_for_sw_interface(
123 void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
126 dhcp_client_proc_callback (uword * client_index)
128 vlib_main_t *vm = vlib_get_main ();
129 ASSERT (vlib_get_thread_index () == 0);
130 vlib_process_signal_event (vm, dhcp_client_process_node.index,
131 EVENT_DHCP_CLIENT_WAKEUP, *client_index);
135 * dhcp_client_for_us - server-to-client callback.
136 * Called from proxy_node.c:dhcp_proxy_to_client_input().
137 * This function first decides that the packet in question is
138 * actually for the dhcp client code in case we're also acting as
139 * a dhcp proxy. Ay caramba, what a folly!
141 int dhcp_client_for_us (u32 bi, vlib_buffer_t * b,
144 dhcp_header_t * dhcp)
146 dhcp_client_main_t * dcm = &dhcp_client_main;
147 vlib_main_t * vm = dcm->vlib_main;
150 f64 now = vlib_time_now (dcm->vlib_main);
151 u8 dhcp_message_type = 0;
155 * Doing dhcp client on this interface?
156 * Presumably we will always receive dhcp clnt for-us pkts on
157 * the interface that's asking for an address.
159 p = hash_get (dcm->client_by_sw_if_index,
160 vnet_buffer(b)->sw_if_index [VLIB_RX]);
164 c = pool_elt_at_index (dcm->clients, p[0]);
166 /* Mixing dhcp relay and dhcp proxy? DGMS... */
167 if (c->state == DHCP_BOUND && c->retry_count == 0)
170 /* parse through the packet, learn what we can */
171 if (dhcp->your_ip_address.as_u32)
172 c->leased_address.as_u32 = dhcp->your_ip_address.as_u32;
174 c->dhcp_server.as_u32 = dhcp->server_ip_address.as_u32;
176 o = (dhcp_option_t *) dhcp->options;
178 while (o->option != 0xFF /* end of options */ &&
179 (u8 *) o < (b->data + b->current_data + b->current_length))
183 case 53: /* dhcp message type */
184 dhcp_message_type = o->data[0];
187 case 51: /* lease time */
189 u32 lease_time_in_seconds =
190 clib_host_to_net_u32 (o->data_as_u32[0]);
191 c->lease_expires = now + (f64) lease_time_in_seconds;
192 c->lease_lifetime = lease_time_in_seconds;
193 /* Set a sensible default, in case we don't get opt 58 */
194 c->lease_renewal_interval = lease_time_in_seconds / 2;
198 case 58: /* lease renew time in seconds */
200 u32 lease_renew_time_in_seconds =
201 clib_host_to_net_u32 (o->data_as_u32[0]);
202 c->lease_renewal_interval = lease_renew_time_in_seconds;
206 case 54: /* dhcp server address */
207 c->dhcp_server.as_u32 = o->data_as_u32[0];
210 case 1: /* subnet mask */
213 clib_host_to_net_u32 (o->data_as_u32[0]);
214 c->subnet_mask_width = count_set_bits (subnet_mask);
217 case 3: /* router address */
219 u32 router_address = o->data_as_u32[0];
220 c->router_address.as_u32 = router_address;
224 case 12: /* hostname */
226 /* Replace the existing hostname if necessary */
227 vec_free (c->hostname);
228 vec_validate (c->hostname, o->length - 1);
229 clib_memcpy (c->hostname, o->data, o->length);
233 /* $$$$ Your message in this space, parse more options */
238 o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
244 if (dhcp_message_type != DHCP_PACKET_OFFER)
246 clib_warning ("sw_if_index %d state %U message type %d",
247 c->sw_if_index, format_dhcp_client_state,
248 c->state, dhcp_message_type);
249 c->next_transmit = now + 5.0;
253 * in order to accept unicasted ACKs we need to configure the offered
254 * address on the interface. However, at this point we may not know the
255 * subnet-mask (an OFFER may not contain it). So add a temporary receice
256 * and uRPF excempt entry
258 dhcp_client_add_rx_address (dcm, c);
260 /* Received an offer, go send a request */
261 c->state = DHCP_REQUEST;
263 c->next_transmit = 0; /* send right now... */
264 /* Poke the client process, which will send the request */
265 uword client_id = c - dcm->clients;
266 vl_api_rpc_call_main_thread (dhcp_client_proc_callback,
267 (u8 *) &client_id, sizeof (uword));
272 if (dhcp_message_type != DHCP_PACKET_ACK)
274 clib_warning ("sw_if_index %d state %U message type %d",
275 c->sw_if_index, format_dhcp_client_state,
276 c->state, dhcp_message_type);
277 c->next_transmit = now + 5.0;
280 /* OK, we own the address (etc), add to the routing table(s) */
281 if (c->state == DHCP_REQUEST)
283 void (*fp)(u32, u32, u8 *, u8, u8, u8 *, u8 *, u8 *) = c->event_callback;
285 /* replace the temporary RX address with the correct subnet */
286 dhcp_client_remove_rx_address (dcm, c);
287 dhcp_client_acquire_address (dcm, c);
290 * Configure default IP route:
292 if (c->router_address.as_u32)
294 fib_prefix_t all_0s =
297 .fp_addr.ip4.as_u32 = 0x0,
298 .fp_proto = FIB_PROTOCOL_IP4,
302 .ip4 = c->router_address,
305 fib_table_entry_path_add (fib_table_get_index_for_sw_if_index(
316 NULL, // no label stack
317 FIB_ROUTE_PATH_FLAG_NONE);
321 * Call the user's event callback to report DHCP information
324 (*fp) (c->client_index, /* clinet index */
327 c->subnet_mask_width,
329 (u8 *)&c->leased_address, /* host IP address */
330 (u8 *)&c->router_address, /* router IP address */
331 (u8 *)(c->l2_rewrite + 6));/* host MAC address */
334 c->state = DHCP_BOUND;
336 c->next_transmit = now + (f64) c->lease_renewal_interval;
337 c->lease_expires = now + (f64) c->lease_lifetime;
341 clib_warning ("client %d bogus state %d",
342 c - dcm->clients, c->state);
346 /* drop the pkt, return 1 */
347 vlib_buffer_free (vm, &bi, 1);
352 send_dhcp_pkt (dhcp_client_main_t * dcm, dhcp_client_t * c,
353 dhcp_packet_type_t type, int is_broadcast)
355 vlib_main_t * vm = dcm->vlib_main;
356 vnet_main_t * vnm = dcm->vnet_main;
357 vnet_hw_interface_t * hw = vnet_get_sup_hw_interface (vnm, c->sw_if_index);
358 vnet_sw_interface_t * sup_sw
359 = vnet_get_sup_sw_interface (vnm, c->sw_if_index);
360 vnet_sw_interface_t * sw = vnet_get_sw_interface (vnm, c->sw_if_index);
365 dhcp_header_t * dhcp;
369 u16 udp_length, ip_length;
371 /* Interface(s) down? */
372 if ((hw->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) == 0)
374 if ((sup_sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
376 if ((sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
379 if (vlib_buffer_alloc (vm, &bi, 1) != 1) {
380 clib_warning ("buffer allocation failure");
381 c->next_transmit = 0;
385 /* Build a dhcpv4 pkt from whole cloth */
386 b = vlib_get_buffer (vm, bi);
388 ASSERT (b->current_data == 0);
390 vnet_buffer(b)->sw_if_index[VLIB_RX] = c->sw_if_index;
393 f = vlib_get_frame_to_node (vm, hw->output_node_index);
394 vnet_buffer(b)->sw_if_index[VLIB_TX] = c->sw_if_index;
395 clib_memcpy (b->data, c->l2_rewrite, vec_len(c->l2_rewrite));
397 (((u8 *)vlib_buffer_get_current (b)) + vec_len (c->l2_rewrite));
401 f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
402 vnet_buffer(b)->sw_if_index[VLIB_TX] = ~0; /* use interface VRF */
403 ip = vlib_buffer_get_current (b);
406 /* Enqueue the packet right now */
407 to_next = vlib_frame_vector_args (f);
412 vlib_put_frame_to_node (vm, hw->output_node_index, f);
414 vlib_put_frame_to_node (vm, ip4_lookup_node.index, f);
416 udp = (udp_header_t *)(ip+1);
417 dhcp = (dhcp_header_t *)(udp+1);
419 /* $$$ optimize, maybe */
420 memset (ip, 0, sizeof (*ip) + sizeof (*udp) + sizeof (*dhcp));
422 ip->ip_version_and_header_length = 0x45;
424 ip->protocol = IP_PROTOCOL_UDP;
428 /* src = 0.0.0.0, dst = 255.255.255.255 */
429 ip->dst_address.as_u32 = ~0;
433 /* Renewing an active lease, plain old ip4 src/dst */
434 ip->src_address.as_u32 = c->leased_address.as_u32;
435 ip->dst_address.as_u32 = c->dhcp_server.as_u32;
438 udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client);
439 udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_server);
441 /* Send the interface MAC address */
442 clib_memcpy (dhcp->client_hardware_address, c->l2_rewrite + 6, 6);
444 /* Lease renewal, set up client_ip_address */
445 if (is_broadcast == 0)
446 dhcp->client_ip_address.as_u32 = c->leased_address.as_u32;
448 dhcp->opcode = 1; /* request, all we send */
449 dhcp->hardware_type = 1; /* ethernet */
450 dhcp->hardware_address_length = 6;
451 dhcp->transaction_identifier = c->transaction_id;
452 dhcp->flags = clib_host_to_net_u16(is_broadcast ? DHCP_FLAG_BROADCAST : 0);
453 dhcp->magic_cookie.as_u32 = DHCP_MAGIC;
455 o = (dhcp_option_t * )dhcp->options;
457 /* Send option 53, the DHCP message type */
458 o->option = DHCP_PACKET_OPTION_MSG_TYPE;
461 o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
463 /* Send option 57, max msg length */
464 if (0 /* not needed, apparently */)
469 u16 *o2 = (u16 *) o->data;
470 *o2 = clib_host_to_net_u16 (1152);
471 o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
476 * If server ip address is available with non-zero value,
477 * option 54 (DHCP Server Identifier) is sent.
479 if (c->dhcp_server.as_u32)
483 clib_memcpy (o->data, &c->dhcp_server.as_u32, 4);
484 o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
487 /* send option 50, requested IP address */
488 if (c->leased_address.as_u32)
492 clib_memcpy (o->data, &c->leased_address.as_u32, 4);
493 o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
496 /* send option 12, host name */
497 if (vec_len (c->hostname))
500 o->length = vec_len (c->hostname);
501 clib_memcpy (o->data, c->hostname, vec_len (c->hostname));
502 o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
505 /* send option 61, client_id */
506 if (vec_len (c->client_identifier))
509 o->length = vec_len (c->client_identifier);
510 clib_memcpy (o->data, c->client_identifier,
511 vec_len (c->client_identifier));
512 o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
515 /* $$ maybe send the client s/w version if anyone cares */
518 * send option 55, parameter request list
519 * The current list - see below, matches the Linux dhcp client's list
520 * Any specific dhcp server config and/or dhcp server may or may
521 * not yield specific options.
524 o->length = vec_len (c->option_55_data);
525 clib_memcpy (o->data, c->option_55_data, vec_len(c->option_55_data));
526 o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
533 b->current_length = ((u8 *)o) - b->data;
535 /* fix ip length, checksum and udp length */
536 ip_length = vlib_buffer_length_in_chain (vm, b);
538 ip_length -= vec_len (c->l2_rewrite);
540 ip->length = clib_host_to_net_u16(ip_length);
541 ip->checksum = ip4_header_checksum(ip);
543 udp_length = ip_length - (sizeof (*ip));
544 udp->length = clib_host_to_net_u16 (udp_length);
548 dhcp_discover_state (dhcp_client_main_t * dcm, dhcp_client_t * c, f64 now)
551 * State machine "DISCOVER" state. Send a dhcp discover packet,
552 * eventually back off the retry rate.
554 send_dhcp_pkt (dcm, c, DHCP_PACKET_DISCOVER, 1 /* is_broadcast */);
557 if (c->retry_count > 10)
558 c->next_transmit = now + 5.0;
560 c->next_transmit = now + 1.0;
565 dhcp_request_state (dhcp_client_main_t * dcm, dhcp_client_t * c, f64 now)
568 * State machine "REQUEST" state. Send a dhcp request packet,
569 * eventually drop back to the discover state.
571 send_dhcp_pkt (dcm, c, DHCP_PACKET_REQUEST, 1 /* is_broadcast */);
574 if (c->retry_count > 7 /* lucky you */)
576 c->state = DHCP_DISCOVER;
577 c->next_transmit = now;
581 c->next_transmit = now + 1.0;
586 dhcp_bound_state (dhcp_client_main_t * dcm, dhcp_client_t * c, f64 now)
589 * State machine "BOUND" state. Send a dhcp request packet,
590 * eventually, when the lease expires, forget the dhcp data
591 * and go back to the stone age.
593 send_dhcp_pkt (dcm, c, DHCP_PACKET_REQUEST, 0 /* is_broadcast */);
596 if (c->retry_count > 10)
597 c->next_transmit = now + 5.0;
599 c->next_transmit = now + 1.0;
601 if (now > c->lease_expires)
603 if (c->router_address.as_u32)
605 fib_prefix_t all_0s =
608 .fp_addr.ip4.as_u32 = 0x0,
609 .fp_proto = FIB_PROTOCOL_IP4,
611 ip46_address_t nh = {
612 .ip4 = c->router_address,
615 fib_table_entry_path_remove(fib_table_get_index_for_sw_if_index(
625 FIB_ROUTE_PATH_FLAG_NONE);
628 dhcp_client_release_address (dcm, c);
629 c->state = DHCP_DISCOVER;
630 c->next_transmit = now;
632 /* Wipe out any memory of the address we had... */
633 c->leased_address.as_u32 = 0;
634 c->subnet_mask_width = 0;
635 c->router_address.as_u32 = 0;
636 c->lease_renewal_interval = 0;
637 c->dhcp_server.as_u32 = 0;
643 static f64 dhcp_client_sm (f64 now, f64 timeout, uword pool_index)
645 dhcp_client_main_t * dcm = &dhcp_client_main;
648 /* deleted, pooched, yadda yadda yadda */
649 if (pool_is_free_index (dcm->clients, pool_index))
652 c = pool_elt_at_index (dcm->clients, pool_index);
654 /* Time for us to do something with this client? */
655 if (now < c->next_transmit)
661 case DHCP_DISCOVER: /* send a discover */
662 if (dhcp_discover_state (dcm, c, now))
666 case DHCP_REQUEST: /* send a request */
667 if (dhcp_request_state (dcm, c, now))
671 case DHCP_BOUND: /* bound, renew needed? */
672 if (dhcp_bound_state (dcm, c, now))
677 clib_warning ("dhcp client %d bogus state %d",
678 c - dcm->clients, c->state);
682 if (c->next_transmit < now + timeout)
683 return c->next_transmit - now;
689 dhcp_client_process (vlib_main_t * vm,
690 vlib_node_runtime_t * rt,
696 uword * event_data = 0;
697 dhcp_client_main_t * dcm = &dhcp_client_main;
703 vlib_process_wait_for_event_or_clock (vm, timeout);
705 event_type = vlib_process_get_events (vm, &event_data);
707 now = vlib_time_now (vm);
711 case EVENT_DHCP_CLIENT_WAKEUP:
712 for (i = 0; i < vec_len (event_data); i++)
713 timeout = dhcp_client_sm (now, timeout, event_data[i]);
717 pool_foreach (c, dcm->clients,
719 timeout = dhcp_client_sm (now, timeout,
720 (uword)(c - dcm->clients));
722 if (pool_elts (dcm->clients) == 0)
727 vec_reset_length (event_data);
734 VLIB_REGISTER_NODE (dhcp_client_process_node,static) = {
735 .function = dhcp_client_process,
736 .type = VLIB_NODE_TYPE_PROCESS,
737 .name = "dhcp-client-process",
738 .process_log2_n_stack_bytes = 16,
741 static u8 * format_dhcp_client_state (u8 * s, va_list * va)
743 dhcp_client_state_t state = va_arg (*va, dhcp_client_state_t);
744 char * str = "BOGUS!";
752 foreach_dhcp_client_state;
758 s = format (s, "%s", str);
762 static u8 * format_dhcp_client (u8 * s, va_list * va)
764 dhcp_client_main_t * dcm = va_arg (*va, dhcp_client_main_t *);
765 dhcp_client_t * c = va_arg (*va, dhcp_client_t *);
766 int verbose = va_arg (*va, int);
768 s = format (s, "[%d] %U state %U ", c - dcm->clients,
769 format_vnet_sw_if_index_name, dcm->vnet_main, c->sw_if_index,
770 format_dhcp_client_state, c->state);
772 if (c->leased_address.as_u32)
773 s = format (s, "addr %U/%d gw %U\n",
774 format_ip4_address, &c->leased_address,
775 c->subnet_mask_width, format_ip4_address, &c->router_address);
777 s = format (s, "no address\n");
781 s = format (s, "retry count %d, next xmt %.2f",
782 c->retry_count, c->next_transmit);
787 static clib_error_t *
788 show_dhcp_client_command_fn (vlib_main_t * vm,
789 unformat_input_t * input,
790 vlib_cli_command_t * cmd)
792 dhcp_client_main_t * dcm = &dhcp_client_main;
795 u32 sw_if_index = ~0;
798 while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT)
800 if (unformat (input, "intfc %U",
801 unformat_vnet_sw_interface, dcm->vnet_main,
804 else if (unformat (input, "verbose"))
810 if (sw_if_index != ~0)
812 p = hash_get (dcm->client_by_sw_if_index, sw_if_index);
814 return clib_error_return (0, "dhcp client not configured");
815 c = pool_elt_at_index (dcm->clients, p[0]);
816 vlib_cli_output (vm, "%U", format_dhcp_client, dcm, c, verbose);
820 pool_foreach (c, dcm->clients,
822 vlib_cli_output (vm, "%U", format_dhcp_client, dcm, c, verbose);
828 VLIB_CLI_COMMAND (show_dhcp_client_command, static) = {
829 .path = "show dhcp client",
830 .short_help = "show dhcp client [intfc <intfc>][verbose]",
831 .function = show_dhcp_client_command_fn,
835 int dhcp_client_add_del (dhcp_client_add_del_args_t * a)
837 dhcp_client_main_t * dcm = &dhcp_client_main;
838 vlib_main_t * vm = dcm->vlib_main;
841 fib_prefix_t all_1s =
844 .fp_addr.ip4.as_u32 = 0xffffffff,
845 .fp_proto = FIB_PROTOCOL_IP4,
847 fib_prefix_t all_0s =
850 .fp_addr.ip4.as_u32 = 0x0,
851 .fp_proto = FIB_PROTOCOL_IP4,
854 p = hash_get (dcm->client_by_sw_if_index, a->sw_if_index);
856 if ((p && a->is_add) || (!p && a->is_add == 0))
857 return VNET_API_ERROR_INVALID_VALUE;
861 pool_get (dcm->clients, c);
862 memset (c, 0, sizeof (*c));
863 c->state = DHCP_DISCOVER;
864 c->sw_if_index = a->sw_if_index;
865 c->client_index = a->client_index;
867 c->event_callback = a->event_callback;
868 c->option_55_data = a->option_55_data;
869 c->hostname = a->hostname;
870 c->client_identifier = a->client_identifier;
872 c->transaction_id = random_u32 (&dcm->seed);
873 } while (c->transaction_id == 0);
874 set_l2_rewrite (dcm, c);
875 hash_set (dcm->client_by_sw_if_index, a->sw_if_index, c - dcm->clients);
877 /* this add is ref counted by FIB so we can add for each itf */
878 fib_table_entry_special_add(fib_table_get_index_for_sw_if_index(
883 FIB_ENTRY_FLAG_LOCAL);
886 * enable the interface to RX IPv4 packets
887 * this is also ref counted
889 ip4_sw_interface_enable_disable (c->sw_if_index, 1);
891 vlib_process_signal_event (vm, dhcp_client_process_node.index,
892 EVENT_DHCP_CLIENT_WAKEUP, c - dcm->clients);
896 c = pool_elt_at_index (dcm->clients, p[0]);
898 fib_table_entry_special_remove(fib_table_get_index_for_sw_if_index(
904 if (c->router_address.as_u32)
906 ip46_address_t nh = {
907 .ip4 = c->router_address,
910 fib_table_entry_path_remove(fib_table_get_index_for_sw_if_index(
920 FIB_ROUTE_PATH_FLAG_NONE);
922 dhcp_client_remove_rx_address (dcm, c);
923 dhcp_client_release_address (dcm, c);
924 ip4_sw_interface_enable_disable (c->sw_if_index, 0);
926 vec_free (c->option_55_data);
927 vec_free (c->hostname);
928 vec_free (c->client_identifier);
929 vec_free (c->l2_rewrite);
930 hash_unset (dcm->client_by_sw_if_index, c->sw_if_index);
931 pool_put (dcm->clients, c);
937 dhcp_client_config (vlib_main_t * vm,
943 void * event_callback,
946 dhcp_client_add_del_args_t _a, *a = &_a;
949 memset (a, 0, sizeof (*a));
951 a->sw_if_index = sw_if_index;
952 a->client_index = client_index;
954 a->event_callback = event_callback;
955 vec_validate(a->hostname, strlen((char *)hostname) - 1);
956 strncpy((char *)a->hostname, (char *)hostname, vec_len(a->hostname));
957 vec_validate(a->client_identifier, strlen((char *)client_id) - 1);
958 strncpy((char *)a->client_identifier, (char *)client_id, vec_len(a->client_identifier));
961 * Option 55 request list. These data precisely match
962 * the Ubuntu dhcp client. YMMV.
966 vec_add1 (a->option_55_data, 1);
967 /* Broadcast address */
968 vec_add1 (a->option_55_data, 28);
970 vec_add1 (a->option_55_data, 2);
972 vec_add1 (a->option_55_data, 3);
974 vec_add1 (a->option_55_data, 15);
976 vec_add1 (a->option_55_data, 6);
978 vec_add1 (a->option_55_data, 119);
980 vec_add1 (a->option_55_data, 12);
981 /* NetBIOS name server */
982 vec_add1 (a->option_55_data, 44);
984 vec_add1 (a->option_55_data, 47);
986 vec_add1 (a->option_55_data, 26);
987 /* Classless static route */
988 vec_add1 (a->option_55_data, 121);
990 vec_add1 (a->option_55_data, 42);
992 rv = dhcp_client_add_del (a);
999 case VNET_API_ERROR_INVALID_VALUE:
1001 vec_free (a->hostname);
1002 vec_free (a->client_identifier);
1003 vec_free (a->option_55_data);
1006 clib_warning ("dhcp client already enabled on intf_idx %d",
1009 clib_warning ("dhcp client not enabled on on intf_idx %d",
1014 clib_warning ("dhcp_client_add_del returned %d", rv);
1020 static clib_error_t *
1021 dhcp_client_set_command_fn (vlib_main_t * vm,
1022 unformat_input_t * input,
1023 vlib_cli_command_t * cmd)
1026 dhcp_client_main_t * dcm = &dhcp_client_main;
1029 u8 sw_if_index_set = 0;
1031 dhcp_client_add_del_args_t _a, *a = &_a;
1034 while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT)
1036 if (unformat (input, "intfc %U",
1037 unformat_vnet_sw_interface, dcm->vnet_main,
1039 sw_if_index_set = 1;
1040 else if (unformat (input, "hostname %v", &hostname))
1042 else if (unformat (input, "del"))
1048 if (sw_if_index_set == 0)
1049 return clib_error_return (0, "interface not specified");
1051 memset (a, 0, sizeof (*a));
1053 a->sw_if_index = sw_if_index;
1054 a->hostname = hostname;
1055 a->client_identifier = format (0, "vpe 1.0%c", 0);
1058 * Option 55 request list. These data precisely match
1059 * the Ubuntu dhcp client. YMMV.
1063 vec_add1 (a->option_55_data, 1);
1064 /* Broadcast address */
1065 vec_add1 (a->option_55_data, 28);
1067 vec_add1 (a->option_55_data, 2);
1069 vec_add1 (a->option_55_data, 3);
1071 vec_add1 (a->option_55_data, 15);
1073 vec_add1 (a->option_55_data, 6);
1075 vec_add1 (a->option_55_data, 119);
1077 vec_add1 (a->option_55_data, 12);
1078 /* NetBIOS name server */
1079 vec_add1 (a->option_55_data, 44);
1081 vec_add1 (a->option_55_data, 47);
1083 vec_add1 (a->option_55_data, 26);
1084 /* Classless static route */
1085 vec_add1 (a->option_55_data, 121);
1087 vec_add1 (a->option_55_data, 42);
1089 rv = dhcp_client_add_del (a);
1096 case VNET_API_ERROR_INVALID_VALUE:
1098 vec_free (a->hostname);
1099 vec_free (a->client_identifier);
1100 vec_free (a->option_55_data);
1102 return clib_error_return (0, "dhcp client already enabled on %U",
1103 format_vnet_sw_if_index_name,
1104 dcm->vnet_main, sw_if_index);
1106 return clib_error_return (0, "dhcp client not enabled on %U",
1107 format_vnet_sw_if_index_name,
1108 dcm->vnet_main, sw_if_index);
1112 vlib_cli_output (vm, "dhcp_client_add_del returned %d", rv);
1118 VLIB_CLI_COMMAND (dhcp_client_set_command, static) = {
1119 .path = "set dhcp client",
1120 .short_help = "set dhcp client [del] intfc <interface> [hostname <name>]",
1121 .function = dhcp_client_set_command_fn,
1124 static clib_error_t *
1125 dhcp_client_init (vlib_main_t * vm)
1127 dhcp_client_main_t * dcm = &dhcp_client_main;
1129 dcm->vlib_main = vm;
1130 dcm->vnet_main = vnet_get_main();
1131 dcm->seed = 0xdeaddabe;
1135 VLIB_INIT_FUNCTION (dhcp_client_init);