FD.io VPP  v16.09
Vector Packet Processing
client.c
Go to the documentation of this file.
1 /*
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:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15 #include <vlib/vlib.h>
16 #include <vnet/dhcp/proxy.h>
17 
19 static u8 * format_dhcp_client_state (u8 * s, va_list * va);
21 
22 void __attribute__((weak))
23 api_config_default_ip_route (u8 is_ipv6, u8 is_add, u32 vrf_id,
24  u32 sw_if_index, u8 *next_hop_addr)
25 {
26  /* dummy function */
27  return;
28 }
29 
30 static void
32 {
33  /*
34  * Install any/all info gleaned from dhcp, right here
35  */
37  (void *) &c->leased_address,
38  c->subnet_mask_width, 0 /*is_del*/);
39 }
40 
41 static void
43 {
44  /*
45  * Remove any/all info gleaned from dhcp, right here. Caller(s)
46  * have not wiped out the info yet.
47  */
48 
50  (void *) &c->leased_address,
51  c->subnet_mask_width, 1 /*is_del*/);
52 }
53 
55 {
56  vnet_main_t * vnm = dcm->vnet_main;
60  u32 n_rw;
61 
62  /* Acquire the L2 rewrite string for the indicated sw_if_index */
63  vec_validate (c->l2_rewrite, 32);
64  ASSERT (hc->set_rewrite);
65  n_rw = hc->set_rewrite (dcm->vnet_main, c->sw_if_index,
66  VNET_L3_PACKET_TYPE_IP4,
67  0 /* broadcast */, c->l2_rewrite,
68  vec_len(c->l2_rewrite));
69 
70  _vec_len (c->l2_rewrite) = n_rw;
71 }
72 
73 /*
74  * dhcp_client_for_us - server-to-client callback.
75  * Called from proxy_node.c:dhcp_proxy_to_client_input().
76  * This function first decides that the packet in question is
77  * actually for the dhcp client code in case we're also acting as
78  * a dhcp proxy. Ay caramba, what a folly!
79  */
81  ip4_header_t * ip,
82  udp_header_t * udp,
83  dhcp_header_t * dhcp)
84 {
86  vlib_main_t * vm = dcm->vlib_main;
87  dhcp_client_t * c;
88  uword * p;
89  f64 now = vlib_time_now (dcm->vlib_main);
90  u8 dhcp_message_type = 0;
91  dhcp_option_t * o;
92 
93  /*
94  * Doing dhcp client on this interface?
95  * Presumably we will always receive dhcp clnt for-us pkts on
96  * the interface that's asking for an address.
97  */
99  vnet_buffer(b)->sw_if_index [VLIB_RX]);
100  if (p == 0)
101  return 0; /* no */
102 
103  c = pool_elt_at_index (dcm->clients, p[0]);
104 
105  /* Mixing dhcp relay and dhcp proxy? DGMS... */
106  if (c->state == DHCP_BOUND && c->retry_count == 0)
107  return 0;
108 
109  /* parse through the packet, learn what we can */
110  if (dhcp->your_ip_address.as_u32)
112 
113  o = (dhcp_option_t *) dhcp->options;
114 
115  while (o->option != 0xFF /* end of options */ &&
116  (u8 *) o < (b->data + b->current_data + b->current_length))
117  {
118  switch (o->option)
119  {
120  case 53: /* dhcp message type */
121  dhcp_message_type = o->data[0];
122  break;
123 
124  case 51: /* lease time */
125  {
126  u32 lease_time_in_seconds =
127  clib_host_to_net_u32 (o->data_as_u32[0]);
128  c->lease_expires = now + (f64) lease_time_in_seconds;
129  c->lease_lifetime = lease_time_in_seconds;
130  /* Set a sensible default, in case we don't get opt 58 */
131  c->lease_renewal_interval = lease_time_in_seconds / 2;
132  }
133  break;
134 
135  case 58: /* lease renew time in seconds */
136  {
137  u32 lease_renew_time_in_seconds =
138  clib_host_to_net_u32 (o->data_as_u32[0]);
139  c->lease_renewal_interval = lease_renew_time_in_seconds;
140  }
141  break;
142 
143  case 54: /* dhcp server address */
144  c->dhcp_server.as_u32 = o->data_as_u32[0];
145  break;
146 
147  case 1: /* subnet mask */
148  {
149  u32 subnet_mask =
150  clib_host_to_net_u32 (o->data_as_u32[0]);
151  c->subnet_mask_width = count_set_bits (subnet_mask);
152  }
153  break;
154  case 3: /* router address */
155  {
156  u32 router_address = o->data_as_u32[0];
157  c->router_address.as_u32 = router_address;
158  }
159  break;
160 
161  case 12: /* hostname */
162  {
163  /* Replace the existing hostname if necessary */
164  vec_free (c->hostname);
165  vec_validate (c->hostname, o->length - 1);
166  clib_memcpy (c->hostname, o->data, o->length);
167  }
168  break;
169 
170  /* $$$$ Your message in this space, parse more options */
171  default:
172  break;
173  }
174 
175  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
176  }
177 
178  switch (c->state)
179  {
180  case DHCP_DISCOVER:
181  if (dhcp_message_type != DHCP_PACKET_OFFER)
182  {
183  clib_warning ("sw_if_index %d state %U message type %d",
185  c->state, dhcp_message_type);
186  c->next_transmit = now + 5.0;
187  break;
188  }
189  /* Received an offer, go send a request */
190  c->state = DHCP_REQUEST;
191  c->retry_count = 0;
192  c->next_transmit = 0; /* send right now... */
193  /* Poke the client process, which will send the request */
194  vlib_process_signal_event (vm, dhcp_client_process_node.index,
196  break;
197 
198  case DHCP_BOUND:
199  case DHCP_REQUEST:
200  if (dhcp_message_type != DHCP_PACKET_ACK)
201  {
202  clib_warning ("sw_if_index %d state %U message type %d",
204  c->state, dhcp_message_type);
205  c->next_transmit = now + 5.0;
206  break;
207  }
208  /* OK, we own the address (etc), add to the routing table(s) */
209  if (c->state == DHCP_REQUEST)
210  {
211  void (*fp)(u32, u32, u8 *, u8, u8 *, u8 *, u8 *) = c->event_callback;
212 
214 
215  /*
216  * Configure default IP route:
217  * - vrf_id is 0 by default.
218  */
219  if (c->router_address.as_u32)
220  api_config_default_ip_route (0 /* is_ipv6 */,
221  1 /* is_add */,
222  0 /* vrf_id */,
223  c->sw_if_index,
224  (u8 *)&c->router_address);
225 
226  /*
227  * Call the user's event callback to report DHCP information
228  */
229  if (fp)
230  (*fp) (c->client_index, /* clinet index */
231  c->pid,
232  c->hostname,
233  0, /* is_ipv6 */
234  (u8 *)&c->leased_address, /* host IP address */
235  (u8 *)&c->router_address, /* router IP address */
236  (u8 *)(c->l2_rewrite + 6));/* host MAC address */
237  }
238 
239  c->state = DHCP_BOUND;
240  c->retry_count = 0;
241  c->next_transmit = now + (f64) c->lease_renewal_interval;
242  c->lease_expires = now + (f64) c->lease_lifetime;
243  break;
244 
245  default:
246  clib_warning ("client %d bogus state %d",
247  c - dcm->clients, c->state);
248  break;
249  }
250 
251  /* drop the pkt, return 1 */
252  vlib_buffer_free (vm, &bi, 1);
253  return 1;
254 }
255 
256 static void
258  dhcp_packet_type_t type, int is_broadcast)
259 {
260  vlib_main_t * vm = dcm->vlib_main;
261  vnet_main_t * vnm = dcm->vnet_main;
263  vnet_sw_interface_t * sup_sw
266  vlib_buffer_t * b;
267  u32 bi;
268  ip4_header_t * ip;
269  udp_header_t * udp;
270  dhcp_header_t * dhcp;
271  u32 * to_next;
272  vlib_frame_t * f;
273  dhcp_option_t * o;
274  u16 udp_length, ip_length;
275 
276  /* Interface(s) down? */
277  if ((hw->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) == 0)
278  return;
279  if ((sup_sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
280  return;
281  if ((sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
282  return;
283 
284  if (vlib_buffer_alloc (vm, &bi, 1) != 1) {
285  clib_warning ("buffer allocation failure");
286  c->next_transmit = 0;
287  return;
288  }
289 
290  /* Build a dhcpv4 pkt from whole cloth */
291  b = vlib_get_buffer (vm, bi);
292 
293  ASSERT (b->current_data == 0);
294 
295  vnet_buffer(b)->sw_if_index[VLIB_RX] = c->sw_if_index;
296  if (is_broadcast)
297  {
299  vnet_buffer(b)->sw_if_index[VLIB_TX] = c->sw_if_index;
301  ip = (void *)
302  (((u8 *)vlib_buffer_get_current (b)) + vec_len (c->l2_rewrite));
303  }
304  else
305  {
306  f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
307  vnet_buffer(b)->sw_if_index[VLIB_TX] = ~0; /* use interface VRF */
308  ip = vlib_buffer_get_current (b);
309  }
310 
311  /* Enqueue the packet right now */
312  to_next = vlib_frame_vector_args (f);
313  to_next[0] = bi;
314  f->n_vectors = 1;
315 
316  if (is_broadcast)
318  else
320 
321  udp = (udp_header_t *)(ip+1);
322  dhcp = (dhcp_header_t *)(udp+1);
323 
324  /* $$$ optimize, maybe */
325  memset (ip, 0, sizeof (*ip) + sizeof (*udp) + sizeof (*dhcp));
326 
327  ip->ip_version_and_header_length = 0x45;
328  ip->ttl = 128;
329  ip->protocol = IP_PROTOCOL_UDP;
330 
331  if (is_broadcast)
332  {
333  /* src = 0.0.0.0, dst = 255.255.255.255 */
334  ip->dst_address.as_u32 = ~0;
335  }
336  else
337  {
338  /* Renewing an active lease, plain old ip4 src/dst */
341  }
342 
343  udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client);
344  udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_server);
345 
346  /* Send the interface MAC address */
348 
349  /* Lease renewal, set up client_ip_address */
350  if (is_broadcast == 0)
352 
353  dhcp->opcode = 1; /* request, all we send */
354  dhcp->hardware_type = 1; /* ethernet */
355  dhcp->hardware_address_length = 6;
357  dhcp->flags = clib_host_to_net_u16(is_broadcast ? DHCP_FLAG_BROADCAST : 0);
359 
360  o = (dhcp_option_t * )dhcp->options;
361 
362  /* Send option 53, the DHCP message type */
363  o->option = 53;
364  o->length = 1;
365  o->data[0] = type;
366  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
367 
368  /* Send option 57, max msg length */
369  if (0 /* not needed, apparently */)
370  {
371  o->option = 57;
372  o->length = 2;
373  {
374  u16 *o2 = (u16 *) o->data;
375  *o2 = clib_host_to_net_u16 (1152);
376  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
377  }
378  }
379 
380  /*
381  * If server ip address is available with non-zero value,
382  * option 54 (DHCP Server Identifier) is sent.
383  */
384  if (c->dhcp_server.as_u32)
385  {
386  o->option = 54;
387  o->length = 4;
388  clib_memcpy (o->data, &c->dhcp_server.as_u32, 4);
389  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
390  }
391 
392  /* send option 50, requested IP address */
393  if (c->leased_address.as_u32)
394  {
395  o->option = 50;
396  o->length = 4;
397  clib_memcpy (o->data, &c->leased_address.as_u32, 4);
398  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
399  }
400 
401  /* send option 12, host name */
402  if (vec_len (c->hostname))
403  {
404  o->option = 12;
405  o->length = vec_len (c->hostname);
406  clib_memcpy (o->data, c->hostname, vec_len (c->hostname));
407  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
408  }
409 
410  /* $$ maybe send the client s/w version if anyone cares */
411 
412  /*
413  * send option 55, parameter request list
414  * The current list - see below, matches the Linux dhcp client's list
415  * Any specific dhcp server config and/or dhcp server may or may
416  * not yield specific options.
417  */
418  o->option = 55;
419  o->length = vec_len (c->option_55_data);
421  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
422 
423  /* End of list */
424  o->option = 0xff;
425  o->length = 0;
426  o++;
427 
428  b->current_length = ((u8 *)o) - b->data;
429 
430  /* fix ip length, checksum and udp length */
431  ip_length = vlib_buffer_length_in_chain (vm, b);
432  if (is_broadcast)
433  ip_length -= vec_len (c->l2_rewrite);
434 
435  ip->length = clib_host_to_net_u16(ip_length);
436  ip->checksum = ip4_header_checksum(ip);
437 
438  udp_length = ip_length - (sizeof (*ip));
439  udp->length = clib_host_to_net_u16 (udp_length);
440 }
441 
442 static int
444 {
445  /*
446  * State machine "DISCOVER" state. Send a dhcp discover packet,
447  * eventually back off the retry rate.
448  */
449  send_dhcp_pkt (dcm, c, DHCP_PACKET_DISCOVER, 1 /* is_broadcast */);
450 
451  c->retry_count++;
452  if (c->retry_count > 10)
453  c->next_transmit = now + 5.0;
454  else
455  c->next_transmit = now + 1.0;
456  return 0;
457 }
458 
459 static int
461 {
462  /*
463  * State machine "REQUEST" state. Send a dhcp request packet,
464  * eventually drop back to the discover state.
465  */
466  send_dhcp_pkt (dcm, c, DHCP_PACKET_REQUEST, 1 /* is_broadcast */);
467 
468  c->retry_count++;
469  if (c->retry_count > 7 /* lucky you */)
470  {
471  c->state = DHCP_DISCOVER;
472  c->next_transmit = now;
473  c->retry_count = 0;
474  return 1;
475  }
476  c->next_transmit = now + 1.0;
477  return 0;
478 }
479 
480 static int
482 {
483  /*
484  * State machine "BOUND" state. Send a dhcp request packet,
485  * eventually, when the lease expires, forget the dhcp data
486  * and go back to the stone age.
487  */
488  send_dhcp_pkt (dcm, c, DHCP_PACKET_REQUEST, 0 /* is_broadcast */);
489 
490  c->retry_count++;
491  if (c->retry_count > 10)
492  c->next_transmit = now + 5.0;
493  else
494  c->next_transmit = now + 1.0;
495 
496  if (now > c->lease_expires)
497  {
498  if (c->router_address.as_u32)
499  api_config_default_ip_route (0 /* is_ipv6 */,
500  0 /* is_add */,
501  0 /* vrf_id */,
502  c->sw_if_index,
503  (u8 *)&c->router_address);
504 
506  c->state = DHCP_DISCOVER;
507  c->next_transmit = now;
508  c->retry_count = 0;
509  /* Wipe out any memory of the address we had... */
510  c->leased_address.as_u32 = 0;
511  c->subnet_mask_width = 0;
512  c->router_address.as_u32 = 0;
513  c->lease_renewal_interval = 0;
514  c->dhcp_server.as_u32 = 0;
515  return 1;
516  }
517  return 0;
518 }
519 
520 static f64 dhcp_client_sm (f64 now, f64 timeout, uword pool_index)
521 {
523  dhcp_client_t * c;
524 
525  /* deleted, pooched, yadda yadda yadda */
526  if (pool_is_free_index (dcm->clients, pool_index))
527  return timeout;
528 
529  c = pool_elt_at_index (dcm->clients, pool_index);
530 
531  /* Time for us to do something with this client? */
532  if (now < c->next_transmit)
533  return timeout;
534 
535  again:
536  switch (c->state)
537  {
538  case DHCP_DISCOVER: /* send a discover */
539  if (dhcp_discover_state (dcm, c, now))
540  goto again;
541  break;
542 
543  case DHCP_REQUEST: /* send a request */
544  if (dhcp_request_state (dcm, c, now))
545  goto again;
546  break;
547 
548  case DHCP_BOUND: /* bound, renew needed? */
549  if (dhcp_bound_state (dcm, c, now))
550  goto again;
551  break;
552 
553  default:
554  clib_warning ("dhcp client %d bogus state %d",
555  c - dcm->clients, c->state);
556  break;
557  }
558 
559  if (c->next_transmit < now + timeout)
560  return c->next_transmit - now;
561 
562  return timeout;
563 }
564 
565 static uword
567  vlib_node_runtime_t * rt,
568  vlib_frame_t * f)
569 {
570  f64 timeout = 100.0;
571  f64 now;
572  uword event_type;
573  uword * event_data = 0;
575  dhcp_client_t * c;
576  int i;
577 
578  while (1)
579  {
581 
582  event_type = vlib_process_get_events (vm, &event_data);
583 
584  now = vlib_time_now (vm);
585 
586  switch (event_type)
587  {
589  for (i = 0; i < vec_len (event_data); i++)
590  timeout = dhcp_client_sm (now, timeout, event_data[i]);
591  break;
592 
593  case ~0:
594  pool_foreach (c, dcm->clients,
595  ({
596  timeout = dhcp_client_sm (now, timeout,
597  (uword)(c - dcm->clients));
598  }));
599  if (pool_elts (dcm->clients) == 0)
600  timeout = 100.0;
601  break;
602  }
603 
604  vec_reset_length (event_data);
605  }
606 
607  /* NOTREACHED */
608  return 0;
609 }
610 
611 VLIB_REGISTER_NODE (dhcp_client_process_node,static) = {
612  .function = dhcp_client_process,
613  .type = VLIB_NODE_TYPE_PROCESS,
614  .name = "dhcp-client-process",
615  .process_log2_n_stack_bytes = 16,
616 };
617 
618 static u8 * format_dhcp_client_state (u8 * s, va_list * va)
619 {
621  char * str = "BOGUS!";
622 
623  switch (state)
624  {
625 #define _(a) \
626  case a: \
627  str = #a; \
628  break;
630 #undef _
631  default:
632  break;
633  }
634 
635  s = format (s, "%s", str);
636  return s;
637 }
638 
639 static u8 * format_dhcp_client (u8 * s, va_list * va)
640 {
641  dhcp_client_main_t * dcm = va_arg (*va, dhcp_client_main_t *);
642  dhcp_client_t * c = va_arg (*va, dhcp_client_t *);
643  int verbose = va_arg (*va, int);
644 
645  s = format (s, "[%d] %U state %U ", c - dcm->clients,
648 
649  if (c->leased_address.as_u32)
650  s = format (s, "addr %U/%d gw %U\n",
653  else
654  s = format (s, "no address\n");
655 
656  if (verbose)
657  {
658  s = format (s, "retry count %d, next xmt %.2f",
659  c->retry_count, c->next_transmit);
660  }
661  return s;
662 }
663 
664 static clib_error_t *
666  unformat_input_t * input,
667  vlib_cli_command_t * cmd)
668 {
670  dhcp_client_t * c;
671  int verbose = 0;
672  u32 sw_if_index = ~0;
673  uword * p;
674 
676  {
677  if (unformat (input, "intfc %U",
679  &sw_if_index))
680  ;
681  else if (unformat (input, "verbose"))
682  verbose = 1;
683  else
684  break;
685  }
686 
687  if (sw_if_index != ~0)
688  {
689  p = hash_get (dcm->client_by_sw_if_index, sw_if_index);
690  if (p == 0)
691  return clib_error_return (0, "dhcp client not configured");
692  c = pool_elt_at_index (dcm->clients, sw_if_index);
693  vlib_cli_output (vm, "%U", format_dhcp_client, dcm, c, verbose);
694  return 0;
695  }
696 
697  pool_foreach (c, dcm->clients,
698  ({
699  vlib_cli_output (vm, "%U", format_dhcp_client, dcm, c, verbose);
700  }));
701 
702  return 0;
703 }
704 
705 VLIB_CLI_COMMAND (show_dhcp_client_command, static) = {
706  .path = "show dhcp client",
707  .short_help = "show dhcp client [intfc <intfc>][verbose]",
708  .function = show_dhcp_client_command_fn,
709 };
710 
711 
713 {
715  vlib_main_t * vm = dcm->vlib_main;
716  dhcp_client_t * c;
717  uword * p;
718 
720 
721  if ((p && a->is_add) || (!p && a->is_add == 0))
722  return VNET_API_ERROR_INVALID_VALUE;
723 
724  if (a->is_add)
725  {
726  pool_get (dcm->clients, c);
727  memset (c, 0, sizeof (*c));
728  c->state = DHCP_DISCOVER;
729  c->sw_if_index = a->sw_if_index;
730  c->client_index = a->client_index;
731  c->pid = a->pid;
734  c->hostname = a->hostname;
736  do {
737  c->transaction_id = random_u32 (&dcm->seed);
738  } while (c->transaction_id == 0);
739  set_l2_rewrite (dcm, c);
740  hash_set (dcm->client_by_sw_if_index, a->sw_if_index, c - dcm->clients);
741  vlib_process_signal_event (vm, dhcp_client_process_node.index,
743  }
744  else
745  {
746  c = pool_elt_at_index (dcm->clients, p[0]);
747 
748  if (c->router_address.as_u32)
749  api_config_default_ip_route (0 /* is_ipv6 */,
750  0 /* is_add */,
751  0 /* vrf_id */,
752  c->sw_if_index,
753  (u8 *)&c->router_address);
755  vec_free (c->hostname);
757  vec_free (c->l2_rewrite);
759  pool_put (dcm->clients, c);
760  }
761  return 0;
762 }
763 
764 int
766  u32 sw_if_index,
767  u8 * hostname,
768  u32 is_add,
769  u32 client_index,
770  void * event_callback,
771  u32 pid)
772 {
773  dhcp_client_add_del_args_t _a, *a = &_a;
774  int rv;
775 
776  memset (a, 0, sizeof (*a));
777  a->is_add = is_add;
778  a->sw_if_index = sw_if_index;
779  a->client_index = client_index;
780  a->pid = pid;
781  a->event_callback = event_callback;
782  vec_validate(a->hostname, strlen((char *)hostname) - 1);
783  strncpy((char *)a->hostname, (char *)hostname, vec_len(a->hostname));
784  a->client_identifier = format (0, "vpe 1.0%c", 0);
785  /*
786  * Option 55 request list. These data precisely match
787  * the Ubuntu dhcp client. YMMV.
788  */
789 
790  /* Subnet Mask */
791  vec_add1 (a->option_55_data, 1);
792  /* Broadcast address */
793  vec_add1 (a->option_55_data, 28);
794  /* time offset */
795  vec_add1 (a->option_55_data, 2);
796  /* Router */
797  vec_add1 (a->option_55_data, 3);
798  /* Domain Name */
799  vec_add1 (a->option_55_data, 15);
800  /* DNS */
801  vec_add1 (a->option_55_data, 6);
802  /* Domain search */
803  vec_add1 (a->option_55_data, 119);
804  /* Host name */
805  vec_add1 (a->option_55_data, 12);
806  /* NetBIOS name server */
807  vec_add1 (a->option_55_data, 44);
808  /* NetBIOS Scope */
809  vec_add1 (a->option_55_data, 47);
810  /* MTU */
811  vec_add1 (a->option_55_data, 26);
812  /* Classless static route */
813  vec_add1 (a->option_55_data, 121);
814  /* NTP servers */
815  vec_add1 (a->option_55_data, 42);
816 
817  rv = dhcp_client_add_del (a);
818 
819  switch (rv)
820  {
821  case 0:
822  break;
823 
824  case VNET_API_ERROR_INVALID_VALUE:
825 
826  vec_free (a->hostname);
829 
830  if (is_add)
831  clib_warning ("dhcp client already enabled on intf_idx %d",
832  sw_if_index);
833  else
834  clib_warning ("dhcp client not enabled on on intf_idx %d",
835  sw_if_index);
836  break;
837 
838  default:
839  clib_warning ("dhcp_client_add_del returned %d", rv);
840  }
841 
842  return rv;
843 }
844 
845 static clib_error_t *
847  unformat_input_t * input,
848  vlib_cli_command_t * cmd)
849 {
850 
852  u32 sw_if_index;
853  u8 * hostname = 0;
854  u8 sw_if_index_set = 0;
855  int is_add = 1;
856  dhcp_client_add_del_args_t _a, *a = &_a;
857  int rv;
858 
860  {
861  if (unformat (input, "intfc %U",
863  &sw_if_index))
864  sw_if_index_set = 1;
865  else if (unformat (input, "hostname %v", &hostname))
866  ;
867  else if (unformat (input, "del"))
868  is_add = 0;
869  else
870  break;
871  }
872 
873  if (sw_if_index_set == 0)
874  return clib_error_return (0, "interface not specified");
875 
876  memset (a, 0, sizeof (*a));
877  a->is_add = is_add;
878  a->sw_if_index = sw_if_index;
879  a->hostname = hostname;
880  a->client_identifier = format (0, "vpe 1.0%c", 0);
881 
882  /*
883  * Option 55 request list. These data precisely match
884  * the Ubuntu dhcp client. YMMV.
885  */
886 
887  /* Subnet Mask */
888  vec_add1 (a->option_55_data, 1);
889  /* Broadcast address */
890  vec_add1 (a->option_55_data, 28);
891  /* time offset */
892  vec_add1 (a->option_55_data, 2);
893  /* Router */
894  vec_add1 (a->option_55_data, 3);
895  /* Domain Name */
896  vec_add1 (a->option_55_data, 15);
897  /* DNS */
898  vec_add1 (a->option_55_data, 6);
899  /* Domain search */
900  vec_add1 (a->option_55_data, 119);
901  /* Host name */
902  vec_add1 (a->option_55_data, 12);
903  /* NetBIOS name server */
904  vec_add1 (a->option_55_data, 44);
905  /* NetBIOS Scope */
906  vec_add1 (a->option_55_data, 47);
907  /* MTU */
908  vec_add1 (a->option_55_data, 26);
909  /* Classless static route */
910  vec_add1 (a->option_55_data, 121);
911  /* NTP servers */
912  vec_add1 (a->option_55_data, 42);
913 
914  rv = dhcp_client_add_del (a);
915 
916  switch (rv)
917  {
918  case 0:
919  break;
920 
921  case VNET_API_ERROR_INVALID_VALUE:
922 
923  vec_free (a->hostname);
926  if (is_add)
927  return clib_error_return (0, "dhcp client already enabled on %U",
929  dcm->vnet_main, sw_if_index);
930  else
931  return clib_error_return (0, "dhcp client not enabled on %U",
933  dcm->vnet_main, sw_if_index);
934  break;
935 
936  default:
937  vlib_cli_output (vm, "dhcp_client_add_del returned %d", rv);
938  }
939 
940  return 0;
941 }
942 
943 VLIB_CLI_COMMAND (dhcp_client_set_command, static) = {
944  .path = "set dhcp client",
945  .short_help = "set dhcp client [del] intfc <interface> [hostname <name>]",
946  .function = dhcp_client_set_command_fn,
947 };
948 
949 static clib_error_t *
951 {
953 
954  dcm->vlib_main = vm;
955  dcm->vnet_main = vnet_get_main();
956  dcm->seed = 0xdeaddabe;
957  return 0;
958 }
959 
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:396
u32 retry_count
Definition: client.h:40
u8 client_hardware_address[16]
Definition: packet.h:35
static int dhcp_discover_state(dhcp_client_main_t *dcm, dhcp_client_t *c, f64 now)
Definition: client.c:443
#define hash_set(h, key, value)
Definition: hash.h:254
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
dhcp_packet_type_t
Definition: packet.h:51
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
static f64 vlib_process_wait_for_event_or_clock(vlib_main_t *vm, f64 dt)
Suspend a cooperative multi-tasking thread Waits for an event, or for the indicated number of seconds...
Definition: node_funcs.h:682
#define hash_unset(h, key)
Definition: hash.h:260
a
Definition: bitmap.h:516
ip4_address_t src_address
Definition: ip4_packet.h:138
bad routing header type(not 4)") sr_error (NO_MORE_SEGMENTS
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
#define DHCP_FLAG_BROADCAST
Definition: packet.h:30
f64 next_transmit
Definition: client.h:43
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:182
u32 transaction_id
Definition: client.h:47
u8 * hostname
Definition: client.h:63
static u8 * format_dhcp_client(u8 *s, va_list *va)
Definition: client.c:639
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
dhcp_client_t * clients
Definition: client.h:74
struct _vlib_node_registration vlib_node_registration_t
static vnet_sw_interface_t * vnet_get_sw_interface(vnet_main_t *vnm, u32 sw_if_index)
unformat_function_t unformat_vnet_sw_interface
#define VNET_HW_INTERFACE_FLAG_LINK_UP
Definition: interface.h:273
static uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:112
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:200
format_function_t format_ip4_address
Definition: format.h:71
static void dhcp_client_acquire_address(dhcp_client_main_t *dcm, dhcp_client_t *c)
Definition: client.c:31
format_function_t format_vnet_sw_if_index_name
int dhcp_client_add_del(dhcp_client_add_del_args_t *a)
Definition: client.c:712
static vlib_node_registration_t dhcp_client_process_node
(constructor) VLIB_REGISTER_NODE (dhcp_client_process_node)
Definition: client.c:20
u32 data_as_u32[0]
Definition: packet.h:47
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
vlib_node_registration_t ip4_lookup_node
(constructor) VLIB_REGISTER_NODE (ip4_lookup_node)
Definition: ip4_forward.c:1541
#define DHCP_MAGIC
Definition: packet.h:59
vnet_main_t * vnet_get_main(void)
Definition: misc.c:45
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:78
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:348
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
static uword vlib_process_get_events(vlib_main_t *vm, uword **data_vector)
Return the first event type which has occurred and a vector of per-event data of that type...
Definition: node_funcs.h:525
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:187
static void dhcp_client_release_address(dhcp_client_main_t *dcm, dhcp_client_t *c)
Definition: client.c:42
ip4_address_t dst_address
Definition: ip4_packet.h:138
u32 lease_lifetime
Definition: client.h:55
static vnet_sw_interface_t * vnet_get_sup_sw_interface(vnet_main_t *vnm, u32 sw_if_index)
u8 * l2_rewrite
Definition: client.h:60
#define clib_warning(format, args...)
Definition: error.h:59
static uword dhcp_client_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: client.c:566
u32 client_index
Definition: client.h:67
void api_config_default_ip_route(u8 is_ipv6, u8 is_add, u32 vrf_id, u32 sw_if_index, u8 *next_hop_addr)
Definition: client.c:23
clib_error_t * ip4_add_del_interface_address(vlib_main_t *vm, u32 sw_if_index, ip4_address_t *address, u32 address_length, u32 is_del)
Definition: ip4_forward.c:1355
#define hash_get(h, key)
Definition: hash.h:248
dhcp_client_state_t
Definition: client.h:27
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:369
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:82
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:929
vlib_main_t * vlib_main
Definition: client.h:79
u32 subnet_mask_width
Definition: client.h:52
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:214
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:194
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:575
ip4_address_t client_ip_address
Definition: packet.h:31
svmdb_client_t * c
u16 n_vectors
Definition: node.h:344
static void send_dhcp_pkt(dhcp_client_main_t *dcm, dhcp_client_t *c, dhcp_packet_type_t type, int is_broadcast)
Definition: client.c:257
static f64 dhcp_client_sm(f64 now, f64 timeout, uword pool_index)
Definition: client.c:520
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
#define clib_memcpy(a, b, c)
Definition: string.h:63
u8 options[0]
Definition: packet.h:39
dhcp_client_state_t state
Definition: client.h:34
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:211
u8 * option_55_data
Definition: client.h:58
#define EVENT_DHCP_CLIENT_WAKEUP
Definition: client.h:102
#define VNET_SW_INTERFACE_FLAG_ADMIN_UP
Definition: interface.h:415
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u32 lease_renewal_interval
Definition: client.h:54
#define vnet_buffer(b)
Definition: buffer.h:335
u16 flags
Definition: packet.h:29
u32 sw_if_index
Definition: client.h:37
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:418
void vlib_buffer_free(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Free buffers Frees the entire buffer chain for each buffer.
Definition: dpdk_buffer.c:766
vhost_vring_state_t state
Definition: vhost-user.h:81
int dhcp_client_config(vlib_main_t *vm, u32 sw_if_index, u8 *hostname, u32 is_add, u32 client_index, void *event_callback, u32 pid)
Definition: client.c:765
static void set_l2_rewrite(dhcp_client_main_t *dcm, dhcp_client_t *c)
Definition: client.c:54
static vnet_hw_interface_class_t * vnet_get_hw_interface_class(vnet_main_t *vnm, u32 hw_class_index)
u32 transaction_identifier
Definition: packet.h:27
u8 hardware_address_length
Definition: packet.h:25
u32 vlib_buffer_alloc(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Allocate buffers into supplied array.
Definition: dpdk_buffer.c:643
u8 data[0]
Definition: packet.h:46
u64 uword
Definition: types.h:112
f64 lease_expires
Definition: client.h:44
Definition: defs.h:47
unsigned short u16
Definition: types.h:57
VLIB_CLI_COMMAND(set_interface_ip_source_and_port_range_check_command, static)
ip4_address_t magic_cookie
Definition: packet.h:38
struct _vnet_hw_interface_class vnet_hw_interface_class_t
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
unsigned char u8
Definition: types.h:56
ip4_address_t dhcp_server
Definition: client.h:51
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:251
static int dhcp_bound_state(dhcp_client_main_t *dcm, dhcp_client_t *c, f64 now)
Definition: client.c:481
uword * client_by_sw_if_index
Definition: client.h:75
static int dhcp_request_state(dhcp_client_main_t *dcm, dhcp_client_t *c, f64 now)
Definition: client.c:460
static clib_error_t * show_dhcp_client_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: client.c:665
static u8 * format_dhcp_client_state(u8 *s, va_list *va)
Definition: client.c:618
void * event_callback
Definition: client.h:69
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
static u32 random_u32(u32 *seed)
32-bit random number generator
Definition: random.h:69
static clib_error_t * dhcp_client_set_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: client.c:846
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
u8 data[0]
Packet data.
Definition: buffer.h:151
dhcp_client_main_t dhcp_client_main
Definition: client.c:18
static uword count_set_bits(uword x)
Definition: bitops.h:45
ip4_address_t router_address
Definition: client.h:53
static clib_error_t * dhcp_client_init(vlib_main_t *vm)
Definition: client.c:950
#define clib_error_return(e, args...)
Definition: error.h:111
vnet_main_t * vnet_main
Definition: client.h:80
int dhcp_client_for_us(u32 bi, vlib_buffer_t *b, ip4_header_t *ip, udp_header_t *udp, dhcp_header_t *dhcp)
Definition: client.c:80
u8 ip_version_and_header_length
Definition: ip4_packet.h:108
struct _unformat_input_t unformat_input_t
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:185
u8 hardware_type
Definition: packet.h:24
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:69
ip4_address_t leased_address
Definition: client.h:50
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:194
Definition: defs.h:46
ip4_address_t your_ip_address
Definition: packet.h:32
u8 * client_identifier
Definition: client.h:64
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:109