FD.io VPP  v16.06
Vector Packet Processing
tuntap.c
Go to the documentation of this file.
1 /*
2  *------------------------------------------------------------------
3  * tuntap.c - kernel stack (reverse) punt/inject path
4  *
5  * Copyright (c) 2009 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19 
20 #include <fcntl.h> /* for open */
21 #include <sys/ioctl.h>
22 #include <sys/socket.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <sys/uio.h> /* for iovec */
26 #include <netinet/in.h>
27 
28 #include <linux/if_arp.h>
29 #include <linux/if_tun.h>
30 
31 #include <vlib/vlib.h>
32 #include <vlib/unix/unix.h>
33 
34 #include <vnet/ip/ip.h>
35 
36 #include <vnet/ethernet/ethernet.h>
37 
38 #if DPDK == 1
39 #include <vnet/devices/dpdk/dpdk.h>
40 #endif
41 
44 
45 static void tuntap_punt_frame (vlib_main_t * vm,
46  vlib_node_runtime_t * node,
47  vlib_frame_t * frame);
48 static void tuntap_nopunt_frame (vlib_main_t * vm,
49  vlib_node_runtime_t * node,
50  vlib_frame_t * frame);
51 
52 /*
53  * This driver runs in one of two distinct modes:
54  * "punt/inject" mode, where we send pkts not otherwise processed
55  * by the forwarding to the Linux kernel stack, and
56  * "normal interface" mode, where we treat the Linux kernel stack
57  * as a peer.
58  *
59  * By default, we select punt/inject mode.
60  */
61 
62 typedef struct {
65  u8 addr[16];
67 
68 typedef struct {
69  /* Vector of iovecs for readv/writev calls. */
70  struct iovec * iovecs;
71 
72  /* Vector of VLIB rx buffers to use. We allocate them in blocks
73  of VLIB_FRAME_SIZE (256). */
75 
76  /* File descriptors for /dev/net/tun and provisioning socket. */
77  int dev_net_tun_fd, dev_tap_fd;
78 
79  /* Create a "tap" [ethernet] encaps device */
80  int is_ether;
81 
82  /* 1 if a "normal" routed intfc, 0 if a punt/inject interface */
83 
85 
86  /* tap device destination MAC address. Required, or Linux drops pkts */
87  u8 ether_dst_mac[6];
88 
89  /* Interface MTU in bytes and # of default sized buffers. */
90  u32 mtu_bytes, mtu_buffers;
91 
92  /* Linux interface name for tun device. */
93  char * tun_name;
94 
95  /* Pool of subinterface addresses */
97 
98  /* Hash for subif addresses */
100 
102 
103  /* For the "normal" interface, if configured */
104  u32 hw_if_index, sw_if_index;
105 
106 } tuntap_main_t;
107 
108 static tuntap_main_t tuntap_main = {
109  .tun_name = "vnet",
110 
111  /* Suitable defaults for an Ethernet-like tun/tap device */
112  .mtu_bytes = 4096 + 256,
113 };
114 
115 /*
116  * tuntap_tx
117  * Output node, writes the buffers comprising the incoming frame
118  * to the tun/tap device, aka hands them to the Linux kernel stack.
119  *
120  */
121 static uword
123  vlib_node_runtime_t * node,
124  vlib_frame_t * frame)
125 {
126  u32 * buffers = vlib_frame_args (frame);
127  uword n_packets = frame->n_vectors;
128  tuntap_main_t * tm = &tuntap_main;
129  int i;
130 
131  for (i = 0; i < n_packets; i++)
132  {
133  struct iovec * iov;
134  vlib_buffer_t * b;
135  uword l;
136 
137  b = vlib_get_buffer (vm, buffers[i]);
138 
139  if (tm->is_ether && (!tm->have_normal_interface))
140  {
143  }
144 
145  /* Re-set iovecs if present. */
146  if (tm->iovecs)
147  _vec_len (tm->iovecs) = 0;
148 
149  /* VLIB buffer chain -> Unix iovec(s). */
150  vec_add2 (tm->iovecs, iov, 1);
151  iov->iov_base = b->data + b->current_data;
152  iov->iov_len = l = b->current_length;
153 
155  {
156  do {
157  b = vlib_get_buffer (vm, b->next_buffer);
158 
159  vec_add2 (tm->iovecs, iov, 1);
160 
161  iov->iov_base = b->data + b->current_data;
162  iov->iov_len = b->current_length;
163  l += b->current_length;
164  } while (b->flags & VLIB_BUFFER_NEXT_PRESENT);
165  }
166 
167  if (writev (tm->dev_net_tun_fd, tm->iovecs, vec_len (tm->iovecs)) < l)
168  clib_unix_warning ("writev");
169  }
170 
171  /* The normal interface path flattens the buffer chain */
172  if (tm->have_normal_interface)
173  vlib_buffer_free_no_next (vm, buffers, n_packets);
174  else
175  vlib_buffer_free (vm, buffers, n_packets);
176 
177  return n_packets;
178 }
179 
181  .function = tuntap_tx,
182  .name = "tuntap-tx",
183  .type = VLIB_NODE_TYPE_INTERNAL,
184  .vector_size = 4,
185 };
186 
187 enum {
193 };
194 
195 static uword
197  vlib_node_runtime_t * node,
198  vlib_frame_t * frame)
199 {
200  tuntap_main_t * tm = &tuntap_main;
201  vlib_buffer_t * b;
202  u32 bi;
203  const uword buffer_size = VLIB_BUFFER_DATA_SIZE;
204 #if DPDK == 0
205  u32 free_list_index = VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX;
206 #else
207  dpdk_main_t * dm = &dpdk_main;
208  u32 free_list_index = dm->vlib_buffer_free_list_index;
209 #endif
210 
211  /* Make sure we have some RX buffers. */
212  {
213  uword n_left = vec_len (tm->rx_buffers);
214  uword n_alloc;
215 
216  if (n_left < VLIB_FRAME_SIZE / 2)
217  {
218  if (! tm->rx_buffers)
220 
222  (vm, tm->rx_buffers + n_left, VLIB_FRAME_SIZE - n_left,
223  free_list_index);
224  _vec_len (tm->rx_buffers) = n_left + n_alloc;
225  }
226  }
227 
228  /* Allocate RX buffers from end of rx_buffers.
229  Turn them into iovecs to pass to readv. */
230  {
231  uword i_rx = vec_len (tm->rx_buffers) - 1;
232  vlib_buffer_t * b;
233  word i, n_bytes_left, n_bytes_in_packet;
234 
235  /* We should have enough buffers left for an MTU sized packet. */
236  ASSERT (vec_len (tm->rx_buffers) >= tm->mtu_buffers);
237 
238  vec_validate (tm->iovecs, tm->mtu_buffers - 1);
239  for (i = 0; i < tm->mtu_buffers; i++)
240  {
241  b = vlib_get_buffer (vm, tm->rx_buffers[i_rx - i]);
242  tm->iovecs[i].iov_base = b->data;
243  tm->iovecs[i].iov_len = buffer_size;
244  }
245 
246  n_bytes_left = readv (tm->dev_net_tun_fd, tm->iovecs, tm->mtu_buffers);
247  n_bytes_in_packet = n_bytes_left;
248  if (n_bytes_left <= 0)
249  {
250  if (errno != EAGAIN)
251  clib_unix_warning ("readv %d", n_bytes_left);
252  return 0;
253  }
254 
255  bi = tm->rx_buffers[i_rx];
256 
257  while (1)
258  {
259 #if DPDK == 1
260  struct rte_mbuf * mb;
261 #endif
262  b = vlib_get_buffer (vm, tm->rx_buffers[i_rx]);
263 #if DPDK == 1
264  mb = rte_mbuf_from_vlib_buffer(b);
265 #endif
266  b->flags = 0;
267  b->current_data = 0;
268  b->current_length = n_bytes_left < buffer_size ? n_bytes_left : buffer_size;
269 
270  n_bytes_left -= buffer_size;
271 #if DPDK == 1
272  rte_pktmbuf_data_len (mb) = b->current_length;
273 #endif
274 
275  if (n_bytes_left <= 0)
276  {
277 #if DPDK == 1
278  rte_pktmbuf_pkt_len (mb) = n_bytes_in_packet;
279 #endif
280  break;
281  }
282 
283  i_rx--;
285  b->next_buffer = tm->rx_buffers[i_rx];
286 #if DPDK == 1
287  ASSERT(0);
288  // ((struct rte_pktmbuf *)(b->mb))->next =
289  // vlib_get_buffer (vm, tm->rx_buffers[i_rx])->mb;
290 #endif
291  }
292 
293  /* Interface counters for tuntap interface. */
298  tm->sw_if_index,
299  1, n_bytes_in_packet);
300 
301  _vec_len (tm->rx_buffers) = i_rx;
302  }
303 
304  b = vlib_get_buffer (vm, bi);
305 
306  {
307  u32 next_index;
308  uword n_trace = vlib_get_trace_count (vm, node);
309 
310  vnet_buffer (b)->sw_if_index[VLIB_RX] = tm->sw_if_index;
311  vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32)~0;
312 
313  /*
314  * Turn this on if you run into
315  * "bad monkey" contexts, and you want to know exactly
316  * which nodes they've visited...
317  */
319  b->pre_data[0] = 0;
320 
321  b->error = node->errors[0];
322 
323  if (tm->is_ether)
324  {
325  next_index = TUNTAP_RX_NEXT_ETHERNET_INPUT;
326  }
327  else
328  switch (b->data[0] & 0xf0)
329  {
330  case 0x40:
331  next_index = TUNTAP_RX_NEXT_IP4_INPUT;
332  break;
333  case 0x60:
334  next_index = TUNTAP_RX_NEXT_IP6_INPUT;
335  break;
336  default:
337  next_index = TUNTAP_RX_NEXT_DROP;
338  break;
339  }
340 
341  /* The linux kernel couldn't care less if our interface is up */
342  if (tm->have_normal_interface)
343  {
344  vnet_main_t *vnm = vnet_get_main();
345  vnet_sw_interface_t * si;
346  si = vnet_get_sw_interface (vnm, tm->sw_if_index);
348  next_index = TUNTAP_RX_NEXT_DROP;
349  }
350 
351  vlib_set_next_frame_buffer (vm, node, next_index, bi);
352 
353  if (n_trace > 0)
354  {
355  vlib_trace_buffer (vm, node, next_index,
356  b, /* follow_chain */ 1);
357  vlib_set_trace_count (vm, node, n_trace - 1);
358  }
359  }
360 
361  return 1;
362 }
363 
364 static char * tuntap_rx_error_strings[] = {
365  "unknown packet type",
366 };
367 
369  .function = tuntap_rx,
370  .name = "tuntap-rx",
371  .type = VLIB_NODE_TYPE_INPUT,
372  .state = VLIB_NODE_STATE_INTERRUPT,
373  .vector_size = 4,
374  .n_errors = 1,
375  .error_strings = tuntap_rx_error_strings,
376 
377  .n_next_nodes = TUNTAP_RX_N_NEXT,
378  .next_nodes = {
379  [TUNTAP_RX_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
380  [TUNTAP_RX_NEXT_IP6_INPUT] = "ip6-input",
381  [TUNTAP_RX_NEXT_DROP] = "error-drop",
382  [TUNTAP_RX_NEXT_ETHERNET_INPUT] = "ethernet-input",
383  },
384 };
385 
386 /* Gets called when file descriptor is ready from epoll. */
388 {
389  vlib_main_t * vm = vlib_get_main();
391  return 0;
392 }
393 
394 /*
395  * tuntap_exit
396  * Clean up the tun/tap device
397  */
398 
399 static clib_error_t *
401 {
402  tuntap_main_t *tm = &tuntap_main;
403  struct ifreq ifr;
404  int sfd;
405 
406  /* Not present. */
407  if (! tm->dev_net_tun_fd || tm->dev_net_tun_fd < 0)
408  return 0;
409 
410  sfd = socket (AF_INET, SOCK_STREAM, 0);
411  if (sfd < 0)
412  clib_unix_warning("provisioning socket");
413 
414  memset(&ifr, 0, sizeof (ifr));
415  strncpy (ifr.ifr_name, tm->tun_name, sizeof (ifr.ifr_name)-1);
416 
417  /* get flags, modify to bring down interface... */
418  if (ioctl (sfd, SIOCGIFFLAGS, &ifr) < 0)
419  clib_unix_warning ("SIOCGIFFLAGS");
420 
421  ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
422 
423  if (ioctl (sfd, SIOCSIFFLAGS, &ifr) < 0)
424  clib_unix_warning ("SIOCSIFFLAGS");
425 
426  /* Turn off persistence */
427  if (ioctl (tm->dev_net_tun_fd, TUNSETPERSIST, 0) < 0)
428  clib_unix_warning ("TUNSETPERSIST");
429  close(tm->dev_tap_fd);
430  close(tm->dev_net_tun_fd);
431  close (sfd);
432 
433  return 0;
434 }
435 
437 
438 static clib_error_t *
440 {
441  tuntap_main_t *tm = &tuntap_main;
442  clib_error_t * error = 0;
443  struct ifreq ifr;
444  u8 * name;
445  int flags = IFF_TUN | IFF_NO_PI;
446  int is_enabled = 0, is_ether = 0, have_normal_interface = 0;
447  const uword buffer_size = VLIB_BUFFER_DATA_SIZE;
448 
450  {
451  if (unformat (input, "mtu %d", &tm->mtu_bytes))
452  ;
453  else if (unformat (input, "enable"))
454  is_enabled = 1;
455  else if (unformat (input, "disable"))
456  is_enabled = 0;
457  else if (unformat (input, "ethernet") ||
458  unformat (input, "ether"))
459  is_ether = 1;
460  else if (unformat (input, "have-normal-interface") ||
461  unformat (input, "have-normal"))
462  have_normal_interface = 1;
463  else if (unformat (input, "name %s", &name))
464  tm->tun_name = (char *) name;
465  else
466  return clib_error_return (0, "unknown input `%U'",
467  format_unformat_error, input);
468  }
469 
470  tm->dev_net_tun_fd = -1;
471  tm->dev_tap_fd = -1;
472 
473  if (is_enabled == 0)
474  return 0;
475 
476  if (geteuid())
477  {
478  clib_warning ("tuntap disabled: must be superuser");
479  return 0;
480  }
481 
482  tm->is_ether = is_ether;
483  tm->have_normal_interface = have_normal_interface;
484 
485  if (is_ether)
486  flags = IFF_TAP | IFF_NO_PI;
487 
488  if ((tm->dev_net_tun_fd = open ("/dev/net/tun", O_RDWR)) < 0)
489  {
490  error = clib_error_return_unix (0, "open /dev/net/tun");
491  goto done;
492  }
493 
494  memset (&ifr, 0, sizeof (ifr));
495  strncpy(ifr.ifr_name, tm->tun_name, sizeof(ifr.ifr_name)-1);
496  ifr.ifr_flags = flags;
497  if (ioctl (tm->dev_net_tun_fd, TUNSETIFF, (void *)&ifr) < 0)
498  {
499  error = clib_error_return_unix (0, "ioctl TUNSETIFF");
500  goto done;
501  }
502 
503  /* Make it persistent, at least until we split. */
504  if (ioctl (tm->dev_net_tun_fd, TUNSETPERSIST, 1) < 0)
505  {
506  error = clib_error_return_unix (0, "TUNSETPERSIST");
507  goto done;
508  }
509 
510  /* Open a provisioning socket */
511  if ((tm->dev_tap_fd = socket(PF_PACKET, SOCK_RAW,
512  htons(ETH_P_ALL))) < 0 )
513  {
514  error = clib_error_return_unix (0, "socket");
515  goto done;
516  }
517 
518  /* Find the interface index. */
519  {
520  struct ifreq ifr;
521  struct sockaddr_ll sll;
522 
523  memset (&ifr, 0, sizeof(ifr));
524  strncpy (ifr.ifr_name, tm->tun_name, sizeof(ifr.ifr_name)-1);
525  if (ioctl (tm->dev_tap_fd, SIOCGIFINDEX, &ifr) < 0 )
526  {
527  error = clib_error_return_unix (0, "ioctl SIOCGIFINDEX");
528  goto done;
529  }
530 
531  /* Bind the provisioning socket to the interface. */
532  memset(&sll, 0, sizeof(sll));
533  sll.sll_family = AF_PACKET;
534  sll.sll_ifindex = ifr.ifr_ifindex;
535  sll.sll_protocol = htons(ETH_P_ALL);
536 
537  if (bind(tm->dev_tap_fd, (struct sockaddr*) &sll, sizeof(sll)) < 0)
538  {
539  error = clib_error_return_unix (0, "bind");
540  goto done;
541  }
542  }
543 
544  /* non-blocking I/O on /dev/tapX */
545  {
546  int one = 1;
547  if (ioctl (tm->dev_net_tun_fd, FIONBIO, &one) < 0)
548  {
549  error = clib_error_return_unix (0, "ioctl FIONBIO");
550  goto done;
551  }
552  }
553 
554  tm->mtu_buffers = (tm->mtu_bytes + (buffer_size - 1)) / buffer_size;
555 
556  ifr.ifr_mtu = tm->mtu_bytes;
557  if (ioctl (tm->dev_tap_fd, SIOCSIFMTU, &ifr) < 0)
558  {
559  error = clib_error_return_unix (0, "ioctl SIOCSIFMTU");
560  goto done;
561  }
562 
563  /* get flags, modify to bring up interface... */
564  if (ioctl (tm->dev_tap_fd, SIOCGIFFLAGS, &ifr) < 0)
565  {
566  error = clib_error_return_unix (0, "ioctl SIOCGIFFLAGS");
567  goto done;
568  }
569 
570  ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
571 
572  if (ioctl (tm->dev_tap_fd, SIOCSIFFLAGS, &ifr) < 0)
573  {
574  error = clib_error_return_unix (0, "ioctl SIOCSIFFLAGS");
575  goto done;
576  }
577 
578  if (is_ether)
579  {
580  if (ioctl (tm->dev_tap_fd, SIOCGIFHWADDR, &ifr) < 0)
581  {
582  error = clib_error_return_unix (0, "ioctl SIOCGIFHWADDR");
583  goto done;
584  }
585  else
586  clib_memcpy (tm->ether_dst_mac, ifr.ifr_hwaddr.sa_data, 6);
587  }
588 
589  if (have_normal_interface)
590  {
591  vnet_main_t *vnm = vnet_get_main();
593  (vnm,
594  tuntap_dev_class.index,
595  0 /* device instance */,
596  tm->ether_dst_mac /* ethernet address */,
597  &tm->hw_if_index,
598  0 /* flag change */);
599  if (error)
600  clib_error_report (error);
601  tm->sw_if_index = tm->hw_if_index;
603  }
604  else
605  {
606  vnet_main_t *vnm = vnet_get_main();
608 
610 
612  (vnm,
613  tuntap_dev_class.index, 0 /* device instance */,
614  tuntap_interface_class.index, 0);
615  hi = vnet_get_hw_interface (vnm, tm->hw_if_index);
616  tm->sw_if_index = hi->sw_if_index;
617 
618  /* Interface is always up. */
623  }
624 
625  {
626  unix_file_t template = {0};
627  template.read_function = tuntap_read_ready;
628  template.file_descriptor = tm->dev_net_tun_fd;
629  tm->unix_file_index = unix_file_add (&unix_main, &template);
630  }
631 
632  done:
633  if (error)
634  {
635  if (tm->dev_net_tun_fd >= 0)
636  close (tm->dev_net_tun_fd);
637  if (tm->dev_tap_fd >= 0)
638  close (tm->dev_tap_fd);
639  }
640 
641  return error;
642 }
643 
645 
646 void
648  uword opaque,
649  u32 sw_if_index,
650  ip4_address_t * address,
651  u32 address_length,
652  u32 if_address_index,
653  u32 is_delete)
654 {
655  tuntap_main_t * tm = &tuntap_main;
656  struct ifreq ifr;
657  subif_address_t subif_addr, * ap;
658  uword * p;
659 
660  /* Tuntap disabled, or using a "normal" interface. */
661  if (tm->have_normal_interface || tm->dev_tap_fd < 0)
662  return;
663 
664  /* See if we already know about this subif */
665  memset (&subif_addr, 0, sizeof (subif_addr));
666  subif_addr.sw_if_index = sw_if_index;
667  clib_memcpy (&subif_addr.addr, address, sizeof (*address));
668 
669  p = mhash_get (&tm->subif_mhash, &subif_addr);
670 
671  if (p)
672  ap = pool_elt_at_index (tm->subifs, p[0]);
673  else
674  {
675  pool_get (tm->subifs, ap);
676  *ap = subif_addr;
677  mhash_set (&tm->subif_mhash, ap, ap - tm->subifs, 0);
678  }
679 
680  /* Use subif pool index to select alias device. */
681  memset (&ifr, 0, sizeof (ifr));
682  snprintf (ifr.ifr_name, sizeof(ifr.ifr_name),
683  "%s:%d", tm->tun_name, (int)(ap - tm->subifs));
684 
685  if (! is_delete)
686  {
687  struct sockaddr_in * sin;
688 
689  sin = (struct sockaddr_in *)&ifr.ifr_addr;
690 
691  /* Set ipv4 address, netmask. */
692  sin->sin_family = AF_INET;
693  clib_memcpy (&sin->sin_addr.s_addr, address, 4);
694  if (ioctl (tm->dev_tap_fd, SIOCSIFADDR, &ifr) < 0)
695  clib_unix_warning ("ioctl SIOCSIFADDR");
696 
697  sin->sin_addr.s_addr = im->fib_masks[address_length];
698  if (ioctl (tm->dev_tap_fd, SIOCSIFNETMASK, &ifr) < 0)
699  clib_unix_warning ("ioctl SIOCSIFNETMASK");
700  }
701  else
702  {
703  mhash_unset (&tm->subif_mhash, &subif_addr, 0 /* old value ptr */);
704  pool_put (tm->subifs, ap);
705  }
706 
707  /* get flags, modify to bring up interface... */
708  if (ioctl (tm->dev_tap_fd, SIOCGIFFLAGS, &ifr) < 0)
709  clib_unix_warning ("ioctl SIOCGIFFLAGS");
710 
711  if (is_delete)
712  ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
713  else
714  ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
715 
716  if (ioctl (tm->dev_tap_fd, SIOCSIFFLAGS, &ifr) < 0)
717  clib_unix_warning ("ioctl SIOCSIFFLAGS");
718 }
719 
720 /*
721  * $$$$ gross workaround for a known #include bug
722  * #include <linux/ipv6.h> causes multiple definitions if
723  * netinet/in.h is also included.
724  */
725 struct in6_ifreq {
726  struct in6_addr ifr6_addr;
729 };
730 
731 /*
732  * Both the v6 interface address API and the way ifconfig
733  * displays subinterfaces differ from their v4 couterparts.
734  * The code given here seems to work but YMMV.
735  */
736 void
738  uword opaque,
739  u32 sw_if_index,
740  ip6_address_t * address,
741  u32 address_length,
742  u32 if_address_index,
743  u32 is_delete)
744 {
745  tuntap_main_t * tm = &tuntap_main;
746  struct ifreq ifr;
747  struct in6_ifreq ifr6;
748  subif_address_t subif_addr, * ap;
749  uword * p;
750 
751  /* Tuntap disabled, or using a "normal" interface. */
752  if (tm->have_normal_interface || tm->dev_tap_fd < 0)
753  return;
754 
755  /* See if we already know about this subif */
756  memset (&subif_addr, 0, sizeof (subif_addr));
757  subif_addr.sw_if_index = sw_if_index;
758  subif_addr.is_v6 = 1;
759  clib_memcpy (&subif_addr.addr, address, sizeof (*address));
760 
761  p = mhash_get (&tm->subif_mhash, &subif_addr);
762 
763  if (p)
764  ap = pool_elt_at_index (tm->subifs, p[0]);
765  else
766  {
767  pool_get (tm->subifs, ap);
768  *ap = subif_addr;
769  mhash_set (&tm->subif_mhash, ap, ap - tm->subifs, 0);
770  }
771 
772  /* Use subif pool index to select alias device. */
773  memset (&ifr, 0, sizeof (ifr));
774  memset (&ifr6, 0, sizeof (ifr6));
775  snprintf (ifr.ifr_name, sizeof(ifr.ifr_name),
776  "%s:%d", tm->tun_name, (int)(ap - tm->subifs));
777 
778  if (! is_delete)
779  {
780  int sockfd = socket (AF_INET6, SOCK_STREAM, 0);
781  if (sockfd < 0)
782  clib_unix_warning ("get ifindex socket");
783 
784  if (ioctl (sockfd, SIOGIFINDEX, &ifr) < 0)
785  clib_unix_warning ("get ifindex");
786 
787  ifr6.ifr6_ifindex = ifr.ifr_ifindex;
788  ifr6.ifr6_prefixlen = address_length;
789  clib_memcpy (&ifr6.ifr6_addr, address, 16);
790 
791  if (ioctl (sockfd, SIOCSIFADDR, &ifr6) < 0)
792  clib_unix_warning ("set address");
793 
794  close (sockfd);
795  }
796  else
797  {
798  int sockfd = socket (AF_INET6, SOCK_STREAM, 0);
799  if (sockfd < 0)
800  clib_unix_warning ("get ifindex socket");
801 
802  if (ioctl (sockfd, SIOGIFINDEX, &ifr) < 0)
803  clib_unix_warning ("get ifindex");
804 
805  ifr6.ifr6_ifindex = ifr.ifr_ifindex;
806  ifr6.ifr6_prefixlen = address_length;
807  clib_memcpy (&ifr6.ifr6_addr, address, 16);
808 
809  if (ioctl (sockfd, SIOCDIFADDR, &ifr6) < 0)
810  clib_unix_warning ("del address");
811 
812  close (sockfd);
813 
814  mhash_unset (&tm->subif_mhash, &subif_addr, 0 /* old value ptr */);
815  pool_put (tm->subifs, ap);
816  }
817 }
818 
819 static void
821  vlib_node_runtime_t * node,
822  vlib_frame_t * frame)
823 {
824  tuntap_tx (vm, node, frame);
825  vlib_frame_free (vm, node, frame);
826 }
827 
828 static void
830  vlib_node_runtime_t * node,
831  vlib_frame_t * frame)
832 {
833  u32 * buffers = vlib_frame_args (frame);
834  uword n_packets = frame->n_vectors;
835  vlib_buffer_free (vm, buffers, n_packets);
836  vlib_frame_free (vm, node, frame);
837 }
838 
840  .name = "tuntap",
841 };
842 
843 static u8 * format_tuntap_interface_name (u8 * s, va_list * args)
844 {
845  u32 i = va_arg (*args, u32);
846 
847  s = format (s, "tuntap-%d", i);
848  return s;
849 }
850 
851 static uword
853  vlib_node_runtime_t * node,
854  vlib_frame_t * frame)
855 {
856  tuntap_main_t * tm = &tuntap_main;
857  u32 * buffers = vlib_frame_args (frame);
858  uword n_buffers = frame->n_vectors;
859 
860  /* Normal interface transmit happens only on the normal interface... */
861  if (tm->have_normal_interface)
862  return tuntap_tx (vm, node, frame);
863 
864  vlib_buffer_free (vm, buffers, n_buffers);
865  return n_buffers;
866 }
867 
869  .name = "tuntap",
870  .tx_function = tuntap_intfc_tx,
871  .format_device_name = format_tuntap_interface_name,
872 };
873 
874 static clib_error_t *
876 {
877  clib_error_t * error;
878  ip4_main_t * im4 = &ip4_main;
879  ip6_main_t * im6 = &ip6_main;
882  tuntap_main_t * tm = &tuntap_main;
883 
884  error = vlib_call_init_function (vm, ip4_init);
885  if (error)
886  return error;
887 
888  mhash_init (&tm->subif_mhash, sizeof (u32), sizeof(subif_address_t));
889 
891  cb4.function_opaque = 0;
893 
895  cb6.function_opaque = 0;
897 
898  return 0;
899 }
900 
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:394
static clib_error_t * tuntap_exit(vlib_main_t *vm)
Definition: tuntap.c:400
vmrglw vmrglh hi
Definition: mhash.h:46
static uword tuntap_rx(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: tuntap.c:196
vlib_node_registration_t tuntap_tx_node
(constructor) VLIB_REGISTER_NODE (tuntap_tx_node)
Definition: tuntap.c:180
void(* os_punt_frame)(struct vlib_main_t *vm, struct vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: main.h:128
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
#define VLIB_BUFFER_TRACE_TRAJECTORY
Compile time buffer trajectory tracing option Turn this on if you run into "bad monkey" contexts...
Definition: buffer.h:378
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:942
clib_error_t * vnet_hw_interface_set_flags(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
Definition: interface.c:454
ip4_add_del_interface_address_callback_t * add_del_interface_address_callbacks
Definition: ip4.h:150
unix_file_function_t * read_function
Definition: unix.h:61
void tuntap_ip4_add_del_interface_address(ip4_main_t *im, uword opaque, u32 sw_if_index, ip4_address_t *address, u32 address_length, u32 if_address_index, u32 is_delete)
Definition: tuntap.c:647
dpdk_main_t dpdk_main
Definition: dpdk.h:415
vnet_interface_main_t interface_main
Definition: vnet.h:62
#define UNFORMAT_END_OF_INPUT
Definition: format.h:142
uword mhash_unset(mhash_t *h, void *key, uword *old_value)
Definition: mhash.c:350
always_inline uword unix_file_add(unix_main_t *um, unix_file_t *template)
Definition: unix.h:131
int ifr6_ifindex
Definition: tuntap.c:728
always_inline void vlib_set_trace_count(vlib_main_t *vm, vlib_node_runtime_t *rt, u32 count)
Definition: trace_funcs.h:160
mhash_t subif_mhash
Definition: tuntap.c:99
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:480
char * tun_name
Definition: tuntap.c:93
always_inline void vlib_node_set_interrupt_pending(vlib_main_t *vm, u32 node_index)
Definition: node_funcs.h:134
always_inline uword mhash_set(mhash_t *h, void *key, uword new_value, uword *old_value)
Definition: mhash.h:111
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:519
#define clib_error_report(e)
Definition: error.h:126
#define VNET_HW_INTERFACE_FLAG_LINK_UP
Definition: interface.h:241
struct _vnet_device_class vnet_device_class_t
vlib_error_t * errors
Definition: node.h:378
#define pool_get(P, E)
Definition: pool.h:186
struct in6_addr ifr6_addr
Definition: tuntap.c:726
#define vec_alloc(V, N)
Allocate space for N more elements (no header, unspecified alignment)
Definition: vec.h:237
int dev_net_tun_fd
Definition: tuntap.c:77
always_inline void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:184
always_inline vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
always_inline uword unformat_check_input(unformat_input_t *i)
Definition: format.h:168
int dev_tap_fd
Definition: tuntap.c:77
vnet_main_t * vnet_get_main(void)
Definition: misc.c:45
u32 hw_if_index
Definition: tuntap.c:104
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:77
always_inline u32 vlib_get_trace_count(vlib_main_t *vm, vlib_node_runtime_t *rt)
Definition: trace_funcs.h:144
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:109
static clib_error_t * ip4_init(vlib_main_t *vm)
Definition: ip4_input.c:392
vlib_combined_counter_main_t * combined_sw_if_counters
Definition: interface.h:458
always_inline void vlib_increment_combined_counter(vlib_combined_counter_main_t *cm, u32 cpu_index, u32 index, u32 packet_increment, u32 byte_increment)
Definition: counter.h:210
void vlib_buffer_free_no_next(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Free buffers, does not free the buffer chain for each buffer.
Definition: buffer.c:1067
u8 pre_data[VLIB_BUFFER_PRE_DATA_SIZE]
Space for inserting data before buffer start.
Definition: buffer.h:142
static vnet_device_class_t tuntap_dev_class
Definition: tuntap.c:42
#define clib_warning(format, args...)
Definition: error.h:59
static clib_error_t * tuntap_read_ready(unix_file_t *uf)
Definition: tuntap.c:387
#define vlib_call_init_function(vm, x)
Definition: init.h:159
u32 vnet_register_interface(vnet_main_t *vnm, u32 dev_class_index, u32 dev_instance, u32 hw_class_index, u32 hw_instance)
Definition: interface.c:583
static u8 * format_tuntap_interface_name(u8 *s, va_list *args)
Definition: tuntap.c:843
#define VLIB_BUFFER_NEXT_PRESENT
Definition: buffer.h:93
#define pool_elt_at_index(p, i)
Definition: pool.h:346
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.c:1060
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:81
subif_address_t * subifs
Definition: tuntap.c:96
void vlib_frame_free(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_frame_t *f)
Definition: main.c:211
uword os_get_cpu_number(void)
Definition: unix-misc.c:206
#define clib_error_return_unix(e, args...)
Definition: error.h:115
#define pool_put(P, E)
Definition: pool.h:200
static tuntap_main_t tuntap_main
Definition: tuntap.c:108
u32 vlib_buffer_alloc_from_free_list(vlib_main_t *vm, u32 *buffers, u32 n_buffers, u32 free_list_index)
Allocate buffers from specific freelist into supplied array.
Definition: buffer.c:782
#define PREDICT_FALSE(x)
Definition: clib.h:97
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:116
vnet_main_t vnet_main
Definition: misc.c:42
#define VLIB_FRAME_SIZE
Definition: node.h:292
always_inline void vlib_buffer_reset(vlib_buffer_t *b)
Reset current header & length to state they were in when packet was received.
Definition: buffer.h:211
always_inline void * vlib_frame_args(vlib_frame_t *f)
Definition: node_funcs.h:209
static uword tuntap_intfc_tx(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: tuntap.c:852
ip6_add_del_interface_address_callback_t * add_del_interface_address_callbacks
Definition: ip6.h:161
struct iovec * iovecs
Definition: tuntap.c:70
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:129
void tuntap_ip6_add_del_interface_address(ip6_main_t *im, uword opaque, u32 sw_if_index, ip6_address_t *address, u32 address_length, u32 if_address_index, u32 is_delete)
Definition: tuntap.c:737
static void tuntap_nopunt_frame(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: tuntap.c:829
void mhash_init(mhash_t *h, uword n_value_bytes, uword n_key_bytes)
Definition: mhash.c:169
u16 n_vectors
Definition: node.h:307
ip4_add_del_interface_address_function_t * function
Definition: ip4.h:100
u8 addr[16]
Definition: tuntap.c:65
#define VLIB_MAIN_LOOP_EXIT_FUNCTION(x)
Definition: init.h:113
#define clib_memcpy(a, b, c)
Definition: string.h:63
#define clib_unix_warning(format, args...)
Definition: error.h:68
static void tuntap_punt_frame(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: tuntap.c:820
always_inline vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
#define VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX
Definition: buffer.h:296
ip6_add_del_interface_address_function_t * function
Definition: ip6.h:101
#define VNET_SW_INTERFACE_FLAG_ADMIN_UP
Definition: interface.h:373
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u32 mtu_buffers
Definition: tuntap.c:90
u8 ether_dst_mac[6]
Definition: tuntap.c:87
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:87
#define vnet_buffer(b)
Definition: buffer.h:300
ip6_main_t ip6_main
Definition: ip6_forward.c:2490
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:405
u32 mtu_bytes
Definition: tuntap.c:90
vlib_node_registration_t tuntap_rx_node
(constructor) VLIB_REGISTER_NODE (tuntap_rx_node)
Definition: tuntap.c:368
u32 next_buffer
Next buffer for this linked-list of buffers.
Definition: buffer.h:112
clib_error_t * ethernet_register_interface(vnet_main_t *vnm, u32 dev_class_index, u32 dev_instance, u8 *address, u32 *hw_if_index_return, ethernet_flag_change_function_t flag_change)
Definition: interface.c:157
u32 unix_file_index
Definition: tuntap.c:101
int have_normal_interface
Definition: tuntap.c:84
u32 * rx_buffers
Definition: tuntap.c:74
unix_main_t unix_main
Definition: main.c:57
u32 ifr6_prefixlen
Definition: tuntap.c:727
VNET_DEVICE_CLASS(tuntap_dev_class, static)
int is_ether
Definition: tuntap.c:80
u64 uword
Definition: types.h:112
static uword tuntap_tx(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: tuntap.c:122
Definition: defs.h:46
static clib_error_t * tuntap_config(vlib_main_t *vm, unformat_input_t *input)
Definition: tuntap.c:439
i64 word
Definition: types.h:111
struct _vnet_hw_interface_class vnet_hw_interface_class_t
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
always_inline vnet_sw_interface_t * vnet_get_sw_interface(vnet_main_t *vnm, u32 sw_if_index)
Definition: unix.h:49
always_inline void vlib_set_next_frame_buffer(vlib_main_t *vm, vlib_node_runtime_t *node, u32 next_index, u32 buffer_index)
Definition: node_funcs.h:292
#define VLIB_BUFFER_DATA_SIZE
Definition: buffer.h:55
u32 vlib_buffer_free_list_index
Definition: dpdk.h:329
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:140
ip4_main_t ip4_main
Definition: ip4_forward.c:1394
u8 data[0]
Packet data.
Definition: buffer.h:150
clib_error_t * vnet_sw_interface_set_flags(vnet_main_t *vnm, u32 sw_if_index, u32 flags)
Definition: interface.c:462
u32 sw_if_index
Definition: tuntap.c:104
vhost_vring_addr_t addr
Definition: vhost-user.h:78
static clib_error_t * tuntap_init(vlib_main_t *vm)
Definition: tuntap.c:875
#define clib_error_return(e, args...)
Definition: error.h:112
struct _unformat_input_t unformat_input_t
VNET_HW_INTERFACE_CLASS(tuntap_interface_class, static)
static vnet_hw_interface_class_t tuntap_interface_class
Definition: tuntap.c:43
static char * tuntap_rx_error_strings[]
Definition: tuntap.c:364
u32 flags
Definition: vhost-user.h:73
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:84
always_inline void vlib_trace_buffer(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, vlib_buffer_t *b, int follow_chain)
Definition: trace_funcs.h:106
always_inline vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:69
u32 sw_if_index
Definition: tuntap.c:63
always_inline uword * mhash_get(mhash_t *h, void *key)
Definition: mhash.h:104
Definition: defs.h:45
u32 fib_masks[33]
Definition: ip4.h:134