xref: /qemu/net/tap-solaris.c (revision f03e0cf6)
1966ea5ecSMark McLoughlin /*
2966ea5ecSMark McLoughlin  * QEMU System Emulator
3966ea5ecSMark McLoughlin  *
4966ea5ecSMark McLoughlin  * Copyright (c) 2003-2008 Fabrice Bellard
5966ea5ecSMark McLoughlin  *
6966ea5ecSMark McLoughlin  * Permission is hereby granted, free of charge, to any person obtaining a copy
7966ea5ecSMark McLoughlin  * of this software and associated documentation files (the "Software"), to deal
8966ea5ecSMark McLoughlin  * in the Software without restriction, including without limitation the rights
9966ea5ecSMark McLoughlin  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10966ea5ecSMark McLoughlin  * copies of the Software, and to permit persons to whom the Software is
11966ea5ecSMark McLoughlin  * furnished to do so, subject to the following conditions:
12966ea5ecSMark McLoughlin  *
13966ea5ecSMark McLoughlin  * The above copyright notice and this permission notice shall be included in
14966ea5ecSMark McLoughlin  * all copies or substantial portions of the Software.
15966ea5ecSMark McLoughlin  *
16966ea5ecSMark McLoughlin  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17966ea5ecSMark McLoughlin  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18966ea5ecSMark McLoughlin  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19966ea5ecSMark McLoughlin  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20966ea5ecSMark McLoughlin  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21966ea5ecSMark McLoughlin  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22966ea5ecSMark McLoughlin  * THE SOFTWARE.
23966ea5ecSMark McLoughlin  */
24966ea5ecSMark McLoughlin 
252744d920SPeter Maydell #include "qemu/osdep.h"
26da34e65cSMarkus Armbruster #include "qapi/error.h"
271422e32dSPaolo Bonzini #include "tap_int.h"
28856dfd8aSMarkus Armbruster #include "qemu/ctype.h"
29f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
30966ea5ecSMark McLoughlin 
31966ea5ecSMark McLoughlin #include <sys/ethernet.h>
32966ea5ecSMark McLoughlin #include <sys/sockio.h>
33966ea5ecSMark McLoughlin #include <netinet/arp.h>
34966ea5ecSMark McLoughlin #include <netinet/in.h>
35966ea5ecSMark McLoughlin #include <netinet/in_systm.h>
36966ea5ecSMark McLoughlin #include <netinet/ip.h>
37966ea5ecSMark McLoughlin #include <netinet/ip_icmp.h> // must come after ip.h
38966ea5ecSMark McLoughlin #include <netinet/udp.h>
39966ea5ecSMark McLoughlin #include <netinet/tcp.h>
40966ea5ecSMark McLoughlin #include <net/if.h>
41966ea5ecSMark McLoughlin #include <stropts.h>
421de7afc9SPaolo Bonzini #include "qemu/error-report.h"
43966ea5ecSMark McLoughlin 
tap_read_packet(int tapfd,uint8_t * buf,int maxlen)44966ea5ecSMark McLoughlin ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen)
45966ea5ecSMark McLoughlin {
46966ea5ecSMark McLoughlin     struct strbuf sbuf;
47966ea5ecSMark McLoughlin     int f = 0;
48966ea5ecSMark McLoughlin 
49966ea5ecSMark McLoughlin     sbuf.maxlen = maxlen;
50966ea5ecSMark McLoughlin     sbuf.buf = (char *)buf;
51966ea5ecSMark McLoughlin 
52966ea5ecSMark McLoughlin     return getmsg(tapfd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1;
53966ea5ecSMark McLoughlin }
54966ea5ecSMark McLoughlin 
55966ea5ecSMark McLoughlin #define TUNNEWPPA       (('T'<<16) | 0x0001)
56966ea5ecSMark McLoughlin /*
57966ea5ecSMark McLoughlin  * Allocate TAP device, returns opened fd.
58966ea5ecSMark McLoughlin  * Stores dev name in the first arg(must be large enough).
59966ea5ecSMark McLoughlin  */
tap_alloc(char * dev,size_t dev_size,Error ** errp)60576c6eb6SMarkus Armbruster static int tap_alloc(char *dev, size_t dev_size, Error **errp)
61966ea5ecSMark McLoughlin {
62576c6eb6SMarkus Armbruster     /* FIXME leaks like a sieve on error paths */
63576c6eb6SMarkus Armbruster     /* FIXME suspicious: many errors are reported, then ignored */
64966ea5ecSMark McLoughlin     int tap_fd, if_fd, ppa = -1;
65966ea5ecSMark McLoughlin     static int ip_fd = 0;
66966ea5ecSMark McLoughlin     char *ptr;
67966ea5ecSMark McLoughlin 
68966ea5ecSMark McLoughlin     static int arp_fd = 0;
69966ea5ecSMark McLoughlin     int ip_muxid, arp_muxid;
70966ea5ecSMark McLoughlin     struct strioctl  strioc_if, strioc_ppa;
713a93113aSDong Xu Wang     int link_type = I_PLINK;
72966ea5ecSMark McLoughlin     struct lifreq ifr;
73966ea5ecSMark McLoughlin     char actual_name[32] = "";
74966ea5ecSMark McLoughlin 
75966ea5ecSMark McLoughlin     memset(&ifr, 0x0, sizeof(ifr));
76966ea5ecSMark McLoughlin 
77966ea5ecSMark McLoughlin     if( *dev ){
78966ea5ecSMark McLoughlin        ptr = dev;
79966ea5ecSMark McLoughlin        while( *ptr && !qemu_isdigit((int)*ptr) ) ptr++;
80966ea5ecSMark McLoughlin        ppa = atoi(ptr);
81966ea5ecSMark McLoughlin     }
82966ea5ecSMark McLoughlin 
83966ea5ecSMark McLoughlin     /* Check if IP device was opened */
84966ea5ecSMark McLoughlin     if( ip_fd )
85966ea5ecSMark McLoughlin        close(ip_fd);
86966ea5ecSMark McLoughlin 
878b6aa693SNikita Ivanov     ip_fd = RETRY_ON_EINTR(open("/dev/udp", O_RDWR, 0));
88966ea5ecSMark McLoughlin     if (ip_fd < 0) {
89576c6eb6SMarkus Armbruster         error_setg(errp, "Can't open /dev/ip (actually /dev/udp)");
90966ea5ecSMark McLoughlin         return -1;
91966ea5ecSMark McLoughlin     }
92966ea5ecSMark McLoughlin 
938b6aa693SNikita Ivanov     tap_fd = RETRY_ON_EINTR(open("/dev/tap", O_RDWR, 0));
94966ea5ecSMark McLoughlin     if (tap_fd < 0) {
95576c6eb6SMarkus Armbruster         error_setg(errp, "Can't open /dev/tap");
96966ea5ecSMark McLoughlin         return -1;
97966ea5ecSMark McLoughlin     }
98966ea5ecSMark McLoughlin 
99966ea5ecSMark McLoughlin     /* Assign a new PPA and get its unit number. */
100966ea5ecSMark McLoughlin     strioc_ppa.ic_cmd = TUNNEWPPA;
101966ea5ecSMark McLoughlin     strioc_ppa.ic_timout = 0;
102966ea5ecSMark McLoughlin     strioc_ppa.ic_len = sizeof(ppa);
103966ea5ecSMark McLoughlin     strioc_ppa.ic_dp = (char *)&ppa;
104966ea5ecSMark McLoughlin     if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0)
105576c6eb6SMarkus Armbruster         error_report("Can't assign new interface");
106966ea5ecSMark McLoughlin 
1078b6aa693SNikita Ivanov     if_fd = RETRY_ON_EINTR(open("/dev/tap", O_RDWR, 0));
108966ea5ecSMark McLoughlin     if (if_fd < 0) {
109576c6eb6SMarkus Armbruster         error_setg(errp, "Can't open /dev/tap (2)");
110966ea5ecSMark McLoughlin         return -1;
111966ea5ecSMark McLoughlin     }
112966ea5ecSMark McLoughlin     if(ioctl(if_fd, I_PUSH, "ip") < 0){
113576c6eb6SMarkus Armbruster         error_setg(errp, "Can't push IP module");
114966ea5ecSMark McLoughlin         return -1;
115966ea5ecSMark McLoughlin     }
116966ea5ecSMark McLoughlin 
117966ea5ecSMark McLoughlin     if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0)
118576c6eb6SMarkus Armbruster         error_report("Can't get flags");
119966ea5ecSMark McLoughlin 
120966ea5ecSMark McLoughlin     snprintf (actual_name, 32, "tap%d", ppa);
121966ea5ecSMark McLoughlin     pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name);
122966ea5ecSMark McLoughlin 
123966ea5ecSMark McLoughlin     ifr.lifr_ppa = ppa;
124966ea5ecSMark McLoughlin     /* Assign ppa according to the unit number returned by tun device */
125966ea5ecSMark McLoughlin 
126966ea5ecSMark McLoughlin     if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0)
127576c6eb6SMarkus Armbruster         error_report("Can't set PPA %d", ppa);
128966ea5ecSMark McLoughlin     if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0)
129576c6eb6SMarkus Armbruster         error_report("Can't get flags");
130966ea5ecSMark McLoughlin     /* Push arp module to if_fd */
131966ea5ecSMark McLoughlin     if (ioctl (if_fd, I_PUSH, "arp") < 0)
132576c6eb6SMarkus Armbruster         error_report("Can't push ARP module (2)");
133966ea5ecSMark McLoughlin 
134966ea5ecSMark McLoughlin     /* Push arp module to ip_fd */
135966ea5ecSMark McLoughlin     if (ioctl (ip_fd, I_POP, NULL) < 0)
136576c6eb6SMarkus Armbruster         error_report("I_POP failed");
137966ea5ecSMark McLoughlin     if (ioctl (ip_fd, I_PUSH, "arp") < 0)
138576c6eb6SMarkus Armbruster         error_report("Can't push ARP module (3)");
139966ea5ecSMark McLoughlin     /* Open arp_fd */
1408b6aa693SNikita Ivanov     arp_fd = RETRY_ON_EINTR(open("/dev/tap", O_RDWR, 0));
141966ea5ecSMark McLoughlin     if (arp_fd < 0)
142576c6eb6SMarkus Armbruster         error_report("Can't open %s", "/dev/tap");
143966ea5ecSMark McLoughlin 
144966ea5ecSMark McLoughlin     /* Set ifname to arp */
145966ea5ecSMark McLoughlin     strioc_if.ic_cmd = SIOCSLIFNAME;
146966ea5ecSMark McLoughlin     strioc_if.ic_timout = 0;
147966ea5ecSMark McLoughlin     strioc_if.ic_len = sizeof(ifr);
148966ea5ecSMark McLoughlin     strioc_if.ic_dp = (char *)&ifr;
149966ea5ecSMark McLoughlin     if (ioctl(arp_fd, I_STR, &strioc_if) < 0){
150576c6eb6SMarkus Armbruster         error_report("Can't set ifname to arp");
151966ea5ecSMark McLoughlin     }
152966ea5ecSMark McLoughlin 
153966ea5ecSMark McLoughlin     if((ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0){
154576c6eb6SMarkus Armbruster         error_setg(errp, "Can't link TAP device to IP");
155966ea5ecSMark McLoughlin         return -1;
156966ea5ecSMark McLoughlin     }
157966ea5ecSMark McLoughlin 
158966ea5ecSMark McLoughlin     if ((arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0)
159576c6eb6SMarkus Armbruster         error_report("Can't link TAP device to ARP");
160966ea5ecSMark McLoughlin 
161966ea5ecSMark McLoughlin     close (if_fd);
162966ea5ecSMark McLoughlin 
163966ea5ecSMark McLoughlin     memset(&ifr, 0x0, sizeof(ifr));
164966ea5ecSMark McLoughlin     pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name);
165966ea5ecSMark McLoughlin     ifr.lifr_ip_muxid  = ip_muxid;
166966ea5ecSMark McLoughlin     ifr.lifr_arp_muxid = arp_muxid;
167966ea5ecSMark McLoughlin 
168966ea5ecSMark McLoughlin     if (ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0)
169966ea5ecSMark McLoughlin     {
170966ea5ecSMark McLoughlin       ioctl (ip_fd, I_PUNLINK , arp_muxid);
171966ea5ecSMark McLoughlin       ioctl (ip_fd, I_PUNLINK, ip_muxid);
172576c6eb6SMarkus Armbruster       error_report("Can't set multiplexor id");
173966ea5ecSMark McLoughlin     }
174966ea5ecSMark McLoughlin 
175966ea5ecSMark McLoughlin     snprintf(dev, dev_size, "tap%d", ppa);
176966ea5ecSMark McLoughlin     return tap_fd;
177966ea5ecSMark McLoughlin }
178966ea5ecSMark McLoughlin 
tap_open(char * ifname,int ifname_size,int * vnet_hdr,int vnet_hdr_required,int mq_required,Error ** errp)179264986e2SJason Wang int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
180468dd824SMarkus Armbruster              int vnet_hdr_required, int mq_required, Error **errp)
181966ea5ecSMark McLoughlin {
182966ea5ecSMark McLoughlin     char  dev[10]="";
183966ea5ecSMark McLoughlin     int fd;
184576c6eb6SMarkus Armbruster 
185576c6eb6SMarkus Armbruster     fd = tap_alloc(dev, sizeof(dev), errp);
186576c6eb6SMarkus Armbruster     if (fd < 0) {
187966ea5ecSMark McLoughlin         return -1;
188966ea5ecSMark McLoughlin     }
189966ea5ecSMark McLoughlin     pstrcpy(ifname, ifname_size, dev);
190f5c5e381SMark McLoughlin     if (*vnet_hdr) {
191f5c5e381SMark McLoughlin         /* Solaris doesn't have IFF_VNET_HDR */
192f5c5e381SMark McLoughlin         *vnet_hdr = 0;
193f5c5e381SMark McLoughlin 
194f5c5e381SMark McLoughlin         if (vnet_hdr_required && !*vnet_hdr) {
195576c6eb6SMarkus Armbruster             error_setg(errp, "vnet_hdr=1 requested, but no kernel "
196f5c5e381SMark McLoughlin                        "support for IFF_VNET_HDR available");
197f5c5e381SMark McLoughlin             close(fd);
198f5c5e381SMark McLoughlin             return -1;
199f5c5e381SMark McLoughlin         }
200f5c5e381SMark McLoughlin     }
20122e135fcSMarc-André Lureau     g_unix_set_fd_nonblocking(fd, true, NULL);
202966ea5ecSMark McLoughlin     return fd;
203966ea5ecSMark McLoughlin }
20415ac913bSMark McLoughlin 
tap_set_sndbuf(int fd,const NetdevTapOptions * tap,Error ** errp)20580b832c3SMarkus Armbruster void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp)
20615ac913bSMark McLoughlin {
20715ac913bSMark McLoughlin }
208dc69004cSMark McLoughlin 
tap_probe_vnet_hdr(int fd,Error ** errp)209e7b347d0SDaniel P. Berrange int tap_probe_vnet_hdr(int fd, Error **errp)
210dc69004cSMark McLoughlin {
211dc69004cSMark McLoughlin     return 0;
212dc69004cSMark McLoughlin }
2131faac1f7SMark McLoughlin 
tap_probe_has_ufo(int fd)2149c282718SMark McLoughlin int tap_probe_has_ufo(int fd)
2159c282718SMark McLoughlin {
2169c282718SMark McLoughlin     return 0;
2179c282718SMark McLoughlin }
2189c282718SMark McLoughlin 
tap_probe_has_uso(int fd)219f03e0cf6SYuri Benditovich int tap_probe_has_uso(int fd)
220f03e0cf6SYuri Benditovich {
221f03e0cf6SYuri Benditovich     return 0;
222f03e0cf6SYuri Benditovich }
223f03e0cf6SYuri Benditovich 
tap_probe_vnet_hdr_len(int fd,int len)224445d892fSMichael S. Tsirkin int tap_probe_vnet_hdr_len(int fd, int len)
225445d892fSMichael S. Tsirkin {
226445d892fSMichael S. Tsirkin     return 0;
227445d892fSMichael S. Tsirkin }
228445d892fSMichael S. Tsirkin 
tap_fd_set_vnet_hdr_len(int fd,int len)229445d892fSMichael S. Tsirkin void tap_fd_set_vnet_hdr_len(int fd, int len)
230445d892fSMichael S. Tsirkin {
231445d892fSMichael S. Tsirkin }
232445d892fSMichael S. Tsirkin 
tap_fd_set_vnet_le(int fd,int is_le)2334ee9b43bSMichael S. Tsirkin int tap_fd_set_vnet_le(int fd, int is_le)
2344ee9b43bSMichael S. Tsirkin {
2354ee9b43bSMichael S. Tsirkin     return -EINVAL;
2364ee9b43bSMichael S. Tsirkin }
2374ee9b43bSMichael S. Tsirkin 
tap_fd_set_vnet_be(int fd,int is_be)2384ee9b43bSMichael S. Tsirkin int tap_fd_set_vnet_be(int fd, int is_be)
2394ee9b43bSMichael S. Tsirkin {
2404ee9b43bSMichael S. Tsirkin     return -EINVAL;
2414ee9b43bSMichael S. Tsirkin }
2424ee9b43bSMichael S. Tsirkin 
tap_fd_set_offload(int fd,int csum,int tso4,int tso6,int ecn,int ufo,int uso4,int uso6)2431faac1f7SMark McLoughlin void tap_fd_set_offload(int fd, int csum, int tso4,
2442ab0ec31SAndrew Melnychenko                         int tso6, int ecn, int ufo, int uso4, int uso6)
2451faac1f7SMark McLoughlin {
2461faac1f7SMark McLoughlin }
24794fdc6d0SJason Wang 
tap_fd_enable(int fd)24894fdc6d0SJason Wang int tap_fd_enable(int fd)
24994fdc6d0SJason Wang {
25094fdc6d0SJason Wang     return -1;
25194fdc6d0SJason Wang }
25294fdc6d0SJason Wang 
tap_fd_disable(int fd)25394fdc6d0SJason Wang int tap_fd_disable(int fd)
25494fdc6d0SJason Wang {
25594fdc6d0SJason Wang     return -1;
25694fdc6d0SJason Wang }
25794fdc6d0SJason Wang 
tap_fd_get_ifname(int fd,char * ifname)258e5dc0b40SJason Wang int tap_fd_get_ifname(int fd, char *ifname)
259e5dc0b40SJason Wang {
260e5dc0b40SJason Wang     return -1;
261e5dc0b40SJason Wang }
2628f364e34SAndrew Melnychenko 
tap_fd_set_steering_ebpf(int fd,int prog_fd)2638f364e34SAndrew Melnychenko int tap_fd_set_steering_ebpf(int fd, int prog_fd)
2648f364e34SAndrew Melnychenko {
2658f364e34SAndrew Melnychenko     return -1;
2668f364e34SAndrew Melnychenko }
267