xref: /openbmc/qemu/net/tap-bsd.c (revision cc1838c2)
1  /*
2   * QEMU System Emulator
3   *
4   * Copyright (c) 2003-2008 Fabrice Bellard
5   *
6   * Permission is hereby granted, free of charge, to any person obtaining a copy
7   * of this software and associated documentation files (the "Software"), to deal
8   * in the Software without restriction, including without limitation the rights
9   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10   * copies of the Software, and to permit persons to whom the Software is
11   * furnished to do so, subject to the following conditions:
12   *
13   * The above copyright notice and this permission notice shall be included in
14   * all copies or substantial portions of the Software.
15   *
16   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19   * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22   * THE SOFTWARE.
23   */
24  
25  #include "qemu/osdep.h"
26  #include "qemu-common.h"
27  #include "qapi/error.h"
28  #include "tap_int.h"
29  #include "qemu/cutils.h"
30  #include "qemu/error-report.h"
31  
32  #if defined(__NetBSD__) || defined(__FreeBSD__)
33  #include <sys/ioctl.h>
34  #include <net/if.h>
35  #include <net/if_tap.h>
36  #endif
37  
38  #ifndef __FreeBSD__
39  int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
40               int vnet_hdr_required, int mq_required, Error **errp)
41  {
42      int fd;
43  #ifdef TAPGIFNAME
44      struct ifreq ifr;
45  #else
46      char *dev;
47      struct stat s;
48  #endif
49  
50      /* if no ifname is given, always start the search from tap0/tun0. */
51      int i;
52      char dname[100];
53  
54      for (i = 0; i < 10; i++) {
55          if (*ifname) {
56              snprintf(dname, sizeof dname, "/dev/%s", ifname);
57          } else {
58              snprintf(dname, sizeof dname, "/dev/tap%d", i);
59          }
60          TFR(fd = open(dname, O_RDWR));
61          if (fd >= 0) {
62              break;
63          }
64          else if (errno == ENXIO || errno == ENOENT) {
65              break;
66          }
67          if (*ifname) {
68              break;
69          }
70      }
71      if (fd < 0) {
72          error_setg_errno(errp, errno, "could not open %s", dname);
73          return -1;
74      }
75  
76  #ifdef TAPGIFNAME
77      if (ioctl(fd, TAPGIFNAME, (void *)&ifr) < 0) {
78          error_setg_errno(errp, errno, "could not get tap name");
79          return -1;
80      }
81      pstrcpy(ifname, ifname_size, ifr.ifr_name);
82  #else
83      if (fstat(fd, &s) < 0) {
84          error_setg_errno(errp, errno, "could not stat %s", dname);
85          return -1;
86      }
87      dev = devname(s.st_rdev, S_IFCHR);
88      pstrcpy(ifname, ifname_size, dev);
89  #endif
90  
91      if (*vnet_hdr) {
92          /* BSD doesn't have IFF_VNET_HDR */
93          *vnet_hdr = 0;
94  
95          if (vnet_hdr_required && !*vnet_hdr) {
96              error_setg(errp, "vnet_hdr=1 requested, but no kernel "
97                         "support for IFF_VNET_HDR available");
98              close(fd);
99              return -1;
100          }
101      }
102      fcntl(fd, F_SETFL, O_NONBLOCK);
103      return fd;
104  }
105  
106  #else /* __FreeBSD__ */
107  
108  #define PATH_NET_TAP "/dev/tap"
109  
110  static int tap_open_clone(char *ifname, int ifname_size, Error **errp)
111  {
112      int fd, s, ret;
113      struct ifreq ifr;
114  
115      TFR(fd = open(PATH_NET_TAP, O_RDWR));
116      if (fd < 0) {
117          error_setg_errno(errp, errno, "could not open %s", PATH_NET_TAP);
118          return -1;
119      }
120  
121      memset(&ifr, 0, sizeof(ifr));
122  
123      ret = ioctl(fd, TAPGIFNAME, (void *)&ifr);
124      if (ret < 0) {
125          error_setg_errno(errp, errno, "could not get tap interface name");
126          close(fd);
127          return -1;
128      }
129  
130      if (ifname[0] != '\0') {
131          /* User requested the interface to have a specific name */
132          s = socket(AF_LOCAL, SOCK_DGRAM, 0);
133          if (s < 0) {
134              error_setg_errno(errp, errno,
135                               "could not open socket to set interface name");
136              close(fd);
137              return -1;
138          }
139          ifr.ifr_data = ifname;
140          ret = ioctl(s, SIOCSIFNAME, (void *)&ifr);
141          close(s);
142          if (ret < 0) {
143              error_setg(errp, "could not set tap interface name");
144              close(fd);
145              return -1;
146          }
147      } else {
148          pstrcpy(ifname, ifname_size, ifr.ifr_name);
149      }
150  
151      return fd;
152  }
153  
154  int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
155               int vnet_hdr_required, int mq_required, Error **errp)
156  {
157      int fd = -1;
158  
159      /* If the specified tap device already exists just use it. */
160      if (ifname[0] != '\0') {
161          char dname[100];
162          snprintf(dname, sizeof dname, "/dev/%s", ifname);
163          TFR(fd = open(dname, O_RDWR));
164          if (fd < 0 && errno != ENOENT) {
165              error_setg_errno(errp, errno, "could not open %s", dname);
166              return -1;
167          }
168      }
169  
170      if (fd < 0) {
171          /* Tap device not specified or does not exist. */
172          if ((fd = tap_open_clone(ifname, ifname_size, errp)) < 0) {
173              return -1;
174          }
175      }
176  
177      if (*vnet_hdr) {
178          /* BSD doesn't have IFF_VNET_HDR */
179          *vnet_hdr = 0;
180  
181          if (vnet_hdr_required && !*vnet_hdr) {
182              error_setg(errp, "vnet_hdr=1 requested, but no kernel "
183                         "support for IFF_VNET_HDR available");
184              goto error;
185          }
186      }
187      if (mq_required) {
188          error_setg(errp, "mq_required requested, but no kernel support"
189                     " for IFF_MULTI_QUEUE available");
190          goto error;
191      }
192  
193      fcntl(fd, F_SETFL, O_NONBLOCK);
194      return fd;
195  
196  error:
197      close(fd);
198      return -1;
199  }
200  #endif /* __FreeBSD__ */
201  
202  void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp)
203  {
204  }
205  
206  int tap_probe_vnet_hdr(int fd, Error **errp)
207  {
208      return 0;
209  }
210  
211  int tap_probe_has_ufo(int fd)
212  {
213      return 0;
214  }
215  
216  int tap_probe_vnet_hdr_len(int fd, int len)
217  {
218      return 0;
219  }
220  
221  void tap_fd_set_vnet_hdr_len(int fd, int len)
222  {
223  }
224  
225  int tap_fd_set_vnet_le(int fd, int is_le)
226  {
227      return -EINVAL;
228  }
229  
230  int tap_fd_set_vnet_be(int fd, int is_be)
231  {
232      return -EINVAL;
233  }
234  
235  void tap_fd_set_offload(int fd, int csum, int tso4,
236                          int tso6, int ecn, int ufo)
237  {
238  }
239  
240  int tap_fd_enable(int fd)
241  {
242      return -1;
243  }
244  
245  int tap_fd_disable(int fd)
246  {
247      return -1;
248  }
249  
250  int tap_fd_get_ifname(int fd, char *ifname)
251  {
252      return -1;
253  }
254  
255  int tap_fd_set_steering_ebpf(int fd, int prog_fd)
256  {
257      return -1;
258  }
259