FD.io VPP  v17.10-9-gd594711
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/client.h>
17 #include <vnet/dhcp/dhcp_proxy.h>
18 #include <vnet/fib/fib_table.h>
19 
21 static u8 * format_dhcp_client_state (u8 * s, va_list * va);
23 
24 static void
26 {
27  /* Install a local entry for the offered address */
28  fib_prefix_t rx =
29  {
30  .fp_len = 32,
31  .fp_addr.ip4 = c->leased_address,
32  .fp_proto = FIB_PROTOCOL_IP4,
33  };
34 
37  c->sw_if_index),
38  &rx,
41 
42  /* And add the server's address as uRPF exempt so we can accept
43  * local packets from it */
44  fib_prefix_t server =
45  {
46  .fp_len = 32,
47  .fp_addr.ip4 = c->dhcp_server,
48  .fp_proto = FIB_PROTOCOL_IP4,
49  };
50 
53  c->sw_if_index),
54  &server,
57 }
58 
59 static void
61 {
62  fib_prefix_t rx =
63  {
64  .fp_len = 32,
65  .fp_addr.ip4 = c->leased_address,
66  .fp_proto = FIB_PROTOCOL_IP4,
67  };
68 
71  c->sw_if_index),
72  &rx,
74  fib_prefix_t server =
75  {
76  .fp_len = 32,
77  .fp_addr.ip4 = c->dhcp_server,
78  .fp_proto = FIB_PROTOCOL_IP4,
79  };
80 
83  c->sw_if_index),
84  &server,
86 }
87 
88 static void
90 {
91  /*
92  * Install any/all info gleaned from dhcp, right here
93  */
95  (void *) &c->leased_address,
96  c->subnet_mask_width, 0 /*is_del*/);
97 }
98 
99 static void
101 {
102  /*
103  * Remove any/all info gleaned from dhcp, right here. Caller(s)
104  * have not wiped out the info yet.
105  */
106 
108  (void *) &c->leased_address,
109  c->subnet_mask_width, 1 /*is_del*/);
110 }
111 
112 static void
114 {
115  /* Acquire the L2 rewrite string for the indicated sw_if_index */
117  dcm->vnet_main,
118  c->sw_if_index,
120  0 /* broadcast */);
121 }
122 
123 void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
124 
125 static void
127 {
129  ASSERT (vlib_get_thread_index () == 0);
131  EVENT_DHCP_CLIENT_WAKEUP, *client_index);
132 }
133 
134 /*
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!
140  */
142  ip4_header_t * ip,
143  udp_header_t * udp,
144  dhcp_header_t * dhcp)
145 {
147  vlib_main_t * vm = dcm->vlib_main;
148  dhcp_client_t * c;
149  uword * p;
150  f64 now = vlib_time_now (dcm->vlib_main);
151  u8 dhcp_message_type = 0;
152  dhcp_option_t * o;
153 
154  /*
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.
158  */
159  p = hash_get (dcm->client_by_sw_if_index,
160  vnet_buffer(b)->sw_if_index [VLIB_RX]);
161  if (p == 0)
162  return 0; /* no */
163 
164  c = pool_elt_at_index (dcm->clients, p[0]);
165 
166  /* Mixing dhcp relay and dhcp proxy? DGMS... */
167  if (c->state == DHCP_BOUND && c->retry_count == 0)
168  return 0;
169 
170  /* parse through the packet, learn what we can */
171  if (dhcp->your_ip_address.as_u32)
173 
175 
176  o = (dhcp_option_t *) dhcp->options;
177 
178  while (o->option != 0xFF /* end of options */ &&
179  (u8 *) o < (b->data + b->current_data + b->current_length))
180  {
181  switch (o->option)
182  {
183  case 53: /* dhcp message type */
184  dhcp_message_type = o->data[0];
185  break;
186 
187  case 51: /* lease time */
188  {
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;
195  }
196  break;
197 
198  case 58: /* lease renew time in seconds */
199  {
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;
203  }
204  break;
205 
206  case 54: /* dhcp server address */
207  c->dhcp_server.as_u32 = o->data_as_u32[0];
208  break;
209 
210  case 1: /* subnet mask */
211  {
212  u32 subnet_mask =
213  clib_host_to_net_u32 (o->data_as_u32[0]);
214  c->subnet_mask_width = count_set_bits (subnet_mask);
215  }
216  break;
217  case 3: /* router address */
218  {
219  u32 router_address = o->data_as_u32[0];
220  c->router_address.as_u32 = router_address;
221  }
222  break;
223 
224  case 12: /* hostname */
225  {
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);
230  }
231  break;
232 
233  /* $$$$ Your message in this space, parse more options */
234  default:
235  break;
236  }
237 
238  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
239  }
240 
241  switch (c->state)
242  {
243  case DHCP_DISCOVER:
244  if (dhcp_message_type != DHCP_PACKET_OFFER)
245  {
246  clib_warning ("sw_if_index %d state %U message type %d",
248  c->state, dhcp_message_type);
249  c->next_transmit = now + 5.0;
250  break;
251  }
252  /*
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
257  */
259 
260  /* Received an offer, go send a request */
261  c->state = DHCP_REQUEST;
262  c->retry_count = 0;
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;
267  (u8 *) &client_id, sizeof (uword));
268  break;
269 
270  case DHCP_BOUND:
271  case DHCP_REQUEST:
272  if (dhcp_message_type != DHCP_PACKET_ACK)
273  {
274  clib_warning ("sw_if_index %d state %U message type %d",
276  c->state, dhcp_message_type);
277  c->next_transmit = now + 5.0;
278  break;
279  }
280  /* OK, we own the address (etc), add to the routing table(s) */
281  if (c->state == DHCP_REQUEST)
282  {
283  void (*fp)(u32, u32, u8 *, u8, u8, u8 *, u8 *, u8 *) = c->event_callback;
284 
285  /* replace the temporary RX address with the correct subnet */
288 
289  /*
290  * Configure default IP route:
291  */
292  if (c->router_address.as_u32)
293  {
294  fib_prefix_t all_0s =
295  {
296  .fp_len = 0,
297  .fp_addr.ip4.as_u32 = 0x0,
298  .fp_proto = FIB_PROTOCOL_IP4,
299  };
300  ip46_address_t nh =
301  {
302  .ip4 = c->router_address,
303  };
304 
307  c->sw_if_index),
308  &all_0s,
312  &nh,
313  c->sw_if_index,
314  ~0,
315  1,
316  NULL, // no label stack
318  }
319 
320  /*
321  * Call the user's event callback to report DHCP information
322  */
323  if (fp)
324  (*fp) (c->client_index, /* clinet index */
325  c->pid,
326  c->hostname,
328  0, /* is_ipv6 */
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 */
332  }
333 
334  c->state = DHCP_BOUND;
335  c->retry_count = 0;
336  c->next_transmit = now + (f64) c->lease_renewal_interval;
337  c->lease_expires = now + (f64) c->lease_lifetime;
338  break;
339 
340  default:
341  clib_warning ("client %d bogus state %d",
342  c - dcm->clients, c->state);
343  break;
344  }
345 
346  /* drop the pkt, return 1 */
347  vlib_buffer_free (vm, &bi, 1);
348  return 1;
349 }
350 
351 static void
353  dhcp_packet_type_t type, int is_broadcast)
354 {
355  vlib_main_t * vm = dcm->vlib_main;
356  vnet_main_t * vnm = dcm->vnet_main;
358  vnet_sw_interface_t * sup_sw
361  vlib_buffer_t * b;
362  u32 bi;
363  ip4_header_t * ip;
364  udp_header_t * udp;
365  dhcp_header_t * dhcp;
366  u32 * to_next;
367  vlib_frame_t * f;
368  dhcp_option_t * o;
369  u16 udp_length, ip_length;
370 
371  /* Interface(s) down? */
372  if ((hw->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) == 0)
373  return;
374  if ((sup_sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
375  return;
376  if ((sw->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) == 0)
377  return;
378 
379  if (vlib_buffer_alloc (vm, &bi, 1) != 1) {
380  clib_warning ("buffer allocation failure");
381  c->next_transmit = 0;
382  return;
383  }
384 
385  /* Build a dhcpv4 pkt from whole cloth */
386  b = vlib_get_buffer (vm, bi);
387 
388  ASSERT (b->current_data == 0);
389 
390  vnet_buffer(b)->sw_if_index[VLIB_RX] = c->sw_if_index;
391  if (is_broadcast)
392  {
394  vnet_buffer(b)->sw_if_index[VLIB_TX] = c->sw_if_index;
396  ip = (void *)
397  (((u8 *)vlib_buffer_get_current (b)) + vec_len (c->l2_rewrite));
398  }
399  else
400  {
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);
404  }
405 
406  /* Enqueue the packet right now */
407  to_next = vlib_frame_vector_args (f);
408  to_next[0] = bi;
409  f->n_vectors = 1;
410 
411  if (is_broadcast)
413  else
415 
416  udp = (udp_header_t *)(ip+1);
417  dhcp = (dhcp_header_t *)(udp+1);
418 
419  /* $$$ optimize, maybe */
420  memset (ip, 0, sizeof (*ip) + sizeof (*udp) + sizeof (*dhcp));
421 
422  ip->ip_version_and_header_length = 0x45;
423  ip->ttl = 128;
424  ip->protocol = IP_PROTOCOL_UDP;
425 
426  if (is_broadcast)
427  {
428  /* src = 0.0.0.0, dst = 255.255.255.255 */
429  ip->dst_address.as_u32 = ~0;
430  }
431  else
432  {
433  /* Renewing an active lease, plain old ip4 src/dst */
436  }
437 
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);
440 
441  /* Send the interface MAC address */
443 
444  /* Lease renewal, set up client_ip_address */
445  if (is_broadcast == 0)
447 
448  dhcp->opcode = 1; /* request, all we send */
449  dhcp->hardware_type = 1; /* ethernet */
450  dhcp->hardware_address_length = 6;
452  dhcp->flags = clib_host_to_net_u16(is_broadcast ? DHCP_FLAG_BROADCAST : 0);
454 
455  o = (dhcp_option_t * )dhcp->options;
456 
457  /* Send option 53, the DHCP message type */
459  o->length = 1;
460  o->data[0] = type;
461  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
462 
463  /* Send option 57, max msg length */
464  if (0 /* not needed, apparently */)
465  {
466  o->option = 57;
467  o->length = 2;
468  {
469  u16 *o2 = (u16 *) o->data;
470  *o2 = clib_host_to_net_u16 (1152);
471  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
472  }
473  }
474 
475  /*
476  * If server ip address is available with non-zero value,
477  * option 54 (DHCP Server Identifier) is sent.
478  */
479  if (c->dhcp_server.as_u32)
480  {
481  o->option = 54;
482  o->length = 4;
483  clib_memcpy (o->data, &c->dhcp_server.as_u32, 4);
484  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
485  }
486 
487  /* send option 50, requested IP address */
488  if (c->leased_address.as_u32)
489  {
490  o->option = 50;
491  o->length = 4;
492  clib_memcpy (o->data, &c->leased_address.as_u32, 4);
493  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
494  }
495 
496  /* send option 12, host name */
497  if (vec_len (c->hostname))
498  {
499  o->option = 12;
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));
503  }
504 
505  /* send option 61, client_id */
506  if (vec_len (c->client_identifier))
507  {
508  o->option = 61;
509  o->length = vec_len (c->client_identifier);
512  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
513  }
514 
515  /* $$ maybe send the client s/w version if anyone cares */
516 
517  /*
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.
522  */
523  o->option = 55;
524  o->length = vec_len (c->option_55_data);
526  o = (dhcp_option_t *) (((uword) o) + (o->length + 2));
527 
528  /* End of list */
529  o->option = 0xff;
530  o->length = 0;
531  o++;
532 
533  b->current_length = ((u8 *)o) - b->data;
534 
535  /* fix ip length, checksum and udp length */
536  ip_length = vlib_buffer_length_in_chain (vm, b);
537  if (is_broadcast)
538  ip_length -= vec_len (c->l2_rewrite);
539 
540  ip->length = clib_host_to_net_u16(ip_length);
541  ip->checksum = ip4_header_checksum(ip);
542 
543  udp_length = ip_length - (sizeof (*ip));
544  udp->length = clib_host_to_net_u16 (udp_length);
545 }
546 
547 static int
549 {
550  /*
551  * State machine "DISCOVER" state. Send a dhcp discover packet,
552  * eventually back off the retry rate.
553  */
554  send_dhcp_pkt (dcm, c, DHCP_PACKET_DISCOVER, 1 /* is_broadcast */);
555 
556  c->retry_count++;
557  if (c->retry_count > 10)
558  c->next_transmit = now + 5.0;
559  else
560  c->next_transmit = now + 1.0;
561  return 0;
562 }
563 
564 static int
566 {
567  /*
568  * State machine "REQUEST" state. Send a dhcp request packet,
569  * eventually drop back to the discover state.
570  */
571  send_dhcp_pkt (dcm, c, DHCP_PACKET_REQUEST, 1 /* is_broadcast */);
572 
573  c->retry_count++;
574  if (c->retry_count > 7 /* lucky you */)
575  {
576  c->state = DHCP_DISCOVER;
577  c->next_transmit = now;
578  c->retry_count = 0;
579  return 1;
580  }
581  c->next_transmit = now + 1.0;
582  return 0;
583 }
584 
585 static int
587 {
588  /*
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.
592  */
593  send_dhcp_pkt (dcm, c, DHCP_PACKET_REQUEST, 0 /* is_broadcast */);
594 
595  c->retry_count++;
596  if (c->retry_count > 10)
597  c->next_transmit = now + 5.0;
598  else
599  c->next_transmit = now + 1.0;
600 
601  if (now > c->lease_expires)
602  {
603  if (c->router_address.as_u32)
604  {
605  fib_prefix_t all_0s =
606  {
607  .fp_len = 0,
608  .fp_addr.ip4.as_u32 = 0x0,
609  .fp_proto = FIB_PROTOCOL_IP4,
610  };
611  ip46_address_t nh = {
612  .ip4 = c->router_address,
613  };
614 
617  c->sw_if_index),
618  &all_0s,
621  &nh,
622  c->sw_if_index,
623  ~0,
624  1,
626  }
627 
629  c->state = DHCP_DISCOVER;
630  c->next_transmit = now;
631  c->retry_count = 0;
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;
638  return 1;
639  }
640  return 0;
641 }
642 
643 static f64 dhcp_client_sm (f64 now, f64 timeout, uword pool_index)
644 {
646  dhcp_client_t * c;
647 
648  /* deleted, pooched, yadda yadda yadda */
649  if (pool_is_free_index (dcm->clients, pool_index))
650  return timeout;
651 
652  c = pool_elt_at_index (dcm->clients, pool_index);
653 
654  /* Time for us to do something with this client? */
655  if (now < c->next_transmit)
656  return timeout;
657 
658  again:
659  switch (c->state)
660  {
661  case DHCP_DISCOVER: /* send a discover */
662  if (dhcp_discover_state (dcm, c, now))
663  goto again;
664  break;
665 
666  case DHCP_REQUEST: /* send a request */
667  if (dhcp_request_state (dcm, c, now))
668  goto again;
669  break;
670 
671  case DHCP_BOUND: /* bound, renew needed? */
672  if (dhcp_bound_state (dcm, c, now))
673  goto again;
674  break;
675 
676  default:
677  clib_warning ("dhcp client %d bogus state %d",
678  c - dcm->clients, c->state);
679  break;
680  }
681 
682  if (c->next_transmit < now + timeout)
683  return c->next_transmit - now;
684 
685  return timeout;
686 }
687 
688 static uword
690  vlib_node_runtime_t * rt,
691  vlib_frame_t * f)
692 {
693  f64 timeout = 100.0;
694  f64 now;
695  uword event_type;
696  uword * event_data = 0;
698  dhcp_client_t * c;
699  int i;
700 
701  while (1)
702  {
704 
705  event_type = vlib_process_get_events (vm, &event_data);
706 
707  now = vlib_time_now (vm);
708 
709  switch (event_type)
710  {
712  for (i = 0; i < vec_len (event_data); i++)
713  timeout = dhcp_client_sm (now, timeout, event_data[i]);
714  break;
715 
716  case ~0:
717  pool_foreach (c, dcm->clients,
718  ({
719  timeout = dhcp_client_sm (now, timeout,
720  (uword)(c - dcm->clients));
721  }));
722  if (pool_elts (dcm->clients) == 0)
723  timeout = 100.0;
724  break;
725  }
726 
727  vec_reset_length (event_data);
728  }
729 
730  /* NOTREACHED */
731  return 0;
732 }
733 
735  .function = dhcp_client_process,
736  .type = VLIB_NODE_TYPE_PROCESS,
737  .name = "dhcp-client-process",
738  .process_log2_n_stack_bytes = 16,
739 };
740 
741 static u8 * format_dhcp_client_state (u8 * s, va_list * va)
742 {
744  char * str = "BOGUS!";
745 
746  switch (state)
747  {
748 #define _(a) \
749  case a: \
750  str = #a; \
751  break;
753 #undef _
754  default:
755  break;
756  }
757 
758  s = format (s, "%s", str);
759  return s;
760 }
761 
762 static u8 * format_dhcp_client (u8 * s, va_list * va)
763 {
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);
767 
768  s = format (s, "[%d] %U state %U ", c - dcm->clients,
771 
772  if (c->leased_address.as_u32)
773  s = format (s, "addr %U/%d gw %U\n",
776  else
777  s = format (s, "no address\n");
778 
779  if (verbose)
780  {
781  s = format (s, "retry count %d, next xmt %.2f",
782  c->retry_count, c->next_transmit);
783  }
784  return s;
785 }
786 
787 static clib_error_t *
789  unformat_input_t * input,
790  vlib_cli_command_t * cmd)
791 {
793  dhcp_client_t * c;
794  int verbose = 0;
795  u32 sw_if_index = ~0;
796  uword * p;
797 
799  {
800  if (unformat (input, "intfc %U",
802  &sw_if_index))
803  ;
804  else if (unformat (input, "verbose"))
805  verbose = 1;
806  else
807  break;
808  }
809 
810  if (sw_if_index != ~0)
811  {
812  p = hash_get (dcm->client_by_sw_if_index, sw_if_index);
813  if (p == 0)
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);
817  return 0;
818  }
819 
820  pool_foreach (c, dcm->clients,
821  ({
822  vlib_cli_output (vm, "%U", format_dhcp_client, dcm, c, verbose);
823  }));
824 
825  return 0;
826 }
827 
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,
832 };
833 
834 
836 {
838  vlib_main_t * vm = dcm->vlib_main;
839  dhcp_client_t * c;
840  uword * p;
841  fib_prefix_t all_1s =
842  {
843  .fp_len = 32,
844  .fp_addr.ip4.as_u32 = 0xffffffff,
845  .fp_proto = FIB_PROTOCOL_IP4,
846  };
847  fib_prefix_t all_0s =
848  {
849  .fp_len = 0,
850  .fp_addr.ip4.as_u32 = 0x0,
851  .fp_proto = FIB_PROTOCOL_IP4,
852  };
853 
855 
856  if ((p && a->is_add) || (!p && a->is_add == 0))
857  return VNET_API_ERROR_INVALID_VALUE;
858 
859  if (a->is_add)
860  {
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;
866  c->pid = a->pid;
869  c->hostname = a->hostname;
871  do {
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);
876 
877  /* this add is ref counted by FIB so we can add for each itf */
880  c->sw_if_index),
881  &all_1s,
884 
885  /*
886  * enable the interface to RX IPv4 packets
887  * this is also ref counted
888  */
890 
893  }
894  else
895  {
896  c = pool_elt_at_index (dcm->clients, p[0]);
897 
900  c->sw_if_index),
901  &all_1s,
903 
904  if (c->router_address.as_u32)
905  {
906  ip46_address_t nh = {
907  .ip4 = c->router_address,
908  };
909 
912  c->sw_if_index),
913  &all_0s,
916  &nh,
917  c->sw_if_index,
918  ~0,
919  1,
921  }
925 
927  vec_free (c->hostname);
929  vec_free (c->l2_rewrite);
931  pool_put (dcm->clients, c);
932  }
933  return 0;
934 }
935 
936 int
938  u32 sw_if_index,
939  u8 * hostname,
940  u8 * client_id,
941  u32 is_add,
942  u32 client_index,
943  void * event_callback,
944  u32 pid)
945 {
946  dhcp_client_add_del_args_t _a, *a = &_a;
947  int rv;
948 
949  memset (a, 0, sizeof (*a));
950  a->is_add = is_add;
951  a->sw_if_index = sw_if_index;
952  a->client_index = client_index;
953  a->pid = pid;
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));
959 
960  /*
961  * Option 55 request list. These data precisely match
962  * the Ubuntu dhcp client. YMMV.
963  */
964 
965  /* Subnet Mask */
966  vec_add1 (a->option_55_data, 1);
967  /* Broadcast address */
968  vec_add1 (a->option_55_data, 28);
969  /* time offset */
970  vec_add1 (a->option_55_data, 2);
971  /* Router */
972  vec_add1 (a->option_55_data, 3);
973  /* Domain Name */
974  vec_add1 (a->option_55_data, 15);
975  /* DNS */
976  vec_add1 (a->option_55_data, 6);
977  /* Domain search */
978  vec_add1 (a->option_55_data, 119);
979  /* Host name */
980  vec_add1 (a->option_55_data, 12);
981  /* NetBIOS name server */
982  vec_add1 (a->option_55_data, 44);
983  /* NetBIOS Scope */
984  vec_add1 (a->option_55_data, 47);
985  /* MTU */
986  vec_add1 (a->option_55_data, 26);
987  /* Classless static route */
988  vec_add1 (a->option_55_data, 121);
989  /* NTP servers */
990  vec_add1 (a->option_55_data, 42);
991 
992  rv = dhcp_client_add_del (a);
993 
994  switch (rv)
995  {
996  case 0:
997  break;
998 
999  case VNET_API_ERROR_INVALID_VALUE:
1000 
1001  vec_free (a->hostname);
1003  vec_free (a->option_55_data);
1004 
1005  if (is_add)
1006  clib_warning ("dhcp client already enabled on intf_idx %d",
1007  sw_if_index);
1008  else
1009  clib_warning ("dhcp client not enabled on on intf_idx %d",
1010  sw_if_index);
1011  break;
1012 
1013  default:
1014  clib_warning ("dhcp_client_add_del returned %d", rv);
1015  }
1016 
1017  return rv;
1018 }
1019 
1020 static clib_error_t *
1022  unformat_input_t * input,
1023  vlib_cli_command_t * cmd)
1024 {
1025 
1027  u32 sw_if_index;
1028  u8 * hostname = 0;
1029  u8 sw_if_index_set = 0;
1030  int is_add = 1;
1031  dhcp_client_add_del_args_t _a, *a = &_a;
1032  int rv;
1033 
1034  while (unformat_check_input(input) != UNFORMAT_END_OF_INPUT)
1035  {
1036  if (unformat (input, "intfc %U",
1038  &sw_if_index))
1039  sw_if_index_set = 1;
1040  else if (unformat (input, "hostname %v", &hostname))
1041  ;
1042  else if (unformat (input, "del"))
1043  is_add = 0;
1044  else
1045  break;
1046  }
1047 
1048  if (sw_if_index_set == 0)
1049  return clib_error_return (0, "interface not specified");
1050 
1051  memset (a, 0, sizeof (*a));
1052  a->is_add = is_add;
1053  a->sw_if_index = sw_if_index;
1054  a->hostname = hostname;
1055  a->client_identifier = format (0, "vpe 1.0%c", 0);
1056 
1057  /*
1058  * Option 55 request list. These data precisely match
1059  * the Ubuntu dhcp client. YMMV.
1060  */
1061 
1062  /* Subnet Mask */
1063  vec_add1 (a->option_55_data, 1);
1064  /* Broadcast address */
1065  vec_add1 (a->option_55_data, 28);
1066  /* time offset */
1067  vec_add1 (a->option_55_data, 2);
1068  /* Router */
1069  vec_add1 (a->option_55_data, 3);
1070  /* Domain Name */
1071  vec_add1 (a->option_55_data, 15);
1072  /* DNS */
1073  vec_add1 (a->option_55_data, 6);
1074  /* Domain search */
1075  vec_add1 (a->option_55_data, 119);
1076  /* Host name */
1077  vec_add1 (a->option_55_data, 12);
1078  /* NetBIOS name server */
1079  vec_add1 (a->option_55_data, 44);
1080  /* NetBIOS Scope */
1081  vec_add1 (a->option_55_data, 47);
1082  /* MTU */
1083  vec_add1 (a->option_55_data, 26);
1084  /* Classless static route */
1085  vec_add1 (a->option_55_data, 121);
1086  /* NTP servers */
1087  vec_add1 (a->option_55_data, 42);
1088 
1089  rv = dhcp_client_add_del (a);
1090 
1091  switch (rv)
1092  {
1093  case 0:
1094  break;
1095 
1096  case VNET_API_ERROR_INVALID_VALUE:
1097 
1098  vec_free (a->hostname);
1100  vec_free (a->option_55_data);
1101  if (is_add)
1102  return clib_error_return (0, "dhcp client already enabled on %U",
1104  dcm->vnet_main, sw_if_index);
1105  else
1106  return clib_error_return (0, "dhcp client not enabled on %U",
1108  dcm->vnet_main, sw_if_index);
1109  break;
1110 
1111  default:
1112  vlib_cli_output (vm, "dhcp_client_add_del returned %d", rv);
1113  }
1114 
1115  return 0;
1116 }
1117 
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,
1122 };
1123 
1124 static clib_error_t *
1126 {
1128 
1129  dcm->vlib_main = vm;
1130  dcm->vnet_main = vnet_get_main();
1131  dcm->seed = 0xdeaddabe;
1132  return 0;
1133 }
1134 
static u8 * format_dhcp_client(u8 *s, va_list *va)
Definition: client.c:762
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:432
u32 retry_count
Definition: client.h:43
u8 client_hardware_address[16]
Definition: dhcp4_packet.h:35
int dhcp_client_config(vlib_main_t *vm, u32 sw_if_index, u8 *hostname, u8 *client_id, u32 is_add, u32 client_index, void *event_callback, u32 pid)
Definition: client.c:937
#define hash_set(h, key, value)
Definition: hash.h:254
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
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:699
#define hash_unset(h, key)
Definition: hash.h:260
a
Definition: bitmap.h:516
static void vlib_buffer_free(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Free buffers Frees the entire buffer chain for each buffer.
Definition: buffer_funcs.h:317
ip4_address_t src_address
Definition: ip4_packet.h:164
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
f64 next_transmit
Definition: client.h:46
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:352
#define NULL
Definition: clib.h:55
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:221
u32 transaction_id
Definition: client.h:50
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:929
u8 * hostname
Definition: client.h:66
static void dhcp_client_release_address(dhcp_client_main_t *dcm, dhcp_client_t *c)
Definition: client.c:100
static int dhcp_discover_state(dhcp_client_main_t *dcm, dhcp_client_t *c, f64 now)
Definition: client.c:548
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:518
dhcp_client_t * clients
Definition: client.h:77
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:141
struct _vlib_node_registration vlib_node_registration_t
#define DHCP_MAGIC
Definition: dhcp4_packet.h:64
static vnet_sw_interface_t * vnet_get_sw_interface(vnet_main_t *vnm, u32 sw_if_index)
static void dhcp_client_add_rx_address(dhcp_client_main_t *dcm, dhcp_client_t *c)
Definition: client.c:25
void vlib_cli_output(struct vlib_main_t *vm, char *fmt,...)
Definition: client.c:106
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
unformat_function_t unformat_vnet_sw_interface
static int dhcp_request_state(dhcp_client_main_t *dcm, dhcp_client_t *c, f64 now)
Definition: client.c:565
ip4_address_t server_ip_address
Definition: dhcp4_packet.h:33
static u8 * format_dhcp_client_state(u8 *s, va_list *va)
Definition: client.c:741
#define VNET_HW_INTERFACE_FLAG_LINK_UP
Definition: interface.h:394
uRPF bypass/exemption.
Definition: fib_entry.h:114
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:107
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:225
format_function_t format_vnet_sw_if_index_name
u32 data_as_u32[0]
Definition: dhcp4_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:479
format_function_t format_ip4_address
Definition: format.h:79
static vlib_node_registration_t dhcp_client_process_node
(constructor) VLIB_REGISTER_NODE (dhcp_client_process_node)
Definition: client.c:22
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:68
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:437
#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:542
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:390
ip4_address_t dst_address
Definition: ip4_packet.h:164
u32 lease_lifetime
Definition: client.h:58
static uword dhcp_client_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: client.c:689
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:160
vlib_frame_t * vlib_get_frame_to_node(vlib_main_t *vm, u32 to_node_index)
Definition: main.c:182
#define clib_error_return(e, args...)
Definition: error.h:99
static int dhcp_bound_state(dhcp_client_main_t *dcm, dhcp_client_t *c, f64 now)
Definition: client.c:586
u8 * l2_rewrite
Definition: client.h:63
u16 fp_len
The mask length.
Definition: fib_types.h:164
u32 client_index
Definition: client.h:70
Definition: fib_entry.h:228
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:982
Definition: fib_entry.h:233
static void dhcp_client_acquire_address(dhcp_client_main_t *dcm, dhcp_client_t *c)
Definition: client.c:89
#define hash_get(h, key)
Definition: hash.h:248
dhcp_client_state_t
Definition: client.h:30
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:458
void ip4_sw_interface_enable_disable(u32 sw_if_index, u32 is_enable)
Definition: ip4_forward.c:860
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:72
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:950
vlib_main_t * vlib_main
Definition: client.h:82
u32 subnet_mask_width
Definition: client.h:55
static void dhcp_client_remove_rx_address(dhcp_client_main_t *dcm, dhcp_client_t *c)
Definition: client.c:60
static clib_error_t * dhcp_client_init(vlib_main_t *vm)
Definition: client.c:1125
struct _unformat_input_t unformat_input_t
void vlib_put_frame_to_node(vlib_main_t *vm, u32 to_node_index, vlib_frame_t *f)
Definition: main.c:191
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:193
static f64 dhcp_client_sm(f64 now, f64 timeout, uword pool_index)
Definition: client.c:643
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:270
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:202
dhcp_client_main_t dhcp_client_main
Definition: client.c:20
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:788
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)
Add a &#39;special&#39; entry to the FIB.
Definition: fib_table.c:371
ip4_address_t client_ip_address
Definition: dhcp4_packet.h:31
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
svmdb_client_t * c
u16 n_vectors
Definition: node.h:344
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:221
vlib_main_t * vm
Definition: buffer.c:283
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:336
#define clib_warning(format, args...)
Definition: error.h:59
Definition: fib_entry.h:231
#define clib_memcpy(a, b, c)
Definition: string.h:69
static void dhcp_client_proc_callback(uword *client_index)
Definition: client.c:126
dhcp_client_state_t state
Definition: client.h:37
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:267
u8 * option_55_data
Definition: client.h:61
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
#define EVENT_DHCP_CLIENT_WAKEUP
Definition: client.h:105
#define VNET_SW_INTERFACE_FLAG_ADMIN_UP
Definition: interface.h:572
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u32 lease_renewal_interval
Definition: client.h:57
u32 sw_if_index
Definition: client.h:40
vhost_vring_state_t state
Definition: vhost-user.h:82
u32 transaction_identifier
Definition: dhcp4_packet.h:27
u8 hardware_address_length
Definition: dhcp4_packet.h:25
void fib_table_entry_path_remove(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, dpo_proto_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:664
#define DHCP_FLAG_BROADCAST
Definition: dhcp4_packet.h:30
void vl_api_rpc_call_main_thread(void *fp, u8 *data, u32 data_length)
Definition: memory_vlib.c:1517
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
u64 uword
Definition: types.h:112
f64 lease_expires
Definition: client.h:47
Definition: defs.h:47
unsigned short u16
Definition: types.h:57
ip4_address_t magic_cookie
Definition: dhcp4_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:54
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:267
uword * client_by_sw_if_index
Definition: client.h:78
int dhcp_client_add_del(dhcp_client_add_del_args_t *a)
Definition: client.c:835
void * event_callback
Definition: client.h:72
#define vnet_buffer(b)
Definition: buffer.h:306
static u32 random_u32(u32 *seed)
32-bit random number generator
Definition: random.h:69
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
u8 data[0]
Packet data.
Definition: buffer.h:157
static uword count_set_bits(uword x)
Definition: bitops.h:45
ip4_address_t router_address
Definition: client.h:56
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:1021
vnet_main_t * vnet_main
Definition: client.h:83
u8 ip_version_and_header_length
Definition: ip4_packet.h:132
dhcp_packet_type_t
Definition: dhcp4_packet.h:51
static u32 vlib_buffer_alloc(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Allocate buffers into supplied array.
Definition: buffer_funcs.h:254
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:53
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:239
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
Definition: defs.h:46
ip4_address_t your_ip_address
Definition: dhcp4_packet.h:32
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
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, dpo_proto_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:504
u8 * client_identifier
Definition: client.h:67
static void set_l2_rewrite(dhcp_client_main_t *dcm, dhcp_client_t *c)
Definition: client.c:113
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:128