tap_inject_tap.c revision 042a782c
1/*
2 * Copyright 2016 Intel Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *   http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "tap_inject.h"
18
19#include <fcntl.h>
20#include <sys/ioctl.h>
21#include <sys/socket.h>
22#include <linux/if.h>
23#include <linux/if_arp.h>
24#include <linux/if_ether.h>
25#include <linux/if_tun.h>
26#include <netinet/in.h>
27#include <vnet/unix/tuntap.h>
28
29#include <vlib/unix/unix.h>
30
31
32static clib_error_t *
33tap_inject_tap_read (clib_file_t * f)
34{
35  vlib_main_t * vm = vlib_get_main ();
36  tap_inject_main_t * im = tap_inject_get_main ();
37
38  vec_add1 (im->rx_file_descriptors, f->file_descriptor);
39
40  vlib_node_set_interrupt_pending (vm, im->rx_node_index);
41
42  return 0;
43}
44
45#define TAP_INJECT_TAP_BASE_NAME "vpp"
46
47clib_error_t *
48tap_inject_tap_connect (vnet_hw_interface_t * hw)
49{
50  vnet_main_t * vnet_main = vnet_get_main ();
51  vnet_sw_interface_t * sw = vnet_get_sw_interface (vnet_main, hw->hw_if_index);
52  static const int one = 1;
53  int fd;
54  struct ifreq ifr;
55  clib_file_t template;
56  u32 tap_fd;
57  u8 * name;
58
59  memset (&ifr, 0, sizeof (ifr));
60  memset (&template, 0, sizeof (template));
61
62  ASSERT (hw->hw_if_index == sw->sw_if_index);
63
64  /* Create the tap. */
65  tap_fd = open ("/dev/net/tun", O_RDWR);
66
67  if ((int)tap_fd < 0)
68    return clib_error_return (0, "failed to open tun device");
69
70  name = format (0, TAP_INJECT_TAP_BASE_NAME "%u%c", hw->hw_instance, 0);
71
72  strncpy (ifr.ifr_name, (char *) name, sizeof (ifr.ifr_name) - 1);
73  ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
74
75  if (ioctl (tap_fd, TUNSETIFF, (void *)&ifr) < 0)
76    {
77      close (tap_fd);
78      return clib_error_return (0, "failed to create tap");
79    }
80
81  if (ioctl (tap_fd, FIONBIO, &one) < 0)
82    {
83      close (tap_fd);
84      return clib_error_return (0, "failed to set tap to non-blocking io");
85    }
86
87  /* Open a socket to configure the device. */
88  fd = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL));
89
90  if (fd < 0)
91    {
92      close (tap_fd);
93      return clib_error_return (0, "failed to configure tap");
94    }
95
96  if (hw->hw_address)
97    clib_memcpy (ifr.ifr_hwaddr.sa_data, hw->hw_address, ETHER_ADDR_LEN);
98
99  ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
100
101  /* Set the hardware address. */
102  if (ioctl (fd, SIOCSIFHWADDR, &ifr) < 0)
103    {
104      close (tap_fd);
105      close (fd);
106      return clib_error_return (0, "failed to set tap hardware address");
107    }
108
109  /* Get the tap if index. */
110  if (ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
111    {
112      close (tap_fd);
113      close (fd);
114      return clib_error_return (0, "failed to procure tap if index");
115    }
116
117  close (fd);
118
119  /* Get notified when the tap needs to be read. */
120  template.read_function = tap_inject_tap_read;
121  template.file_descriptor = tap_fd;
122
123  clib_file_add (&file_main, &template);
124
125  tap_inject_insert_tap (sw->sw_if_index, tap_fd, ifr.ifr_ifindex);
126
127  return 0;
128}
129
130clib_error_t *
131tap_inject_tap_disconnect (u32 sw_if_index)
132{
133  u32 tap_fd;
134
135  tap_fd = tap_inject_lookup_tap_fd (sw_if_index);
136  if (tap_fd == ~0)
137    return clib_error_return (0, "failed to disconnect tap");
138
139  tap_inject_delete_tap (sw_if_index);
140
141  close (tap_fd);
142  return 0;
143}
144
145
146u8 *
147format_tap_inject_tap_name (u8 * s, va_list * args)
148{
149  int fd;
150  struct ifreq ifr;
151
152  fd = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL));
153
154  if (fd < 0)
155    return 0;
156
157  memset (&ifr, 0, sizeof (ifr));
158
159  ifr.ifr_ifindex = va_arg (*args, u32);
160
161  if (ioctl (fd, SIOCGIFNAME, &ifr) < 0)
162    {
163      close (fd);
164      return 0;
165    }
166
167  close (fd);
168
169  return format (s, "%s", ifr.ifr_name);
170}
171