FD.io VPP  v17.01.1-3-gc6833f8
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 #include <vnet/fib/fib_table.h>
18 
20 static u8 * format_dhcp_client_state (u8 * s, va_list * va);
22 
23 static void
25 {
26  /*
27  * Install any/all info gleaned from dhcp, right here
28  */
30  (void *) &c->leased_address,
31  c->subnet_mask_width, 0 /*is_del*/);
32 }
33 
34 static void
36 {
37  /*
38  * Remove any/all info gleaned from dhcp, right here. Caller(s)
39  * have not wiped out the info yet.
40  */
41 
43  (void *) &c->leased_address,
44  c->subnet_mask_width, 1 /*is_del*/);
45 }
46 
47 static void
49 {
50  /* Acquire the L2 rewrite string for the indicated sw_if_index */
52  dcm->vnet_main,
53  c->sw_if_index,
55  0 /* broadcast */);
56 }
57 
58 /*
59  * dhcp_client_for_us - server-to-client callback.
60  * Called from proxy_node.c:dhcp_proxy_to_client_input().
61  * This function first decides that the packet in question is
62  * actually for the dhcp client code in case we're also acting as
63  * a dhcp proxy. Ay caramba, what a folly!
64  */
66  ip4_header_t * ip,
67  udp_header_t * udp,
68  dhcp_header_t * dhcp)
69 {
71  vlib_main_t * vm = dcm->vlib_main;
72  dhcp_client_t * c;
73  uword * p;
74  f64 now = vlib_time_now (dcm->vlib_main);
75  u8 dhcp_message_type = 0;
76  dhcp_option_t * o;
77 
78  /*
79  * Doing dhcp client on this interface?
80  * Presumably we will always receive dhcp clnt for-us pkts on
81  * the interface that's asking for an address.
82  */
84  vnet_buffer(b)->sw_if_index [VLIB_RX]);
85  if (p == 0)
86  return 0; /* no */
87 
88  c = pool_elt_at_index (dcm->clients, p[0]);
89 
90  /* Mixing dhcp relay and dhcp proxy? DGMS... */
91  if (c->state == DHCP_BOUND && c->retry_count == 0)
92  return 0;
93 
94  /* parse through the packet, learn what we can */
95  if (dhcp->your_ip_address.as_u32)
97 
98  o = (dhcp_option_t *) dhcp->options;
99 
100  while (o->option != 0xFF /* end of options */ &&
101  (u8 *) o < (b->data + b->current_data + b->current_length))
102  {
103  switch (o->option)
104  {
105  case 53: /* dhcp message type */
106  dhcp_message_type = o->data[0];
107  break;
108 
109  case 51: /* lease time */
110  {
111  u32 lease_time_in_seconds =
112  clib_host_to_net_u32 (o->data_as_u32[0]);
113  c->lease_expires = now + (f64) lease_time_in_seconds;
114  c->lease_lifetime = lease_time_in_seconds;
115  /* Set a sensible default, in case we don't get opt 58 */
116  c->lease_renewal_interval = lease_time_in_seconds / 2;
117  }
118  break;
119 
120  case 58: /* lease renew time in seconds */
121  {
122  u32 lease_renew_time_in_seconds =
123  clib_host_to_net_u32 (o->data_as_u32[0]);
124  c->lease_renewal_interval = lease_renew_time_in_seconds;
125  }
126  break;
127 
128  case 54: /* dhcp server address */
129  c->dhcp_server.as_u32 = o->data_as_u32[0];
130  break;
131 
132  case 1: /* subnet mask */
133  {
134  u32 subnet_mask =
135  clib_host_to_net_u32 (o->data_as_u32[0]);
136  c->subnet_mask_width = count_set_bits (subnet_mask);
137  }
138  break;
139  case 3: /* router address */
140  {
141  u32 router_address = o->data_as_u32[0];
142  c->router_address.as_u32 = router_address;
143  }
144  break;
145 
146  case 12: /* hostname */
147  {
148  /* Replace the existing hostname if necessary */
149  vec_free (c->hostname);
150  vec_validate (c->hostname, o->length - 1);
151  clib_memcpy (c->hostname, o->data, o->length);
152  }
153  break;
154 
155  /* $$$$ Your message in this space, parse more options */
156  default:
157  break;
158  }
159 
160  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
161  }
162 
163  switch (c->state)
164  {
165  case DHCP_DISCOVER:
166  if (dhcp_message_type != DHCP_PACKET_OFFER)
167  {
168  clib_warning ("sw_if_index %d state %U message type %d",
170  c->state, dhcp_message_type);
171  c->next_transmit = now + 5.0;
172  break;
173  }
174  /* Received an offer, go send a request */
175  c->state = DHCP_REQUEST;
176  c->retry_count = 0;
177  c->next_transmit = 0; /* send right now... */
178  /* Poke the client process, which will send the request */
181  break;
182 
183  case DHCP_BOUND:
184  case DHCP_REQUEST:
185  if (dhcp_message_type != DHCP_PACKET_ACK)
186  {
187  clib_warning ("sw_if_index %d state %U message type %d",
189  c->state, dhcp_message_type);
190  c->next_transmit = now + 5.0;
191  break;
192  }
193  /* OK, we own the address (etc), add to the routing table(s) */
194  if (c->state == DHCP_REQUEST)
195  {
196  void (*fp)(u32, u32, u8 *, u8, u8 *, u8 *, u8 *) = c->event_callback;
197 
199 
200  /*
201  * Configure default IP route:
202  */
203  if (c->router_address.as_u32)
204  {
205  fib_prefix_t all_0s =
206  {
207  .fp_len = 0,
208  .fp_addr.ip4.as_u32 = 0x0,
209  .fp_proto = FIB_PROTOCOL_IP4,
210  };
211  ip46_address_t nh =
212  {
213  .ip4 = c->router_address,
214  };
215 
218  c->sw_if_index),
219  &all_0s,
223  &nh,
224  c->sw_if_index,
225  ~0,
226  1,
227  NULL, // no label stack
229  }
230 
231  /*
232  * Call the user's event callback to report DHCP information
233  */
234  if (fp)
235  (*fp) (c->client_index, /* clinet index */
236  c->pid,
237  c->hostname,
238  0, /* is_ipv6 */
239  (u8 *)&c->leased_address, /* host IP address */
240  (u8 *)&c->router_address, /* router IP address */
241  (u8 *)(c->l2_rewrite + 6));/* host MAC address */
242  }
243 
244  c->state = DHCP_BOUND;
245  c->retry_count = 0;
246  c->next_transmit = now + (f64) c->lease_renewal_interval;
247  c->lease_expires = now + (f64) c->lease_lifetime;
248  break;
249 
250  default:
251  clib_warning ("client %d bogus state %d",
252  c - dcm->clients, c->state);
253  break;
254  }
255 
256  /* drop the pkt, return 1 */
257  vlib_buffer_free (vm, &bi, 1);
258  return 1;
259 }
260 
261 static void
263  dhcp_packet_type_t type, int is_broadcast)
264 {
265  vlib_main_t * vm = dcm->vlib_main;
266  vnet_main_t * vnm = dcm->vnet_main;
268  vnet_sw_interface_t * sup_sw
271  vlib_buffer_t * b;
272  u32 bi;
273  ip4_header_t * ip;
274  udp_header_t * udp;
275  dhcp_header_t * dhcp;
276  u32 * to_next;
277  vlib_frame_t * f;
278  dhcp_option_t * o;
279  u16 udp_length, ip_length;
280 
281  /* Interface(s) down? */
282  if ((hw->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) == 0)
283  return;
284  if ((sup_sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
285  return;
286  if ((sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
287  return;
288 
289  if (vlib_buffer_alloc (vm, &bi, 1) != 1) {
290  clib_warning ("buffer allocation failure");
291  c->next_transmit = 0;
292  return;
293  }
294 
295  /* Build a dhcpv4 pkt from whole cloth */
296  b = vlib_get_buffer (vm, bi);
297 
298  ASSERT (b->current_data == 0);
299 
300  vnet_buffer(b)->sw_if_index[VLIB_RX] = c->sw_if_index;
301  if (is_broadcast)
302  {
304  vnet_buffer(b)->sw_if_index[VLIB_TX] = c->sw_if_index;
306  ip = (void *)
307  (((u8 *)vlib_buffer_get_current (b)) + vec_len (c->l2_rewrite));
308  }
309  else
310  {
311  f = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
312  vnet_buffer(b)->sw_if_index[VLIB_TX] = ~0; /* use interface VRF */
313  ip = vlib_buffer_get_current (b);
314  }
315 
316  /* Enqueue the packet right now */
317  to_next = vlib_frame_vector_args (f);
318  to_next[0] = bi;
319  f->n_vectors = 1;
320 
321  if (is_broadcast)
323  else
325 
326  udp = (udp_header_t *)(ip+1);
327  dhcp = (dhcp_header_t *)(udp+1);
328 
329  /* $$$ optimize, maybe */
330  memset (ip, 0, sizeof (*ip) + sizeof (*udp) + sizeof (*dhcp));
331 
332  ip->ip_version_and_header_length = 0x45;
333  ip->ttl = 128;
334  ip->protocol = IP_PROTOCOL_UDP;
335 
336  if (is_broadcast)
337  {
338  /* src = 0.0.0.0, dst = 255.255.255.255 */
339  ip->dst_address.as_u32 = ~0;
340  }
341  else
342  {
343  /* Renewing an active lease, plain old ip4 src/dst */
346  }
347 
348  udp->src_port = clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client);
349  udp->dst_port = clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_server);
350 
351  /* Send the interface MAC address */
353 
354  /* Lease renewal, set up client_ip_address */
355  if (is_broadcast == 0)
357 
358  dhcp->opcode = 1; /* request, all we send */
359  dhcp->hardware_type = 1; /* ethernet */
360  dhcp->hardware_address_length = 6;
362  dhcp->flags = clib_host_to_net_u16(is_broadcast ? DHCP_FLAG_BROADCAST : 0);
364 
365  o = (dhcp_option_t * )dhcp->options;
366 
367  /* Send option 53, the DHCP message type */
368  o->option = 53;
369  o->length = 1;
370  o->data[0] = type;
371  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
372 
373  /* Send option 57, max msg length */
374  if (0 /* not needed, apparently */)
375  {
376  o->option = 57;
377  o->length = 2;
378  {
379  u16 *o2 = (u16 *) o->data;
380  *o2 = clib_host_to_net_u16 (1152);
381  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
382  }
383  }
384 
385  /*
386  * If server ip address is available with non-zero value,
387  * option 54 (DHCP Server Identifier) is sent.
388  */
389  if (c->dhcp_server.as_u32)
390  {
391  o->option = 54;
392  o->length = 4;
393  clib_memcpy (o->data, &c->dhcp_server.as_u32, 4);
394  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
395  }
396 
397  /* send option 50, requested IP address */
398  if (c->leased_address.as_u32)
399  {
400  o->option = 50;
401  o->length = 4;
402  clib_memcpy (o->data, &c->leased_address.as_u32, 4);
403  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
404  }
405 
406  /* send option 12, host name */
407  if (vec_len (c->hostname))
408  {
409  o->option = 12;
410  o->length = vec_len (c->hostname);
411  clib_memcpy (o->data, c->hostname, vec_len (c->hostname));
412  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
413  }
414 
415  /* $$ maybe send the client s/w version if anyone cares */
416 
417  /*
418  * send option 55, parameter request list
419  * The current list - see below, matches the Linux dhcp client's list
420  * Any specific dhcp server config and/or dhcp server may or may
421  * not yield specific options.
422  */
423  o->option = 55;
424  o->length = vec_len (c->option_55_data);
426  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
427 
428  /* End of list */
429  o->option = 0xff;
430  o->length = 0;
431  o++;
432 
433  b->current_length = ((u8 *)o) - b->data;
434 
435  /* fix ip length, checksum and udp length */
436  ip_length = vlib_buffer_length_in_chain (vm, b);
437  if (is_broadcast)
438  ip_length -= vec_len (c->l2_rewrite);
439 
440  ip->length = clib_host_to_net_u16(ip_length);
441  ip->checksum = ip4_header_checksum(ip);
442 
443  udp_length = ip_length - (sizeof (*ip));
444  udp->length = clib_host_to_net_u16 (udp_length);
445 }
446 
447 static int
449 {
450  /*
451  * State machine "DISCOVER" state. Send a dhcp discover packet,
452  * eventually back off the retry rate.
453  */
454  send_dhcp_pkt (dcm, c, DHCP_PACKET_DISCOVER, 1 /* is_broadcast */);
455 
456  c->retry_count++;
457  if (c->retry_count > 10)
458  c->next_transmit = now + 5.0;
459  else
460  c->next_transmit = now + 1.0;
461  return 0;
462 }
463 
464 static int
466 {
467  /*
468  * State machine "REQUEST" state. Send a dhcp request packet,
469  * eventually drop back to the discover state.
470  */
471  send_dhcp_pkt (dcm, c, DHCP_PACKET_REQUEST, 1 /* is_broadcast */);
472 
473  c->retry_count++;
474  if (c->retry_count > 7 /* lucky you */)
475  {
476  c->state = DHCP_DISCOVER;
477  c->next_transmit = now;
478  c->retry_count = 0;
479  return 1;
480  }
481  c->next_transmit = now + 1.0;
482  return 0;
483 }
484 
485 static int
487 {
488  /*
489  * State machine "BOUND" state. Send a dhcp request packet,
490  * eventually, when the lease expires, forget the dhcp data
491  * and go back to the stone age.
492  */
493  send_dhcp_pkt (dcm, c, DHCP_PACKET_REQUEST, 0 /* is_broadcast */);
494 
495  c->retry_count++;
496  if (c->retry_count > 10)
497  c->next_transmit = now + 5.0;
498  else
499  c->next_transmit = now + 1.0;
500 
501  if (now > c->lease_expires)
502  {
503  if (c->router_address.as_u32)
504  {
505  fib_prefix_t all_0s =
506  {
507  .fp_len = 0,
508  .fp_addr.ip4.as_u32 = 0x0,
509  .fp_proto = FIB_PROTOCOL_IP4,
510  };
511  ip46_address_t nh = {
512  .ip4 = c->router_address,
513  };
514 
517  c->sw_if_index),
518  &all_0s,
521  &nh,
522  c->sw_if_index,
523  ~0,
524  1,
526  }
527 
529  c->state = DHCP_DISCOVER;
530  c->next_transmit = now;
531  c->retry_count = 0;
532  /* Wipe out any memory of the address we had... */
533  c->leased_address.as_u32 = 0;
534  c->subnet_mask_width = 0;
535  c->router_address.as_u32 = 0;
536  c->lease_renewal_interval = 0;
537  c->dhcp_server.as_u32 = 0;
538  return 1;
539  }
540  return 0;
541 }
542 
543 static f64 dhcp_client_sm (f64 now, f64 timeout, uword pool_index)
544 {
546  dhcp_client_t * c;
547 
548  /* deleted, pooched, yadda yadda yadda */
549  if (pool_is_free_index (dcm->clients, pool_index))
550  return timeout;
551 
552  c = pool_elt_at_index (dcm->clients, pool_index);
553 
554  /* Time for us to do something with this client? */
555  if (now < c->next_transmit)
556  return timeout;
557 
558  again:
559  switch (c->state)
560  {
561  case DHCP_DISCOVER: /* send a discover */
562  if (dhcp_discover_state (dcm, c, now))
563  goto again;
564  break;
565 
566  case DHCP_REQUEST: /* send a request */
567  if (dhcp_request_state (dcm, c, now))
568  goto again;
569  break;
570 
571  case DHCP_BOUND: /* bound, renew needed? */
572  if (dhcp_bound_state (dcm, c, now))
573  goto again;
574  break;
575 
576  default:
577  clib_warning ("dhcp client %d bogus state %d",
578  c - dcm->clients, c->state);
579  break;
580  }
581 
582  if (c->next_transmit < now + timeout)
583  return c->next_transmit - now;
584 
585  return timeout;
586 }
587 
588 static uword
590  vlib_node_runtime_t * rt,
591  vlib_frame_t * f)
592 {
593  f64 timeout = 100.0;
594  f64 now;
595  uword event_type;
596  uword * event_data = 0;
598  dhcp_client_t * c;
599  int i;
600 
601  while (1)
602  {
604 
605  event_type = vlib_process_get_events (vm, &event_data);
606 
607  now = vlib_time_now (vm);
608 
609  switch (event_type)
610  {
612  for (i = 0; i < vec_len (event_data); i++)
613  timeout = dhcp_client_sm (now, timeout, event_data[i]);
614  break;
615 
616  case ~0:
617  pool_foreach (c, dcm->clients,
618  ({
619  timeout = dhcp_client_sm (now, timeout,
620  (uword)(c - dcm->clients));
621  }));
622  if (pool_elts (dcm->clients) == 0)
623  timeout = 100.0;
624  break;
625  }
626 
627  vec_reset_length (event_data);
628  }
629 
630  /* NOTREACHED */
631  return 0;
632 }
633 
635  .function = dhcp_client_process,
636  .type = VLIB_NODE_TYPE_PROCESS,
637  .name = "dhcp-client-process",
638  .process_log2_n_stack_bytes = 16,
639 };
640 
641 static u8 * format_dhcp_client_state (u8 * s, va_list * va)
642 {
644  char * str = "BOGUS!";
645 
646  switch (state)
647  {
648 #define _(a) \
649  case a: \
650  str = #a; \
651  break;
653 #undef _
654  default:
655  break;
656  }
657 
658  s = format (s, "%s", str);
659  return s;
660 }
661 
662 static u8 * format_dhcp_client (u8 * s, va_list * va)
663 {
664  dhcp_client_main_t * dcm = va_arg (*va, dhcp_client_main_t *);
665  dhcp_client_t * c = va_arg (*va, dhcp_client_t *);
666  int verbose = va_arg (*va, int);
667 
668  s = format (s, "[%d] %U state %U ", c - dcm->clients,
671 
672  if (c->leased_address.as_u32)
673  s = format (s, "addr %U/%d gw %U\n",
676  else
677  s = format (s, "no address\n");
678 
679  if (verbose)
680  {
681  s = format (s, "retry count %d, next xmt %.2f",
682  c->retry_count, c->next_transmit);
683  }
684  return s;
685 }
686 
687 static clib_error_t *
689  unformat_input_t * input,
690  vlib_cli_command_t * cmd)
691 {
693  dhcp_client_t * c;
694  int verbose = 0;
695  u32 sw_if_index = ~0;
696  uword * p;
697 
699  {
700  if (unformat (input, "intfc %U",
702  &sw_if_index))
703  ;
704  else if (unformat (input, "verbose"))
705  verbose = 1;
706  else
707  break;
708  }
709 
710  if (sw_if_index != ~0)
711  {
712  p = hash_get (dcm->client_by_sw_if_index, sw_if_index);
713  if (p == 0)
714  return clib_error_return (0, "dhcp client not configured");
715  c = pool_elt_at_index (dcm->clients, p[0]);
716  vlib_cli_output (vm, "%U", format_dhcp_client, dcm, c, verbose);
717  return 0;
718  }
719 
720  pool_foreach (c, dcm->clients,
721  ({
722  vlib_cli_output (vm, "%U", format_dhcp_client, dcm, c, verbose);
723  }));
724 
725  return 0;
726 }
727 
728 VLIB_CLI_COMMAND (show_dhcp_client_command, static) = {
729  .path = "show dhcp client",
730  .short_help = "show dhcp client [intfc <intfc>][verbose]",
731  .function = show_dhcp_client_command_fn,
732 };
733 
734 
736 {
738  vlib_main_t * vm = dcm->vlib_main;
739  dhcp_client_t * c;
740  uword * p;
741  fib_prefix_t all_1s =
742  {
743  .fp_len = 32,
744  .fp_addr.ip4.as_u32 = 0xffffffff,
745  .fp_proto = FIB_PROTOCOL_IP4,
746  };
747  fib_prefix_t all_0s =
748  {
749  .fp_len = 0,
750  .fp_addr.ip4.as_u32 = 0x0,
751  .fp_proto = FIB_PROTOCOL_IP4,
752  };
753 
755 
756  if ((p && a->is_add) || (!p && a->is_add == 0))
757  return VNET_API_ERROR_INVALID_VALUE;
758 
759  if (a->is_add)
760  {
761  pool_get (dcm->clients, c);
762  memset (c, 0, sizeof (*c));
763  c->state = DHCP_DISCOVER;
764  c->sw_if_index = a->sw_if_index;
765  c->client_index = a->client_index;
766  c->pid = a->pid;
769  c->hostname = a->hostname;
771  do {
772  c->transaction_id = random_u32 (&dcm->seed);
773  } while (c->transaction_id == 0);
774  set_l2_rewrite (dcm, c);
775  hash_set (dcm->client_by_sw_if_index, a->sw_if_index, c - dcm->clients);
776 
777  /* this add is ref counted by FIB so we can add for each itf */
780  c->sw_if_index),
781  &all_1s,
785 
786  /*
787  * enable the interface to RX IPv4 packets
788  * this is also ref counted
789  */
791 
794  }
795  else
796  {
797  c = pool_elt_at_index (dcm->clients, p[0]);
798 
801  c->sw_if_index),
802  &all_1s,
804 
805  if (c->router_address.as_u32)
806  {
807  ip46_address_t nh = {
808  .ip4 = c->router_address,
809  };
810 
813  c->sw_if_index),
814  &all_0s,
817  &nh,
818  c->sw_if_index,
819  ~0,
820  1,
822  }
824 
826  vec_free (c->hostname);
828  vec_free (c->l2_rewrite);
830  pool_put (dcm->clients, c);
831  }
832  return 0;
833 }
834 
835 int
837  u32 sw_if_index,
838  u8 * hostname,
839  u32 is_add,
840  u32 client_index,
841  void * event_callback,
842  u32 pid)
843 {
844  dhcp_client_add_del_args_t _a, *a = &_a;
845  int rv;
846 
847  memset (a, 0, sizeof (*a));
848  a->is_add = is_add;
849  a->sw_if_index = sw_if_index;
850  a->client_index = client_index;
851  a->pid = pid;
852  a->event_callback = event_callback;
853  vec_validate(a->hostname, strlen((char *)hostname) - 1);
854  strncpy((char *)a->hostname, (char *)hostname, vec_len(a->hostname));
855  a->client_identifier = format (0, "vpe 1.0%c", 0);
856  /*
857  * Option 55 request list. These data precisely match
858  * the Ubuntu dhcp client. YMMV.
859  */
860 
861  /* Subnet Mask */
862  vec_add1 (a->option_55_data, 1);
863  /* Broadcast address */
864  vec_add1 (a->option_55_data, 28);
865  /* time offset */
866  vec_add1 (a->option_55_data, 2);
867  /* Router */
868  vec_add1 (a->option_55_data, 3);
869  /* Domain Name */
870  vec_add1 (a->option_55_data, 15);
871  /* DNS */
872  vec_add1 (a->option_55_data, 6);
873  /* Domain search */
874  vec_add1 (a->option_55_data, 119);
875  /* Host name */
876  vec_add1 (a->option_55_data, 12);
877  /* NetBIOS name server */
878  vec_add1 (a->option_55_data, 44);
879  /* NetBIOS Scope */
880  vec_add1 (a->option_55_data, 47);
881  /* MTU */
882  vec_add1 (a->option_55_data, 26);
883  /* Classless static route */
884  vec_add1 (a->option_55_data, 121);
885  /* NTP servers */
886  vec_add1 (a->option_55_data, 42);
887 
888  rv = dhcp_client_add_del (a);
889 
890  switch (rv)
891  {
892  case 0:
893  break;
894 
895  case VNET_API_ERROR_INVALID_VALUE:
896 
897  vec_free (a->hostname);
900 
901  if (is_add)
902  clib_warning ("dhcp client already enabled on intf_idx %d",
903  sw_if_index);
904  else
905  clib_warning ("dhcp client not enabled on on intf_idx %d",
906  sw_if_index);
907  break;
908 
909  default:
910  clib_warning ("dhcp_client_add_del returned %d", rv);
911  }
912 
913  return rv;
914 }
915 
916 static clib_error_t *
918  unformat_input_t * input,
919  vlib_cli_command_t * cmd)
920 {
921 
923  u32 sw_if_index;
924  u8 * hostname = 0;
925  u8 sw_if_index_set = 0;
926  int is_add = 1;
927  dhcp_client_add_del_args_t _a, *a = &_a;
928  int rv;
929 
931  {
932  if (unformat (input, "intfc %U",
934  &sw_if_index))
935  sw_if_index_set = 1;
936  else if (unformat (input, "hostname %v", &hostname))
937  ;
938  else if (unformat (input, "del"))
939  is_add = 0;
940  else
941  break;
942  }
943 
944  if (sw_if_index_set == 0)
945  return clib_error_return (0, "interface not specified");
946 
947  memset (a, 0, sizeof (*a));
948  a->is_add = is_add;
949  a->sw_if_index = sw_if_index;
950  a->hostname = hostname;
951  a->client_identifier = format (0, "vpe 1.0%c", 0);
952 
953  /*
954  * Option 55 request list. These data precisely match
955  * the Ubuntu dhcp client. YMMV.
956  */
957 
958  /* Subnet Mask */
959  vec_add1 (a->option_55_data, 1);
960  /* Broadcast address */
961  vec_add1 (a->option_55_data, 28);
962  /* time offset */
963  vec_add1 (a->option_55_data, 2);
964  /* Router */
965  vec_add1 (a->option_55_data, 3);
966  /* Domain Name */
967  vec_add1 (a->option_55_data, 15);
968  /* DNS */
969  vec_add1 (a->option_55_data, 6);
970  /* Domain search */
971  vec_add1 (a->option_55_data, 119);
972  /* Host name */
973  vec_add1 (a->option_55_data, 12);
974  /* NetBIOS name server */
975  vec_add1 (a->option_55_data, 44);
976  /* NetBIOS Scope */
977  vec_add1 (a->option_55_data, 47);
978  /* MTU */
979  vec_add1 (a->option_55_data, 26);
980  /* Classless static route */
981  vec_add1 (a->option_55_data, 121);
982  /* NTP servers */
983  vec_add1 (a->option_55_data, 42);
984 
985  rv = dhcp_client_add_del (a);
986 
987  switch (rv)
988  {
989  case 0:
990  break;
991 
992  case VNET_API_ERROR_INVALID_VALUE:
993 
994  vec_free (a->hostname);
997  if (is_add)
998  return clib_error_return (0, "dhcp client already enabled on %U",
1000  dcm->vnet_main, sw_if_index);
1001  else
1002  return clib_error_return (0, "dhcp client not enabled on %U",
1004  dcm->vnet_main, sw_if_index);
1005  break;
1006 
1007  default:
1008  vlib_cli_output (vm, "dhcp_client_add_del returned %d", rv);
1009  }
1010 
1011  return 0;
1012 }
1013 
1014 VLIB_CLI_COMMAND (dhcp_client_set_command, static) = {
1015  .path = "set dhcp client",
1016  .short_help = "set dhcp client [del] intfc <interface> [hostname <name>]",
1017  .function = dhcp_client_set_command_fn,
1018 };
1019 
1020 static clib_error_t *
1022 {
1024 
1025  dcm->vlib_main = vm;
1026  dcm->vnet_main = vnet_get_main();
1027  dcm->seed = 0xdeaddabe;
1028  return 0;
1029 }
1030 
#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:448
#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:684
#define hash_unset(h, key)
Definition: hash.h:260
a
Definition: bitmap.h:516
ip4_address_t src_address
Definition: ip4_packet.h:163
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
#define NULL
Definition: clib.h:55
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:182
u32 transaction_id
Definition: client.h:47
u32 fib_table_get_index_for_sw_if_index(fib_protocol_t proto, u32 sw_if_index)
Get the index of the FIB bound to the interface.
Definition: fib_table.c:902
u8 * hostname
Definition: client.h:63
static u8 * format_dhcp_client(u8 *s, va_list *va)
Definition: client.c:662
#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
void fib_table_entry_path_remove(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_protocol_t next_hop_proto, const ip46_address_t *next_hop, u32 next_hop_sw_if_index, u32 next_hop_fib_index, u32 next_hop_weight, fib_route_path_flags_t path_flags)
remove one path to an entry (aka route) in the FIB.
Definition: fib_table.c:635
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:377
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:100
#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:79
static void dhcp_client_acquire_address(dhcp_client_main_t *dcm, dhcp_client_t *c)
Definition: client.c:24
format_function_t format_vnet_sw_if_index_name
int dhcp_client_add_del(dhcp_client_add_del_args_t *a)
Definition: client.c:735
static vlib_node_registration_t dhcp_client_process_node
(constructor) VLIB_REGISTER_NODE (dhcp_client_process_node)
Definition: client.c:21
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:511
#define DHCP_MAGIC
Definition: packet.h:59
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
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:527
void fib_table_entry_special_remove(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source)
Remove a &#39;special&#39; entry from the FIB.
Definition: fib_table.c:399
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:194
static void dhcp_client_release_address(dhcp_client_main_t *dcm, dhcp_client_t *c)
Definition: client.c:35
ip4_address_t dst_address
Definition: ip4_packet.h:163
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)
Aggregrate type for a prefix.
Definition: fib_types.h:145
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:589
u16 fp_len
The mask length.
Definition: fib_types.h:149
u32 client_index
Definition: client.h:67
Definition: fib_entry.h:216
fib_node_index_t fib_table_entry_path_add(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, fib_protocol_t next_hop_proto, const ip46_address_t *next_hop, u32 next_hop_sw_if_index, u32 next_hop_fib_index, u32 next_hop_weight, mpls_label_t *next_hop_labels, fib_route_path_flags_t path_flags)
Add one path to an entry (aka route) in the FIB.
Definition: fib_table.c:487
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:921
Definition: fib_entry.h:221
#define hash_get(h, key)
Definition: hash.h:248
dhcp_client_state_t
Definition: client.h:27
#define ADJ_INDEX_INVALID
Invalid ADJ index - used when no adj is known likewise blazoned capitals INVALID speak volumes where ...
Definition: adj_types.h:36
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:369
fib_node_index_t fib_table_entry_special_add(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, adj_index_t adj_index)
Add a &#39;special&#39; entry to the FIB that links to the adj passed A special entry is an entry that the FI...
Definition: fib_table.c:369
void ip4_sw_interface_enable_disable(u32 sw_if_index, u32 is_enable)
Definition: ip4_forward.c:807
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:931
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
u8 * vnet_build_rewrite_for_sw_interface(vnet_main_t *vnm, u32 sw_if_index, vnet_link_t link_type, const void *dst_address)
Definition: rewrite.c:297
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:196
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:576
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:262
static f64 dhcp_client_sm(f64 now, f64 timeout, uword pool_index)
Definition: client.c:543
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
#define clib_memcpy(a, b, c)
Definition: string.h:69
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 VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
#define EVENT_DHCP_CLIENT_WAKEUP
Definition: client.h:102
#define VNET_SW_INTERFACE_FLAG_ADMIN_UP
Definition: interface.h:528
#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:361
u16 flags
Definition: packet.h:29
u32 sw_if_index
Definition: client.h:37
void vlib_buffer_free(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Free buffers Frees the entire buffer chain for each buffer.
vhost_vring_state_t state
Definition: vhost-user.h:80
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:836
static void set_l2_rewrite(dhcp_client_main_t *dcm, dhcp_client_t *c)
Definition: client.c:48
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.
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
ip4_address_t magic_cookie
Definition: packet.h:38
#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
DHCP.
Definition: fib_entry.h:82
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:253
static int dhcp_bound_state(dhcp_client_main_t *dcm, dhcp_client_t *c, f64 now)
Definition: client.c:486
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:465
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:688
static u8 * format_dhcp_client_state(u8 *s, va_list *va)
Definition: client.c:641
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:917
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
u8 data[0]
Packet data.
Definition: buffer.h:158
dhcp_client_main_t dhcp_client_main
Definition: client.c:19
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:1021
#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:65
u8 ip_version_and_header_length
Definition: ip4_packet.h:131
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:187
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:57
ip4_address_t leased_address
Definition: client.h:50
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:238
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