2 *------------------------------------------------------------------
3 * tuntap.c - kernel stack (reverse) punt/inject path
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:
10 * http://www.apache.org/licenses/LICENSE-2.0
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 *------------------------------------------------------------------
21 * @brief TunTap Kernel stack (reverse) punt/inject path.
23 * This driver runs in one of two distinct modes:
24 * - "punt/inject" mode, where we send pkts not otherwise processed
25 * by the forwarding to the Linux kernel stack, and
27 * - "normal interface" mode, where we treat the Linux kernel stack
30 * By default, we select punt/inject mode.
33 #include <fcntl.h> /* for open */
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
37 #include <sys/types.h>
38 #include <sys/uio.h> /* for iovec */
39 #include <netinet/in.h>
41 #include <linux/if_arp.h>
42 #include <linux/if_tun.h>
44 #include <vlib/vlib.h>
45 #include <vlib/unix/unix.h>
47 #include <vnet/ip/ip.h>
49 #include <vnet/ethernet/ethernet.h>
50 #include <vnet/feature/feature.h>
53 #include <vnet/devices/dpdk/dpdk.h>
56 static vnet_device_class_t tuntap_dev_class;
57 static vnet_hw_interface_class_t tuntap_interface_class;
59 static void tuntap_punt_frame (vlib_main_t * vm,
60 vlib_node_runtime_t * node,
61 vlib_frame_t * frame);
62 static void tuntap_nopunt_frame (vlib_main_t * vm,
63 vlib_node_runtime_t * node,
64 vlib_frame_t * frame);
73 * @brief TUNTAP node main state
76 /** Vector of iovecs for readv/writev calls. */
77 struct iovec * iovecs;
79 /** Vector of VLIB rx buffers to use. We allocate them in blocks
80 of VLIB_FRAME_SIZE (256). */
83 /** File descriptors for /dev/net/tun and provisioning socket. */
84 int dev_net_tun_fd, dev_tap_fd;
86 /** Create a "tap" [ethernet] encaps device */
89 /** 1 if a "normal" routed intfc, 0 if a punt/inject interface */
91 int have_normal_interface;
93 /** tap device destination MAC address. Required, or Linux drops pkts */
96 /** Interface MTU in bytes and # of default sized buffers. */
97 u32 mtu_bytes, mtu_buffers;
99 /** Linux interface name for tun device. */
102 /** Pool of subinterface addresses */
103 subif_address_t *subifs;
105 /** Hash for subif addresses */
108 /** Unix file index */
111 /** For the "normal" interface, if configured */
112 u32 hw_if_index, sw_if_index;
116 static tuntap_main_t tuntap_main = {
119 /** Suitable defaults for an Ethernet-like tun/tap device */
120 .mtu_bytes = 4096 + 256,
127 * Output node, writes the buffers comprising the incoming frame
128 * to the tun/tap device, aka hands them to the Linux kernel stack.
130 * @param *vm - vlib_main_t
131 * @param *node - vlib_node_runtime_t
132 * @param *frame - vlib_frame_t
138 tuntap_tx (vlib_main_t * vm,
139 vlib_node_runtime_t * node,
140 vlib_frame_t * frame)
142 u32 * buffers = vlib_frame_args (frame);
143 uword n_packets = frame->n_vectors;
144 tuntap_main_t * tm = &tuntap_main;
145 vnet_main_t *vnm = vnet_get_main ();
146 vnet_interface_main_t *im = &vnm->interface_main;
150 for (i = 0; i < n_packets; i++)
156 b = vlib_get_buffer (vm, buffers[i]);
158 if (tm->is_ether && (!tm->have_normal_interface))
160 vlib_buffer_reset(b);
161 clib_memcpy (vlib_buffer_get_current (b), tm->ether_dst_mac, 6);
164 /* Re-set iovecs if present. */
166 _vec_len (tm->iovecs) = 0;
168 /** VLIB buffer chain -> Unix iovec(s). */
169 vec_add2 (tm->iovecs, iov, 1);
170 iov->iov_base = b->data + b->current_data;
171 iov->iov_len = l = b->current_length;
173 if (PREDICT_FALSE (b->flags & VLIB_BUFFER_NEXT_PRESENT))
176 b = vlib_get_buffer (vm, b->next_buffer);
178 vec_add2 (tm->iovecs, iov, 1);
180 iov->iov_base = b->data + b->current_data;
181 iov->iov_len = b->current_length;
182 l += b->current_length;
183 } while (b->flags & VLIB_BUFFER_NEXT_PRESENT);
186 if (writev (tm->dev_net_tun_fd, tm->iovecs, vec_len (tm->iovecs)) < l)
187 clib_unix_warning ("writev");
192 /* Update tuntap interface output stats. */
193 vlib_increment_combined_counter (im->combined_sw_if_counters
194 + VNET_INTERFACE_COUNTER_TX,
196 tm->sw_if_index, n_packets, n_bytes);
199 /** The normal interface path flattens the buffer chain */
200 if (tm->have_normal_interface)
201 vlib_buffer_free_no_next (vm, buffers, n_packets);
203 vlib_buffer_free (vm, buffers, n_packets);
208 VLIB_REGISTER_NODE (tuntap_tx_node,static) = {
209 .function = tuntap_tx,
211 .type = VLIB_NODE_TYPE_INTERNAL,
216 TUNTAP_RX_NEXT_IP4_INPUT,
217 TUNTAP_RX_NEXT_IP6_INPUT,
218 TUNTAP_RX_NEXT_ETHERNET_INPUT,
224 * @brief TUNTAP receive node
227 * @param *vm - vlib_main_t
228 * @param *node - vlib_node_runtime_t
229 * @param *frame - vlib_frame_t
235 tuntap_rx (vlib_main_t * vm,
236 vlib_node_runtime_t * node,
237 vlib_frame_t * frame)
239 tuntap_main_t * tm = &tuntap_main;
242 const uword buffer_size = VLIB_BUFFER_DATA_SIZE;
244 u32 free_list_index = VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX;
246 dpdk_main_t * dm = &dpdk_main;
247 u32 free_list_index = dm->vlib_buffer_free_list_index;
248 struct rte_mbuf *first_mb = NULL, *prev_mb = NULL;
251 /** Make sure we have some RX buffers. */
253 uword n_left = vec_len (tm->rx_buffers);
256 if (n_left < VLIB_FRAME_SIZE / 2)
258 if (! tm->rx_buffers)
259 vec_alloc (tm->rx_buffers, VLIB_FRAME_SIZE);
261 n_alloc = vlib_buffer_alloc_from_free_list
262 (vm, tm->rx_buffers + n_left, VLIB_FRAME_SIZE - n_left,
264 _vec_len (tm->rx_buffers) = n_left + n_alloc;
268 /** Allocate RX buffers from end of rx_buffers.
269 Turn them into iovecs to pass to readv. */
271 uword i_rx = vec_len (tm->rx_buffers) - 1;
273 word i, n_bytes_left, n_bytes_in_packet;
275 /** We should have enough buffers left for an MTU sized packet. */
276 ASSERT (vec_len (tm->rx_buffers) >= tm->mtu_buffers);
278 vec_validate (tm->iovecs, tm->mtu_buffers - 1);
279 for (i = 0; i < tm->mtu_buffers; i++)
281 b = vlib_get_buffer (vm, tm->rx_buffers[i_rx - i]);
282 tm->iovecs[i].iov_base = b->data;
283 tm->iovecs[i].iov_len = buffer_size;
286 n_bytes_left = readv (tm->dev_net_tun_fd, tm->iovecs, tm->mtu_buffers);
287 n_bytes_in_packet = n_bytes_left;
288 if (n_bytes_left <= 0)
291 clib_unix_warning ("readv %d", n_bytes_left);
295 bi = tm->rx_buffers[i_rx];
300 struct rte_mbuf * mb;
302 b = vlib_get_buffer (vm, tm->rx_buffers[i_rx]);
304 mb = rte_mbuf_from_vlib_buffer(b);
306 if (first_mb == NULL)
317 b->current_length = n_bytes_left < buffer_size ? n_bytes_left : buffer_size;
319 n_bytes_left -= buffer_size;
321 rte_pktmbuf_data_len (mb) = b->current_length;
322 mb->data_off = RTE_PKTMBUF_HEADROOM + b->current_data;
325 if (n_bytes_left <= 0)
328 rte_pktmbuf_pkt_len (first_mb) = n_bytes_in_packet;
334 b->flags |= VLIB_BUFFER_NEXT_PRESENT;
335 b->next_buffer = tm->rx_buffers[i_rx];
341 /** Interface counters for tuntap interface. */
342 vlib_increment_combined_counter
343 (vnet_main.interface_main.combined_sw_if_counters
344 + VNET_INTERFACE_COUNTER_RX,
347 1, n_bytes_in_packet);
349 _vec_len (tm->rx_buffers) = i_rx;
352 b = vlib_get_buffer (vm, bi);
356 uword n_trace = vlib_get_trace_count (vm, node);
358 vnet_buffer (b)->sw_if_index[VLIB_RX] = tm->sw_if_index;
359 vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32)~0;
362 * Turn this on if you run into
363 * "bad monkey" contexts, and you want to know exactly
364 * which nodes they've visited...
366 if (VLIB_BUFFER_TRACE_TRAJECTORY)
369 b->error = node->errors[0];
373 next_index = TUNTAP_RX_NEXT_ETHERNET_INPUT;
376 switch (b->data[0] & 0xf0)
379 next_index = TUNTAP_RX_NEXT_IP4_INPUT;
382 next_index = TUNTAP_RX_NEXT_IP6_INPUT;
385 next_index = TUNTAP_RX_NEXT_DROP;
389 /* The linux kernel couldn't care less if our interface is up */
390 if (tm->have_normal_interface)
392 vnet_main_t *vnm = vnet_get_main();
393 vnet_sw_interface_t * si;
394 si = vnet_get_sw_interface (vnm, tm->sw_if_index);
395 if (!(si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
396 next_index = TUNTAP_RX_NEXT_DROP;
399 vnet_feature_device_input_redirect_x1 (node, tm->hw_if_index, &next_index, b, 0);
401 vlib_set_next_frame_buffer (vm, node, next_index, bi);
405 vlib_trace_buffer (vm, node, next_index,
406 b, /* follow_chain */ 1);
407 vlib_set_trace_count (vm, node, n_trace - 1);
415 * @brief TUNTAP_RX error strings
417 static char * tuntap_rx_error_strings[] = {
418 "unknown packet type",
421 VLIB_REGISTER_NODE (tuntap_rx_node,static) = {
422 .function = tuntap_rx,
424 .type = VLIB_NODE_TYPE_INPUT,
425 .state = VLIB_NODE_STATE_INTERRUPT,
428 .error_strings = tuntap_rx_error_strings,
430 .n_next_nodes = TUNTAP_RX_N_NEXT,
432 [TUNTAP_RX_NEXT_IP4_INPUT] = "ip4-input-no-checksum",
433 [TUNTAP_RX_NEXT_IP6_INPUT] = "ip6-input",
434 [TUNTAP_RX_NEXT_DROP] = "error-drop",
435 [TUNTAP_RX_NEXT_ETHERNET_INPUT] = "ethernet-input",
440 * @brief Gets called when file descriptor is ready from epoll.
442 * @param *uf - unix_file_t
444 * @return error - clib_error_t
446 static clib_error_t * tuntap_read_ready (unix_file_t * uf)
448 vlib_main_t * vm = vlib_get_main();
449 vlib_node_set_interrupt_pending (vm, tuntap_rx_node.index);
454 * @brief Clean up the tun/tap device
456 * @param *vm - vlib_main_t
458 * @return error - clib_error_t
461 static clib_error_t *
462 tuntap_exit (vlib_main_t * vm)
464 tuntap_main_t *tm = &tuntap_main;
469 if (! tm->dev_net_tun_fd || tm->dev_net_tun_fd < 0)
472 sfd = socket (AF_INET, SOCK_STREAM, 0);
474 clib_unix_warning("provisioning socket");
476 memset(&ifr, 0, sizeof (ifr));
477 strncpy (ifr.ifr_name, tm->tun_name, sizeof (ifr.ifr_name)-1);
479 /* get flags, modify to bring down interface... */
480 if (ioctl (sfd, SIOCGIFFLAGS, &ifr) < 0)
481 clib_unix_warning ("SIOCGIFFLAGS");
483 ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
485 if (ioctl (sfd, SIOCSIFFLAGS, &ifr) < 0)
486 clib_unix_warning ("SIOCSIFFLAGS");
488 /* Turn off persistence */
489 if (ioctl (tm->dev_net_tun_fd, TUNSETPERSIST, 0) < 0)
490 clib_unix_warning ("TUNSETPERSIST");
491 close(tm->dev_tap_fd);
492 if (tm->dev_net_tun_fd >= 0)
493 close(tm->dev_net_tun_fd);
500 VLIB_MAIN_LOOP_EXIT_FUNCTION (tuntap_exit);
503 * @brief CLI function for tun/tap config
505 * @param *vm - vlib_main_t
506 * @param *input - unformat_input_t
508 * @return error - clib_error_t
511 static clib_error_t *
512 tuntap_config (vlib_main_t * vm, unformat_input_t * input)
514 tuntap_main_t *tm = &tuntap_main;
515 clib_error_t * error = 0;
518 int flags = IFF_TUN | IFF_NO_PI;
519 int is_enabled = 0, is_ether = 0, have_normal_interface = 0;
520 const uword buffer_size = VLIB_BUFFER_DATA_SIZE;
522 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
524 if (unformat (input, "mtu %d", &tm->mtu_bytes))
526 else if (unformat (input, "enable"))
528 else if (unformat (input, "disable"))
530 else if (unformat (input, "ethernet") ||
531 unformat (input, "ether"))
533 else if (unformat (input, "have-normal-interface") ||
534 unformat (input, "have-normal"))
535 have_normal_interface = 1;
536 else if (unformat (input, "name %s", &name))
537 tm->tun_name = (char *) name;
539 return clib_error_return (0, "unknown input `%U'",
540 format_unformat_error, input);
543 tm->dev_net_tun_fd = -1;
551 clib_warning ("tuntap disabled: must be superuser");
555 tm->is_ether = is_ether;
556 tm->have_normal_interface = have_normal_interface;
559 flags = IFF_TAP | IFF_NO_PI;
561 if ((tm->dev_net_tun_fd = open ("/dev/net/tun", O_RDWR)) < 0)
563 error = clib_error_return_unix (0, "open /dev/net/tun");
567 memset (&ifr, 0, sizeof (ifr));
568 strncpy(ifr.ifr_name, tm->tun_name, sizeof(ifr.ifr_name)-1);
569 ifr.ifr_flags = flags;
570 if (ioctl (tm->dev_net_tun_fd, TUNSETIFF, (void *)&ifr) < 0)
572 error = clib_error_return_unix (0, "ioctl TUNSETIFF");
576 /* Make it persistent, at least until we split. */
577 if (ioctl (tm->dev_net_tun_fd, TUNSETPERSIST, 1) < 0)
579 error = clib_error_return_unix (0, "TUNSETPERSIST");
583 /* Open a provisioning socket */
584 if ((tm->dev_tap_fd = socket(PF_PACKET, SOCK_RAW,
585 htons(ETH_P_ALL))) < 0 )
587 error = clib_error_return_unix (0, "socket");
591 /* Find the interface index. */
594 struct sockaddr_ll sll;
596 memset (&ifr, 0, sizeof(ifr));
597 strncpy (ifr.ifr_name, tm->tun_name, sizeof(ifr.ifr_name)-1);
598 if (ioctl (tm->dev_tap_fd, SIOCGIFINDEX, &ifr) < 0 )
600 error = clib_error_return_unix (0, "ioctl SIOCGIFINDEX");
604 /* Bind the provisioning socket to the interface. */
605 memset(&sll, 0, sizeof(sll));
606 sll.sll_family = AF_PACKET;
607 sll.sll_ifindex = ifr.ifr_ifindex;
608 sll.sll_protocol = htons(ETH_P_ALL);
610 if (bind(tm->dev_tap_fd, (struct sockaddr*) &sll, sizeof(sll)) < 0)
612 error = clib_error_return_unix (0, "bind");
617 /* non-blocking I/O on /dev/tapX */
620 if (ioctl (tm->dev_net_tun_fd, FIONBIO, &one) < 0)
622 error = clib_error_return_unix (0, "ioctl FIONBIO");
627 tm->mtu_buffers = (tm->mtu_bytes + (buffer_size - 1)) / buffer_size;
629 ifr.ifr_mtu = tm->mtu_bytes;
630 if (ioctl (tm->dev_tap_fd, SIOCSIFMTU, &ifr) < 0)
632 error = clib_error_return_unix (0, "ioctl SIOCSIFMTU");
636 /* get flags, modify to bring up interface... */
637 if (ioctl (tm->dev_tap_fd, SIOCGIFFLAGS, &ifr) < 0)
639 error = clib_error_return_unix (0, "ioctl SIOCGIFFLAGS");
643 ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
645 if (ioctl (tm->dev_tap_fd, SIOCSIFFLAGS, &ifr) < 0)
647 error = clib_error_return_unix (0, "ioctl SIOCSIFFLAGS");
653 if (ioctl (tm->dev_tap_fd, SIOCGIFHWADDR, &ifr) < 0)
655 error = clib_error_return_unix (0, "ioctl SIOCGIFHWADDR");
659 clib_memcpy (tm->ether_dst_mac, ifr.ifr_hwaddr.sa_data, 6);
662 if (have_normal_interface)
664 vnet_main_t *vnm = vnet_get_main();
665 error = ethernet_register_interface
667 tuntap_dev_class.index,
668 0 /* device instance */,
669 tm->ether_dst_mac /* ethernet address */,
671 0 /* flag change */);
673 clib_error_report (error);
674 tm->sw_if_index = tm->hw_if_index;
675 vm->os_punt_frame = tuntap_nopunt_frame;
679 vnet_main_t *vnm = vnet_get_main();
680 vnet_hw_interface_t * hi;
682 vm->os_punt_frame = tuntap_punt_frame;
684 tm->hw_if_index = vnet_register_interface
686 tuntap_dev_class.index, 0 /* device instance */,
687 tuntap_interface_class.index, 0);
688 hi = vnet_get_hw_interface (vnm, tm->hw_if_index);
689 tm->sw_if_index = hi->sw_if_index;
691 /* Interface is always up. */
692 vnet_hw_interface_set_flags (vnm, tm->hw_if_index,
693 VNET_HW_INTERFACE_FLAG_LINK_UP);
694 vnet_sw_interface_set_flags (vnm, tm->sw_if_index,
695 VNET_SW_INTERFACE_FLAG_ADMIN_UP);
699 unix_file_t template = {0};
700 template.read_function = tuntap_read_ready;
701 template.file_descriptor = tm->dev_net_tun_fd;
702 tm->unix_file_index = unix_file_add (&unix_main, &template);
708 if (tm->dev_net_tun_fd >= 0)
709 close (tm->dev_net_tun_fd);
710 if (tm->dev_tap_fd >= 0)
711 close (tm->dev_tap_fd);
717 VLIB_CONFIG_FUNCTION (tuntap_config, "tuntap");
720 * @brief Add or Del IP4 address to tun/tap interface
722 * @param *im - ip4_main_t
723 * @param opaque - uword
724 * @param sw_if_index - u32
725 * @param *address - ip4_address_t
726 * @param is_delete - u32
730 tuntap_ip4_add_del_interface_address (ip4_main_t * im,
733 ip4_address_t * address,
735 u32 if_address_index,
738 tuntap_main_t * tm = &tuntap_main;
740 subif_address_t subif_addr, * ap;
743 /** Tuntap disabled, or using a "normal" interface. */
744 if (tm->have_normal_interface || tm->dev_tap_fd < 0)
747 /** See if we already know about this subif */
748 memset (&subif_addr, 0, sizeof (subif_addr));
749 subif_addr.sw_if_index = sw_if_index;
750 clib_memcpy (&subif_addr.addr, address, sizeof (*address));
752 p = mhash_get (&tm->subif_mhash, &subif_addr);
755 ap = pool_elt_at_index (tm->subifs, p[0]);
758 pool_get (tm->subifs, ap);
760 mhash_set (&tm->subif_mhash, ap, ap - tm->subifs, 0);
763 /* Use subif pool index to select alias device. */
764 memset (&ifr, 0, sizeof (ifr));
765 snprintf (ifr.ifr_name, sizeof(ifr.ifr_name),
766 "%s:%d", tm->tun_name, (int)(ap - tm->subifs));
770 struct sockaddr_in * sin;
772 sin = (struct sockaddr_in *)&ifr.ifr_addr;
774 /* Set ipv4 address, netmask. */
775 sin->sin_family = AF_INET;
776 clib_memcpy (&sin->sin_addr.s_addr, address, 4);
777 if (ioctl (tm->dev_tap_fd, SIOCSIFADDR, &ifr) < 0)
778 clib_unix_warning ("ioctl SIOCSIFADDR");
780 sin->sin_addr.s_addr = im->fib_masks[address_length];
781 if (ioctl (tm->dev_tap_fd, SIOCSIFNETMASK, &ifr) < 0)
782 clib_unix_warning ("ioctl SIOCSIFNETMASK");
786 mhash_unset (&tm->subif_mhash, &subif_addr, 0 /* old value ptr */);
787 pool_put (tm->subifs, ap);
790 /* get flags, modify to bring up interface... */
791 if (ioctl (tm->dev_tap_fd, SIOCGIFFLAGS, &ifr) < 0)
792 clib_unix_warning ("ioctl SIOCGIFFLAGS");
795 ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
797 ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
799 if (ioctl (tm->dev_tap_fd, SIOCSIFFLAGS, &ifr) < 0)
800 clib_unix_warning ("ioctl SIOCSIFFLAGS");
804 * @brief workaround for a known include file bug.
805 * including @c <linux/ipv6.h> causes multiple definitions if
806 * @c <netinet/in.h is also included.
809 struct in6_addr ifr6_addr;
815 * @brief Add or Del tun/tap interface address.
817 * Both the v6 interface address API and the way ifconfig
818 * displays subinterfaces differ from their v4 couterparts.
819 * The code given here seems to work but YMMV.
821 * @param *im - ip6_main_t
822 * @param opaque - uword
823 * @param sw_if_index - u32
824 * @param *address - ip6_address_t
825 * @param address_length - u32
826 * @param if_address_index - u32
827 * @param is_delete - u32
830 tuntap_ip6_add_del_interface_address (ip6_main_t * im,
833 ip6_address_t * address,
835 u32 if_address_index,
838 tuntap_main_t * tm = &tuntap_main;
840 struct in6_ifreq ifr6;
841 subif_address_t subif_addr, * ap;
844 /* Tuntap disabled, or using a "normal" interface. */
845 if (tm->have_normal_interface || tm->dev_tap_fd < 0)
848 /* See if we already know about this subif */
849 memset (&subif_addr, 0, sizeof (subif_addr));
850 subif_addr.sw_if_index = sw_if_index;
851 subif_addr.is_v6 = 1;
852 clib_memcpy (&subif_addr.addr, address, sizeof (*address));
854 p = mhash_get (&tm->subif_mhash, &subif_addr);
857 ap = pool_elt_at_index (tm->subifs, p[0]);
860 pool_get (tm->subifs, ap);
862 mhash_set (&tm->subif_mhash, ap, ap - tm->subifs, 0);
865 /* Use subif pool index to select alias device. */
866 memset (&ifr, 0, sizeof (ifr));
867 memset (&ifr6, 0, sizeof (ifr6));
868 snprintf (ifr.ifr_name, sizeof(ifr.ifr_name),
869 "%s:%d", tm->tun_name, (int)(ap - tm->subifs));
873 int sockfd = socket (AF_INET6, SOCK_STREAM, 0);
875 clib_unix_warning ("get ifindex socket");
877 if (ioctl (sockfd, SIOGIFINDEX, &ifr) < 0)
878 clib_unix_warning ("get ifindex");
880 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
881 ifr6.ifr6_prefixlen = address_length;
882 clib_memcpy (&ifr6.ifr6_addr, address, 16);
884 if (ioctl (sockfd, SIOCSIFADDR, &ifr6) < 0)
885 clib_unix_warning ("set address");
892 int sockfd = socket (AF_INET6, SOCK_STREAM, 0);
894 clib_unix_warning ("get ifindex socket");
896 if (ioctl (sockfd, SIOGIFINDEX, &ifr) < 0)
897 clib_unix_warning ("get ifindex");
899 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
900 ifr6.ifr6_prefixlen = address_length;
901 clib_memcpy (&ifr6.ifr6_addr, address, 16);
903 if (ioctl (sockfd, SIOCDIFADDR, &ifr6) < 0)
904 clib_unix_warning ("del address");
909 mhash_unset (&tm->subif_mhash, &subif_addr, 0 /* old value ptr */);
910 pool_put (tm->subifs, ap);
915 * @brief TX the tun/tap frame
917 * @param *vm - vlib_main_t
918 * @param *node - vlib_node_runtime_t
919 * @param *frame - vlib_frame_t
923 tuntap_punt_frame (vlib_main_t * vm,
924 vlib_node_runtime_t * node,
925 vlib_frame_t * frame)
927 tuntap_tx (vm, node, frame);
928 vlib_frame_free (vm, node, frame);
932 * @brief Free the tun/tap frame
934 * @param *vm - vlib_main_t
935 * @param *node - vlib_node_runtime_t
936 * @param *frame - vlib_frame_t
940 tuntap_nopunt_frame (vlib_main_t * vm,
941 vlib_node_runtime_t * node,
942 vlib_frame_t * frame)
944 u32 * buffers = vlib_frame_args (frame);
945 uword n_packets = frame->n_vectors;
946 vlib_buffer_free (vm, buffers, n_packets);
947 vlib_frame_free (vm, node, frame);
950 VNET_HW_INTERFACE_CLASS (tuntap_interface_class,static) = {
952 .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
956 * @brief Format tun/tap interface name
958 * @param *s - u8 - formatter string
959 * @param *args - va_list
961 * @return *s - u8 - formatted string
964 static u8 * format_tuntap_interface_name (u8 * s, va_list * args)
966 u32 i = va_arg (*args, u32);
968 s = format (s, "tuntap-%d", i);
973 * @brief TX packet out tun/tap
975 * @param *vm - vlib_main_t
976 * @param *node - vlib_node_runtime_t
977 * @param *frame - vlib_frame_t
979 * @return n_buffers - uword - Packets transmitted
983 tuntap_intfc_tx (vlib_main_t * vm,
984 vlib_node_runtime_t * node,
985 vlib_frame_t * frame)
987 tuntap_main_t * tm = &tuntap_main;
988 u32 * buffers = vlib_frame_args (frame);
989 uword n_buffers = frame->n_vectors;
991 /* Normal interface transmit happens only on the normal interface... */
992 if (tm->have_normal_interface)
993 return tuntap_tx (vm, node, frame);
995 vlib_buffer_free (vm, buffers, n_buffers);
999 VNET_DEVICE_CLASS (tuntap_dev_class,static) = {
1001 .tx_function = tuntap_intfc_tx,
1002 .format_device_name = format_tuntap_interface_name,
1006 * @brief tun/tap node init
1008 * @param *vm - vlib_main_t
1010 * @return error - clib_error_t
1013 static clib_error_t *
1014 tuntap_init (vlib_main_t * vm)
1016 clib_error_t * error;
1017 ip4_main_t * im4 = &ip4_main;
1018 ip6_main_t * im6 = &ip6_main;
1019 ip4_add_del_interface_address_callback_t cb4;
1020 ip6_add_del_interface_address_callback_t cb6;
1021 tuntap_main_t * tm = &tuntap_main;
1023 error = vlib_call_init_function (vm, ip4_init);
1027 mhash_init (&tm->subif_mhash, sizeof (u32), sizeof(subif_address_t));
1029 cb4.function = tuntap_ip4_add_del_interface_address;
1030 cb4.function_opaque = 0;
1031 vec_add1 (im4->add_del_interface_address_callbacks, cb4);
1033 cb6.function = tuntap_ip6_add_del_interface_address;
1034 cb6.function_opaque = 0;
1035 vec_add1 (im6->add_del_interface_address_callbacks, cb6);
1040 VLIB_INIT_FUNCTION (tuntap_init);