diff options
Diffstat (limited to 'qemu/net')
-rw-r--r-- | qemu/net/Makefile.objs | 18 | ||||
-rw-r--r-- | qemu/net/checksum.c | 122 | ||||
-rw-r--r-- | qemu/net/clients.h | 65 | ||||
-rw-r--r-- | qemu/net/dump.c | 364 | ||||
-rw-r--r-- | qemu/net/eth.c | 218 | ||||
-rw-r--r-- | qemu/net/filter-buffer.c | 212 | ||||
-rw-r--r-- | qemu/net/filter-mirror.c | 427 | ||||
-rw-r--r-- | qemu/net/filter.c | 275 | ||||
-rw-r--r-- | qemu/net/hub.c | 355 | ||||
-rw-r--r-- | qemu/net/hub.h | 26 | ||||
-rw-r--r-- | qemu/net/l2tpv3.c | 744 | ||||
-rw-r--r-- | qemu/net/net.c | 1575 | ||||
-rw-r--r-- | qemu/net/netmap.c | 448 | ||||
-rw-r--r-- | qemu/net/queue.c | 279 | ||||
-rw-r--r-- | qemu/net/slirp.c | 902 | ||||
-rw-r--r-- | qemu/net/socket.c | 772 | ||||
-rw-r--r-- | qemu/net/tap-aix.c | 88 | ||||
-rw-r--r-- | qemu/net/tap-bsd.c | 257 | ||||
-rw-r--r-- | qemu/net/tap-haiku.c | 87 | ||||
-rw-r--r-- | qemu/net/tap-linux.c | 316 | ||||
-rw-r--r-- | qemu/net/tap-linux.h | 53 | ||||
-rw-r--r-- | qemu/net/tap-solaris.c | 256 | ||||
-rw-r--r-- | qemu/net/tap-win32.c | 820 | ||||
-rw-r--r-- | qemu/net/tap.c | 931 | ||||
-rw-r--r-- | qemu/net/tap_int.h | 49 | ||||
-rw-r--r-- | qemu/net/util.c | 59 | ||||
-rw-r--r-- | qemu/net/util.h | 31 | ||||
-rw-r--r-- | qemu/net/vde.c | 128 | ||||
-rw-r--r-- | qemu/net/vhost-user.c | 331 |
29 files changed, 0 insertions, 10208 deletions
diff --git a/qemu/net/Makefile.objs b/qemu/net/Makefile.objs deleted file mode 100644 index b7c22fddb..000000000 --- a/qemu/net/Makefile.objs +++ /dev/null @@ -1,18 +0,0 @@ -common-obj-y = net.o queue.o checksum.o util.o hub.o -common-obj-y += socket.o -common-obj-y += dump.o -common-obj-y += eth.o -common-obj-$(CONFIG_L2TPV3) += l2tpv3.o -common-obj-$(CONFIG_POSIX) += tap.o vhost-user.o -common-obj-$(CONFIG_LINUX) += tap-linux.o -common-obj-$(CONFIG_WIN32) += tap-win32.o -common-obj-$(CONFIG_BSD) += tap-bsd.o -common-obj-$(CONFIG_SOLARIS) += tap-solaris.o -common-obj-$(CONFIG_AIX) += tap-aix.o -common-obj-$(CONFIG_HAIKU) += tap-haiku.o -common-obj-$(CONFIG_SLIRP) += slirp.o -common-obj-$(CONFIG_VDE) += vde.o -common-obj-$(CONFIG_NETMAP) += netmap.o -common-obj-y += filter.o -common-obj-y += filter-buffer.o -common-obj-y += filter-mirror.o diff --git a/qemu/net/checksum.c b/qemu/net/checksum.c deleted file mode 100644 index d0fa424cc..000000000 --- a/qemu/net/checksum.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * IP checksumming functions. - * (c) 2008 Gerd Hoffmann <kraxel@redhat.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; under version 2 or later of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "net/checksum.h" - -#define PROTO_TCP 6 -#define PROTO_UDP 17 - -uint32_t net_checksum_add_cont(int len, uint8_t *buf, int seq) -{ - uint32_t sum = 0; - int i; - - for (i = seq; i < seq + len; i++) { - if (i & 1) { - sum += (uint32_t)buf[i - seq]; - } else { - sum += (uint32_t)buf[i - seq] << 8; - } - } - return sum; -} - -uint16_t net_checksum_finish(uint32_t sum) -{ - while (sum>>16) - sum = (sum & 0xFFFF)+(sum >> 16); - return ~sum; -} - -uint16_t net_checksum_tcpudp(uint16_t length, uint16_t proto, - uint8_t *addrs, uint8_t *buf) -{ - uint32_t sum = 0; - - sum += net_checksum_add(length, buf); // payload - sum += net_checksum_add(8, addrs); // src + dst address - sum += proto + length; // protocol & length - return net_checksum_finish(sum); -} - -void net_checksum_calculate(uint8_t *data, int length) -{ - int hlen, plen, proto, csum_offset; - uint16_t csum; - - /* Ensure data has complete L2 & L3 headers. */ - if (length < 14 + 20) { - return; - } - - if ((data[14] & 0xf0) != 0x40) - return; /* not IPv4 */ - hlen = (data[14] & 0x0f) * 4; - plen = (data[16] << 8 | data[17]) - hlen; - proto = data[23]; - - switch (proto) { - case PROTO_TCP: - csum_offset = 16; - break; - case PROTO_UDP: - csum_offset = 6; - break; - default: - return; - } - - if (plen < csum_offset + 2 || 14 + hlen + plen > length) { - return; - } - - data[14+hlen+csum_offset] = 0; - data[14+hlen+csum_offset+1] = 0; - csum = net_checksum_tcpudp(plen, proto, data+14+12, data+14+hlen); - data[14+hlen+csum_offset] = csum >> 8; - data[14+hlen+csum_offset+1] = csum & 0xff; -} - -uint32_t -net_checksum_add_iov(const struct iovec *iov, const unsigned int iov_cnt, - uint32_t iov_off, uint32_t size) -{ - size_t iovec_off, buf_off; - unsigned int i; - uint32_t res = 0; - uint32_t seq = 0; - - iovec_off = 0; - buf_off = 0; - for (i = 0; i < iov_cnt && size; i++) { - if (iov_off < (iovec_off + iov[i].iov_len)) { - size_t len = MIN((iovec_off + iov[i].iov_len) - iov_off , size); - void *chunk_buf = iov[i].iov_base + (iov_off - iovec_off); - - res += net_checksum_add_cont(len, chunk_buf, seq); - seq += len; - - buf_off += len; - iov_off += len; - size -= len; - } - iovec_off += iov[i].iov_len; - } - return res; -} diff --git a/qemu/net/clients.h b/qemu/net/clients.h deleted file mode 100644 index d47530e82..000000000 --- a/qemu/net/clients.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef QEMU_NET_CLIENTS_H -#define QEMU_NET_CLIENTS_H - -#include "net/net.h" -#include "qapi-types.h" - -int net_init_dump(const NetClientOptions *opts, const char *name, - NetClientState *peer, Error **errp); - -#ifdef CONFIG_SLIRP -int net_init_slirp(const NetClientOptions *opts, const char *name, - NetClientState *peer, Error **errp); -#endif - -int net_init_hubport(const NetClientOptions *opts, const char *name, - NetClientState *peer, Error **errp); - -int net_init_socket(const NetClientOptions *opts, const char *name, - NetClientState *peer, Error **errp); - -int net_init_tap(const NetClientOptions *opts, const char *name, - NetClientState *peer, Error **errp); - -int net_init_bridge(const NetClientOptions *opts, const char *name, - NetClientState *peer, Error **errp); - -int net_init_l2tpv3(const NetClientOptions *opts, const char *name, - NetClientState *peer, Error **errp); -#ifdef CONFIG_VDE -int net_init_vde(const NetClientOptions *opts, const char *name, - NetClientState *peer, Error **errp); -#endif - -#ifdef CONFIG_NETMAP -int net_init_netmap(const NetClientOptions *opts, const char *name, - NetClientState *peer, Error **errp); -#endif - -int net_init_vhost_user(const NetClientOptions *opts, const char *name, - NetClientState *peer, Error **errp); - -#endif /* QEMU_NET_CLIENTS_H */ diff --git a/qemu/net/dump.c b/qemu/net/dump.c deleted file mode 100644 index 41f7673ef..000000000 --- a/qemu/net/dump.c +++ /dev/null @@ -1,364 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "clients.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "qemu/error-report.h" -#include "qemu/iov.h" -#include "qemu/log.h" -#include "qemu/timer.h" -#include "qapi/visitor.h" -#include "net/filter.h" - -typedef struct DumpState { - int64_t start_ts; - int fd; - int pcap_caplen; -} DumpState; - -#define PCAP_MAGIC 0xa1b2c3d4 - -struct pcap_file_hdr { - uint32_t magic; - uint16_t version_major; - uint16_t version_minor; - int32_t thiszone; - uint32_t sigfigs; - uint32_t snaplen; - uint32_t linktype; -}; - -struct pcap_sf_pkthdr { - struct { - int32_t tv_sec; - int32_t tv_usec; - } ts; - uint32_t caplen; - uint32_t len; -}; - -static ssize_t dump_receive_iov(DumpState *s, const struct iovec *iov, int cnt) -{ - struct pcap_sf_pkthdr hdr; - int64_t ts; - int caplen; - size_t size = iov_size(iov, cnt); - struct iovec dumpiov[cnt + 1]; - - /* Early return in case of previous error. */ - if (s->fd < 0) { - return size; - } - - ts = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL); - caplen = size > s->pcap_caplen ? s->pcap_caplen : size; - - hdr.ts.tv_sec = ts / 1000000 + s->start_ts; - hdr.ts.tv_usec = ts % 1000000; - hdr.caplen = caplen; - hdr.len = size; - - dumpiov[0].iov_base = &hdr; - dumpiov[0].iov_len = sizeof(hdr); - cnt = iov_copy(&dumpiov[1], cnt, iov, cnt, 0, caplen); - - if (writev(s->fd, dumpiov, cnt + 1) != sizeof(hdr) + caplen) { - error_report("network dump write error - stopping dump"); - close(s->fd); - s->fd = -1; - } - - return size; -} - -static void dump_cleanup(DumpState *s) -{ - close(s->fd); - s->fd = -1; -} - -static int net_dump_state_init(DumpState *s, const char *filename, - int len, Error **errp) -{ - struct pcap_file_hdr hdr; - struct tm tm; - int fd; - - fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0644); - if (fd < 0) { - error_setg_errno(errp, errno, "-net dump: can't open %s", filename); - return -1; - } - - hdr.magic = PCAP_MAGIC; - hdr.version_major = 2; - hdr.version_minor = 4; - hdr.thiszone = 0; - hdr.sigfigs = 0; - hdr.snaplen = len; - hdr.linktype = 1; - - if (write(fd, &hdr, sizeof(hdr)) < sizeof(hdr)) { - error_setg_errno(errp, errno, "-net dump write error"); - close(fd); - return -1; - } - - s->fd = fd; - s->pcap_caplen = len; - - qemu_get_timedate(&tm, 0); - s->start_ts = mktime(&tm); - - return 0; -} - -/* Dumping via VLAN netclient */ - -struct DumpNetClient { - NetClientState nc; - DumpState ds; -}; -typedef struct DumpNetClient DumpNetClient; - -static ssize_t dumpclient_receive(NetClientState *nc, const uint8_t *buf, - size_t size) -{ - DumpNetClient *dc = DO_UPCAST(DumpNetClient, nc, nc); - struct iovec iov = { - .iov_base = (void *)buf, - .iov_len = size - }; - - return dump_receive_iov(&dc->ds, &iov, 1); -} - -static ssize_t dumpclient_receive_iov(NetClientState *nc, - const struct iovec *iov, int cnt) -{ - DumpNetClient *dc = DO_UPCAST(DumpNetClient, nc, nc); - - return dump_receive_iov(&dc->ds, iov, cnt); -} - -static void dumpclient_cleanup(NetClientState *nc) -{ - DumpNetClient *dc = DO_UPCAST(DumpNetClient, nc, nc); - - dump_cleanup(&dc->ds); -} - -static NetClientInfo net_dump_info = { - .type = NET_CLIENT_OPTIONS_KIND_DUMP, - .size = sizeof(DumpNetClient), - .receive = dumpclient_receive, - .receive_iov = dumpclient_receive_iov, - .cleanup = dumpclient_cleanup, -}; - -int net_init_dump(const NetClientOptions *opts, const char *name, - NetClientState *peer, Error **errp) -{ - int len, rc; - const char *file; - char def_file[128]; - const NetdevDumpOptions *dump; - NetClientState *nc; - DumpNetClient *dnc; - - assert(opts->type == NET_CLIENT_OPTIONS_KIND_DUMP); - dump = opts->u.dump.data; - - assert(peer); - - if (dump->has_file) { - file = dump->file; - } else { - int id; - int ret; - - ret = net_hub_id_for_client(peer, &id); - assert(ret == 0); /* peer must be on a hub */ - - snprintf(def_file, sizeof(def_file), "qemu-vlan%d.pcap", id); - file = def_file; - } - - if (dump->has_len) { - if (dump->len > INT_MAX) { - error_setg(errp, "invalid length: %"PRIu64, dump->len); - return -1; - } - len = dump->len; - } else { - len = 65536; - } - - nc = qemu_new_net_client(&net_dump_info, peer, "dump", name); - snprintf(nc->info_str, sizeof(nc->info_str), - "dump to %s (len=%d)", file, len); - - dnc = DO_UPCAST(DumpNetClient, nc, nc); - rc = net_dump_state_init(&dnc->ds, file, len, errp); - if (rc) { - qemu_del_net_client(nc); - } - return rc; -} - -/* Dumping via filter */ - -#define TYPE_FILTER_DUMP "filter-dump" - -#define FILTER_DUMP(obj) \ - OBJECT_CHECK(NetFilterDumpState, (obj), TYPE_FILTER_DUMP) - -struct NetFilterDumpState { - NetFilterState nfs; - DumpState ds; - char *filename; - uint32_t maxlen; -}; -typedef struct NetFilterDumpState NetFilterDumpState; - -static ssize_t filter_dump_receive_iov(NetFilterState *nf, NetClientState *sndr, - unsigned flags, const struct iovec *iov, - int iovcnt, NetPacketSent *sent_cb) -{ - NetFilterDumpState *nfds = FILTER_DUMP(nf); - - dump_receive_iov(&nfds->ds, iov, iovcnt); - return 0; -} - -static void filter_dump_cleanup(NetFilterState *nf) -{ - NetFilterDumpState *nfds = FILTER_DUMP(nf); - - dump_cleanup(&nfds->ds); -} - -static void filter_dump_setup(NetFilterState *nf, Error **errp) -{ - NetFilterDumpState *nfds = FILTER_DUMP(nf); - - if (!nfds->filename) { - error_setg(errp, "dump filter needs 'file' property set!"); - return; - } - - net_dump_state_init(&nfds->ds, nfds->filename, nfds->maxlen, errp); -} - -static void filter_dump_get_maxlen(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - NetFilterDumpState *nfds = FILTER_DUMP(obj); - uint32_t value = nfds->maxlen; - - visit_type_uint32(v, name, &value, errp); -} - -static void filter_dump_set_maxlen(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - NetFilterDumpState *nfds = FILTER_DUMP(obj); - Error *local_err = NULL; - uint32_t value; - - visit_type_uint32(v, name, &value, &local_err); - if (local_err) { - goto out; - } - if (value == 0) { - error_setg(&local_err, "Property '%s.%s' doesn't take value '%u'", - object_get_typename(obj), name, value); - goto out; - } - nfds->maxlen = value; - -out: - error_propagate(errp, local_err); -} - -static char *file_dump_get_filename(Object *obj, Error **errp) -{ - NetFilterDumpState *nfds = FILTER_DUMP(obj); - - return g_strdup(nfds->filename); -} - -static void file_dump_set_filename(Object *obj, const char *value, Error **errp) -{ - NetFilterDumpState *nfds = FILTER_DUMP(obj); - - g_free(nfds->filename); - nfds->filename = g_strdup(value); -} - -static void filter_dump_instance_init(Object *obj) -{ - NetFilterDumpState *nfds = FILTER_DUMP(obj); - - nfds->maxlen = 65536; - - object_property_add(obj, "maxlen", "int", filter_dump_get_maxlen, - filter_dump_set_maxlen, NULL, NULL, NULL); - object_property_add_str(obj, "file", file_dump_get_filename, - file_dump_set_filename, NULL); -} - -static void filter_dump_instance_finalize(Object *obj) -{ - NetFilterDumpState *nfds = FILTER_DUMP(obj); - - g_free(nfds->filename); -} - -static void filter_dump_class_init(ObjectClass *oc, void *data) -{ - NetFilterClass *nfc = NETFILTER_CLASS(oc); - - nfc->setup = filter_dump_setup; - nfc->cleanup = filter_dump_cleanup; - nfc->receive_iov = filter_dump_receive_iov; -} - -static const TypeInfo filter_dump_info = { - .name = TYPE_FILTER_DUMP, - .parent = TYPE_NETFILTER, - .class_init = filter_dump_class_init, - .instance_init = filter_dump_instance_init, - .instance_finalize = filter_dump_instance_finalize, - .instance_size = sizeof(NetFilterDumpState), -}; - -static void filter_dump_register_types(void) -{ - type_register_static(&filter_dump_info); -} - -type_init(filter_dump_register_types); diff --git a/qemu/net/eth.c b/qemu/net/eth.c deleted file mode 100644 index 7e32d274c..000000000 --- a/qemu/net/eth.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * QEMU network structures definitions and helper functions - * - * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com) - * - * Developed by Daynix Computing LTD (http://www.daynix.com) - * - * Authors: - * Dmitry Fleytman <dmitry@daynix.com> - * Tamir Shomer <tamirs@daynix.com> - * Yan Vugenfirer <yan@daynix.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - */ - -#include "qemu/osdep.h" -#include "net/eth.h" -#include "net/checksum.h" -#include "qemu-common.h" -#include "net/tap.h" - -void eth_setup_vlan_headers(struct eth_header *ehdr, uint16_t vlan_tag, - bool *is_new) -{ - struct vlan_header *vhdr = PKT_GET_VLAN_HDR(ehdr); - - switch (be16_to_cpu(ehdr->h_proto)) { - case ETH_P_VLAN: - case ETH_P_DVLAN: - /* vlan hdr exists */ - *is_new = false; - break; - - default: - /* No VLAN header, put a new one */ - vhdr->h_proto = ehdr->h_proto; - ehdr->h_proto = cpu_to_be16(ETH_P_VLAN); - *is_new = true; - break; - } - vhdr->h_tci = cpu_to_be16(vlan_tag); -} - -uint8_t -eth_get_gso_type(uint16_t l3_proto, uint8_t *l3_hdr, uint8_t l4proto) -{ - uint8_t ecn_state = 0; - - if (l3_proto == ETH_P_IP) { - struct ip_header *iphdr = (struct ip_header *) l3_hdr; - - if (IP_HEADER_VERSION(iphdr) == IP_HEADER_VERSION_4) { - if (IPTOS_ECN(iphdr->ip_tos) == IPTOS_ECN_CE) { - ecn_state = VIRTIO_NET_HDR_GSO_ECN; - } - if (l4proto == IP_PROTO_TCP) { - return VIRTIO_NET_HDR_GSO_TCPV4 | ecn_state; - } else if (l4proto == IP_PROTO_UDP) { - return VIRTIO_NET_HDR_GSO_UDP | ecn_state; - } - } - } else if (l3_proto == ETH_P_IPV6) { - struct ip6_header *ip6hdr = (struct ip6_header *) l3_hdr; - - if (IP6_ECN(ip6hdr->ip6_ecn_acc) == IP6_ECN_CE) { - ecn_state = VIRTIO_NET_HDR_GSO_ECN; - } - - if (l4proto == IP_PROTO_TCP) { - return VIRTIO_NET_HDR_GSO_TCPV6 | ecn_state; - } - } - - /* Unsupported offload */ - g_assert_not_reached(); - - return VIRTIO_NET_HDR_GSO_NONE | ecn_state; -} - -void eth_get_protocols(const uint8_t *headers, - uint32_t hdr_length, - bool *isip4, bool *isip6, - bool *isudp, bool *istcp) -{ - int proto; - size_t l2hdr_len = eth_get_l2_hdr_length(headers); - assert(hdr_length >= eth_get_l2_hdr_length(headers)); - *isip4 = *isip6 = *isudp = *istcp = false; - - proto = eth_get_l3_proto(headers, l2hdr_len); - if (proto == ETH_P_IP) { - *isip4 = true; - - struct ip_header *iphdr; - - assert(hdr_length >= - eth_get_l2_hdr_length(headers) + sizeof(struct ip_header)); - - iphdr = PKT_GET_IP_HDR(headers); - - if (IP_HEADER_VERSION(iphdr) == IP_HEADER_VERSION_4) { - if (iphdr->ip_p == IP_PROTO_TCP) { - *istcp = true; - } else if (iphdr->ip_p == IP_PROTO_UDP) { - *isudp = true; - } - } - } else if (proto == ETH_P_IPV6) { - uint8_t l4proto; - size_t full_ip6hdr_len; - - struct iovec hdr_vec; - hdr_vec.iov_base = (void *) headers; - hdr_vec.iov_len = hdr_length; - - *isip6 = true; - if (eth_parse_ipv6_hdr(&hdr_vec, 1, l2hdr_len, - &l4proto, &full_ip6hdr_len)) { - if (l4proto == IP_PROTO_TCP) { - *istcp = true; - } else if (l4proto == IP_PROTO_UDP) { - *isudp = true; - } - } - } -} - -void -eth_setup_ip4_fragmentation(const void *l2hdr, size_t l2hdr_len, - void *l3hdr, size_t l3hdr_len, - size_t l3payload_len, - size_t frag_offset, bool more_frags) -{ - if (eth_get_l3_proto(l2hdr, l2hdr_len) == ETH_P_IP) { - uint16_t orig_flags; - struct ip_header *iphdr = (struct ip_header *) l3hdr; - uint16_t frag_off_units = frag_offset / IP_FRAG_UNIT_SIZE; - uint16_t new_ip_off; - - assert(frag_offset % IP_FRAG_UNIT_SIZE == 0); - assert((frag_off_units & ~IP_OFFMASK) == 0); - - orig_flags = be16_to_cpu(iphdr->ip_off) & ~(IP_OFFMASK|IP_MF); - new_ip_off = frag_off_units | orig_flags | (more_frags ? IP_MF : 0); - iphdr->ip_off = cpu_to_be16(new_ip_off); - iphdr->ip_len = cpu_to_be16(l3payload_len + l3hdr_len); - } -} - -void -eth_fix_ip4_checksum(void *l3hdr, size_t l3hdr_len) -{ - struct ip_header *iphdr = (struct ip_header *) l3hdr; - iphdr->ip_sum = 0; - iphdr->ip_sum = cpu_to_be16(net_raw_checksum(l3hdr, l3hdr_len)); -} - -uint32_t -eth_calc_pseudo_hdr_csum(struct ip_header *iphdr, uint16_t csl) -{ - struct ip_pseudo_header ipph; - ipph.ip_src = iphdr->ip_src; - ipph.ip_dst = iphdr->ip_dst; - ipph.ip_payload = cpu_to_be16(csl); - ipph.ip_proto = iphdr->ip_p; - ipph.zeros = 0; - return net_checksum_add(sizeof(ipph), (uint8_t *) &ipph); -} - -static bool -eth_is_ip6_extension_header_type(uint8_t hdr_type) -{ - switch (hdr_type) { - case IP6_HOP_BY_HOP: - case IP6_ROUTING: - case IP6_FRAGMENT: - case IP6_ESP: - case IP6_AUTHENTICATION: - case IP6_DESTINATON: - case IP6_MOBILITY: - return true; - default: - return false; - } -} - -bool eth_parse_ipv6_hdr(struct iovec *pkt, int pkt_frags, - size_t ip6hdr_off, uint8_t *l4proto, - size_t *full_hdr_len) -{ - struct ip6_header ip6_hdr; - struct ip6_ext_hdr ext_hdr; - size_t bytes_read; - - bytes_read = iov_to_buf(pkt, pkt_frags, ip6hdr_off, - &ip6_hdr, sizeof(ip6_hdr)); - if (bytes_read < sizeof(ip6_hdr)) { - return false; - } - - *full_hdr_len = sizeof(struct ip6_header); - - if (!eth_is_ip6_extension_header_type(ip6_hdr.ip6_nxt)) { - *l4proto = ip6_hdr.ip6_nxt; - return true; - } - - do { - bytes_read = iov_to_buf(pkt, pkt_frags, ip6hdr_off + *full_hdr_len, - &ext_hdr, sizeof(ext_hdr)); - *full_hdr_len += (ext_hdr.ip6r_len + 1) * IP6_EXT_GRANULARITY; - } while (eth_is_ip6_extension_header_type(ext_hdr.ip6r_nxt)); - - *l4proto = ext_hdr.ip6r_nxt; - return true; -} diff --git a/qemu/net/filter-buffer.c b/qemu/net/filter-buffer.c deleted file mode 100644 index cc6bd9444..000000000 --- a/qemu/net/filter-buffer.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 2015 FUJITSU LIMITED - * Author: Yang Hongyang <yanghy@cn.fujitsu.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or - * later. See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "net/filter.h" -#include "net/queue.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "qemu/timer.h" -#include "qemu/iov.h" -#include "qapi/qmp/qerror.h" -#include "qapi-visit.h" -#include "qom/object.h" - -#define TYPE_FILTER_BUFFER "filter-buffer" - -#define FILTER_BUFFER(obj) \ - OBJECT_CHECK(FilterBufferState, (obj), TYPE_FILTER_BUFFER) - -typedef struct FilterBufferState { - NetFilterState parent_obj; - - NetQueue *incoming_queue; - uint32_t interval; - QEMUTimer release_timer; -} FilterBufferState; - -static void filter_buffer_flush(NetFilterState *nf) -{ - FilterBufferState *s = FILTER_BUFFER(nf); - - if (!qemu_net_queue_flush(s->incoming_queue)) { - /* Unable to empty the queue, purge remaining packets */ - qemu_net_queue_purge(s->incoming_queue, nf->netdev); - } -} - -static void filter_buffer_release_timer(void *opaque) -{ - NetFilterState *nf = opaque; - FilterBufferState *s = FILTER_BUFFER(nf); - - /* - * Note: filter_buffer_flush() drops packets that can't be sent - * TODO: We should leave them queued. But currently there's no way - * for the next filter or receiver to notify us that it can receive - * more packets. - */ - filter_buffer_flush(nf); - /* Timer rearmed to fire again in s->interval microseconds. */ - timer_mod(&s->release_timer, - qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + s->interval); -} - -/* filter APIs */ -static ssize_t filter_buffer_receive_iov(NetFilterState *nf, - NetClientState *sender, - unsigned flags, - const struct iovec *iov, - int iovcnt, - NetPacketSent *sent_cb) -{ - FilterBufferState *s = FILTER_BUFFER(nf); - - /* - * We return size when buffer a packet, the sender will take it as - * a already sent packet, so sent_cb should not be called later. - * - * FIXME: Even if the guest can't receive packets for some reasons, - * the filter can still accept packets until its internal queue is full. - * For example: - * For some reason, receiver could not receive more packets - * (.can_receive() returns zero). Without a filter, at most one packet - * will be queued in incoming queue and sender's poll will be disabled - * unit its sent_cb() was called. With a filter, it will keep receiving - * the packets without caring about the receiver. This is suboptimal. - * May need more thoughts (e.g keeping sent_cb). - */ - qemu_net_queue_append_iov(s->incoming_queue, sender, flags, - iov, iovcnt, NULL); - return iov_size(iov, iovcnt); -} - -static void filter_buffer_cleanup(NetFilterState *nf) -{ - FilterBufferState *s = FILTER_BUFFER(nf); - - if (s->interval) { - timer_del(&s->release_timer); - } - - /* flush packets */ - if (s->incoming_queue) { - filter_buffer_flush(nf); - g_free(s->incoming_queue); - } -} - -static void filter_buffer_setup_timer(NetFilterState *nf) -{ - FilterBufferState *s = FILTER_BUFFER(nf); - - if (s->interval) { - timer_init_us(&s->release_timer, QEMU_CLOCK_VIRTUAL, - filter_buffer_release_timer, nf); - /* Timer armed to fire in s->interval microseconds. */ - timer_mod(&s->release_timer, - qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + s->interval); - } -} - -static void filter_buffer_setup(NetFilterState *nf, Error **errp) -{ - FilterBufferState *s = FILTER_BUFFER(nf); - - /* - * We may want to accept zero interval when VM FT solutions like MC - * or COLO use this filter to release packets on demand. - */ - if (!s->interval) { - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "interval", - "a non-zero interval"); - return; - } - - s->incoming_queue = qemu_new_net_queue(qemu_netfilter_pass_to_next, nf); - filter_buffer_setup_timer(nf); -} - -static void filter_buffer_status_changed(NetFilterState *nf, Error **errp) -{ - FilterBufferState *s = FILTER_BUFFER(nf); - - if (!nf->on) { - if (s->interval) { - timer_del(&s->release_timer); - } - filter_buffer_flush(nf); - } else { - filter_buffer_setup_timer(nf); - } -} - -static void filter_buffer_class_init(ObjectClass *oc, void *data) -{ - NetFilterClass *nfc = NETFILTER_CLASS(oc); - - nfc->setup = filter_buffer_setup; - nfc->cleanup = filter_buffer_cleanup; - nfc->receive_iov = filter_buffer_receive_iov; - nfc->status_changed = filter_buffer_status_changed; -} - -static void filter_buffer_get_interval(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) -{ - FilterBufferState *s = FILTER_BUFFER(obj); - uint32_t value = s->interval; - - visit_type_uint32(v, name, &value, errp); -} - -static void filter_buffer_set_interval(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) -{ - FilterBufferState *s = FILTER_BUFFER(obj); - Error *local_err = NULL; - uint32_t value; - - visit_type_uint32(v, name, &value, &local_err); - if (local_err) { - goto out; - } - if (!value) { - error_setg(&local_err, "Property '%s.%s' requires a positive value", - object_get_typename(obj), name); - goto out; - } - s->interval = value; - -out: - error_propagate(errp, local_err); -} - -static void filter_buffer_init(Object *obj) -{ - object_property_add(obj, "interval", "int", - filter_buffer_get_interval, - filter_buffer_set_interval, NULL, NULL, NULL); -} - -static const TypeInfo filter_buffer_info = { - .name = TYPE_FILTER_BUFFER, - .parent = TYPE_NETFILTER, - .class_init = filter_buffer_class_init, - .instance_init = filter_buffer_init, - .instance_size = sizeof(FilterBufferState), -}; - -static void register_types(void) -{ - type_register_static(&filter_buffer_info); -} - -type_init(register_types); diff --git a/qemu/net/filter-mirror.c b/qemu/net/filter-mirror.c deleted file mode 100644 index c0c4dc60b..000000000 --- a/qemu/net/filter-mirror.c +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. - * Copyright (c) 2016 FUJITSU LIMITED - * Copyright (c) 2016 Intel Corporation - * - * Author: Zhang Chen <zhangchen.fnst@cn.fujitsu.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or - * later. See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "net/filter.h" -#include "net/net.h" -#include "qemu-common.h" -#include "qapi/error.h" -#include "qapi/qmp/qerror.h" -#include "qapi-visit.h" -#include "qom/object.h" -#include "qemu/main-loop.h" -#include "qemu/error-report.h" -#include "trace.h" -#include "sysemu/char.h" -#include "qemu/iov.h" -#include "qemu/sockets.h" - -#define FILTER_MIRROR(obj) \ - OBJECT_CHECK(MirrorState, (obj), TYPE_FILTER_MIRROR) - -#define FILTER_REDIRECTOR(obj) \ - OBJECT_CHECK(MirrorState, (obj), TYPE_FILTER_REDIRECTOR) - -#define TYPE_FILTER_MIRROR "filter-mirror" -#define TYPE_FILTER_REDIRECTOR "filter-redirector" -#define REDIRECTOR_MAX_LEN NET_BUFSIZE - -typedef struct MirrorState { - NetFilterState parent_obj; - char *indev; - char *outdev; - CharDriverState *chr_in; - CharDriverState *chr_out; - int state; /* 0 = getting length, 1 = getting data */ - unsigned int index; - unsigned int packet_len; - uint8_t buf[REDIRECTOR_MAX_LEN]; -} MirrorState; - -static int filter_mirror_send(CharDriverState *chr_out, - const struct iovec *iov, - int iovcnt) -{ - int ret = 0; - ssize_t size = 0; - uint32_t len = 0; - char *buf; - - size = iov_size(iov, iovcnt); - if (!size) { - return 0; - } - - len = htonl(size); - ret = qemu_chr_fe_write_all(chr_out, (uint8_t *)&len, sizeof(len)); - if (ret != sizeof(len)) { - goto err; - } - - buf = g_malloc(size); - iov_to_buf(iov, iovcnt, 0, buf, size); - ret = qemu_chr_fe_write_all(chr_out, (uint8_t *)buf, size); - g_free(buf); - if (ret != size) { - goto err; - } - - return 0; - -err: - return ret < 0 ? ret : -EIO; -} - -static void -redirector_to_filter(NetFilterState *nf, const uint8_t *buf, int len) -{ - struct iovec iov = { - .iov_base = (void *)buf, - .iov_len = len, - }; - - if (nf->direction == NET_FILTER_DIRECTION_ALL || - nf->direction == NET_FILTER_DIRECTION_TX) { - qemu_netfilter_pass_to_next(nf->netdev, 0, &iov, 1, nf); - } - - if (nf->direction == NET_FILTER_DIRECTION_ALL || - nf->direction == NET_FILTER_DIRECTION_RX) { - qemu_netfilter_pass_to_next(nf->netdev->peer, 0, &iov, 1, nf); - } -} - -static int redirector_chr_can_read(void *opaque) -{ - return REDIRECTOR_MAX_LEN; -} - -static void redirector_chr_read(void *opaque, const uint8_t *buf, int size) -{ - NetFilterState *nf = opaque; - MirrorState *s = FILTER_REDIRECTOR(nf); - unsigned int l; - - while (size > 0) { - /* reassemble a packet from the network */ - switch (s->state) { /* 0 = getting length, 1 = getting data */ - case 0: - l = 4 - s->index; - if (l > size) { - l = size; - } - memcpy(s->buf + s->index, buf, l); - buf += l; - size -= l; - s->index += l; - if (s->index == 4) { - /* got length */ - s->packet_len = ntohl(*(uint32_t *)s->buf); - s->index = 0; - s->state = 1; - } - break; - case 1: - l = s->packet_len - s->index; - if (l > size) { - l = size; - } - if (s->index + l <= sizeof(s->buf)) { - memcpy(s->buf + s->index, buf, l); - } else { - error_report("serious error: oversized packet received."); - s->index = s->state = 0; - qemu_chr_add_handlers(s->chr_in, NULL, NULL, NULL, NULL); - return; - } - - s->index += l; - buf += l; - size -= l; - if (s->index >= s->packet_len) { - s->index = 0; - s->state = 0; - redirector_to_filter(nf, s->buf, s->packet_len); - } - break; - } - } -} - -static void redirector_chr_event(void *opaque, int event) -{ - NetFilterState *nf = opaque; - MirrorState *s = FILTER_REDIRECTOR(nf); - - switch (event) { - case CHR_EVENT_CLOSED: - qemu_chr_add_handlers(s->chr_in, NULL, NULL, NULL, NULL); - break; - default: - break; - } -} - -static ssize_t filter_mirror_receive_iov(NetFilterState *nf, - NetClientState *sender, - unsigned flags, - const struct iovec *iov, - int iovcnt, - NetPacketSent *sent_cb) -{ - MirrorState *s = FILTER_MIRROR(nf); - int ret; - - ret = filter_mirror_send(s->chr_out, iov, iovcnt); - if (ret) { - error_report("filter_mirror_send failed(%s)", strerror(-ret)); - } - - /* - * we don't hope this error interrupt the normal - * path of net packet, so we always return zero. - */ - return 0; -} - -static ssize_t filter_redirector_receive_iov(NetFilterState *nf, - NetClientState *sender, - unsigned flags, - const struct iovec *iov, - int iovcnt, - NetPacketSent *sent_cb) -{ - MirrorState *s = FILTER_REDIRECTOR(nf); - int ret; - - if (s->chr_out) { - ret = filter_mirror_send(s->chr_out, iov, iovcnt); - if (ret) { - error_report("filter_mirror_send failed(%s)", strerror(-ret)); - } - return iov_size(iov, iovcnt); - } else { - return 0; - } -} - -static void filter_mirror_cleanup(NetFilterState *nf) -{ - MirrorState *s = FILTER_MIRROR(nf); - - if (s->chr_out) { - qemu_chr_fe_release(s->chr_out); - } -} - -static void filter_redirector_cleanup(NetFilterState *nf) -{ - MirrorState *s = FILTER_REDIRECTOR(nf); - - if (s->chr_in) { - qemu_chr_add_handlers(s->chr_in, NULL, NULL, NULL, NULL); - qemu_chr_fe_release(s->chr_in); - } - if (s->chr_out) { - qemu_chr_fe_release(s->chr_out); - } -} - -static void filter_mirror_setup(NetFilterState *nf, Error **errp) -{ - MirrorState *s = FILTER_MIRROR(nf); - - if (!s->outdev) { - error_setg(errp, "filter filter mirror needs 'outdev' " - "property set"); - return; - } - - s->chr_out = qemu_chr_find(s->outdev); - if (s->chr_out == NULL) { - error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, - "Device '%s' not found", s->outdev); - return; - } - - if (qemu_chr_fe_claim(s->chr_out) != 0) { - error_setg(errp, QERR_DEVICE_IN_USE, s->outdev); - return; - } -} - -static void filter_redirector_setup(NetFilterState *nf, Error **errp) -{ - MirrorState *s = FILTER_REDIRECTOR(nf); - - if (!s->indev && !s->outdev) { - error_setg(errp, "filter redirector needs 'indev' or " - "'outdev' at least one property set"); - return; - } else if (s->indev && s->outdev) { - if (!strcmp(s->indev, s->outdev)) { - error_setg(errp, "'indev' and 'outdev' could not be same " - "for filter redirector"); - return; - } - } - - s->state = s->index = 0; - - if (s->indev) { - s->chr_in = qemu_chr_find(s->indev); - if (s->chr_in == NULL) { - error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, - "IN Device '%s' not found", s->indev); - return; - } - - qemu_chr_fe_claim_no_fail(s->chr_in); - qemu_chr_add_handlers(s->chr_in, redirector_chr_can_read, - redirector_chr_read, redirector_chr_event, nf); - } - - if (s->outdev) { - s->chr_out = qemu_chr_find(s->outdev); - if (s->chr_out == NULL) { - error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, - "OUT Device '%s' not found", s->outdev); - return; - } - qemu_chr_fe_claim_no_fail(s->chr_out); - } -} - -static void filter_mirror_class_init(ObjectClass *oc, void *data) -{ - NetFilterClass *nfc = NETFILTER_CLASS(oc); - - nfc->setup = filter_mirror_setup; - nfc->cleanup = filter_mirror_cleanup; - nfc->receive_iov = filter_mirror_receive_iov; -} - -static void filter_redirector_class_init(ObjectClass *oc, void *data) -{ - NetFilterClass *nfc = NETFILTER_CLASS(oc); - - nfc->setup = filter_redirector_setup; - nfc->cleanup = filter_redirector_cleanup; - nfc->receive_iov = filter_redirector_receive_iov; -} - -static char *filter_redirector_get_indev(Object *obj, Error **errp) -{ - MirrorState *s = FILTER_REDIRECTOR(obj); - - return g_strdup(s->indev); -} - -static void -filter_redirector_set_indev(Object *obj, const char *value, Error **errp) -{ - MirrorState *s = FILTER_REDIRECTOR(obj); - - g_free(s->indev); - s->indev = g_strdup(value); -} - -static char *filter_mirror_get_outdev(Object *obj, Error **errp) -{ - MirrorState *s = FILTER_MIRROR(obj); - - return g_strdup(s->outdev); -} - -static void -filter_mirror_set_outdev(Object *obj, const char *value, Error **errp) -{ - MirrorState *s = FILTER_MIRROR(obj); - - g_free(s->outdev); - s->outdev = g_strdup(value); - if (!s->outdev) { - error_setg(errp, "filter filter mirror needs 'outdev' " - "property set"); - return; - } -} - -static char *filter_redirector_get_outdev(Object *obj, Error **errp) -{ - MirrorState *s = FILTER_REDIRECTOR(obj); - - return g_strdup(s->outdev); -} - -static void -filter_redirector_set_outdev(Object *obj, const char *value, Error **errp) -{ - MirrorState *s = FILTER_REDIRECTOR(obj); - - g_free(s->outdev); - s->outdev = g_strdup(value); -} - -static void filter_mirror_init(Object *obj) -{ - object_property_add_str(obj, "outdev", filter_mirror_get_outdev, - filter_mirror_set_outdev, NULL); -} - -static void filter_redirector_init(Object *obj) -{ - object_property_add_str(obj, "indev", filter_redirector_get_indev, - filter_redirector_set_indev, NULL); - object_property_add_str(obj, "outdev", filter_redirector_get_outdev, - filter_redirector_set_outdev, NULL); -} - -static void filter_mirror_fini(Object *obj) -{ - MirrorState *s = FILTER_MIRROR(obj); - - g_free(s->outdev); -} - -static void filter_redirector_fini(Object *obj) -{ - MirrorState *s = FILTER_REDIRECTOR(obj); - - g_free(s->indev); - g_free(s->outdev); -} - -static const TypeInfo filter_redirector_info = { - .name = TYPE_FILTER_REDIRECTOR, - .parent = TYPE_NETFILTER, - .class_init = filter_redirector_class_init, - .instance_init = filter_redirector_init, - .instance_finalize = filter_redirector_fini, - .instance_size = sizeof(MirrorState), -}; - -static const TypeInfo filter_mirror_info = { - .name = TYPE_FILTER_MIRROR, - .parent = TYPE_NETFILTER, - .class_init = filter_mirror_class_init, - .instance_init = filter_mirror_init, - .instance_finalize = filter_mirror_fini, - .instance_size = sizeof(MirrorState), -}; - -static void register_types(void) -{ - type_register_static(&filter_mirror_info); - type_register_static(&filter_redirector_info); -} - -type_init(register_types); diff --git a/qemu/net/filter.c b/qemu/net/filter.c deleted file mode 100644 index 8ac79f3b7..000000000 --- a/qemu/net/filter.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright (c) 2015 FUJITSU LIMITED - * Author: Yang Hongyang <yanghy@cn.fujitsu.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or - * later. See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "qapi/qmp/qerror.h" -#include "qemu/error-report.h" - -#include "net/filter.h" -#include "net/net.h" -#include "net/vhost_net.h" -#include "qom/object_interfaces.h" -#include "qemu/iov.h" - -static inline bool qemu_can_skip_netfilter(NetFilterState *nf) -{ - return !nf->on; -} - -ssize_t qemu_netfilter_receive(NetFilterState *nf, - NetFilterDirection direction, - NetClientState *sender, - unsigned flags, - const struct iovec *iov, - int iovcnt, - NetPacketSent *sent_cb) -{ - if (qemu_can_skip_netfilter(nf)) { - return 0; - } - if (nf->direction == direction || - nf->direction == NET_FILTER_DIRECTION_ALL) { - return NETFILTER_GET_CLASS(OBJECT(nf))->receive_iov( - nf, sender, flags, iov, iovcnt, sent_cb); - } - - return 0; -} - -static NetFilterState *netfilter_next(NetFilterState *nf, - NetFilterDirection dir) -{ - NetFilterState *next; - - if (dir == NET_FILTER_DIRECTION_TX) { - /* forward walk through filters */ - next = QTAILQ_NEXT(nf, next); - } else { - /* reverse order */ - next = QTAILQ_PREV(nf, NetFilterHead, next); - } - - return next; -} - -ssize_t qemu_netfilter_pass_to_next(NetClientState *sender, - unsigned flags, - const struct iovec *iov, - int iovcnt, - void *opaque) -{ - int ret = 0; - int direction; - NetFilterState *nf = opaque; - NetFilterState *next = NULL; - - if (!sender || !sender->peer) { - /* no receiver, or sender been deleted, no need to pass it further */ - goto out; - } - - if (nf->direction == NET_FILTER_DIRECTION_ALL) { - if (sender == nf->netdev) { - /* This packet is sent by netdev itself */ - direction = NET_FILTER_DIRECTION_TX; - } else { - direction = NET_FILTER_DIRECTION_RX; - } - } else { - direction = nf->direction; - } - - next = netfilter_next(nf, direction); - while (next) { - /* - * if qemu_netfilter_pass_to_next been called, means that - * the packet has been hold by filter and has already retured size - * to the sender, so sent_cb shouldn't be called later, just - * pass NULL to next. - */ - ret = qemu_netfilter_receive(next, direction, sender, flags, iov, - iovcnt, NULL); - if (ret) { - return ret; - } - next = netfilter_next(next, direction); - } - - /* - * We have gone through all filters, pass it to receiver. - * Do the valid check again incase sender or receiver been - * deleted while we go through filters. - */ - if (sender && sender->peer) { - qemu_net_queue_send_iov(sender->peer->incoming_queue, - sender, flags, iov, iovcnt, NULL); - } - -out: - /* no receiver, or sender been deleted */ - return iov_size(iov, iovcnt); -} - -static char *netfilter_get_netdev_id(Object *obj, Error **errp) -{ - NetFilterState *nf = NETFILTER(obj); - - return g_strdup(nf->netdev_id); -} - -static void netfilter_set_netdev_id(Object *obj, const char *str, Error **errp) -{ - NetFilterState *nf = NETFILTER(obj); - - nf->netdev_id = g_strdup(str); -} - -static int netfilter_get_direction(Object *obj, Error **errp G_GNUC_UNUSED) -{ - NetFilterState *nf = NETFILTER(obj); - return nf->direction; -} - -static void netfilter_set_direction(Object *obj, int direction, Error **errp) -{ - NetFilterState *nf = NETFILTER(obj); - nf->direction = direction; -} - -static char *netfilter_get_status(Object *obj, Error **errp) -{ - NetFilterState *nf = NETFILTER(obj); - - return nf->on ? g_strdup("on") : g_strdup("off"); -} - -static void netfilter_set_status(Object *obj, const char *str, Error **errp) -{ - NetFilterState *nf = NETFILTER(obj); - NetFilterClass *nfc = NETFILTER_GET_CLASS(obj); - - if (strcmp(str, "on") && strcmp(str, "off")) { - error_setg(errp, "Invalid value for netfilter status, " - "should be 'on' or 'off'"); - return; - } - if (nf->on == !strcmp(str, "on")) { - return; - } - nf->on = !nf->on; - if (nf->netdev && nfc->status_changed) { - nfc->status_changed(nf, errp); - } -} - -static void netfilter_init(Object *obj) -{ - NetFilterState *nf = NETFILTER(obj); - - nf->on = true; - - object_property_add_str(obj, "netdev", - netfilter_get_netdev_id, netfilter_set_netdev_id, - NULL); - object_property_add_enum(obj, "queue", "NetFilterDirection", - NetFilterDirection_lookup, - netfilter_get_direction, netfilter_set_direction, - NULL); - object_property_add_str(obj, "status", - netfilter_get_status, netfilter_set_status, - NULL); -} - -static void netfilter_complete(UserCreatable *uc, Error **errp) -{ - NetFilterState *nf = NETFILTER(uc); - NetClientState *ncs[MAX_QUEUE_NUM]; - NetFilterClass *nfc = NETFILTER_GET_CLASS(uc); - int queues; - Error *local_err = NULL; - - if (!nf->netdev_id) { - error_setg(errp, "Parameter 'netdev' is required"); - return; - } - - queues = qemu_find_net_clients_except(nf->netdev_id, ncs, - NET_CLIENT_OPTIONS_KIND_NIC, - MAX_QUEUE_NUM); - if (queues < 1) { - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "netdev", - "a network backend id"); - return; - } else if (queues > 1) { - error_setg(errp, "multiqueue is not supported"); - return; - } - - if (get_vhost_net(ncs[0])) { - error_setg(errp, "Vhost is not supported"); - return; - } - - nf->netdev = ncs[0]; - - if (nfc->setup) { - nfc->setup(nf, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } - } - QTAILQ_INSERT_TAIL(&nf->netdev->filters, nf, next); -} - -static void netfilter_finalize(Object *obj) -{ - NetFilterState *nf = NETFILTER(obj); - NetFilterClass *nfc = NETFILTER_GET_CLASS(obj); - - if (nfc->cleanup) { - nfc->cleanup(nf); - } - - if (nf->netdev && !QTAILQ_EMPTY(&nf->netdev->filters) && - nf->next.tqe_prev) { - QTAILQ_REMOVE(&nf->netdev->filters, nf, next); - } - g_free(nf->netdev_id); -} - -static void netfilter_class_init(ObjectClass *oc, void *data) -{ - UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); - - ucc->complete = netfilter_complete; -} - -static const TypeInfo netfilter_info = { - .name = TYPE_NETFILTER, - .parent = TYPE_OBJECT, - .abstract = true, - .class_size = sizeof(NetFilterClass), - .class_init = netfilter_class_init, - .instance_size = sizeof(NetFilterState), - .instance_init = netfilter_init, - .instance_finalize = netfilter_finalize, - .interfaces = (InterfaceInfo[]) { - { TYPE_USER_CREATABLE }, - { } - } -}; - -static void register_types(void) -{ - type_register_static(&netfilter_info); -} - -type_init(register_types); diff --git a/qemu/net/hub.c b/qemu/net/hub.c deleted file mode 100644 index 6d90c6ee6..000000000 --- a/qemu/net/hub.c +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Hub net client - * - * Copyright IBM, Corp. 2012 - * - * Authors: - * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> - * Zhi Yong Wu <wuzhy@linux.vnet.ibm.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2 or later. - * See the COPYING.LIB file in the top-level directory. - * - */ - -#include "qemu/osdep.h" -#include "monitor/monitor.h" -#include "net/net.h" -#include "clients.h" -#include "hub.h" -#include "qemu/iov.h" - -/* - * A hub broadcasts incoming packets to all its ports except the source port. - * Hubs can be used to provide independent network segments, also confusingly - * named the QEMU 'vlan' feature. - */ - -typedef struct NetHub NetHub; - -typedef struct NetHubPort { - NetClientState nc; - QLIST_ENTRY(NetHubPort) next; - NetHub *hub; - int id; -} NetHubPort; - -struct NetHub { - int id; - QLIST_ENTRY(NetHub) next; - int num_ports; - QLIST_HEAD(, NetHubPort) ports; -}; - -static QLIST_HEAD(, NetHub) hubs = QLIST_HEAD_INITIALIZER(&hubs); - -static ssize_t net_hub_receive(NetHub *hub, NetHubPort *source_port, - const uint8_t *buf, size_t len) -{ - NetHubPort *port; - - QLIST_FOREACH(port, &hub->ports, next) { - if (port == source_port) { - continue; - } - - qemu_send_packet(&port->nc, buf, len); - } - return len; -} - -static ssize_t net_hub_receive_iov(NetHub *hub, NetHubPort *source_port, - const struct iovec *iov, int iovcnt) -{ - NetHubPort *port; - ssize_t len = iov_size(iov, iovcnt); - - QLIST_FOREACH(port, &hub->ports, next) { - if (port == source_port) { - continue; - } - - qemu_sendv_packet(&port->nc, iov, iovcnt); - } - return len; -} - -static NetHub *net_hub_new(int id) -{ - NetHub *hub; - - hub = g_malloc(sizeof(*hub)); - hub->id = id; - hub->num_ports = 0; - QLIST_INIT(&hub->ports); - - QLIST_INSERT_HEAD(&hubs, hub, next); - - return hub; -} - -static int net_hub_port_can_receive(NetClientState *nc) -{ - NetHubPort *port; - NetHubPort *src_port = DO_UPCAST(NetHubPort, nc, nc); - NetHub *hub = src_port->hub; - - QLIST_FOREACH(port, &hub->ports, next) { - if (port == src_port) { - continue; - } - - if (qemu_can_send_packet(&port->nc)) { - return 1; - } - } - - return 0; -} - -static ssize_t net_hub_port_receive(NetClientState *nc, - const uint8_t *buf, size_t len) -{ - NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc); - - return net_hub_receive(port->hub, port, buf, len); -} - -static ssize_t net_hub_port_receive_iov(NetClientState *nc, - const struct iovec *iov, int iovcnt) -{ - NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc); - - return net_hub_receive_iov(port->hub, port, iov, iovcnt); -} - -static void net_hub_port_cleanup(NetClientState *nc) -{ - NetHubPort *port = DO_UPCAST(NetHubPort, nc, nc); - - QLIST_REMOVE(port, next); -} - -static NetClientInfo net_hub_port_info = { - .type = NET_CLIENT_OPTIONS_KIND_HUBPORT, - .size = sizeof(NetHubPort), - .can_receive = net_hub_port_can_receive, - .receive = net_hub_port_receive, - .receive_iov = net_hub_port_receive_iov, - .cleanup = net_hub_port_cleanup, -}; - -static NetHubPort *net_hub_port_new(NetHub *hub, const char *name) -{ - NetClientState *nc; - NetHubPort *port; - int id = hub->num_ports++; - char default_name[128]; - - if (!name) { - snprintf(default_name, sizeof(default_name), - "hub%dport%d", hub->id, id); - name = default_name; - } - - nc = qemu_new_net_client(&net_hub_port_info, NULL, "hub", name); - port = DO_UPCAST(NetHubPort, nc, nc); - port->id = id; - port->hub = hub; - - QLIST_INSERT_HEAD(&hub->ports, port, next); - - return port; -} - -/** - * Create a port on a given hub - * @name: Net client name or NULL for default name. - * - * If there is no existing hub with the given id then a new hub is created. - */ -NetClientState *net_hub_add_port(int hub_id, const char *name) -{ - NetHub *hub; - NetHubPort *port; - - QLIST_FOREACH(hub, &hubs, next) { - if (hub->id == hub_id) { - break; - } - } - - if (!hub) { - hub = net_hub_new(hub_id); - } - - port = net_hub_port_new(hub, name); - return &port->nc; -} - -/** - * Find a specific client on a hub - */ -NetClientState *net_hub_find_client_by_name(int hub_id, const char *name) -{ - NetHub *hub; - NetHubPort *port; - NetClientState *peer; - - QLIST_FOREACH(hub, &hubs, next) { - if (hub->id == hub_id) { - QLIST_FOREACH(port, &hub->ports, next) { - peer = port->nc.peer; - - if (peer && strcmp(peer->name, name) == 0) { - return peer; - } - } - } - } - return NULL; -} - -/** - * Find a available port on a hub; otherwise create one new port - */ -NetClientState *net_hub_port_find(int hub_id) -{ - NetHub *hub; - NetHubPort *port; - NetClientState *nc; - - QLIST_FOREACH(hub, &hubs, next) { - if (hub->id == hub_id) { - QLIST_FOREACH(port, &hub->ports, next) { - nc = port->nc.peer; - if (!nc) { - return &(port->nc); - } - } - break; - } - } - - nc = net_hub_add_port(hub_id, NULL); - return nc; -} - -/** - * Print hub configuration - */ -void net_hub_info(Monitor *mon) -{ - NetHub *hub; - NetHubPort *port; - - QLIST_FOREACH(hub, &hubs, next) { - monitor_printf(mon, "hub %d\n", hub->id); - QLIST_FOREACH(port, &hub->ports, next) { - monitor_printf(mon, " \\ %s", port->nc.name); - if (port->nc.peer) { - monitor_printf(mon, ": "); - print_net_client(mon, port->nc.peer); - } else { - monitor_printf(mon, "\n"); - } - } - } -} - -/** - * Get the hub id that a client is connected to - * - * @id: Pointer for hub id output, may be NULL - */ -int net_hub_id_for_client(NetClientState *nc, int *id) -{ - NetHubPort *port; - - if (nc->info->type == NET_CLIENT_OPTIONS_KIND_HUBPORT) { - port = DO_UPCAST(NetHubPort, nc, nc); - } else if (nc->peer != NULL && nc->peer->info->type == - NET_CLIENT_OPTIONS_KIND_HUBPORT) { - port = DO_UPCAST(NetHubPort, nc, nc->peer); - } else { - return -ENOENT; - } - - if (id) { - *id = port->hub->id; - } - return 0; -} - -int net_init_hubport(const NetClientOptions *opts, const char *name, - NetClientState *peer, Error **errp) -{ - const NetdevHubPortOptions *hubport; - - assert(opts->type == NET_CLIENT_OPTIONS_KIND_HUBPORT); - assert(!peer); - hubport = opts->u.hubport.data; - - net_hub_add_port(hubport->hubid, name); - return 0; -} - -/** - * Warn if hub configurations are likely wrong - */ -void net_hub_check_clients(void) -{ - NetHub *hub; - NetHubPort *port; - NetClientState *peer; - - QLIST_FOREACH(hub, &hubs, next) { - int has_nic = 0, has_host_dev = 0; - - QLIST_FOREACH(port, &hub->ports, next) { - peer = port->nc.peer; - if (!peer) { - fprintf(stderr, "Warning: hub port %s has no peer\n", - port->nc.name); - continue; - } - - switch (peer->info->type) { - case NET_CLIENT_OPTIONS_KIND_NIC: - has_nic = 1; - break; - case NET_CLIENT_OPTIONS_KIND_USER: - case NET_CLIENT_OPTIONS_KIND_TAP: - case NET_CLIENT_OPTIONS_KIND_SOCKET: - case NET_CLIENT_OPTIONS_KIND_VDE: - case NET_CLIENT_OPTIONS_KIND_VHOST_USER: - has_host_dev = 1; - break; - default: - break; - } - } - if (has_host_dev && !has_nic) { - fprintf(stderr, "Warning: vlan %d with no nics\n", hub->id); - } - if (has_nic && !has_host_dev) { - fprintf(stderr, - "Warning: vlan %d is not connected to host network\n", - hub->id); - } - } -} - -bool net_hub_flush(NetClientState *nc) -{ - NetHubPort *port; - NetHubPort *source_port = DO_UPCAST(NetHubPort, nc, nc); - int ret = 0; - - QLIST_FOREACH(port, &source_port->hub->ports, next) { - if (port != source_port) { - ret += qemu_net_queue_flush(port->nc.incoming_queue); - } - } - return ret ? true : false; -} diff --git a/qemu/net/hub.h b/qemu/net/hub.h deleted file mode 100644 index a625effe0..000000000 --- a/qemu/net/hub.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Hub net client - * - * Copyright IBM, Corp. 2012 - * - * Authors: - * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> - * Zhi Yong Wu <wuzhy@linux.vnet.ibm.com> - * - * This work is licensed under the terms of the GNU LGPL, version 2 or later. - * See the COPYING.LIB file in the top-level directory. - * - */ - -#ifndef NET_HUB_H -#define NET_HUB_H - -#include "qemu-common.h" - -NetClientState *net_hub_add_port(int hub_id, const char *name); -NetClientState *net_hub_find_client_by_name(int hub_id, const char *name); -void net_hub_info(Monitor *mon); -void net_hub_check_clients(void); -bool net_hub_flush(NetClientState *nc); - -#endif /* NET_HUB_H */ diff --git a/qemu/net/l2tpv3.c b/qemu/net/l2tpv3.c deleted file mode 100644 index 5c668f737..000000000 --- a/qemu/net/l2tpv3.c +++ /dev/null @@ -1,744 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * Copyright (c) 2012-2014 Cisco Systems - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include <linux/ip.h> -#include <netdb.h> -#include "net/net.h" -#include "clients.h" -#include "qemu-common.h" -#include "qemu/error-report.h" -#include "qemu/option.h" -#include "qemu/sockets.h" -#include "qemu/iov.h" -#include "qemu/main-loop.h" - - -/* The buffer size needs to be investigated for optimum numbers and - * optimum means of paging in on different systems. This size is - * chosen to be sufficient to accommodate one packet with some headers - */ - -#define BUFFER_ALIGN sysconf(_SC_PAGESIZE) -#define BUFFER_SIZE 2048 -#define IOVSIZE 2 -#define MAX_L2TPV3_MSGCNT 64 -#define MAX_L2TPV3_IOVCNT (MAX_L2TPV3_MSGCNT * IOVSIZE) - -/* Header set to 0x30000 signifies a data packet */ - -#define L2TPV3_DATA_PACKET 0x30000 - -/* IANA-assigned IP protocol ID for L2TPv3 */ - -#ifndef IPPROTO_L2TP -#define IPPROTO_L2TP 0x73 -#endif - -typedef struct NetL2TPV3State { - NetClientState nc; - int fd; - - /* - * these are used for xmit - that happens packet a time - * and for first sign of life packet (easier to parse that once) - */ - - uint8_t *header_buf; - struct iovec *vec; - - /* - * these are used for receive - try to "eat" up to 32 packets at a time - */ - - struct mmsghdr *msgvec; - - /* - * peer address - */ - - struct sockaddr_storage *dgram_dst; - uint32_t dst_size; - - /* - * L2TPv3 parameters - */ - - uint64_t rx_cookie; - uint64_t tx_cookie; - uint32_t rx_session; - uint32_t tx_session; - uint32_t header_size; - uint32_t counter; - - /* - * DOS avoidance in error handling - */ - - bool header_mismatch; - - /* - * Ring buffer handling - */ - - int queue_head; - int queue_tail; - int queue_depth; - - /* - * Precomputed offsets - */ - - uint32_t offset; - uint32_t cookie_offset; - uint32_t counter_offset; - uint32_t session_offset; - - /* Poll Control */ - - bool read_poll; - bool write_poll; - - /* Flags */ - - bool ipv6; - bool udp; - bool has_counter; - bool pin_counter; - bool cookie; - bool cookie_is_64; - -} NetL2TPV3State; - -static void net_l2tpv3_send(void *opaque); -static void l2tpv3_writable(void *opaque); - -static void l2tpv3_update_fd_handler(NetL2TPV3State *s) -{ - qemu_set_fd_handler(s->fd, - s->read_poll ? net_l2tpv3_send : NULL, - s->write_poll ? l2tpv3_writable : NULL, - s); -} - -static void l2tpv3_read_poll(NetL2TPV3State *s, bool enable) -{ - if (s->read_poll != enable) { - s->read_poll = enable; - l2tpv3_update_fd_handler(s); - } -} - -static void l2tpv3_write_poll(NetL2TPV3State *s, bool enable) -{ - if (s->write_poll != enable) { - s->write_poll = enable; - l2tpv3_update_fd_handler(s); - } -} - -static void l2tpv3_writable(void *opaque) -{ - NetL2TPV3State *s = opaque; - l2tpv3_write_poll(s, false); - qemu_flush_queued_packets(&s->nc); -} - -static void l2tpv3_send_completed(NetClientState *nc, ssize_t len) -{ - NetL2TPV3State *s = DO_UPCAST(NetL2TPV3State, nc, nc); - l2tpv3_read_poll(s, true); -} - -static void l2tpv3_poll(NetClientState *nc, bool enable) -{ - NetL2TPV3State *s = DO_UPCAST(NetL2TPV3State, nc, nc); - l2tpv3_write_poll(s, enable); - l2tpv3_read_poll(s, enable); -} - -static void l2tpv3_form_header(NetL2TPV3State *s) -{ - uint32_t *counter; - - if (s->udp) { - stl_be_p((uint32_t *) s->header_buf, L2TPV3_DATA_PACKET); - } - stl_be_p( - (uint32_t *) (s->header_buf + s->session_offset), - s->tx_session - ); - if (s->cookie) { - if (s->cookie_is_64) { - stq_be_p( - (uint64_t *)(s->header_buf + s->cookie_offset), - s->tx_cookie - ); - } else { - stl_be_p( - (uint32_t *) (s->header_buf + s->cookie_offset), - s->tx_cookie - ); - } - } - if (s->has_counter) { - counter = (uint32_t *)(s->header_buf + s->counter_offset); - if (s->pin_counter) { - *counter = 0; - } else { - stl_be_p(counter, ++s->counter); - } - } -} - -static ssize_t net_l2tpv3_receive_dgram_iov(NetClientState *nc, - const struct iovec *iov, - int iovcnt) -{ - NetL2TPV3State *s = DO_UPCAST(NetL2TPV3State, nc, nc); - - struct msghdr message; - int ret; - - if (iovcnt > MAX_L2TPV3_IOVCNT - 1) { - error_report( - "iovec too long %d > %d, change l2tpv3.h", - iovcnt, MAX_L2TPV3_IOVCNT - ); - return -1; - } - l2tpv3_form_header(s); - memcpy(s->vec + 1, iov, iovcnt * sizeof(struct iovec)); - s->vec->iov_base = s->header_buf; - s->vec->iov_len = s->offset; - message.msg_name = s->dgram_dst; - message.msg_namelen = s->dst_size; - message.msg_iov = s->vec; - message.msg_iovlen = iovcnt + 1; - message.msg_control = NULL; - message.msg_controllen = 0; - message.msg_flags = 0; - do { - ret = sendmsg(s->fd, &message, 0); - } while ((ret == -1) && (errno == EINTR)); - if (ret > 0) { - ret -= s->offset; - } else if (ret == 0) { - /* belt and braces - should not occur on DGRAM - * we should get an error and never a 0 send - */ - ret = iov_size(iov, iovcnt); - } else { - /* signal upper layer that socket buffer is full */ - ret = -errno; - if (ret == -EAGAIN || ret == -ENOBUFS) { - l2tpv3_write_poll(s, true); - ret = 0; - } - } - return ret; -} - -static ssize_t net_l2tpv3_receive_dgram(NetClientState *nc, - const uint8_t *buf, - size_t size) -{ - NetL2TPV3State *s = DO_UPCAST(NetL2TPV3State, nc, nc); - - struct iovec *vec; - struct msghdr message; - ssize_t ret = 0; - - l2tpv3_form_header(s); - vec = s->vec; - vec->iov_base = s->header_buf; - vec->iov_len = s->offset; - vec++; - vec->iov_base = (void *) buf; - vec->iov_len = size; - message.msg_name = s->dgram_dst; - message.msg_namelen = s->dst_size; - message.msg_iov = s->vec; - message.msg_iovlen = 2; - message.msg_control = NULL; - message.msg_controllen = 0; - message.msg_flags = 0; - do { - ret = sendmsg(s->fd, &message, 0); - } while ((ret == -1) && (errno == EINTR)); - if (ret > 0) { - ret -= s->offset; - } else if (ret == 0) { - /* belt and braces - should not occur on DGRAM - * we should get an error and never a 0 send - */ - ret = size; - } else { - ret = -errno; - if (ret == -EAGAIN || ret == -ENOBUFS) { - /* signal upper layer that socket buffer is full */ - l2tpv3_write_poll(s, true); - ret = 0; - } - } - return ret; -} - -static int l2tpv3_verify_header(NetL2TPV3State *s, uint8_t *buf) -{ - - uint32_t *session; - uint64_t cookie; - - if ((!s->udp) && (!s->ipv6)) { - buf += sizeof(struct iphdr) /* fix for ipv4 raw */; - } - - /* we do not do a strict check for "data" packets as per - * the RFC spec because the pure IP spec does not have - * that anyway. - */ - - if (s->cookie) { - if (s->cookie_is_64) { - cookie = ldq_be_p(buf + s->cookie_offset); - } else { - cookie = ldl_be_p(buf + s->cookie_offset) & 0xffffffffULL; - } - if (cookie != s->rx_cookie) { - if (!s->header_mismatch) { - error_report("unknown cookie id"); - } - return -1; - } - } - session = (uint32_t *) (buf + s->session_offset); - if (ldl_be_p(session) != s->rx_session) { - if (!s->header_mismatch) { - error_report("session mismatch"); - } - return -1; - } - return 0; -} - -static void net_l2tpv3_process_queue(NetL2TPV3State *s) -{ - int size = 0; - struct iovec *vec; - bool bad_read; - int data_size; - struct mmsghdr *msgvec; - - /* go into ring mode only if there is a "pending" tail */ - if (s->queue_depth > 0) { - do { - msgvec = s->msgvec + s->queue_tail; - if (msgvec->msg_len > 0) { - data_size = msgvec->msg_len - s->header_size; - vec = msgvec->msg_hdr.msg_iov; - if ((data_size > 0) && - (l2tpv3_verify_header(s, vec->iov_base) == 0)) { - vec++; - /* Use the legacy delivery for now, we will - * switch to using our own ring as a queueing mechanism - * at a later date - */ - size = qemu_send_packet_async( - &s->nc, - vec->iov_base, - data_size, - l2tpv3_send_completed - ); - if (size == 0) { - l2tpv3_read_poll(s, false); - } - bad_read = false; - } else { - bad_read = true; - if (!s->header_mismatch) { - /* report error only once */ - error_report("l2tpv3 header verification failed"); - s->header_mismatch = true; - } - } - } else { - bad_read = true; - } - s->queue_tail = (s->queue_tail + 1) % MAX_L2TPV3_MSGCNT; - s->queue_depth--; - } while ( - (s->queue_depth > 0) && - qemu_can_send_packet(&s->nc) && - ((size > 0) || bad_read) - ); - } -} - -static void net_l2tpv3_send(void *opaque) -{ - NetL2TPV3State *s = opaque; - int target_count, count; - struct mmsghdr *msgvec; - - /* go into ring mode only if there is a "pending" tail */ - - if (s->queue_depth) { - - /* The ring buffer we use has variable intake - * count of how much we can read varies - adjust accordingly - */ - - target_count = MAX_L2TPV3_MSGCNT - s->queue_depth; - - /* Ensure we do not overrun the ring when we have - * a lot of enqueued packets - */ - - if (s->queue_head + target_count > MAX_L2TPV3_MSGCNT) { - target_count = MAX_L2TPV3_MSGCNT - s->queue_head; - } - } else { - - /* we do not have any pending packets - we can use - * the whole message vector linearly instead of using - * it as a ring - */ - - s->queue_head = 0; - s->queue_tail = 0; - target_count = MAX_L2TPV3_MSGCNT; - } - - msgvec = s->msgvec + s->queue_head; - if (target_count > 0) { - do { - count = recvmmsg( - s->fd, - msgvec, - target_count, MSG_DONTWAIT, NULL); - } while ((count == -1) && (errno == EINTR)); - if (count < 0) { - /* Recv error - we still need to flush packets here, - * (re)set queue head to current position - */ - count = 0; - } - s->queue_head = (s->queue_head + count) % MAX_L2TPV3_MSGCNT; - s->queue_depth += count; - } - net_l2tpv3_process_queue(s); -} - -static void destroy_vector(struct mmsghdr *msgvec, int count, int iovcount) -{ - int i, j; - struct iovec *iov; - struct mmsghdr *cleanup = msgvec; - if (cleanup) { - for (i = 0; i < count; i++) { - if (cleanup->msg_hdr.msg_iov) { - iov = cleanup->msg_hdr.msg_iov; - for (j = 0; j < iovcount; j++) { - g_free(iov->iov_base); - iov++; - } - g_free(cleanup->msg_hdr.msg_iov); - } - cleanup++; - } - g_free(msgvec); - } -} - -static struct mmsghdr *build_l2tpv3_vector(NetL2TPV3State *s, int count) -{ - int i; - struct iovec *iov; - struct mmsghdr *msgvec, *result; - - msgvec = g_new(struct mmsghdr, count); - result = msgvec; - for (i = 0; i < count ; i++) { - msgvec->msg_hdr.msg_name = NULL; - msgvec->msg_hdr.msg_namelen = 0; - iov = g_new(struct iovec, IOVSIZE); - msgvec->msg_hdr.msg_iov = iov; - iov->iov_base = g_malloc(s->header_size); - iov->iov_len = s->header_size; - iov++ ; - iov->iov_base = qemu_memalign(BUFFER_ALIGN, BUFFER_SIZE); - iov->iov_len = BUFFER_SIZE; - msgvec->msg_hdr.msg_iovlen = 2; - msgvec->msg_hdr.msg_control = NULL; - msgvec->msg_hdr.msg_controllen = 0; - msgvec->msg_hdr.msg_flags = 0; - msgvec++; - } - return result; -} - -static void net_l2tpv3_cleanup(NetClientState *nc) -{ - NetL2TPV3State *s = DO_UPCAST(NetL2TPV3State, nc, nc); - qemu_purge_queued_packets(nc); - l2tpv3_read_poll(s, false); - l2tpv3_write_poll(s, false); - if (s->fd >= 0) { - close(s->fd); - } - destroy_vector(s->msgvec, MAX_L2TPV3_MSGCNT, IOVSIZE); - g_free(s->vec); - g_free(s->header_buf); - g_free(s->dgram_dst); -} - -static NetClientInfo net_l2tpv3_info = { - .type = NET_CLIENT_OPTIONS_KIND_L2TPV3, - .size = sizeof(NetL2TPV3State), - .receive = net_l2tpv3_receive_dgram, - .receive_iov = net_l2tpv3_receive_dgram_iov, - .poll = l2tpv3_poll, - .cleanup = net_l2tpv3_cleanup, -}; - -int net_init_l2tpv3(const NetClientOptions *opts, - const char *name, - NetClientState *peer, Error **errp) -{ - /* FIXME error_setg(errp, ...) on failure */ - const NetdevL2TPv3Options *l2tpv3; - NetL2TPV3State *s; - NetClientState *nc; - int fd = -1, gairet; - struct addrinfo hints; - struct addrinfo *result = NULL; - char *srcport, *dstport; - - nc = qemu_new_net_client(&net_l2tpv3_info, peer, "l2tpv3", name); - - s = DO_UPCAST(NetL2TPV3State, nc, nc); - - s->queue_head = 0; - s->queue_tail = 0; - s->header_mismatch = false; - - assert(opts->type == NET_CLIENT_OPTIONS_KIND_L2TPV3); - l2tpv3 = opts->u.l2tpv3.data; - - if (l2tpv3->has_ipv6 && l2tpv3->ipv6) { - s->ipv6 = l2tpv3->ipv6; - } else { - s->ipv6 = false; - } - - if ((l2tpv3->has_offset) && (l2tpv3->offset > 256)) { - error_report("l2tpv3_open : offset must be less than 256 bytes"); - goto outerr; - } - - if (l2tpv3->has_rxcookie || l2tpv3->has_txcookie) { - if (l2tpv3->has_rxcookie && l2tpv3->has_txcookie) { - s->cookie = true; - } else { - goto outerr; - } - } else { - s->cookie = false; - } - - if (l2tpv3->has_cookie64 || l2tpv3->cookie64) { - s->cookie_is_64 = true; - } else { - s->cookie_is_64 = false; - } - - if (l2tpv3->has_udp && l2tpv3->udp) { - s->udp = true; - if (!(l2tpv3->has_srcport && l2tpv3->has_dstport)) { - error_report("l2tpv3_open : need both src and dst port for udp"); - goto outerr; - } else { - srcport = l2tpv3->srcport; - dstport = l2tpv3->dstport; - } - } else { - s->udp = false; - srcport = NULL; - dstport = NULL; - } - - - s->offset = 4; - s->session_offset = 0; - s->cookie_offset = 4; - s->counter_offset = 4; - - s->tx_session = l2tpv3->txsession; - if (l2tpv3->has_rxsession) { - s->rx_session = l2tpv3->rxsession; - } else { - s->rx_session = s->tx_session; - } - - if (s->cookie) { - s->rx_cookie = l2tpv3->rxcookie; - s->tx_cookie = l2tpv3->txcookie; - if (s->cookie_is_64 == true) { - /* 64 bit cookie */ - s->offset += 8; - s->counter_offset += 8; - } else { - /* 32 bit cookie */ - s->offset += 4; - s->counter_offset += 4; - } - } - - memset(&hints, 0, sizeof(hints)); - - if (s->ipv6) { - hints.ai_family = AF_INET6; - } else { - hints.ai_family = AF_INET; - } - if (s->udp) { - hints.ai_socktype = SOCK_DGRAM; - hints.ai_protocol = 0; - s->offset += 4; - s->counter_offset += 4; - s->session_offset += 4; - s->cookie_offset += 4; - } else { - hints.ai_socktype = SOCK_RAW; - hints.ai_protocol = IPPROTO_L2TP; - } - - gairet = getaddrinfo(l2tpv3->src, srcport, &hints, &result); - - if ((gairet != 0) || (result == NULL)) { - error_report( - "l2tpv3_open : could not resolve src, errno = %s", - gai_strerror(gairet) - ); - goto outerr; - } - fd = socket(result->ai_family, result->ai_socktype, result->ai_protocol); - if (fd == -1) { - fd = -errno; - error_report("l2tpv3_open : socket creation failed, errno = %d", -fd); - goto outerr; - } - if (bind(fd, (struct sockaddr *) result->ai_addr, result->ai_addrlen)) { - error_report("l2tpv3_open : could not bind socket err=%i", errno); - goto outerr; - } - if (result) { - freeaddrinfo(result); - } - - memset(&hints, 0, sizeof(hints)); - - if (s->ipv6) { - hints.ai_family = AF_INET6; - } else { - hints.ai_family = AF_INET; - } - if (s->udp) { - hints.ai_socktype = SOCK_DGRAM; - hints.ai_protocol = 0; - } else { - hints.ai_socktype = SOCK_RAW; - hints.ai_protocol = IPPROTO_L2TP; - } - - result = NULL; - gairet = getaddrinfo(l2tpv3->dst, dstport, &hints, &result); - if ((gairet != 0) || (result == NULL)) { - error_report( - "l2tpv3_open : could not resolve dst, error = %s", - gai_strerror(gairet) - ); - goto outerr; - } - - s->dgram_dst = g_new0(struct sockaddr_storage, 1); - memcpy(s->dgram_dst, result->ai_addr, result->ai_addrlen); - s->dst_size = result->ai_addrlen; - - if (result) { - freeaddrinfo(result); - } - - if (l2tpv3->has_counter && l2tpv3->counter) { - s->has_counter = true; - s->offset += 4; - } else { - s->has_counter = false; - } - - if (l2tpv3->has_pincounter && l2tpv3->pincounter) { - s->has_counter = true; /* pin counter implies that there is counter */ - s->pin_counter = true; - } else { - s->pin_counter = false; - } - - if (l2tpv3->has_offset) { - /* extra offset */ - s->offset += l2tpv3->offset; - } - - if ((s->ipv6) || (s->udp)) { - s->header_size = s->offset; - } else { - s->header_size = s->offset + sizeof(struct iphdr); - } - - s->msgvec = build_l2tpv3_vector(s, MAX_L2TPV3_MSGCNT); - s->vec = g_new(struct iovec, MAX_L2TPV3_IOVCNT); - s->header_buf = g_malloc(s->header_size); - - qemu_set_nonblock(fd); - - s->fd = fd; - s->counter = 0; - - l2tpv3_read_poll(s, true); - - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "l2tpv3: connected"); - return 0; -outerr: - qemu_del_net_client(nc); - if (fd >= 0) { - close(fd); - } - if (result) { - freeaddrinfo(result); - } - return -1; -} - diff --git a/qemu/net/net.c b/qemu/net/net.c deleted file mode 100644 index 0ad6217cb..000000000 --- a/qemu/net/net.c +++ /dev/null @@ -1,1575 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" - -#include "net/net.h" -#include "clients.h" -#include "hub.h" -#include "net/slirp.h" -#include "net/eth.h" -#include "util.h" - -#include "monitor/monitor.h" -#include "qemu-common.h" -#include "qemu/help_option.h" -#include "qapi/qmp/qerror.h" -#include "qemu/error-report.h" -#include "qemu/sockets.h" -#include "qemu/cutils.h" -#include "qemu/config-file.h" -#include "qmp-commands.h" -#include "hw/qdev.h" -#include "qemu/iov.h" -#include "qemu/main-loop.h" -#include "qapi-visit.h" -#include "qapi/opts-visitor.h" -#include "sysemu/sysemu.h" -#include "net/filter.h" -#include "qapi/string-output-visitor.h" - -/* Net bridge is currently not supported for W32. */ -#if !defined(_WIN32) -# define CONFIG_NET_BRIDGE -#endif - -static VMChangeStateEntry *net_change_state_entry; -static QTAILQ_HEAD(, NetClientState) net_clients; - -const char *host_net_devices[] = { - "tap", - "socket", - "dump", -#ifdef CONFIG_NET_BRIDGE - "bridge", -#endif -#ifdef CONFIG_NETMAP - "netmap", -#endif -#ifdef CONFIG_SLIRP - "user", -#endif -#ifdef CONFIG_VDE - "vde", -#endif - "vhost-user", - NULL, -}; - -int default_net = 1; - -/***********************************************************/ -/* network device redirectors */ - -static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) -{ - const char *p, *p1; - int len; - p = *pp; - p1 = strchr(p, sep); - if (!p1) - return -1; - len = p1 - p; - p1++; - if (buf_size > 0) { - if (len > buf_size - 1) - len = buf_size - 1; - memcpy(buf, p, len); - buf[len] = '\0'; - } - *pp = p1; - return 0; -} - -int parse_host_port(struct sockaddr_in *saddr, const char *str) -{ - char buf[512]; - struct hostent *he; - const char *p, *r; - int port; - - p = str; - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) - return -1; - saddr->sin_family = AF_INET; - if (buf[0] == '\0') { - saddr->sin_addr.s_addr = 0; - } else { - if (qemu_isdigit(buf[0])) { - if (!inet_aton(buf, &saddr->sin_addr)) - return -1; - } else { - if ((he = gethostbyname(buf)) == NULL) - return - 1; - saddr->sin_addr = *(struct in_addr *)he->h_addr; - } - } - port = strtol(p, (char **)&r, 0); - if (r == p) - return -1; - saddr->sin_port = htons(port); - return 0; -} - -char *qemu_mac_strdup_printf(const uint8_t *macaddr) -{ - return g_strdup_printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", - macaddr[0], macaddr[1], macaddr[2], - macaddr[3], macaddr[4], macaddr[5]); -} - -void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6]) -{ - snprintf(nc->info_str, sizeof(nc->info_str), - "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x", - nc->model, - macaddr[0], macaddr[1], macaddr[2], - macaddr[3], macaddr[4], macaddr[5]); -} - -static int mac_table[256] = {0}; - -static void qemu_macaddr_set_used(MACAddr *macaddr) -{ - int index; - - for (index = 0x56; index < 0xFF; index++) { - if (macaddr->a[5] == index) { - mac_table[index]++; - } - } -} - -static void qemu_macaddr_set_free(MACAddr *macaddr) -{ - int index; - static const MACAddr base = { .a = { 0x52, 0x54, 0x00, 0x12, 0x34, 0 } }; - - if (memcmp(macaddr->a, &base.a, (sizeof(base.a) - 1)) != 0) { - return; - } - for (index = 0x56; index < 0xFF; index++) { - if (macaddr->a[5] == index) { - mac_table[index]--; - } - } -} - -static int qemu_macaddr_get_free(void) -{ - int index; - - for (index = 0x56; index < 0xFF; index++) { - if (mac_table[index] == 0) { - return index; - } - } - - return -1; -} - -void qemu_macaddr_default_if_unset(MACAddr *macaddr) -{ - static const MACAddr zero = { .a = { 0,0,0,0,0,0 } }; - static const MACAddr base = { .a = { 0x52, 0x54, 0x00, 0x12, 0x34, 0 } }; - - if (memcmp(macaddr, &zero, sizeof(zero)) != 0) { - if (memcmp(macaddr->a, &base.a, (sizeof(base.a) - 1)) != 0) { - return; - } else { - qemu_macaddr_set_used(macaddr); - return; - } - } - - macaddr->a[0] = 0x52; - macaddr->a[1] = 0x54; - macaddr->a[2] = 0x00; - macaddr->a[3] = 0x12; - macaddr->a[4] = 0x34; - macaddr->a[5] = qemu_macaddr_get_free(); - qemu_macaddr_set_used(macaddr); -} - -/** - * Generate a name for net client - * - * Only net clients created with the legacy -net option and NICs need this. - */ -static char *assign_name(NetClientState *nc1, const char *model) -{ - NetClientState *nc; - int id = 0; - - QTAILQ_FOREACH(nc, &net_clients, next) { - if (nc == nc1) { - continue; - } - if (strcmp(nc->model, model) == 0) { - id++; - } - } - - return g_strdup_printf("%s.%d", model, id); -} - -static void qemu_net_client_destructor(NetClientState *nc) -{ - g_free(nc); -} - -static void qemu_net_client_setup(NetClientState *nc, - NetClientInfo *info, - NetClientState *peer, - const char *model, - const char *name, - NetClientDestructor *destructor) -{ - nc->info = info; - nc->model = g_strdup(model); - if (name) { - nc->name = g_strdup(name); - } else { - nc->name = assign_name(nc, model); - } - - if (peer) { - assert(!peer->peer); - nc->peer = peer; - peer->peer = nc; - } - QTAILQ_INSERT_TAIL(&net_clients, nc, next); - - nc->incoming_queue = qemu_new_net_queue(qemu_deliver_packet_iov, nc); - nc->destructor = destructor; - QTAILQ_INIT(&nc->filters); -} - -NetClientState *qemu_new_net_client(NetClientInfo *info, - NetClientState *peer, - const char *model, - const char *name) -{ - NetClientState *nc; - - assert(info->size >= sizeof(NetClientState)); - - nc = g_malloc0(info->size); - qemu_net_client_setup(nc, info, peer, model, name, - qemu_net_client_destructor); - - return nc; -} - -NICState *qemu_new_nic(NetClientInfo *info, - NICConf *conf, - const char *model, - const char *name, - void *opaque) -{ - NetClientState **peers = conf->peers.ncs; - NICState *nic; - int i, queues = MAX(1, conf->peers.queues); - - assert(info->type == NET_CLIENT_OPTIONS_KIND_NIC); - assert(info->size >= sizeof(NICState)); - - nic = g_malloc0(info->size + sizeof(NetClientState) * queues); - nic->ncs = (void *)nic + info->size; - nic->conf = conf; - nic->opaque = opaque; - - for (i = 0; i < queues; i++) { - qemu_net_client_setup(&nic->ncs[i], info, peers[i], model, name, - NULL); - nic->ncs[i].queue_index = i; - } - - return nic; -} - -NetClientState *qemu_get_subqueue(NICState *nic, int queue_index) -{ - return nic->ncs + queue_index; -} - -NetClientState *qemu_get_queue(NICState *nic) -{ - return qemu_get_subqueue(nic, 0); -} - -NICState *qemu_get_nic(NetClientState *nc) -{ - NetClientState *nc0 = nc - nc->queue_index; - - return (NICState *)((void *)nc0 - nc->info->size); -} - -void *qemu_get_nic_opaque(NetClientState *nc) -{ - NICState *nic = qemu_get_nic(nc); - - return nic->opaque; -} - -static void qemu_cleanup_net_client(NetClientState *nc) -{ - QTAILQ_REMOVE(&net_clients, nc, next); - - if (nc->info->cleanup) { - nc->info->cleanup(nc); - } -} - -static void qemu_free_net_client(NetClientState *nc) -{ - if (nc->incoming_queue) { - qemu_del_net_queue(nc->incoming_queue); - } - if (nc->peer) { - nc->peer->peer = NULL; - } - g_free(nc->name); - g_free(nc->model); - if (nc->destructor) { - nc->destructor(nc); - } -} - -void qemu_del_net_client(NetClientState *nc) -{ - NetClientState *ncs[MAX_QUEUE_NUM]; - int queues, i; - NetFilterState *nf, *next; - - assert(nc->info->type != NET_CLIENT_OPTIONS_KIND_NIC); - - /* If the NetClientState belongs to a multiqueue backend, we will change all - * other NetClientStates also. - */ - queues = qemu_find_net_clients_except(nc->name, ncs, - NET_CLIENT_OPTIONS_KIND_NIC, - MAX_QUEUE_NUM); - assert(queues != 0); - - QTAILQ_FOREACH_SAFE(nf, &nc->filters, next, next) { - object_unparent(OBJECT(nf)); - } - - /* If there is a peer NIC, delete and cleanup client, but do not free. */ - if (nc->peer && nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { - NICState *nic = qemu_get_nic(nc->peer); - if (nic->peer_deleted) { - return; - } - nic->peer_deleted = true; - - for (i = 0; i < queues; i++) { - ncs[i]->peer->link_down = true; - } - - if (nc->peer->info->link_status_changed) { - nc->peer->info->link_status_changed(nc->peer); - } - - for (i = 0; i < queues; i++) { - qemu_cleanup_net_client(ncs[i]); - } - - return; - } - - for (i = 0; i < queues; i++) { - qemu_cleanup_net_client(ncs[i]); - qemu_free_net_client(ncs[i]); - } -} - -void qemu_del_nic(NICState *nic) -{ - int i, queues = MAX(nic->conf->peers.queues, 1); - - qemu_macaddr_set_free(&nic->conf->macaddr); - - /* If this is a peer NIC and peer has already been deleted, free it now. */ - if (nic->peer_deleted) { - for (i = 0; i < queues; i++) { - qemu_free_net_client(qemu_get_subqueue(nic, i)->peer); - } - } - - for (i = queues - 1; i >= 0; i--) { - NetClientState *nc = qemu_get_subqueue(nic, i); - - qemu_cleanup_net_client(nc); - qemu_free_net_client(nc); - } - - g_free(nic); -} - -void qemu_foreach_nic(qemu_nic_foreach func, void *opaque) -{ - NetClientState *nc; - - QTAILQ_FOREACH(nc, &net_clients, next) { - if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { - if (nc->queue_index == 0) { - func(qemu_get_nic(nc), opaque); - } - } - } -} - -bool qemu_has_ufo(NetClientState *nc) -{ - if (!nc || !nc->info->has_ufo) { - return false; - } - - return nc->info->has_ufo(nc); -} - -bool qemu_has_vnet_hdr(NetClientState *nc) -{ - if (!nc || !nc->info->has_vnet_hdr) { - return false; - } - - return nc->info->has_vnet_hdr(nc); -} - -bool qemu_has_vnet_hdr_len(NetClientState *nc, int len) -{ - if (!nc || !nc->info->has_vnet_hdr_len) { - return false; - } - - return nc->info->has_vnet_hdr_len(nc, len); -} - -void qemu_using_vnet_hdr(NetClientState *nc, bool enable) -{ - if (!nc || !nc->info->using_vnet_hdr) { - return; - } - - nc->info->using_vnet_hdr(nc, enable); -} - -void qemu_set_offload(NetClientState *nc, int csum, int tso4, int tso6, - int ecn, int ufo) -{ - if (!nc || !nc->info->set_offload) { - return; - } - - nc->info->set_offload(nc, csum, tso4, tso6, ecn, ufo); -} - -void qemu_set_vnet_hdr_len(NetClientState *nc, int len) -{ - if (!nc || !nc->info->set_vnet_hdr_len) { - return; - } - - nc->info->set_vnet_hdr_len(nc, len); -} - -int qemu_set_vnet_le(NetClientState *nc, bool is_le) -{ -#ifdef HOST_WORDS_BIGENDIAN - if (!nc || !nc->info->set_vnet_le) { - return -ENOSYS; - } - - return nc->info->set_vnet_le(nc, is_le); -#else - return 0; -#endif -} - -int qemu_set_vnet_be(NetClientState *nc, bool is_be) -{ -#ifdef HOST_WORDS_BIGENDIAN - return 0; -#else - if (!nc || !nc->info->set_vnet_be) { - return -ENOSYS; - } - - return nc->info->set_vnet_be(nc, is_be); -#endif -} - -int qemu_can_send_packet(NetClientState *sender) -{ - int vm_running = runstate_is_running(); - - if (!vm_running) { - return 0; - } - - if (!sender->peer) { - return 1; - } - - if (sender->peer->receive_disabled) { - return 0; - } else if (sender->peer->info->can_receive && - !sender->peer->info->can_receive(sender->peer)) { - return 0; - } - return 1; -} - -static ssize_t filter_receive_iov(NetClientState *nc, - NetFilterDirection direction, - NetClientState *sender, - unsigned flags, - const struct iovec *iov, - int iovcnt, - NetPacketSent *sent_cb) -{ - ssize_t ret = 0; - NetFilterState *nf = NULL; - - if (direction == NET_FILTER_DIRECTION_TX) { - QTAILQ_FOREACH(nf, &nc->filters, next) { - ret = qemu_netfilter_receive(nf, direction, sender, flags, iov, - iovcnt, sent_cb); - if (ret) { - return ret; - } - } - } else { - QTAILQ_FOREACH_REVERSE(nf, &nc->filters, NetFilterHead, next) { - ret = qemu_netfilter_receive(nf, direction, sender, flags, iov, - iovcnt, sent_cb); - if (ret) { - return ret; - } - } - } - - return ret; -} - -static ssize_t filter_receive(NetClientState *nc, - NetFilterDirection direction, - NetClientState *sender, - unsigned flags, - const uint8_t *data, - size_t size, - NetPacketSent *sent_cb) -{ - struct iovec iov = { - .iov_base = (void *)data, - .iov_len = size - }; - - return filter_receive_iov(nc, direction, sender, flags, &iov, 1, sent_cb); -} - -void qemu_purge_queued_packets(NetClientState *nc) -{ - if (!nc->peer) { - return; - } - - qemu_net_queue_purge(nc->peer->incoming_queue, nc); -} - -static -void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge) -{ - nc->receive_disabled = 0; - - if (nc->peer && nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_HUBPORT) { - if (net_hub_flush(nc->peer)) { - qemu_notify_event(); - } - } - if (qemu_net_queue_flush(nc->incoming_queue)) { - /* We emptied the queue successfully, signal to the IO thread to repoll - * the file descriptor (for tap, for example). - */ - qemu_notify_event(); - } else if (purge) { - /* Unable to empty the queue, purge remaining packets */ - qemu_net_queue_purge(nc->incoming_queue, nc); - } -} - -void qemu_flush_queued_packets(NetClientState *nc) -{ - qemu_flush_or_purge_queued_packets(nc, false); -} - -static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender, - unsigned flags, - const uint8_t *buf, int size, - NetPacketSent *sent_cb) -{ - NetQueue *queue; - int ret; - -#ifdef DEBUG_NET - printf("qemu_send_packet_async:\n"); - qemu_hexdump((const char *)buf, stdout, "net", size); -#endif - - if (sender->link_down || !sender->peer) { - return size; - } - - /* Let filters handle the packet first */ - ret = filter_receive(sender, NET_FILTER_DIRECTION_TX, - sender, flags, buf, size, sent_cb); - if (ret) { - return ret; - } - - ret = filter_receive(sender->peer, NET_FILTER_DIRECTION_RX, - sender, flags, buf, size, sent_cb); - if (ret) { - return ret; - } - - queue = sender->peer->incoming_queue; - - return qemu_net_queue_send(queue, sender, flags, buf, size, sent_cb); -} - -ssize_t qemu_send_packet_async(NetClientState *sender, - const uint8_t *buf, int size, - NetPacketSent *sent_cb) -{ - return qemu_send_packet_async_with_flags(sender, QEMU_NET_PACKET_FLAG_NONE, - buf, size, sent_cb); -} - -void qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size) -{ - qemu_send_packet_async(nc, buf, size, NULL); -} - -ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size) -{ - return qemu_send_packet_async_with_flags(nc, QEMU_NET_PACKET_FLAG_RAW, - buf, size, NULL); -} - -static ssize_t nc_sendv_compat(NetClientState *nc, const struct iovec *iov, - int iovcnt, unsigned flags) -{ - uint8_t *buf = NULL; - uint8_t *buffer; - size_t offset; - ssize_t ret; - - if (iovcnt == 1) { - buffer = iov[0].iov_base; - offset = iov[0].iov_len; - } else { - buf = g_new(uint8_t, NET_BUFSIZE); - buffer = buf; - offset = iov_to_buf(iov, iovcnt, 0, buf, NET_BUFSIZE); - } - - if (flags & QEMU_NET_PACKET_FLAG_RAW && nc->info->receive_raw) { - ret = nc->info->receive_raw(nc, buffer, offset); - } else { - ret = nc->info->receive(nc, buffer, offset); - } - - g_free(buf); - return ret; -} - -ssize_t qemu_deliver_packet_iov(NetClientState *sender, - unsigned flags, - const struct iovec *iov, - int iovcnt, - void *opaque) -{ - NetClientState *nc = opaque; - int ret; - - if (nc->link_down) { - return iov_size(iov, iovcnt); - } - - if (nc->receive_disabled) { - return 0; - } - - if (nc->info->receive_iov) { - ret = nc->info->receive_iov(nc, iov, iovcnt); - } else { - ret = nc_sendv_compat(nc, iov, iovcnt, flags); - } - - if (ret == 0) { - nc->receive_disabled = 1; - } - - return ret; -} - -ssize_t qemu_sendv_packet_async(NetClientState *sender, - const struct iovec *iov, int iovcnt, - NetPacketSent *sent_cb) -{ - NetQueue *queue; - int ret; - - if (sender->link_down || !sender->peer) { - return iov_size(iov, iovcnt); - } - - /* Let filters handle the packet first */ - ret = filter_receive_iov(sender, NET_FILTER_DIRECTION_TX, sender, - QEMU_NET_PACKET_FLAG_NONE, iov, iovcnt, sent_cb); - if (ret) { - return ret; - } - - ret = filter_receive_iov(sender->peer, NET_FILTER_DIRECTION_RX, sender, - QEMU_NET_PACKET_FLAG_NONE, iov, iovcnt, sent_cb); - if (ret) { - return ret; - } - - queue = sender->peer->incoming_queue; - - return qemu_net_queue_send_iov(queue, sender, - QEMU_NET_PACKET_FLAG_NONE, - iov, iovcnt, sent_cb); -} - -ssize_t -qemu_sendv_packet(NetClientState *nc, const struct iovec *iov, int iovcnt) -{ - return qemu_sendv_packet_async(nc, iov, iovcnt, NULL); -} - -NetClientState *qemu_find_netdev(const char *id) -{ - NetClientState *nc; - - QTAILQ_FOREACH(nc, &net_clients, next) { - if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) - continue; - if (!strcmp(nc->name, id)) { - return nc; - } - } - - return NULL; -} - -int qemu_find_net_clients_except(const char *id, NetClientState **ncs, - NetClientOptionsKind type, int max) -{ - NetClientState *nc; - int ret = 0; - - QTAILQ_FOREACH(nc, &net_clients, next) { - if (nc->info->type == type) { - continue; - } - if (!id || !strcmp(nc->name, id)) { - if (ret < max) { - ncs[ret] = nc; - } - ret++; - } - } - - return ret; -} - -static int nic_get_free_idx(void) -{ - int index; - - for (index = 0; index < MAX_NICS; index++) - if (!nd_table[index].used) - return index; - return -1; -} - -int qemu_show_nic_models(const char *arg, const char *const *models) -{ - int i; - - if (!arg || !is_help_option(arg)) { - return 0; - } - - fprintf(stderr, "qemu: Supported NIC models: "); - for (i = 0 ; models[i]; i++) - fprintf(stderr, "%s%c", models[i], models[i+1] ? ',' : '\n'); - return 1; -} - -void qemu_check_nic_model(NICInfo *nd, const char *model) -{ - const char *models[2]; - - models[0] = model; - models[1] = NULL; - - if (qemu_show_nic_models(nd->model, models)) - exit(0); - if (qemu_find_nic_model(nd, models, model) < 0) - exit(1); -} - -int qemu_find_nic_model(NICInfo *nd, const char * const *models, - const char *default_model) -{ - int i; - - if (!nd->model) - nd->model = g_strdup(default_model); - - for (i = 0 ; models[i]; i++) { - if (strcmp(nd->model, models[i]) == 0) - return i; - } - - error_report("Unsupported NIC model: %s", nd->model); - return -1; -} - -static int net_init_nic(const NetClientOptions *opts, const char *name, - NetClientState *peer, Error **errp) -{ - int idx; - NICInfo *nd; - const NetLegacyNicOptions *nic; - - assert(opts->type == NET_CLIENT_OPTIONS_KIND_NIC); - nic = opts->u.nic.data; - - idx = nic_get_free_idx(); - if (idx == -1 || nb_nics >= MAX_NICS) { - error_setg(errp, "too many NICs"); - return -1; - } - - nd = &nd_table[idx]; - - memset(nd, 0, sizeof(*nd)); - - if (nic->has_netdev) { - nd->netdev = qemu_find_netdev(nic->netdev); - if (!nd->netdev) { - error_setg(errp, "netdev '%s' not found", nic->netdev); - return -1; - } - } else { - assert(peer); - nd->netdev = peer; - } - nd->name = g_strdup(name); - if (nic->has_model) { - nd->model = g_strdup(nic->model); - } - if (nic->has_addr) { - nd->devaddr = g_strdup(nic->addr); - } - - if (nic->has_macaddr && - net_parse_macaddr(nd->macaddr.a, nic->macaddr) < 0) { - error_setg(errp, "invalid syntax for ethernet address"); - return -1; - } - if (nic->has_macaddr && - is_multicast_ether_addr(nd->macaddr.a)) { - error_setg(errp, - "NIC cannot have multicast MAC address (odd 1st byte)"); - return -1; - } - qemu_macaddr_default_if_unset(&nd->macaddr); - - if (nic->has_vectors) { - if (nic->vectors > 0x7ffffff) { - error_setg(errp, "invalid # of vectors: %"PRIu32, nic->vectors); - return -1; - } - nd->nvectors = nic->vectors; - } else { - nd->nvectors = DEV_NVECTORS_UNSPECIFIED; - } - - nd->used = 1; - nb_nics++; - - return idx; -} - - -static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND__MAX])( - const NetClientOptions *opts, - const char *name, - NetClientState *peer, Error **errp) = { - [NET_CLIENT_OPTIONS_KIND_NIC] = net_init_nic, -#ifdef CONFIG_SLIRP - [NET_CLIENT_OPTIONS_KIND_USER] = net_init_slirp, -#endif - [NET_CLIENT_OPTIONS_KIND_TAP] = net_init_tap, - [NET_CLIENT_OPTIONS_KIND_SOCKET] = net_init_socket, -#ifdef CONFIG_VDE - [NET_CLIENT_OPTIONS_KIND_VDE] = net_init_vde, -#endif -#ifdef CONFIG_NETMAP - [NET_CLIENT_OPTIONS_KIND_NETMAP] = net_init_netmap, -#endif - [NET_CLIENT_OPTIONS_KIND_DUMP] = net_init_dump, -#ifdef CONFIG_NET_BRIDGE - [NET_CLIENT_OPTIONS_KIND_BRIDGE] = net_init_bridge, -#endif - [NET_CLIENT_OPTIONS_KIND_HUBPORT] = net_init_hubport, -#ifdef CONFIG_VHOST_NET_USED - [NET_CLIENT_OPTIONS_KIND_VHOST_USER] = net_init_vhost_user, -#endif -#ifdef CONFIG_L2TPV3 - [NET_CLIENT_OPTIONS_KIND_L2TPV3] = net_init_l2tpv3, -#endif -}; - - -static int net_client_init1(const void *object, int is_netdev, Error **errp) -{ - const NetClientOptions *opts; - const char *name; - NetClientState *peer = NULL; - - if (is_netdev) { - const Netdev *netdev = object; - opts = netdev->opts; - name = netdev->id; - - if (opts->type == NET_CLIENT_OPTIONS_KIND_DUMP || - opts->type == NET_CLIENT_OPTIONS_KIND_NIC || - !net_client_init_fun[opts->type]) { - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type", - "a netdev backend type"); - return -1; - } - } else { - const NetLegacy *net = object; - opts = net->opts; - /* missing optional values have been initialized to "all bits zero" */ - name = net->has_id ? net->id : net->name; - - if (opts->type == NET_CLIENT_OPTIONS_KIND_NONE) { - return 0; /* nothing to do */ - } - if (opts->type == NET_CLIENT_OPTIONS_KIND_HUBPORT) { - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type", - "a net type"); - return -1; - } - - if (!net_client_init_fun[opts->type]) { - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type", - "a net backend type (maybe it is not compiled " - "into this binary)"); - return -1; - } - - /* Do not add to a vlan if it's a nic with a netdev= parameter. */ - if (opts->type != NET_CLIENT_OPTIONS_KIND_NIC || - !opts->u.nic.data->has_netdev) { - peer = net_hub_add_port(net->has_vlan ? net->vlan : 0, NULL); - } - } - - if (net_client_init_fun[opts->type](opts, name, peer, errp) < 0) { - /* FIXME drop when all init functions store an Error */ - if (errp && !*errp) { - error_setg(errp, QERR_DEVICE_INIT_FAILED, - NetClientOptionsKind_lookup[opts->type]); - } - return -1; - } - return 0; -} - - -int net_client_init(QemuOpts *opts, int is_netdev, Error **errp) -{ - void *object = NULL; - Error *err = NULL; - int ret = -1; - OptsVisitor *ov = opts_visitor_new(opts); - Visitor *v = opts_get_visitor(ov); - - { - /* Parse convenience option format ip6-net=fec0::0[/64] */ - const char *ip6_net = qemu_opt_get(opts, "ipv6-net"); - - if (ip6_net) { - char buf[strlen(ip6_net) + 1]; - - if (get_str_sep(buf, sizeof(buf), &ip6_net, '/') < 0) { - /* Default 64bit prefix length. */ - qemu_opt_set(opts, "ipv6-prefix", ip6_net, &error_abort); - qemu_opt_set_number(opts, "ipv6-prefixlen", 64, &error_abort); - } else { - /* User-specified prefix length. */ - unsigned long len; - int err; - - qemu_opt_set(opts, "ipv6-prefix", buf, &error_abort); - err = qemu_strtoul(ip6_net, NULL, 10, &len); - - if (err) { - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, - "ipv6-prefix", "a number"); - } else { - qemu_opt_set_number(opts, "ipv6-prefixlen", len, - &error_abort); - } - } - qemu_opt_unset(opts, "ipv6-net"); - } - } - - if (is_netdev) { - visit_type_Netdev(v, NULL, (Netdev **)&object, &err); - } else { - visit_type_NetLegacy(v, NULL, (NetLegacy **)&object, &err); - } - - if (!err) { - ret = net_client_init1(object, is_netdev, &err); - } - - if (is_netdev) { - qapi_free_Netdev(object); - } else { - qapi_free_NetLegacy(object); - } - - error_propagate(errp, err); - opts_visitor_cleanup(ov); - return ret; -} - - -static int net_host_check_device(const char *device) -{ - int i; - for (i = 0; host_net_devices[i]; i++) { - if (!strncmp(host_net_devices[i], device, - strlen(host_net_devices[i]))) { - return 1; - } - } - - return 0; -} - -void hmp_host_net_add(Monitor *mon, const QDict *qdict) -{ - const char *device = qdict_get_str(qdict, "device"); - const char *opts_str = qdict_get_try_str(qdict, "opts"); - Error *local_err = NULL; - QemuOpts *opts; - - if (!net_host_check_device(device)) { - monitor_printf(mon, "invalid host network device %s\n", device); - return; - } - - opts = qemu_opts_parse_noisily(qemu_find_opts("net"), - opts_str ? opts_str : "", false); - if (!opts) { - return; - } - - qemu_opt_set(opts, "type", device, &error_abort); - - net_client_init(opts, 0, &local_err); - if (local_err) { - error_report_err(local_err); - monitor_printf(mon, "adding host network device %s failed\n", device); - } -} - -void hmp_host_net_remove(Monitor *mon, const QDict *qdict) -{ - NetClientState *nc; - int vlan_id = qdict_get_int(qdict, "vlan_id"); - const char *device = qdict_get_str(qdict, "device"); - - nc = net_hub_find_client_by_name(vlan_id, device); - if (!nc) { - error_report("Host network device '%s' on hub '%d' not found", - device, vlan_id); - return; - } - if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { - error_report("invalid host network device '%s'", device); - return; - } - - qemu_del_net_client(nc->peer); - qemu_del_net_client(nc); -} - -void netdev_add(QemuOpts *opts, Error **errp) -{ - net_client_init(opts, 1, errp); -} - -void qmp_netdev_add(QDict *qdict, QObject **ret, Error **errp) -{ - Error *local_err = NULL; - QemuOptsList *opts_list; - QemuOpts *opts; - - opts_list = qemu_find_opts_err("netdev", &local_err); - if (local_err) { - goto out; - } - - opts = qemu_opts_from_qdict(opts_list, qdict, &local_err); - if (local_err) { - goto out; - } - - netdev_add(opts, &local_err); - if (local_err) { - qemu_opts_del(opts); - goto out; - } - -out: - error_propagate(errp, local_err); -} - -void qmp_netdev_del(const char *id, Error **errp) -{ - NetClientState *nc; - QemuOpts *opts; - - nc = qemu_find_netdev(id); - if (!nc) { - error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, - "Device '%s' not found", id); - return; - } - - opts = qemu_opts_find(qemu_find_opts_err("netdev", NULL), id); - if (!opts) { - error_setg(errp, "Device '%s' is not a netdev", id); - return; - } - - qemu_del_net_client(nc); - qemu_opts_del(opts); -} - -static void netfilter_print_info(Monitor *mon, NetFilterState *nf) -{ - char *str; - ObjectProperty *prop; - ObjectPropertyIterator iter; - StringOutputVisitor *ov; - - /* generate info str */ - object_property_iter_init(&iter, OBJECT(nf)); - while ((prop = object_property_iter_next(&iter))) { - if (!strcmp(prop->name, "type")) { - continue; - } - ov = string_output_visitor_new(false); - object_property_get(OBJECT(nf), string_output_get_visitor(ov), - prop->name, NULL); - str = string_output_get_string(ov); - string_output_visitor_cleanup(ov); - monitor_printf(mon, ",%s=%s", prop->name, str); - g_free(str); - } - monitor_printf(mon, "\n"); -} - -void print_net_client(Monitor *mon, NetClientState *nc) -{ - NetFilterState *nf; - - monitor_printf(mon, "%s: index=%d,type=%s,%s\n", nc->name, - nc->queue_index, - NetClientOptionsKind_lookup[nc->info->type], - nc->info_str); - if (!QTAILQ_EMPTY(&nc->filters)) { - monitor_printf(mon, "filters:\n"); - } - QTAILQ_FOREACH(nf, &nc->filters, next) { - char *path = object_get_canonical_path_component(OBJECT(nf)); - - monitor_printf(mon, " - %s: type=%s", path, - object_get_typename(OBJECT(nf))); - netfilter_print_info(mon, nf); - g_free(path); - } -} - -RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name, - Error **errp) -{ - NetClientState *nc; - RxFilterInfoList *filter_list = NULL, *last_entry = NULL; - - QTAILQ_FOREACH(nc, &net_clients, next) { - RxFilterInfoList *entry; - RxFilterInfo *info; - - if (has_name && strcmp(nc->name, name) != 0) { - continue; - } - - /* only query rx-filter information of NIC */ - if (nc->info->type != NET_CLIENT_OPTIONS_KIND_NIC) { - if (has_name) { - error_setg(errp, "net client(%s) isn't a NIC", name); - return NULL; - } - continue; - } - - /* only query information on queue 0 since the info is per nic, - * not per queue - */ - if (nc->queue_index != 0) - continue; - - if (nc->info->query_rx_filter) { - info = nc->info->query_rx_filter(nc); - entry = g_malloc0(sizeof(*entry)); - entry->value = info; - - if (!filter_list) { - filter_list = entry; - } else { - last_entry->next = entry; - } - last_entry = entry; - } else if (has_name) { - error_setg(errp, "net client(%s) doesn't support" - " rx-filter querying", name); - return NULL; - } - - if (has_name) { - break; - } - } - - if (filter_list == NULL && has_name) { - error_setg(errp, "invalid net client name: %s", name); - } - - return filter_list; -} - -void hmp_info_network(Monitor *mon, const QDict *qdict) -{ - NetClientState *nc, *peer; - NetClientOptionsKind type; - - net_hub_info(mon); - - QTAILQ_FOREACH(nc, &net_clients, next) { - peer = nc->peer; - type = nc->info->type; - - /* Skip if already printed in hub info */ - if (net_hub_id_for_client(nc, NULL) == 0) { - continue; - } - - if (!peer || type == NET_CLIENT_OPTIONS_KIND_NIC) { - print_net_client(mon, nc); - } /* else it's a netdev connected to a NIC, printed with the NIC */ - if (peer && type == NET_CLIENT_OPTIONS_KIND_NIC) { - monitor_printf(mon, " \\ "); - print_net_client(mon, peer); - } - } -} - -void qmp_set_link(const char *name, bool up, Error **errp) -{ - NetClientState *ncs[MAX_QUEUE_NUM]; - NetClientState *nc; - int queues, i; - - queues = qemu_find_net_clients_except(name, ncs, - NET_CLIENT_OPTIONS_KIND__MAX, - MAX_QUEUE_NUM); - - if (queues == 0) { - error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, - "Device '%s' not found", name); - return; - } - nc = ncs[0]; - - for (i = 0; i < queues; i++) { - ncs[i]->link_down = !up; - } - - if (nc->info->link_status_changed) { - nc->info->link_status_changed(nc); - } - - if (nc->peer) { - /* Change peer link only if the peer is NIC and then notify peer. - * If the peer is a HUBPORT or a backend, we do not change the - * link status. - * - * This behavior is compatible with qemu vlans where there could be - * multiple clients that can still communicate with each other in - * disconnected mode. For now maintain this compatibility. - */ - if (nc->peer->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { - for (i = 0; i < queues; i++) { - ncs[i]->peer->link_down = !up; - } - } - if (nc->peer->info->link_status_changed) { - nc->peer->info->link_status_changed(nc->peer); - } - } -} - -static void net_vm_change_state_handler(void *opaque, int running, - RunState state) -{ - NetClientState *nc; - NetClientState *tmp; - - QTAILQ_FOREACH_SAFE(nc, &net_clients, next, tmp) { - if (running) { - /* Flush queued packets and wake up backends. */ - if (nc->peer && qemu_can_send_packet(nc)) { - qemu_flush_queued_packets(nc->peer); - } - } else { - /* Complete all queued packets, to guarantee we don't modify - * state later when VM is not running. - */ - qemu_flush_or_purge_queued_packets(nc, true); - } - } -} - -void net_cleanup(void) -{ - NetClientState *nc; - - /* We may del multiple entries during qemu_del_net_client(), - * so QTAILQ_FOREACH_SAFE() is also not safe here. - */ - while (!QTAILQ_EMPTY(&net_clients)) { - nc = QTAILQ_FIRST(&net_clients); - if (nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC) { - qemu_del_nic(qemu_get_nic(nc)); - } else { - qemu_del_net_client(nc); - } - } - - qemu_del_vm_change_state_handler(net_change_state_entry); -} - -void net_check_clients(void) -{ - NetClientState *nc; - int i; - - /* Don't warn about the default network setup that you get if - * no command line -net or -netdev options are specified. There - * are two cases that we would otherwise complain about: - * (1) board doesn't support a NIC but the implicit "-net nic" - * requested one - * (2) CONFIG_SLIRP not set, in which case the implicit "-net nic" - * sets up a nic that isn't connected to anything. - */ - if (default_net) { - return; - } - - net_hub_check_clients(); - - QTAILQ_FOREACH(nc, &net_clients, next) { - if (!nc->peer) { - fprintf(stderr, "Warning: %s %s has no peer\n", - nc->info->type == NET_CLIENT_OPTIONS_KIND_NIC ? - "nic" : "netdev", nc->name); - } - } - - /* Check that all NICs requested via -net nic actually got created. - * NICs created via -device don't need to be checked here because - * they are always instantiated. - */ - for (i = 0; i < MAX_NICS; i++) { - NICInfo *nd = &nd_table[i]; - if (nd->used && !nd->instantiated) { - fprintf(stderr, "Warning: requested NIC (%s, model %s) " - "was not created (not supported by this machine?)\n", - nd->name ? nd->name : "anonymous", - nd->model ? nd->model : "unspecified"); - } - } -} - -static int net_init_client(void *dummy, QemuOpts *opts, Error **errp) -{ - Error *local_err = NULL; - - net_client_init(opts, 0, &local_err); - if (local_err) { - error_report_err(local_err); - return -1; - } - - return 0; -} - -static int net_init_netdev(void *dummy, QemuOpts *opts, Error **errp) -{ - Error *local_err = NULL; - int ret; - - ret = net_client_init(opts, 1, &local_err); - if (local_err) { - error_report_err(local_err); - return -1; - } - - return ret; -} - -int net_init_clients(void) -{ - QemuOptsList *net = qemu_find_opts("net"); - - if (default_net) { - /* if no clients, we use a default config */ - qemu_opts_set(net, NULL, "type", "nic", &error_abort); -#ifdef CONFIG_SLIRP - qemu_opts_set(net, NULL, "type", "user", &error_abort); -#endif - } - - net_change_state_entry = - qemu_add_vm_change_state_handler(net_vm_change_state_handler, NULL); - - QTAILQ_INIT(&net_clients); - - if (qemu_opts_foreach(qemu_find_opts("netdev"), - net_init_netdev, NULL, NULL)) { - return -1; - } - - if (qemu_opts_foreach(net, net_init_client, NULL, NULL)) { - return -1; - } - - return 0; -} - -int net_client_parse(QemuOptsList *opts_list, const char *optarg) -{ -#if defined(CONFIG_SLIRP) - int ret; - if (net_slirp_parse_legacy(opts_list, optarg, &ret)) { - return ret; - } -#endif - - if (!qemu_opts_parse_noisily(opts_list, optarg, true)) { - return -1; - } - - default_net = 0; - return 0; -} - -/* From FreeBSD */ -/* XXX: optimize */ -unsigned compute_mcast_idx(const uint8_t *ep) -{ - uint32_t crc; - int carry, i, j; - uint8_t b; - - crc = 0xffffffff; - for (i = 0; i < 6; i++) { - b = *ep++; - for (j = 0; j < 8; j++) { - carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); - crc <<= 1; - b >>= 1; - if (carry) { - crc = ((crc ^ POLYNOMIAL) | carry); - } - } - } - return crc >> 26; -} - -QemuOptsList qemu_netdev_opts = { - .name = "netdev", - .implied_opt_name = "type", - .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head), - .desc = { - /* - * no elements => accept any params - * validation will happen later - */ - { /* end of list */ } - }, -}; - -QemuOptsList qemu_net_opts = { - .name = "net", - .implied_opt_name = "type", - .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head), - .desc = { - /* - * no elements => accept any params - * validation will happen later - */ - { /* end of list */ } - }, -}; diff --git a/qemu/net/netmap.c b/qemu/net/netmap.c deleted file mode 100644 index 6cc0db5ee..000000000 --- a/qemu/net/netmap.c +++ /dev/null @@ -1,448 +0,0 @@ -/* - * netmap access for qemu - * - * Copyright (c) 2012-2013 Luigi Rizzo - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - - -#include "qemu/osdep.h" -#include <sys/ioctl.h> -#include <net/if.h> -#include <sys/mman.h> -#define NETMAP_WITH_LIBS -#include <net/netmap.h> -#include <net/netmap_user.h> - -#include "net/net.h" -#include "net/tap.h" -#include "clients.h" -#include "sysemu/sysemu.h" -#include "qemu/error-report.h" -#include "qapi/error.h" -#include "qemu/iov.h" -#include "qemu/cutils.h" - -typedef struct NetmapState { - NetClientState nc; - struct nm_desc *nmd; - char ifname[IFNAMSIZ]; - struct netmap_ring *tx; - struct netmap_ring *rx; - bool read_poll; - bool write_poll; - struct iovec iov[IOV_MAX]; - int vnet_hdr_len; /* Current virtio-net header length. */ -} NetmapState; - -#ifndef __FreeBSD__ -#define pkt_copy bcopy -#else -/* A fast copy routine only for multiples of 64 bytes, non overlapped. */ -static inline void -pkt_copy(const void *_src, void *_dst, int l) -{ - const uint64_t *src = _src; - uint64_t *dst = _dst; - if (unlikely(l >= 1024)) { - bcopy(src, dst, l); - return; - } - for (; l > 0; l -= 64) { - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - } -} -#endif /* __FreeBSD__ */ - -/* - * Open a netmap device. We assume there is only one queue - * (which is the case for the VALE bridge). - */ -static struct nm_desc *netmap_open(const NetdevNetmapOptions *nm_opts, - Error **errp) -{ - struct nm_desc *nmd; - struct nmreq req; - - memset(&req, 0, sizeof(req)); - - nmd = nm_open(nm_opts->ifname, &req, NETMAP_NO_TX_POLL, - NULL); - if (nmd == NULL) { - error_setg_errno(errp, errno, "Failed to nm_open() %s", - nm_opts->ifname); - return NULL; - } - - return nmd; -} - -static void netmap_send(void *opaque); -static void netmap_writable(void *opaque); - -/* Set the event-loop handlers for the netmap backend. */ -static void netmap_update_fd_handler(NetmapState *s) -{ - qemu_set_fd_handler(s->nmd->fd, - s->read_poll ? netmap_send : NULL, - s->write_poll ? netmap_writable : NULL, - s); -} - -/* Update the read handler. */ -static void netmap_read_poll(NetmapState *s, bool enable) -{ - if (s->read_poll != enable) { /* Do nothing if not changed. */ - s->read_poll = enable; - netmap_update_fd_handler(s); - } -} - -/* Update the write handler. */ -static void netmap_write_poll(NetmapState *s, bool enable) -{ - if (s->write_poll != enable) { - s->write_poll = enable; - netmap_update_fd_handler(s); - } -} - -static void netmap_poll(NetClientState *nc, bool enable) -{ - NetmapState *s = DO_UPCAST(NetmapState, nc, nc); - - if (s->read_poll != enable || s->write_poll != enable) { - s->write_poll = enable; - s->read_poll = enable; - netmap_update_fd_handler(s); - } -} - -/* - * The fd_write() callback, invoked if the fd is marked as - * writable after a poll. Unregister the handler and flush any - * buffered packets. - */ -static void netmap_writable(void *opaque) -{ - NetmapState *s = opaque; - - netmap_write_poll(s, false); - qemu_flush_queued_packets(&s->nc); -} - -static ssize_t netmap_receive(NetClientState *nc, - const uint8_t *buf, size_t size) -{ - NetmapState *s = DO_UPCAST(NetmapState, nc, nc); - struct netmap_ring *ring = s->tx; - uint32_t i; - uint32_t idx; - uint8_t *dst; - - if (unlikely(!ring)) { - /* Drop. */ - return size; - } - - if (unlikely(size > ring->nr_buf_size)) { - RD(5, "[netmap_receive] drop packet of size %d > %d\n", - (int)size, ring->nr_buf_size); - return size; - } - - if (nm_ring_empty(ring)) { - /* No available slots in the netmap TX ring. */ - netmap_write_poll(s, true); - return 0; - } - - i = ring->cur; - idx = ring->slot[i].buf_idx; - dst = (uint8_t *)NETMAP_BUF(ring, idx); - - ring->slot[i].len = size; - ring->slot[i].flags = 0; - pkt_copy(buf, dst, size); - ring->cur = ring->head = nm_ring_next(ring, i); - ioctl(s->nmd->fd, NIOCTXSYNC, NULL); - - return size; -} - -static ssize_t netmap_receive_iov(NetClientState *nc, - const struct iovec *iov, int iovcnt) -{ - NetmapState *s = DO_UPCAST(NetmapState, nc, nc); - struct netmap_ring *ring = s->tx; - uint32_t last; - uint32_t idx; - uint8_t *dst; - int j; - uint32_t i; - - if (unlikely(!ring)) { - /* Drop the packet. */ - return iov_size(iov, iovcnt); - } - - last = i = ring->cur; - - if (nm_ring_space(ring) < iovcnt) { - /* Not enough netmap slots. */ - netmap_write_poll(s, true); - return 0; - } - - for (j = 0; j < iovcnt; j++) { - int iov_frag_size = iov[j].iov_len; - int offset = 0; - int nm_frag_size; - - /* Split each iovec fragment over more netmap slots, if - necessary. */ - while (iov_frag_size) { - nm_frag_size = MIN(iov_frag_size, ring->nr_buf_size); - - if (unlikely(nm_ring_empty(ring))) { - /* We run out of netmap slots while splitting the - iovec fragments. */ - netmap_write_poll(s, true); - return 0; - } - - idx = ring->slot[i].buf_idx; - dst = (uint8_t *)NETMAP_BUF(ring, idx); - - ring->slot[i].len = nm_frag_size; - ring->slot[i].flags = NS_MOREFRAG; - pkt_copy(iov[j].iov_base + offset, dst, nm_frag_size); - - last = i; - i = nm_ring_next(ring, i); - - offset += nm_frag_size; - iov_frag_size -= nm_frag_size; - } - } - /* The last slot must not have NS_MOREFRAG set. */ - ring->slot[last].flags &= ~NS_MOREFRAG; - - /* Now update ring->cur and ring->head. */ - ring->cur = ring->head = i; - - ioctl(s->nmd->fd, NIOCTXSYNC, NULL); - - return iov_size(iov, iovcnt); -} - -/* Complete a previous send (backend --> guest) and enable the - fd_read callback. */ -static void netmap_send_completed(NetClientState *nc, ssize_t len) -{ - NetmapState *s = DO_UPCAST(NetmapState, nc, nc); - - netmap_read_poll(s, true); -} - -static void netmap_send(void *opaque) -{ - NetmapState *s = opaque; - struct netmap_ring *ring = s->rx; - - /* Keep sending while there are available packets into the netmap - RX ring and the forwarding path towards the peer is open. */ - while (!nm_ring_empty(ring)) { - uint32_t i; - uint32_t idx; - bool morefrag; - int iovcnt = 0; - int iovsize; - - do { - i = ring->cur; - idx = ring->slot[i].buf_idx; - morefrag = (ring->slot[i].flags & NS_MOREFRAG); - s->iov[iovcnt].iov_base = (u_char *)NETMAP_BUF(ring, idx); - s->iov[iovcnt].iov_len = ring->slot[i].len; - iovcnt++; - - ring->cur = ring->head = nm_ring_next(ring, i); - } while (!nm_ring_empty(ring) && morefrag); - - if (unlikely(nm_ring_empty(ring) && morefrag)) { - RD(5, "[netmap_send] ran out of slots, with a pending" - "incomplete packet\n"); - } - - iovsize = qemu_sendv_packet_async(&s->nc, s->iov, iovcnt, - netmap_send_completed); - - if (iovsize == 0) { - /* The peer does not receive anymore. Packet is queued, stop - * reading from the backend until netmap_send_completed() - */ - netmap_read_poll(s, false); - break; - } - } -} - -/* Flush and close. */ -static void netmap_cleanup(NetClientState *nc) -{ - NetmapState *s = DO_UPCAST(NetmapState, nc, nc); - - qemu_purge_queued_packets(nc); - - netmap_poll(nc, false); - nm_close(s->nmd); - s->nmd = NULL; -} - -/* Offloading manipulation support callbacks. */ -static int netmap_fd_set_vnet_hdr_len(NetmapState *s, int len) -{ - struct nmreq req; - - /* Issue a NETMAP_BDG_VNET_HDR command to change the virtio-net header - * length for the netmap adapter associated to 's->ifname'. - */ - memset(&req, 0, sizeof(req)); - pstrcpy(req.nr_name, sizeof(req.nr_name), s->ifname); - req.nr_version = NETMAP_API; - req.nr_cmd = NETMAP_BDG_VNET_HDR; - req.nr_arg1 = len; - - return ioctl(s->nmd->fd, NIOCREGIF, &req); -} - -static bool netmap_has_vnet_hdr_len(NetClientState *nc, int len) -{ - NetmapState *s = DO_UPCAST(NetmapState, nc, nc); - int prev_len = s->vnet_hdr_len; - - /* Check that we can set the new length. */ - if (netmap_fd_set_vnet_hdr_len(s, len)) { - return false; - } - - /* Restore the previous length. */ - if (netmap_fd_set_vnet_hdr_len(s, prev_len)) { - error_report("Failed to restore vnet-hdr length %d on %s: %s", - prev_len, s->ifname, strerror(errno)); - abort(); - } - - return true; -} - -/* A netmap interface that supports virtio-net headers always - * supports UFO, so we use this callback also for the has_ufo hook. */ -static bool netmap_has_vnet_hdr(NetClientState *nc) -{ - return netmap_has_vnet_hdr_len(nc, sizeof(struct virtio_net_hdr)); -} - -static void netmap_using_vnet_hdr(NetClientState *nc, bool enable) -{ -} - -static void netmap_set_vnet_hdr_len(NetClientState *nc, int len) -{ - NetmapState *s = DO_UPCAST(NetmapState, nc, nc); - int err; - - err = netmap_fd_set_vnet_hdr_len(s, len); - if (err) { - error_report("Unable to set vnet-hdr length %d on %s: %s", - len, s->ifname, strerror(errno)); - } else { - /* Keep track of the current length. */ - s->vnet_hdr_len = len; - } -} - -static void netmap_set_offload(NetClientState *nc, int csum, int tso4, int tso6, - int ecn, int ufo) -{ - NetmapState *s = DO_UPCAST(NetmapState, nc, nc); - - /* Setting a virtio-net header length greater than zero automatically - * enables the offloadings. */ - if (!s->vnet_hdr_len) { - netmap_set_vnet_hdr_len(nc, sizeof(struct virtio_net_hdr)); - } -} - -/* NetClientInfo methods */ -static NetClientInfo net_netmap_info = { - .type = NET_CLIENT_OPTIONS_KIND_NETMAP, - .size = sizeof(NetmapState), - .receive = netmap_receive, - .receive_iov = netmap_receive_iov, - .poll = netmap_poll, - .cleanup = netmap_cleanup, - .has_ufo = netmap_has_vnet_hdr, - .has_vnet_hdr = netmap_has_vnet_hdr, - .has_vnet_hdr_len = netmap_has_vnet_hdr_len, - .using_vnet_hdr = netmap_using_vnet_hdr, - .set_offload = netmap_set_offload, - .set_vnet_hdr_len = netmap_set_vnet_hdr_len, -}; - -/* The exported init function - * - * ... -net netmap,ifname="..." - */ -int net_init_netmap(const NetClientOptions *opts, - const char *name, NetClientState *peer, Error **errp) -{ - const NetdevNetmapOptions *netmap_opts = opts->u.netmap.data; - struct nm_desc *nmd; - NetClientState *nc; - Error *err = NULL; - NetmapState *s; - - nmd = netmap_open(netmap_opts, &err); - if (err) { - error_propagate(errp, err); - return -1; - } - /* Create the object. */ - nc = qemu_new_net_client(&net_netmap_info, peer, "netmap", name); - s = DO_UPCAST(NetmapState, nc, nc); - s->nmd = nmd; - s->tx = NETMAP_TXRING(nmd->nifp, 0); - s->rx = NETMAP_RXRING(nmd->nifp, 0); - s->vnet_hdr_len = 0; - pstrcpy(s->ifname, sizeof(s->ifname), netmap_opts->ifname); - netmap_read_poll(s, true); /* Initially only poll for reads. */ - - return 0; -} - diff --git a/qemu/net/queue.c b/qemu/net/queue.c deleted file mode 100644 index 9c32abdb8..000000000 --- a/qemu/net/queue.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright (c) 2003-2008 Fabrice Bellard - * Copyright (c) 2009 Red Hat, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "net/queue.h" -#include "qemu/queue.h" -#include "net/net.h" - -/* The delivery handler may only return zero if it will call - * qemu_net_queue_flush() when it determines that it is once again able - * to deliver packets. It must also call qemu_net_queue_purge() in its - * cleanup path. - * - * If a sent callback is provided to send(), the caller must handle a - * zero return from the delivery handler by not sending any more packets - * until we have invoked the callback. Only in that case will we queue - * the packet. - * - * If a sent callback isn't provided, we just drop the packet to avoid - * unbounded queueing. - */ - -struct NetPacket { - QTAILQ_ENTRY(NetPacket) entry; - NetClientState *sender; - unsigned flags; - int size; - NetPacketSent *sent_cb; - uint8_t data[0]; -}; - -struct NetQueue { - void *opaque; - uint32_t nq_maxlen; - uint32_t nq_count; - NetQueueDeliverFunc *deliver; - - QTAILQ_HEAD(packets, NetPacket) packets; - - unsigned delivering : 1; -}; - -NetQueue *qemu_new_net_queue(NetQueueDeliverFunc *deliver, void *opaque) -{ - NetQueue *queue; - - queue = g_new0(NetQueue, 1); - - queue->opaque = opaque; - queue->nq_maxlen = 10000; - queue->nq_count = 0; - queue->deliver = deliver; - - QTAILQ_INIT(&queue->packets); - - queue->delivering = 0; - - return queue; -} - -void qemu_del_net_queue(NetQueue *queue) -{ - NetPacket *packet, *next; - - QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) { - QTAILQ_REMOVE(&queue->packets, packet, entry); - g_free(packet); - } - - g_free(queue); -} - -static void qemu_net_queue_append(NetQueue *queue, - NetClientState *sender, - unsigned flags, - const uint8_t *buf, - size_t size, - NetPacketSent *sent_cb) -{ - NetPacket *packet; - - if (queue->nq_count >= queue->nq_maxlen && !sent_cb) { - return; /* drop if queue full and no callback */ - } - packet = g_malloc(sizeof(NetPacket) + size); - packet->sender = sender; - packet->flags = flags; - packet->size = size; - packet->sent_cb = sent_cb; - memcpy(packet->data, buf, size); - - queue->nq_count++; - QTAILQ_INSERT_TAIL(&queue->packets, packet, entry); -} - -void qemu_net_queue_append_iov(NetQueue *queue, - NetClientState *sender, - unsigned flags, - const struct iovec *iov, - int iovcnt, - NetPacketSent *sent_cb) -{ - NetPacket *packet; - size_t max_len = 0; - int i; - - if (queue->nq_count >= queue->nq_maxlen && !sent_cb) { - return; /* drop if queue full and no callback */ - } - for (i = 0; i < iovcnt; i++) { - max_len += iov[i].iov_len; - } - - packet = g_malloc(sizeof(NetPacket) + max_len); - packet->sender = sender; - packet->sent_cb = sent_cb; - packet->flags = flags; - packet->size = 0; - - for (i = 0; i < iovcnt; i++) { - size_t len = iov[i].iov_len; - - memcpy(packet->data + packet->size, iov[i].iov_base, len); - packet->size += len; - } - - queue->nq_count++; - QTAILQ_INSERT_TAIL(&queue->packets, packet, entry); -} - -static ssize_t qemu_net_queue_deliver(NetQueue *queue, - NetClientState *sender, - unsigned flags, - const uint8_t *data, - size_t size) -{ - ssize_t ret = -1; - struct iovec iov = { - .iov_base = (void *)data, - .iov_len = size - }; - - queue->delivering = 1; - ret = queue->deliver(sender, flags, &iov, 1, queue->opaque); - queue->delivering = 0; - - return ret; -} - -static ssize_t qemu_net_queue_deliver_iov(NetQueue *queue, - NetClientState *sender, - unsigned flags, - const struct iovec *iov, - int iovcnt) -{ - ssize_t ret = -1; - - queue->delivering = 1; - ret = queue->deliver(sender, flags, iov, iovcnt, queue->opaque); - queue->delivering = 0; - - return ret; -} - -ssize_t qemu_net_queue_send(NetQueue *queue, - NetClientState *sender, - unsigned flags, - const uint8_t *data, - size_t size, - NetPacketSent *sent_cb) -{ - ssize_t ret; - - if (queue->delivering || !qemu_can_send_packet(sender)) { - qemu_net_queue_append(queue, sender, flags, data, size, sent_cb); - return 0; - } - - ret = qemu_net_queue_deliver(queue, sender, flags, data, size); - if (ret == 0) { - qemu_net_queue_append(queue, sender, flags, data, size, sent_cb); - return 0; - } - - qemu_net_queue_flush(queue); - - return ret; -} - -ssize_t qemu_net_queue_send_iov(NetQueue *queue, - NetClientState *sender, - unsigned flags, - const struct iovec *iov, - int iovcnt, - NetPacketSent *sent_cb) -{ - ssize_t ret; - - if (queue->delivering || !qemu_can_send_packet(sender)) { - qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, sent_cb); - return 0; - } - - ret = qemu_net_queue_deliver_iov(queue, sender, flags, iov, iovcnt); - if (ret == 0) { - qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, sent_cb); - return 0; - } - - qemu_net_queue_flush(queue); - - return ret; -} - -void qemu_net_queue_purge(NetQueue *queue, NetClientState *from) -{ - NetPacket *packet, *next; - - QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) { - if (packet->sender == from) { - QTAILQ_REMOVE(&queue->packets, packet, entry); - queue->nq_count--; - if (packet->sent_cb) { - packet->sent_cb(packet->sender, 0); - } - g_free(packet); - } - } -} - -bool qemu_net_queue_flush(NetQueue *queue) -{ - while (!QTAILQ_EMPTY(&queue->packets)) { - NetPacket *packet; - int ret; - - packet = QTAILQ_FIRST(&queue->packets); - QTAILQ_REMOVE(&queue->packets, packet, entry); - queue->nq_count--; - - ret = qemu_net_queue_deliver(queue, - packet->sender, - packet->flags, - packet->data, - packet->size); - if (ret == 0) { - queue->nq_count++; - QTAILQ_INSERT_HEAD(&queue->packets, packet, entry); - return false; - } - - if (packet->sent_cb) { - packet->sent_cb(packet->sender, ret); - } - - g_free(packet); - } - return true; -} diff --git a/qemu/net/slirp.c b/qemu/net/slirp.c deleted file mode 100644 index 31630f005..000000000 --- a/qemu/net/slirp.c +++ /dev/null @@ -1,902 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include "net/slirp.h" - - -#ifndef _WIN32 -#include <pwd.h> -#include <sys/wait.h> -#endif -#include "net/net.h" -#include "clients.h" -#include "hub.h" -#include "monitor/monitor.h" -#include "qemu/error-report.h" -#include "qemu/sockets.h" -#include "slirp/libslirp.h" -#include "slirp/ip6.h" -#include "sysemu/char.h" -#include "qemu/cutils.h" - -static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) -{ - const char *p, *p1; - int len; - p = *pp; - p1 = strchr(p, sep); - if (!p1) - return -1; - len = p1 - p; - p1++; - if (buf_size > 0) { - if (len > buf_size - 1) - len = buf_size - 1; - memcpy(buf, p, len); - buf[len] = '\0'; - } - *pp = p1; - return 0; -} - -/* slirp network adapter */ - -#define SLIRP_CFG_HOSTFWD 1 -#define SLIRP_CFG_LEGACY 2 - -struct slirp_config_str { - struct slirp_config_str *next; - int flags; - char str[1024]; - int legacy_format; -}; - -typedef struct SlirpState { - NetClientState nc; - QTAILQ_ENTRY(SlirpState) entry; - Slirp *slirp; -#ifndef _WIN32 - char smb_dir[128]; -#endif -} SlirpState; - -static struct slirp_config_str *slirp_configs; -const char *legacy_tftp_prefix; -const char *legacy_bootp_filename; -static QTAILQ_HEAD(slirp_stacks, SlirpState) slirp_stacks = - QTAILQ_HEAD_INITIALIZER(slirp_stacks); - -static int slirp_hostfwd(SlirpState *s, const char *redir_str, - int legacy_format); -static int slirp_guestfwd(SlirpState *s, const char *config_str, - int legacy_format); - -#ifndef _WIN32 -static const char *legacy_smb_export; - -static int slirp_smb(SlirpState *s, const char *exported_dir, - struct in_addr vserver_addr); -static void slirp_smb_cleanup(SlirpState *s); -#else -static inline void slirp_smb_cleanup(SlirpState *s) { } -#endif - -void slirp_output(void *opaque, const uint8_t *pkt, int pkt_len) -{ - SlirpState *s = opaque; - - qemu_send_packet(&s->nc, pkt, pkt_len); -} - -static ssize_t net_slirp_receive(NetClientState *nc, const uint8_t *buf, size_t size) -{ - SlirpState *s = DO_UPCAST(SlirpState, nc, nc); - - slirp_input(s->slirp, buf, size); - - return size; -} - -static void net_slirp_cleanup(NetClientState *nc) -{ - SlirpState *s = DO_UPCAST(SlirpState, nc, nc); - - slirp_cleanup(s->slirp); - slirp_smb_cleanup(s); - QTAILQ_REMOVE(&slirp_stacks, s, entry); -} - -static NetClientInfo net_slirp_info = { - .type = NET_CLIENT_OPTIONS_KIND_USER, - .size = sizeof(SlirpState), - .receive = net_slirp_receive, - .cleanup = net_slirp_cleanup, -}; - -static int net_slirp_init(NetClientState *peer, const char *model, - const char *name, int restricted, - bool ipv4, const char *vnetwork, const char *vhost, - bool ipv6, const char *vprefix6, int vprefix6_len, - const char *vhost6, - const char *vhostname, const char *tftp_export, - const char *bootfile, const char *vdhcp_start, - const char *vnameserver, const char *vnameserver6, - const char *smb_export, const char *vsmbserver, - const char **dnssearch) -{ - /* default settings according to historic slirp */ - struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */ - struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */ - struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */ - struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */ - struct in_addr dns = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */ - struct in6_addr ip6_prefix; - struct in6_addr ip6_host; - struct in6_addr ip6_dns; -#ifndef _WIN32 - struct in_addr smbsrv = { .s_addr = 0 }; -#endif - NetClientState *nc; - SlirpState *s; - char buf[20]; - uint32_t addr; - int shift; - char *end; - struct slirp_config_str *config; - - if (!ipv4 && (vnetwork || vhost || vnameserver)) { - return -1; - } - - if (!ipv6 && (vprefix6 || vhost6 || vnameserver6)) { - return -1; - } - - if (!ipv4 && !ipv6) { - /* It doesn't make sense to disable both */ - return -1; - } - - if (!tftp_export) { - tftp_export = legacy_tftp_prefix; - } - if (!bootfile) { - bootfile = legacy_bootp_filename; - } - - if (vnetwork) { - if (get_str_sep(buf, sizeof(buf), &vnetwork, '/') < 0) { - if (!inet_aton(vnetwork, &net)) { - return -1; - } - addr = ntohl(net.s_addr); - if (!(addr & 0x80000000)) { - mask.s_addr = htonl(0xff000000); /* class A */ - } else if ((addr & 0xfff00000) == 0xac100000) { - mask.s_addr = htonl(0xfff00000); /* priv. 172.16.0.0/12 */ - } else if ((addr & 0xc0000000) == 0x80000000) { - mask.s_addr = htonl(0xffff0000); /* class B */ - } else if ((addr & 0xffff0000) == 0xc0a80000) { - mask.s_addr = htonl(0xffff0000); /* priv. 192.168.0.0/16 */ - } else if ((addr & 0xffff0000) == 0xc6120000) { - mask.s_addr = htonl(0xfffe0000); /* tests 198.18.0.0/15 */ - } else if ((addr & 0xe0000000) == 0xe0000000) { - mask.s_addr = htonl(0xffffff00); /* class C */ - } else { - mask.s_addr = htonl(0xfffffff0); /* multicast/reserved */ - } - } else { - if (!inet_aton(buf, &net)) { - return -1; - } - shift = strtol(vnetwork, &end, 10); - if (*end != '\0') { - if (!inet_aton(vnetwork, &mask)) { - return -1; - } - } else if (shift < 4 || shift > 32) { - return -1; - } else { - mask.s_addr = htonl(0xffffffff << (32 - shift)); - } - } - net.s_addr &= mask.s_addr; - host.s_addr = net.s_addr | (htonl(0x0202) & ~mask.s_addr); - dhcp.s_addr = net.s_addr | (htonl(0x020f) & ~mask.s_addr); - dns.s_addr = net.s_addr | (htonl(0x0203) & ~mask.s_addr); - } - - if (vhost && !inet_aton(vhost, &host)) { - return -1; - } - if ((host.s_addr & mask.s_addr) != net.s_addr) { - return -1; - } - - if (vnameserver && !inet_aton(vnameserver, &dns)) { - return -1; - } - if ((dns.s_addr & mask.s_addr) != net.s_addr || - dns.s_addr == host.s_addr) { - return -1; - } - - if (vdhcp_start && !inet_aton(vdhcp_start, &dhcp)) { - return -1; - } - if ((dhcp.s_addr & mask.s_addr) != net.s_addr || - dhcp.s_addr == host.s_addr || dhcp.s_addr == dns.s_addr) { - return -1; - } - -#ifndef _WIN32 - if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) { - return -1; - } -#endif - -#if defined(_WIN32) && (_WIN32_WINNT < 0x0600) - /* No inet_pton helper before Vista... */ - if (vprefix6) { - /* Unsupported */ - return -1; - } - memset(&ip6_prefix, 0, sizeof(ip6_prefix)); - ip6_prefix.s6_addr[0] = 0xfe; - ip6_prefix.s6_addr[1] = 0xc0; -#else - if (!vprefix6) { - vprefix6 = "fec0::"; - } - if (!inet_pton(AF_INET6, vprefix6, &ip6_prefix)) { - return -1; - } -#endif - - if (!vprefix6_len) { - vprefix6_len = 64; - } - if (vprefix6_len < 0 || vprefix6_len > 126) { - return -1; - } - - if (vhost6) { -#if defined(_WIN32) && (_WIN32_WINNT < 0x0600) - return -1; -#else - if (!inet_pton(AF_INET6, vhost6, &ip6_host)) { - return -1; - } - if (!in6_equal_net(&ip6_prefix, &ip6_host, vprefix6_len)) { - return -1; - } -#endif - } else { - ip6_host = ip6_prefix; - ip6_host.s6_addr[15] |= 2; - } - - if (vnameserver6) { -#if defined(_WIN32) && (_WIN32_WINNT < 0x0600) - return -1; -#else - if (!inet_pton(AF_INET6, vnameserver6, &ip6_dns)) { - return -1; - } - if (!in6_equal_net(&ip6_prefix, &ip6_dns, vprefix6_len)) { - return -1; - } -#endif - } else { - ip6_dns = ip6_prefix; - ip6_dns.s6_addr[15] |= 3; - } - - - nc = qemu_new_net_client(&net_slirp_info, peer, model, name); - - snprintf(nc->info_str, sizeof(nc->info_str), - "net=%s,restrict=%s", inet_ntoa(net), - restricted ? "on" : "off"); - - s = DO_UPCAST(SlirpState, nc, nc); - - s->slirp = slirp_init(restricted, ipv4, net, mask, host, - ipv6, ip6_prefix, vprefix6_len, ip6_host, - vhostname, tftp_export, bootfile, dhcp, - dns, ip6_dns, dnssearch, s); - QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry); - - for (config = slirp_configs; config; config = config->next) { - if (config->flags & SLIRP_CFG_HOSTFWD) { - if (slirp_hostfwd(s, config->str, - config->flags & SLIRP_CFG_LEGACY) < 0) - goto error; - } else { - if (slirp_guestfwd(s, config->str, - config->flags & SLIRP_CFG_LEGACY) < 0) - goto error; - } - } -#ifndef _WIN32 - if (!smb_export) { - smb_export = legacy_smb_export; - } - if (smb_export) { - if (slirp_smb(s, smb_export, smbsrv) < 0) - goto error; - } -#endif - - return 0; - -error: - qemu_del_net_client(nc); - return -1; -} - -static SlirpState *slirp_lookup(Monitor *mon, const char *vlan, - const char *stack) -{ - - if (vlan) { - NetClientState *nc; - nc = net_hub_find_client_by_name(strtol(vlan, NULL, 0), stack); - if (!nc) { - monitor_printf(mon, "unrecognized (vlan-id, stackname) pair\n"); - return NULL; - } - if (strcmp(nc->model, "user")) { - monitor_printf(mon, "invalid device specified\n"); - return NULL; - } - return DO_UPCAST(SlirpState, nc, nc); - } else { - if (QTAILQ_EMPTY(&slirp_stacks)) { - monitor_printf(mon, "user mode network stack not in use\n"); - return NULL; - } - return QTAILQ_FIRST(&slirp_stacks); - } -} - -void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict) -{ - struct in_addr host_addr = { .s_addr = INADDR_ANY }; - int host_port; - char buf[256]; - const char *src_str, *p; - SlirpState *s; - int is_udp = 0; - int err; - const char *arg1 = qdict_get_str(qdict, "arg1"); - const char *arg2 = qdict_get_try_str(qdict, "arg2"); - const char *arg3 = qdict_get_try_str(qdict, "arg3"); - - if (arg2) { - s = slirp_lookup(mon, arg1, arg2); - src_str = arg3; - } else { - s = slirp_lookup(mon, NULL, NULL); - src_str = arg1; - } - if (!s) { - return; - } - - p = src_str; - if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - goto fail_syntax; - } - - if (!strcmp(buf, "tcp") || buf[0] == '\0') { - is_udp = 0; - } else if (!strcmp(buf, "udp")) { - is_udp = 1; - } else { - goto fail_syntax; - } - - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - goto fail_syntax; - } - if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) { - goto fail_syntax; - } - - host_port = atoi(p); - - err = slirp_remove_hostfwd(s->slirp, is_udp, host_addr, host_port); - - monitor_printf(mon, "host forwarding rule for %s %s\n", src_str, - err ? "not found" : "removed"); - return; - - fail_syntax: - monitor_printf(mon, "invalid format\n"); -} - -static int slirp_hostfwd(SlirpState *s, const char *redir_str, - int legacy_format) -{ - struct in_addr host_addr = { .s_addr = INADDR_ANY }; - struct in_addr guest_addr = { .s_addr = 0 }; - int host_port, guest_port; - const char *p; - char buf[256]; - int is_udp; - char *end; - - p = redir_str; - if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - goto fail_syntax; - } - if (!strcmp(buf, "tcp") || buf[0] == '\0') { - is_udp = 0; - } else if (!strcmp(buf, "udp")) { - is_udp = 1; - } else { - goto fail_syntax; - } - - if (!legacy_format) { - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - goto fail_syntax; - } - if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) { - goto fail_syntax; - } - } - - if (get_str_sep(buf, sizeof(buf), &p, legacy_format ? ':' : '-') < 0) { - goto fail_syntax; - } - host_port = strtol(buf, &end, 0); - if (*end != '\0' || host_port < 1 || host_port > 65535) { - goto fail_syntax; - } - - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - goto fail_syntax; - } - if (buf[0] != '\0' && !inet_aton(buf, &guest_addr)) { - goto fail_syntax; - } - - guest_port = strtol(p, &end, 0); - if (*end != '\0' || guest_port < 1 || guest_port > 65535) { - goto fail_syntax; - } - - if (slirp_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr, - guest_port) < 0) { - error_report("could not set up host forwarding rule '%s'", - redir_str); - return -1; - } - return 0; - - fail_syntax: - error_report("invalid host forwarding rule '%s'", redir_str); - return -1; -} - -void hmp_hostfwd_add(Monitor *mon, const QDict *qdict) -{ - const char *redir_str; - SlirpState *s; - const char *arg1 = qdict_get_str(qdict, "arg1"); - const char *arg2 = qdict_get_try_str(qdict, "arg2"); - const char *arg3 = qdict_get_try_str(qdict, "arg3"); - - if (arg2) { - s = slirp_lookup(mon, arg1, arg2); - redir_str = arg3; - } else { - s = slirp_lookup(mon, NULL, NULL); - redir_str = arg1; - } - if (s) { - slirp_hostfwd(s, redir_str, 0); - } - -} - -int net_slirp_redir(const char *redir_str) -{ - struct slirp_config_str *config; - - if (QTAILQ_EMPTY(&slirp_stacks)) { - config = g_malloc(sizeof(*config)); - pstrcpy(config->str, sizeof(config->str), redir_str); - config->flags = SLIRP_CFG_HOSTFWD | SLIRP_CFG_LEGACY; - config->next = slirp_configs; - slirp_configs = config; - return 0; - } - - return slirp_hostfwd(QTAILQ_FIRST(&slirp_stacks), redir_str, 1); -} - -#ifndef _WIN32 - -/* automatic user mode samba server configuration */ -static void slirp_smb_cleanup(SlirpState *s) -{ - char cmd[128]; - int ret; - - if (s->smb_dir[0] != '\0') { - snprintf(cmd, sizeof(cmd), "rm -rf %s", s->smb_dir); - ret = system(cmd); - if (ret == -1 || !WIFEXITED(ret)) { - error_report("'%s' failed.", cmd); - } else if (WEXITSTATUS(ret)) { - error_report("'%s' failed. Error code: %d", - cmd, WEXITSTATUS(ret)); - } - s->smb_dir[0] = '\0'; - } -} - -static int slirp_smb(SlirpState* s, const char *exported_dir, - struct in_addr vserver_addr) -{ - char smb_conf[128]; - char smb_cmdline[128]; - struct passwd *passwd; - FILE *f; - - passwd = getpwuid(geteuid()); - if (!passwd) { - error_report("failed to retrieve user name"); - return -1; - } - - if (access(CONFIG_SMBD_COMMAND, F_OK)) { - error_report("could not find '%s', please install it", - CONFIG_SMBD_COMMAND); - return -1; - } - - if (access(exported_dir, R_OK | X_OK)) { - error_report("error accessing shared directory '%s': %s", - exported_dir, strerror(errno)); - return -1; - } - - snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.XXXXXX"); - if (!mkdtemp(s->smb_dir)) { - error_report("could not create samba server dir '%s'", s->smb_dir); - s->smb_dir[0] = 0; - return -1; - } - snprintf(smb_conf, sizeof(smb_conf), "%s/%s", s->smb_dir, "smb.conf"); - - f = fopen(smb_conf, "w"); - if (!f) { - slirp_smb_cleanup(s); - error_report("could not create samba server configuration file '%s'", - smb_conf); - return -1; - } - fprintf(f, - "[global]\n" - "private dir=%s\n" - "interfaces=127.0.0.1\n" - "bind interfaces only=yes\n" - "pid directory=%s\n" - "lock directory=%s\n" - "state directory=%s\n" - "cache directory=%s\n" - "ncalrpc dir=%s/ncalrpc\n" - "log file=%s/log.smbd\n" - "smb passwd file=%s/smbpasswd\n" - "security = user\n" - "map to guest = Bad User\n" - "load printers = no\n" - "printing = bsd\n" - "disable spoolss = yes\n" - "usershare max shares = 0\n" - "[qemu]\n" - "path=%s\n" - "read only=no\n" - "guest ok=yes\n" - "force user=%s\n", - s->smb_dir, - s->smb_dir, - s->smb_dir, - s->smb_dir, - s->smb_dir, - s->smb_dir, - s->smb_dir, - s->smb_dir, - exported_dir, - passwd->pw_name - ); - fclose(f); - - snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -l %s -s %s", - CONFIG_SMBD_COMMAND, s->smb_dir, smb_conf); - - if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0 || - slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 445) < 0) { - slirp_smb_cleanup(s); - error_report("conflicting/invalid smbserver address"); - return -1; - } - return 0; -} - -/* automatic user mode samba server configuration (legacy interface) */ -int net_slirp_smb(const char *exported_dir) -{ - struct in_addr vserver_addr = { .s_addr = 0 }; - - if (legacy_smb_export) { - fprintf(stderr, "-smb given twice\n"); - return -1; - } - legacy_smb_export = exported_dir; - if (!QTAILQ_EMPTY(&slirp_stacks)) { - return slirp_smb(QTAILQ_FIRST(&slirp_stacks), exported_dir, - vserver_addr); - } - return 0; -} - -#endif /* !defined(_WIN32) */ - -struct GuestFwd { - CharDriverState *hd; - struct in_addr server; - int port; - Slirp *slirp; -}; - -static int guestfwd_can_read(void *opaque) -{ - struct GuestFwd *fwd = opaque; - return slirp_socket_can_recv(fwd->slirp, fwd->server, fwd->port); -} - -static void guestfwd_read(void *opaque, const uint8_t *buf, int size) -{ - struct GuestFwd *fwd = opaque; - slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size); -} - -static int slirp_guestfwd(SlirpState *s, const char *config_str, - int legacy_format) -{ - struct in_addr server = { .s_addr = 0 }; - struct GuestFwd *fwd; - const char *p; - char buf[128]; - char *end; - int port; - - p = config_str; - if (legacy_format) { - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - goto fail_syntax; - } - } else { - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - goto fail_syntax; - } - if (strcmp(buf, "tcp") && buf[0] != '\0') { - goto fail_syntax; - } - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { - goto fail_syntax; - } - if (buf[0] != '\0' && !inet_aton(buf, &server)) { - goto fail_syntax; - } - if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) { - goto fail_syntax; - } - } - port = strtol(buf, &end, 10); - if (*end != '\0' || port < 1 || port > 65535) { - goto fail_syntax; - } - - snprintf(buf, sizeof(buf), "guestfwd.tcp.%d", port); - - if ((strlen(p) > 4) && !strncmp(p, "cmd:", 4)) { - if (slirp_add_exec(s->slirp, 0, &p[4], &server, port) < 0) { - error_report("conflicting/invalid host:port in guest forwarding " - "rule '%s'", config_str); - return -1; - } - } else { - fwd = g_new(struct GuestFwd, 1); - fwd->hd = qemu_chr_new(buf, p, NULL); - if (!fwd->hd) { - error_report("could not open guest forwarding device '%s'", buf); - g_free(fwd); - return -1; - } - - if (slirp_add_exec(s->slirp, 3, fwd->hd, &server, port) < 0) { - error_report("conflicting/invalid host:port in guest forwarding " - "rule '%s'", config_str); - g_free(fwd); - return -1; - } - fwd->server = server; - fwd->port = port; - fwd->slirp = s->slirp; - - qemu_chr_fe_claim_no_fail(fwd->hd); - qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read, - NULL, fwd); - } - return 0; - - fail_syntax: - error_report("invalid guest forwarding rule '%s'", config_str); - return -1; -} - -void hmp_info_usernet(Monitor *mon, const QDict *qdict) -{ - SlirpState *s; - - QTAILQ_FOREACH(s, &slirp_stacks, entry) { - int id; - bool got_vlan_id = net_hub_id_for_client(&s->nc, &id) == 0; - monitor_printf(mon, "VLAN %d (%s):\n", - got_vlan_id ? id : -1, - s->nc.name); - slirp_connection_info(s->slirp, mon); - } -} - -static void -net_init_slirp_configs(const StringList *fwd, int flags) -{ - while (fwd) { - struct slirp_config_str *config; - - config = g_malloc0(sizeof(*config)); - pstrcpy(config->str, sizeof(config->str), fwd->value->str); - config->flags = flags; - config->next = slirp_configs; - slirp_configs = config; - - fwd = fwd->next; - } -} - -static const char **slirp_dnssearch(const StringList *dnsname) -{ - const StringList *c = dnsname; - size_t i = 0, num_opts = 0; - const char **ret; - - while (c) { - num_opts++; - c = c->next; - } - - if (num_opts == 0) { - return NULL; - } - - ret = g_malloc((num_opts + 1) * sizeof(*ret)); - c = dnsname; - while (c) { - ret[i++] = c->value->str; - c = c->next; - } - ret[i] = NULL; - return ret; -} - -int net_init_slirp(const NetClientOptions *opts, const char *name, - NetClientState *peer, Error **errp) -{ - /* FIXME error_setg(errp, ...) on failure */ - struct slirp_config_str *config; - char *vnet; - int ret; - const NetdevUserOptions *user; - const char **dnssearch; - bool ipv4 = true, ipv6 = true; - - assert(opts->type == NET_CLIENT_OPTIONS_KIND_USER); - user = opts->u.user.data; - - if ((user->has_ipv6 && user->ipv6 && !user->has_ipv4) || - (user->has_ipv4 && !user->ipv4)) { - ipv4 = 0; - } - if ((user->has_ipv4 && user->ipv4 && !user->has_ipv6) || - (user->has_ipv6 && !user->ipv6)) { - ipv6 = 0; - } - - vnet = user->has_net ? g_strdup(user->net) : - user->has_ip ? g_strdup_printf("%s/24", user->ip) : - NULL; - - dnssearch = slirp_dnssearch(user->dnssearch); - - /* all optional fields are initialized to "all bits zero" */ - - net_init_slirp_configs(user->hostfwd, SLIRP_CFG_HOSTFWD); - net_init_slirp_configs(user->guestfwd, 0); - - ret = net_slirp_init(peer, "user", name, user->q_restrict, - ipv4, vnet, user->host, - ipv6, user->ipv6_prefix, user->ipv6_prefixlen, - user->ipv6_host, user->hostname, user->tftp, - user->bootfile, user->dhcpstart, - user->dns, user->ipv6_dns, user->smb, - user->smbserver, dnssearch); - - while (slirp_configs) { - config = slirp_configs; - slirp_configs = config->next; - g_free(config); - } - - g_free(vnet); - g_free(dnssearch); - - return ret; -} - -int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret) -{ - if (strcmp(opts_list->name, "net") != 0 || - strncmp(optarg, "channel,", strlen("channel,")) != 0) { - return 0; - } - - error_report("The '-net channel' option is deprecated. " - "Please use '-netdev user,guestfwd=...' instead."); - - /* handle legacy -net channel,port:chr */ - optarg += strlen("channel,"); - - if (QTAILQ_EMPTY(&slirp_stacks)) { - struct slirp_config_str *config; - - config = g_malloc(sizeof(*config)); - pstrcpy(config->str, sizeof(config->str), optarg); - config->flags = SLIRP_CFG_LEGACY; - config->next = slirp_configs; - slirp_configs = config; - *ret = 0; - } else { - *ret = slirp_guestfwd(QTAILQ_FIRST(&slirp_stacks), optarg, 1); - } - - return 1; -} - diff --git a/qemu/net/socket.c b/qemu/net/socket.c deleted file mode 100644 index 9fa2cd8d5..000000000 --- a/qemu/net/socket.c +++ /dev/null @@ -1,772 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" - -#include "net/net.h" -#include "clients.h" -#include "monitor/monitor.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "qemu/error-report.h" -#include "qemu/option.h" -#include "qemu/sockets.h" -#include "qemu/iov.h" -#include "qemu/main-loop.h" - -typedef struct NetSocketState { - NetClientState nc; - int listen_fd; - int fd; - int state; /* 0 = getting length, 1 = getting data */ - unsigned int index; - unsigned int packet_len; - unsigned int send_index; /* number of bytes sent (only SOCK_STREAM) */ - uint8_t buf[NET_BUFSIZE]; - struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */ - IOHandler *send_fn; /* differs between SOCK_STREAM/SOCK_DGRAM */ - bool read_poll; /* waiting to receive data? */ - bool write_poll; /* waiting to transmit data? */ -} NetSocketState; - -static void net_socket_accept(void *opaque); -static void net_socket_writable(void *opaque); - -static void net_socket_update_fd_handler(NetSocketState *s) -{ - qemu_set_fd_handler(s->fd, - s->read_poll ? s->send_fn : NULL, - s->write_poll ? net_socket_writable : NULL, - s); -} - -static void net_socket_read_poll(NetSocketState *s, bool enable) -{ - s->read_poll = enable; - net_socket_update_fd_handler(s); -} - -static void net_socket_write_poll(NetSocketState *s, bool enable) -{ - s->write_poll = enable; - net_socket_update_fd_handler(s); -} - -static void net_socket_writable(void *opaque) -{ - NetSocketState *s = opaque; - - net_socket_write_poll(s, false); - - qemu_flush_queued_packets(&s->nc); -} - -static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, size_t size) -{ - NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); - uint32_t len = htonl(size); - struct iovec iov[] = { - { - .iov_base = &len, - .iov_len = sizeof(len), - }, { - .iov_base = (void *)buf, - .iov_len = size, - }, - }; - size_t remaining; - ssize_t ret; - - remaining = iov_size(iov, 2) - s->send_index; - ret = iov_send(s->fd, iov, 2, s->send_index, remaining); - - if (ret == -1 && errno == EAGAIN) { - ret = 0; /* handled further down */ - } - if (ret == -1) { - s->send_index = 0; - return -errno; - } - if (ret < (ssize_t)remaining) { - s->send_index += ret; - net_socket_write_poll(s, true); - return 0; - } - s->send_index = 0; - return size; -} - -static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t *buf, size_t size) -{ - NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); - ssize_t ret; - - do { - ret = qemu_sendto(s->fd, buf, size, 0, - (struct sockaddr *)&s->dgram_dst, - sizeof(s->dgram_dst)); - } while (ret == -1 && errno == EINTR); - - if (ret == -1 && errno == EAGAIN) { - net_socket_write_poll(s, true); - return 0; - } - return ret; -} - -static void net_socket_send_completed(NetClientState *nc, ssize_t len) -{ - NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); - - if (!s->read_poll) { - net_socket_read_poll(s, true); - } -} - -static void net_socket_send(void *opaque) -{ - NetSocketState *s = opaque; - int size; - unsigned l; - uint8_t buf1[NET_BUFSIZE]; - const uint8_t *buf; - - size = qemu_recv(s->fd, buf1, sizeof(buf1), 0); - if (size < 0) { - if (errno != EWOULDBLOCK) - goto eoc; - } else if (size == 0) { - /* end of connection */ - eoc: - net_socket_read_poll(s, false); - net_socket_write_poll(s, false); - if (s->listen_fd != -1) { - qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s); - } - closesocket(s->fd); - - s->fd = -1; - s->state = 0; - s->index = 0; - s->packet_len = 0; - s->nc.link_down = true; - memset(s->buf, 0, sizeof(s->buf)); - memset(s->nc.info_str, 0, sizeof(s->nc.info_str)); - - return; - } - buf = buf1; - while (size > 0) { - /* reassemble a packet from the network */ - switch(s->state) { - case 0: - l = 4 - s->index; - if (l > size) - l = size; - memcpy(s->buf + s->index, buf, l); - buf += l; - size -= l; - s->index += l; - if (s->index == 4) { - /* got length */ - s->packet_len = ntohl(*(uint32_t *)s->buf); - s->index = 0; - s->state = 1; - } - break; - case 1: - l = s->packet_len - s->index; - if (l > size) - l = size; - if (s->index + l <= sizeof(s->buf)) { - memcpy(s->buf + s->index, buf, l); - } else { - fprintf(stderr, "serious error: oversized packet received," - "connection terminated.\n"); - s->state = 0; - goto eoc; - } - - s->index += l; - buf += l; - size -= l; - if (s->index >= s->packet_len) { - s->index = 0; - s->state = 0; - if (qemu_send_packet_async(&s->nc, s->buf, s->packet_len, - net_socket_send_completed) == 0) { - net_socket_read_poll(s, false); - break; - } - } - break; - } - } -} - -static void net_socket_send_dgram(void *opaque) -{ - NetSocketState *s = opaque; - int size; - - size = qemu_recv(s->fd, s->buf, sizeof(s->buf), 0); - if (size < 0) - return; - if (size == 0) { - /* end of connection */ - net_socket_read_poll(s, false); - net_socket_write_poll(s, false); - return; - } - if (qemu_send_packet_async(&s->nc, s->buf, size, - net_socket_send_completed) == 0) { - net_socket_read_poll(s, false); - } -} - -static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr *localaddr) -{ - struct ip_mreq imr; - int fd; - int val, ret; -#ifdef __OpenBSD__ - unsigned char loop; -#else - int loop; -#endif - - if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) { - fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) " - "does not contain a multicast address\n", - inet_ntoa(mcastaddr->sin_addr), - (int)ntohl(mcastaddr->sin_addr.s_addr)); - return -1; - - } - fd = qemu_socket(PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - perror("socket(PF_INET, SOCK_DGRAM)"); - return -1; - } - - /* Allow multiple sockets to bind the same multicast ip and port by setting - * SO_REUSEADDR. This is the only situation where SO_REUSEADDR should be set - * on windows. Use socket_set_fast_reuse otherwise as it sets SO_REUSEADDR - * only on posix systems. - */ - val = 1; - ret = qemu_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); - if (ret < 0) { - perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)"); - goto fail; - } - - ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr)); - if (ret < 0) { - perror("bind"); - goto fail; - } - - /* Add host to multicast group */ - imr.imr_multiaddr = mcastaddr->sin_addr; - if (localaddr) { - imr.imr_interface = *localaddr; - } else { - imr.imr_interface.s_addr = htonl(INADDR_ANY); - } - - ret = qemu_setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, - &imr, sizeof(struct ip_mreq)); - if (ret < 0) { - perror("setsockopt(IP_ADD_MEMBERSHIP)"); - goto fail; - } - - /* Force mcast msgs to loopback (eg. several QEMUs in same host */ - loop = 1; - ret = qemu_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, - &loop, sizeof(loop)); - if (ret < 0) { - perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)"); - goto fail; - } - - /* If a bind address is given, only send packets from that address */ - if (localaddr != NULL) { - ret = qemu_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, - localaddr, sizeof(*localaddr)); - if (ret < 0) { - perror("setsockopt(IP_MULTICAST_IF)"); - goto fail; - } - } - - qemu_set_nonblock(fd); - return fd; -fail: - if (fd >= 0) - closesocket(fd); - return -1; -} - -static void net_socket_cleanup(NetClientState *nc) -{ - NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); - if (s->fd != -1) { - net_socket_read_poll(s, false); - net_socket_write_poll(s, false); - close(s->fd); - s->fd = -1; - } - if (s->listen_fd != -1) { - qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL); - closesocket(s->listen_fd); - s->listen_fd = -1; - } -} - -static NetClientInfo net_dgram_socket_info = { - .type = NET_CLIENT_OPTIONS_KIND_SOCKET, - .size = sizeof(NetSocketState), - .receive = net_socket_receive_dgram, - .cleanup = net_socket_cleanup, -}; - -static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer, - const char *model, - const char *name, - int fd, int is_connected) -{ - struct sockaddr_in saddr; - int newfd; - socklen_t saddr_len = sizeof(saddr); - NetClientState *nc; - NetSocketState *s; - - /* fd passed: multicast: "learn" dgram_dst address from bound address and save it - * Because this may be "shared" socket from a "master" process, datagrams would be recv() - * by ONLY ONE process: we must "clone" this dgram socket --jjo - */ - - if (is_connected) { - if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) { - /* must be bound */ - if (saddr.sin_addr.s_addr == 0) { - fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, " - "cannot setup multicast dst addr\n", fd); - goto err; - } - /* clone dgram socket */ - newfd = net_socket_mcast_create(&saddr, NULL); - if (newfd < 0) { - /* error already reported by net_socket_mcast_create() */ - goto err; - } - /* clone newfd to fd, close newfd */ - dup2(newfd, fd); - close(newfd); - - } else { - fprintf(stderr, - "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n", - fd, strerror(errno)); - goto err; - } - } - - nc = qemu_new_net_client(&net_dgram_socket_info, peer, model, name); - - s = DO_UPCAST(NetSocketState, nc, nc); - - s->fd = fd; - s->listen_fd = -1; - s->send_fn = net_socket_send_dgram; - net_socket_read_poll(s, true); - - /* mcast: save bound address as dst */ - if (is_connected) { - s->dgram_dst = saddr; - snprintf(nc->info_str, sizeof(nc->info_str), - "socket: fd=%d (cloned mcast=%s:%d)", - fd, inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); - } else { - snprintf(nc->info_str, sizeof(nc->info_str), - "socket: fd=%d", fd); - } - - return s; - -err: - closesocket(fd); - return NULL; -} - -static void net_socket_connect(void *opaque) -{ - NetSocketState *s = opaque; - s->send_fn = net_socket_send; - net_socket_read_poll(s, true); -} - -static NetClientInfo net_socket_info = { - .type = NET_CLIENT_OPTIONS_KIND_SOCKET, - .size = sizeof(NetSocketState), - .receive = net_socket_receive, - .cleanup = net_socket_cleanup, -}; - -static NetSocketState *net_socket_fd_init_stream(NetClientState *peer, - const char *model, - const char *name, - int fd, int is_connected) -{ - NetClientState *nc; - NetSocketState *s; - - nc = qemu_new_net_client(&net_socket_info, peer, model, name); - - snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d", fd); - - s = DO_UPCAST(NetSocketState, nc, nc); - - s->fd = fd; - s->listen_fd = -1; - - /* Disable Nagle algorithm on TCP sockets to reduce latency */ - socket_set_nodelay(fd); - - if (is_connected) { - net_socket_connect(s); - } else { - qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s); - } - return s; -} - -static NetSocketState *net_socket_fd_init(NetClientState *peer, - const char *model, const char *name, - int fd, int is_connected) -{ - int so_type = -1, optlen=sizeof(so_type); - - if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, - (socklen_t *)&optlen)< 0) { - fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", - fd); - closesocket(fd); - return NULL; - } - switch(so_type) { - case SOCK_DGRAM: - return net_socket_fd_init_dgram(peer, model, name, fd, is_connected); - case SOCK_STREAM: - return net_socket_fd_init_stream(peer, model, name, fd, is_connected); - default: - /* who knows ... this could be a eg. a pty, do warn and continue as stream */ - fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd); - return net_socket_fd_init_stream(peer, model, name, fd, is_connected); - } - return NULL; -} - -static void net_socket_accept(void *opaque) -{ - NetSocketState *s = opaque; - struct sockaddr_in saddr; - socklen_t len; - int fd; - - for(;;) { - len = sizeof(saddr); - fd = qemu_accept(s->listen_fd, (struct sockaddr *)&saddr, &len); - if (fd < 0 && errno != EINTR) { - return; - } else if (fd >= 0) { - qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL); - break; - } - } - - s->fd = fd; - s->nc.link_down = false; - net_socket_connect(s); - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "socket: connection from %s:%d", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); -} - -static int net_socket_listen_init(NetClientState *peer, - const char *model, - const char *name, - const char *host_str) -{ - NetClientState *nc; - NetSocketState *s; - struct sockaddr_in saddr; - int fd, ret; - - if (parse_host_port(&saddr, host_str) < 0) - return -1; - - fd = qemu_socket(PF_INET, SOCK_STREAM, 0); - if (fd < 0) { - perror("socket"); - return -1; - } - qemu_set_nonblock(fd); - - socket_set_fast_reuse(fd); - - ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); - if (ret < 0) { - perror("bind"); - closesocket(fd); - return -1; - } - ret = listen(fd, 0); - if (ret < 0) { - perror("listen"); - closesocket(fd); - return -1; - } - - nc = qemu_new_net_client(&net_socket_info, peer, model, name); - s = DO_UPCAST(NetSocketState, nc, nc); - s->fd = -1; - s->listen_fd = fd; - s->nc.link_down = true; - - qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s); - return 0; -} - -static int net_socket_connect_init(NetClientState *peer, - const char *model, - const char *name, - const char *host_str) -{ - NetSocketState *s; - int fd, connected, ret; - struct sockaddr_in saddr; - - if (parse_host_port(&saddr, host_str) < 0) - return -1; - - fd = qemu_socket(PF_INET, SOCK_STREAM, 0); - if (fd < 0) { - perror("socket"); - return -1; - } - qemu_set_nonblock(fd); - - connected = 0; - for(;;) { - ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); - if (ret < 0) { - if (errno == EINTR || errno == EWOULDBLOCK) { - /* continue */ - } else if (errno == EINPROGRESS || - errno == EALREADY || - errno == EINVAL) { - break; - } else { - perror("connect"); - closesocket(fd); - return -1; - } - } else { - connected = 1; - break; - } - } - s = net_socket_fd_init(peer, model, name, fd, connected); - if (!s) - return -1; - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "socket: connect to %s:%d", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); - return 0; -} - -static int net_socket_mcast_init(NetClientState *peer, - const char *model, - const char *name, - const char *host_str, - const char *localaddr_str) -{ - NetSocketState *s; - int fd; - struct sockaddr_in saddr; - struct in_addr localaddr, *param_localaddr; - - if (parse_host_port(&saddr, host_str) < 0) - return -1; - - if (localaddr_str != NULL) { - if (inet_aton(localaddr_str, &localaddr) == 0) - return -1; - param_localaddr = &localaddr; - } else { - param_localaddr = NULL; - } - - fd = net_socket_mcast_create(&saddr, param_localaddr); - if (fd < 0) - return -1; - - s = net_socket_fd_init(peer, model, name, fd, 0); - if (!s) - return -1; - - s->dgram_dst = saddr; - - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "socket: mcast=%s:%d", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); - return 0; - -} - -static int net_socket_udp_init(NetClientState *peer, - const char *model, - const char *name, - const char *rhost, - const char *lhost) -{ - NetSocketState *s; - int fd, ret; - struct sockaddr_in laddr, raddr; - - if (parse_host_port(&laddr, lhost) < 0) { - return -1; - } - - if (parse_host_port(&raddr, rhost) < 0) { - return -1; - } - - fd = qemu_socket(PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - perror("socket(PF_INET, SOCK_DGRAM)"); - return -1; - } - - ret = socket_set_fast_reuse(fd); - if (ret < 0) { - closesocket(fd); - return -1; - } - ret = bind(fd, (struct sockaddr *)&laddr, sizeof(laddr)); - if (ret < 0) { - perror("bind"); - closesocket(fd); - return -1; - } - qemu_set_nonblock(fd); - - s = net_socket_fd_init(peer, model, name, fd, 0); - if (!s) { - return -1; - } - - s->dgram_dst = raddr; - - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "socket: udp=%s:%d", - inet_ntoa(raddr.sin_addr), ntohs(raddr.sin_port)); - return 0; -} - -int net_init_socket(const NetClientOptions *opts, const char *name, - NetClientState *peer, Error **errp) -{ - /* FIXME error_setg(errp, ...) on failure */ - Error *err = NULL; - const NetdevSocketOptions *sock; - - assert(opts->type == NET_CLIENT_OPTIONS_KIND_SOCKET); - sock = opts->u.socket.data; - - if (sock->has_fd + sock->has_listen + sock->has_connect + sock->has_mcast + - sock->has_udp != 1) { - error_report("exactly one of fd=, listen=, connect=, mcast= or udp=" - " is required"); - return -1; - } - - if (sock->has_localaddr && !sock->has_mcast && !sock->has_udp) { - error_report("localaddr= is only valid with mcast= or udp="); - return -1; - } - - if (sock->has_fd) { - int fd; - - fd = monitor_fd_param(cur_mon, sock->fd, &err); - if (fd == -1) { - error_report_err(err); - return -1; - } - qemu_set_nonblock(fd); - if (!net_socket_fd_init(peer, "socket", name, fd, 1)) { - return -1; - } - return 0; - } - - if (sock->has_listen) { - if (net_socket_listen_init(peer, "socket", name, sock->listen) == -1) { - return -1; - } - return 0; - } - - if (sock->has_connect) { - if (net_socket_connect_init(peer, "socket", name, sock->connect) == - -1) { - return -1; - } - return 0; - } - - if (sock->has_mcast) { - /* if sock->localaddr is missing, it has been initialized to "all bits - * zero" */ - if (net_socket_mcast_init(peer, "socket", name, sock->mcast, - sock->localaddr) == -1) { - return -1; - } - return 0; - } - - assert(sock->has_udp); - if (!sock->has_localaddr) { - error_report("localaddr= is mandatory with udp="); - return -1; - } - if (net_socket_udp_init(peer, "socket", name, sock->udp, sock->localaddr) == - -1) { - return -1; - } - return 0; -} diff --git a/qemu/net/tap-aix.c b/qemu/net/tap-aix.c deleted file mode 100644 index 0e6da6396..000000000 --- a/qemu/net/tap-aix.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "tap_int.h" - -int tap_open(char *ifname, int ifname_size, int *vnet_hdr, - int vnet_hdr_required, int mq_required, Error **errp) -{ - error_setg(errp, "no tap on AIX"); - return -1; -} - -void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp) -{ -} - -int tap_probe_vnet_hdr(int fd) -{ - return 0; -} - -int tap_probe_has_ufo(int fd) -{ - return 0; -} - -int tap_probe_vnet_hdr_len(int fd, int len) -{ - return 0; -} - -void tap_fd_set_vnet_hdr_len(int fd, int len) -{ -} - -int tap_fd_set_vnet_le(int fd, int is_le) -{ - return -EINVAL; -} - -int tap_fd_set_vnet_be(int fd, int is_be) -{ - return -EINVAL; -} - -void tap_fd_set_offload(int fd, int csum, int tso4, - int tso6, int ecn, int ufo) -{ -} - -int tap_fd_enable(int fd) -{ - return -1; -} - -int tap_fd_disable(int fd) -{ - return -1; -} - -int tap_fd_get_ifname(int fd, char *ifname) -{ - return -1; -} - diff --git a/qemu/net/tap-bsd.c b/qemu/net/tap-bsd.c deleted file mode 100644 index c506ac31d..000000000 --- a/qemu/net/tap-bsd.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "tap_int.h" -#include "qemu/cutils.h" -#include "sysemu/sysemu.h" -#include "qemu/error-report.h" - -#if defined(__NetBSD__) || defined(__FreeBSD__) -#include <sys/ioctl.h> -#include <net/if.h> -#include <net/if_tap.h> -#endif - -#ifndef __FreeBSD__ -int tap_open(char *ifname, int ifname_size, int *vnet_hdr, - int vnet_hdr_required, int mq_required, Error **errp) -{ - int fd; -#ifdef TAPGIFNAME - struct ifreq ifr; -#else - char *dev; - struct stat s; -#endif - - /* if no ifname is given, always start the search from tap0/tun0. */ - int i; - char dname[100]; - - for (i = 0; i < 10; i++) { - if (*ifname) { - snprintf(dname, sizeof dname, "/dev/%s", ifname); - } else { -#if defined(__OpenBSD__) - snprintf(dname, sizeof dname, "/dev/tun%d", i); -#else - snprintf(dname, sizeof dname, "/dev/tap%d", i); -#endif - } - TFR(fd = open(dname, O_RDWR)); - if (fd >= 0) { - break; - } - else if (errno == ENXIO || errno == ENOENT) { - break; - } - if (*ifname) { - break; - } - } - if (fd < 0) { - error_setg_errno(errp, errno, "could not open %s", dname); - return -1; - } - -#ifdef TAPGIFNAME - if (ioctl(fd, TAPGIFNAME, (void *)&ifr) < 0) { - error_setg_errno(errp, errno, "could not get tap name"); - return -1; - } - pstrcpy(ifname, ifname_size, ifr.ifr_name); -#else - if (fstat(fd, &s) < 0) { - error_setg_errno(errp, errno, "could not stat %s", dname); - return -1; - } - dev = devname(s.st_rdev, S_IFCHR); - pstrcpy(ifname, ifname_size, dev); -#endif - - if (*vnet_hdr) { - /* BSD doesn't have IFF_VNET_HDR */ - *vnet_hdr = 0; - - if (vnet_hdr_required && !*vnet_hdr) { - error_setg(errp, "vnet_hdr=1 requested, but no kernel " - "support for IFF_VNET_HDR available"); - close(fd); - return -1; - } - } - fcntl(fd, F_SETFL, O_NONBLOCK); - return fd; -} - -#else /* __FreeBSD__ */ - -#define PATH_NET_TAP "/dev/tap" - -static int tap_open_clone(char *ifname, int ifname_size, Error **errp) -{ - int fd, s, ret; - struct ifreq ifr; - - TFR(fd = open(PATH_NET_TAP, O_RDWR)); - if (fd < 0) { - error_setg_errno(errp, errno, "could not open %s", PATH_NET_TAP); - return -1; - } - - memset(&ifr, 0, sizeof(ifr)); - - ret = ioctl(fd, TAPGIFNAME, (void *)&ifr); - if (ret < 0) { - error_setg_errno(errp, errno, "could not get tap interface name"); - close(fd); - return -1; - } - - if (ifname[0] != '\0') { - /* User requested the interface to have a specific name */ - s = socket(AF_LOCAL, SOCK_DGRAM, 0); - if (s < 0) { - error_setg_errno(errp, errno, - "could not open socket to set interface name"); - close(fd); - return -1; - } - ifr.ifr_data = ifname; - ret = ioctl(s, SIOCSIFNAME, (void *)&ifr); - close(s); - if (ret < 0) { - error_setg(errp, "could not set tap interface name"); - close(fd); - return -1; - } - } else { - pstrcpy(ifname, ifname_size, ifr.ifr_name); - } - - return fd; -} - -int tap_open(char *ifname, int ifname_size, int *vnet_hdr, - int vnet_hdr_required, int mq_required, Error **errp) -{ - int fd = -1; - - /* If the specified tap device already exists just use it. */ - if (ifname[0] != '\0') { - char dname[100]; - snprintf(dname, sizeof dname, "/dev/%s", ifname); - TFR(fd = open(dname, O_RDWR)); - if (fd < 0 && errno != ENOENT) { - error_setg_errno(errp, errno, "could not open %s", dname); - return -1; - } - } - - if (fd < 0) { - /* Tap device not specified or does not exist. */ - if ((fd = tap_open_clone(ifname, ifname_size, errp)) < 0) { - return -1; - } - } - - if (*vnet_hdr) { - /* BSD doesn't have IFF_VNET_HDR */ - *vnet_hdr = 0; - - if (vnet_hdr_required && !*vnet_hdr) { - error_setg(errp, "vnet_hdr=1 requested, but no kernel " - "support for IFF_VNET_HDR available"); - goto error; - } - } - if (mq_required) { - error_setg(errp, "mq_required requested, but no kernel support" - " for IFF_MULTI_QUEUE available"); - goto error; - } - - fcntl(fd, F_SETFL, O_NONBLOCK); - return fd; - -error: - close(fd); - return -1; -} -#endif /* __FreeBSD__ */ - -void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp) -{ -} - -int tap_probe_vnet_hdr(int fd) -{ - return 0; -} - -int tap_probe_has_ufo(int fd) -{ - return 0; -} - -int tap_probe_vnet_hdr_len(int fd, int len) -{ - return 0; -} - -void tap_fd_set_vnet_hdr_len(int fd, int len) -{ -} - -int tap_fd_set_vnet_le(int fd, int is_le) -{ - return -EINVAL; -} - -int tap_fd_set_vnet_be(int fd, int is_be) -{ - return -EINVAL; -} - -void tap_fd_set_offload(int fd, int csum, int tso4, - int tso6, int ecn, int ufo) -{ -} - -int tap_fd_enable(int fd) -{ - return -1; -} - -int tap_fd_disable(int fd) -{ - return -1; -} - -int tap_fd_get_ifname(int fd, char *ifname) -{ - return -1; -} diff --git a/qemu/net/tap-haiku.c b/qemu/net/tap-haiku.c deleted file mode 100644 index b27e57e95..000000000 --- a/qemu/net/tap-haiku.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "tap_int.h" - -int tap_open(char *ifname, int ifname_size, int *vnet_hdr, - int vnet_hdr_required, int mq_required, Error **errp) -{ - error_setg(errp, "no tap on Haiku"); - return -1; -} - -void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp) -{ -} - -int tap_probe_vnet_hdr(int fd) -{ - return 0; -} - -int tap_probe_has_ufo(int fd) -{ - return 0; -} - -int tap_probe_vnet_hdr_len(int fd, int len) -{ - return 0; -} - -void tap_fd_set_vnet_hdr_len(int fd, int len) -{ -} - -int tap_fd_set_vnet_le(int fd, int is_le) -{ - return -EINVAL; -} - -int tap_fd_set_vnet_be(int fd, int is_be) -{ - return -EINVAL; -} - -void tap_fd_set_offload(int fd, int csum, int tso4, - int tso6, int ecn, int ufo) -{ -} - -int tap_fd_enable(int fd) -{ - return -1; -} - -int tap_fd_disable(int fd) -{ - return -1; -} - -int tap_fd_get_ifname(int fd, char *ifname) -{ - return -1; -} diff --git a/qemu/net/tap-linux.c b/qemu/net/tap-linux.c deleted file mode 100644 index a503fa9c6..000000000 --- a/qemu/net/tap-linux.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * Copyright (c) 2009 Red Hat, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "tap_int.h" -#include "tap-linux.h" -#include "net/tap.h" - -#include <net/if.h> -#include <sys/ioctl.h> - -#include "sysemu/sysemu.h" -#include "qapi/error.h" -#include "qemu/error-report.h" -#include "qemu/cutils.h" - -#define PATH_NET_TUN "/dev/net/tun" - -int tap_open(char *ifname, int ifname_size, int *vnet_hdr, - int vnet_hdr_required, int mq_required, Error **errp) -{ - struct ifreq ifr; - int fd, ret; - int len = sizeof(struct virtio_net_hdr); - unsigned int features; - - TFR(fd = open(PATH_NET_TUN, O_RDWR)); - if (fd < 0) { - error_setg_errno(errp, errno, "could not open %s", PATH_NET_TUN); - return -1; - } - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - - if (ioctl(fd, TUNGETFEATURES, &features) == -1) { - error_report("warning: TUNGETFEATURES failed: %s", strerror(errno)); - features = 0; - } - - if (features & IFF_ONE_QUEUE) { - ifr.ifr_flags |= IFF_ONE_QUEUE; - } - - if (*vnet_hdr) { - if (features & IFF_VNET_HDR) { - *vnet_hdr = 1; - ifr.ifr_flags |= IFF_VNET_HDR; - } else { - *vnet_hdr = 0; - } - - if (vnet_hdr_required && !*vnet_hdr) { - error_setg(errp, "vnet_hdr=1 requested, but no kernel " - "support for IFF_VNET_HDR available"); - close(fd); - return -1; - } - /* - * Make sure vnet header size has the default value: for a persistent - * tap it might have been modified e.g. by another instance of qemu. - * Ignore errors since old kernels do not support this ioctl: in this - * case the header size implicitly has the correct value. - */ - ioctl(fd, TUNSETVNETHDRSZ, &len); - } - - if (mq_required) { - if (!(features & IFF_MULTI_QUEUE)) { - error_setg(errp, "multiqueue required, but no kernel " - "support for IFF_MULTI_QUEUE available"); - close(fd); - return -1; - } else { - ifr.ifr_flags |= IFF_MULTI_QUEUE; - } - } - - if (ifname[0] != '\0') - pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname); - else - pstrcpy(ifr.ifr_name, IFNAMSIZ, "tap%d"); - ret = ioctl(fd, TUNSETIFF, (void *) &ifr); - if (ret != 0) { - if (ifname[0] != '\0') { - error_setg_errno(errp, errno, "could not configure %s (%s)", - PATH_NET_TUN, ifr.ifr_name); - } else { - error_setg_errno(errp, errno, "could not configure %s", - PATH_NET_TUN); - } - close(fd); - return -1; - } - pstrcpy(ifname, ifname_size, ifr.ifr_name); - fcntl(fd, F_SETFL, O_NONBLOCK); - return fd; -} - -/* sndbuf implements a kind of flow control for tap. - * Unfortunately when it's enabled, and packets are sent - * to other guests on the same host, the receiver - * can lock up the transmitter indefinitely. - * - * To avoid packet loss, sndbuf should be set to a value lower than the tx - * queue capacity of any destination network interface. - * Ethernet NICs generally have txqueuelen=1000, so 1Mb is - * a good value, given a 1500 byte MTU. - */ -#define TAP_DEFAULT_SNDBUF 0 - -void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp) -{ - int sndbuf; - - sndbuf = !tap->has_sndbuf ? TAP_DEFAULT_SNDBUF : - tap->sndbuf > INT_MAX ? INT_MAX : - tap->sndbuf; - - if (!sndbuf) { - sndbuf = INT_MAX; - } - - if (ioctl(fd, TUNSETSNDBUF, &sndbuf) == -1 && tap->has_sndbuf) { - error_setg_errno(errp, errno, "TUNSETSNDBUF ioctl failed"); - } -} - -int tap_probe_vnet_hdr(int fd) -{ - struct ifreq ifr; - - if (ioctl(fd, TUNGETIFF, &ifr) != 0) { - error_report("TUNGETIFF ioctl() failed: %s", strerror(errno)); - return 0; - } - - return ifr.ifr_flags & IFF_VNET_HDR; -} - -int tap_probe_has_ufo(int fd) -{ - unsigned offload; - - offload = TUN_F_CSUM | TUN_F_UFO; - - if (ioctl(fd, TUNSETOFFLOAD, offload) < 0) - return 0; - - return 1; -} - -/* Verify that we can assign given length */ -int tap_probe_vnet_hdr_len(int fd, int len) -{ - int orig; - if (ioctl(fd, TUNGETVNETHDRSZ, &orig) == -1) { - return 0; - } - if (ioctl(fd, TUNSETVNETHDRSZ, &len) == -1) { - return 0; - } - /* Restore original length: we can't handle failure. */ - if (ioctl(fd, TUNSETVNETHDRSZ, &orig) == -1) { - fprintf(stderr, "TUNGETVNETHDRSZ ioctl() failed: %s. Exiting.\n", - strerror(errno)); - abort(); - return -errno; - } - return 1; -} - -void tap_fd_set_vnet_hdr_len(int fd, int len) -{ - if (ioctl(fd, TUNSETVNETHDRSZ, &len) == -1) { - fprintf(stderr, "TUNSETVNETHDRSZ ioctl() failed: %s. Exiting.\n", - strerror(errno)); - abort(); - } -} - -int tap_fd_set_vnet_le(int fd, int is_le) -{ - int arg = is_le ? 1 : 0; - - if (!ioctl(fd, TUNSETVNETLE, &arg)) { - return 0; - } - - /* Check if our kernel supports TUNSETVNETLE */ - if (errno == EINVAL) { - return -errno; - } - - error_report("TUNSETVNETLE ioctl() failed: %s.", strerror(errno)); - abort(); -} - -int tap_fd_set_vnet_be(int fd, int is_be) -{ - int arg = is_be ? 1 : 0; - - if (!ioctl(fd, TUNSETVNETBE, &arg)) { - return 0; - } - - /* Check if our kernel supports TUNSETVNETBE */ - if (errno == EINVAL) { - return -errno; - } - - error_report("TUNSETVNETBE ioctl() failed: %s.", strerror(errno)); - abort(); -} - -void tap_fd_set_offload(int fd, int csum, int tso4, - int tso6, int ecn, int ufo) -{ - unsigned int offload = 0; - - /* Check if our kernel supports TUNSETOFFLOAD */ - if (ioctl(fd, TUNSETOFFLOAD, 0) != 0 && errno == EINVAL) { - return; - } - - if (csum) { - offload |= TUN_F_CSUM; - if (tso4) - offload |= TUN_F_TSO4; - if (tso6) - offload |= TUN_F_TSO6; - if ((tso4 || tso6) && ecn) - offload |= TUN_F_TSO_ECN; - if (ufo) - offload |= TUN_F_UFO; - } - - if (ioctl(fd, TUNSETOFFLOAD, offload) != 0) { - offload &= ~TUN_F_UFO; - if (ioctl(fd, TUNSETOFFLOAD, offload) != 0) { - fprintf(stderr, "TUNSETOFFLOAD ioctl() failed: %s\n", - strerror(errno)); - } - } -} - -/* Enable a specific queue of tap. */ -int tap_fd_enable(int fd) -{ - struct ifreq ifr; - int ret; - - memset(&ifr, 0, sizeof(ifr)); - - ifr.ifr_flags = IFF_ATTACH_QUEUE; - ret = ioctl(fd, TUNSETQUEUE, (void *) &ifr); - - if (ret != 0) { - error_report("could not enable queue"); - } - - return ret; -} - -/* Disable a specific queue of tap/ */ -int tap_fd_disable(int fd) -{ - struct ifreq ifr; - int ret; - - memset(&ifr, 0, sizeof(ifr)); - - ifr.ifr_flags = IFF_DETACH_QUEUE; - ret = ioctl(fd, TUNSETQUEUE, (void *) &ifr); - - if (ret != 0) { - error_report("could not disable queue"); - } - - return ret; -} - -int tap_fd_get_ifname(int fd, char *ifname) -{ - struct ifreq ifr; - - if (ioctl(fd, TUNGETIFF, &ifr) != 0) { - error_report("TUNGETIFF ioctl() failed: %s", - strerror(errno)); - return -1; - } - - pstrcpy(ifname, sizeof(ifr.ifr_name), ifr.ifr_name); - return 0; -} diff --git a/qemu/net/tap-linux.h b/qemu/net/tap-linux.h deleted file mode 100644 index 1dc3a9f27..000000000 --- a/qemu/net/tap-linux.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Universal TUN/TAP device driver. - * Copyright (C) 1999-2000 Maxim Krasnyansky <max_mk@yahoo.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef QEMU_TAP_LINUX_H -#define QEMU_TAP_LINUX_H - -#ifdef __linux__ - -#include <linux/ioctl.h> - -/* Ioctl defines */ -#define TUNSETIFF _IOW('T', 202, int) -#define TUNGETFEATURES _IOR('T', 207, unsigned int) -#define TUNSETOFFLOAD _IOW('T', 208, unsigned int) -#define TUNGETIFF _IOR('T', 210, unsigned int) -#define TUNSETSNDBUF _IOW('T', 212, int) -#define TUNGETVNETHDRSZ _IOR('T', 215, int) -#define TUNSETVNETHDRSZ _IOW('T', 216, int) -#define TUNSETQUEUE _IOW('T', 217, int) -#define TUNSETVNETLE _IOW('T', 220, int) -#define TUNSETVNETBE _IOW('T', 222, int) - -#endif - -/* TUNSETIFF ifr flags */ -#define IFF_TAP 0x0002 -#define IFF_NO_PI 0x1000 -#define IFF_ONE_QUEUE 0x2000 -#define IFF_VNET_HDR 0x4000 -#define IFF_MULTI_QUEUE 0x0100 -#define IFF_ATTACH_QUEUE 0x0200 -#define IFF_DETACH_QUEUE 0x0400 - -/* Features for GSO (TUNSETOFFLOAD). */ -#define TUN_F_CSUM 0x01 /* You can hand me unchecksummed packets. */ -#define TUN_F_TSO4 0x02 /* I can handle TSO for IPv4 packets */ -#define TUN_F_TSO6 0x04 /* I can handle TSO for IPv6 packets */ -#define TUN_F_TSO_ECN 0x08 /* I can handle TSO with ECN bits. */ -#define TUN_F_UFO 0x10 /* I can handle UFO packets */ - -#endif /* QEMU_TAP_H */ diff --git a/qemu/net/tap-solaris.c b/qemu/net/tap-solaris.c deleted file mode 100644 index a2a92356c..000000000 --- a/qemu/net/tap-solaris.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "tap_int.h" -#include "sysemu/sysemu.h" -#include "qemu/cutils.h" - -#include <sys/ethernet.h> -#include <sys/sockio.h> -#include <netinet/arp.h> -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/ip_icmp.h> // must come after ip.h -#include <netinet/udp.h> -#include <netinet/tcp.h> -#include <net/if.h> -#include <stropts.h> -#include "qemu/error-report.h" - -ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen) -{ - struct strbuf sbuf; - int f = 0; - - sbuf.maxlen = maxlen; - sbuf.buf = (char *)buf; - - return getmsg(tapfd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1; -} - -#define TUNNEWPPA (('T'<<16) | 0x0001) -/* - * Allocate TAP device, returns opened fd. - * Stores dev name in the first arg(must be large enough). - */ -static int tap_alloc(char *dev, size_t dev_size, Error **errp) -{ - /* FIXME leaks like a sieve on error paths */ - /* FIXME suspicious: many errors are reported, then ignored */ - int tap_fd, if_fd, ppa = -1; - static int ip_fd = 0; - char *ptr; - - static int arp_fd = 0; - int ip_muxid, arp_muxid; - struct strioctl strioc_if, strioc_ppa; - int link_type = I_PLINK; - struct lifreq ifr; - char actual_name[32] = ""; - - memset(&ifr, 0x0, sizeof(ifr)); - - if( *dev ){ - ptr = dev; - while( *ptr && !qemu_isdigit((int)*ptr) ) ptr++; - ppa = atoi(ptr); - } - - /* Check if IP device was opened */ - if( ip_fd ) - close(ip_fd); - - TFR(ip_fd = open("/dev/udp", O_RDWR, 0)); - if (ip_fd < 0) { - error_setg(errp, "Can't open /dev/ip (actually /dev/udp)"); - return -1; - } - - TFR(tap_fd = open("/dev/tap", O_RDWR, 0)); - if (tap_fd < 0) { - error_setg(errp, "Can't open /dev/tap"); - return -1; - } - - /* Assign a new PPA and get its unit number. */ - strioc_ppa.ic_cmd = TUNNEWPPA; - strioc_ppa.ic_timout = 0; - strioc_ppa.ic_len = sizeof(ppa); - strioc_ppa.ic_dp = (char *)&ppa; - if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0) - error_report("Can't assign new interface"); - - TFR(if_fd = open("/dev/tap", O_RDWR, 0)); - if (if_fd < 0) { - error_setg(errp, "Can't open /dev/tap (2)"); - return -1; - } - if(ioctl(if_fd, I_PUSH, "ip") < 0){ - error_setg(errp, "Can't push IP module"); - return -1; - } - - if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0) - error_report("Can't get flags"); - - snprintf (actual_name, 32, "tap%d", ppa); - pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name); - - ifr.lifr_ppa = ppa; - /* Assign ppa according to the unit number returned by tun device */ - - if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0) - error_report("Can't set PPA %d", ppa); - if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0) - error_report("Can't get flags"); - /* Push arp module to if_fd */ - if (ioctl (if_fd, I_PUSH, "arp") < 0) - error_report("Can't push ARP module (2)"); - - /* Push arp module to ip_fd */ - if (ioctl (ip_fd, I_POP, NULL) < 0) - error_report("I_POP failed"); - if (ioctl (ip_fd, I_PUSH, "arp") < 0) - error_report("Can't push ARP module (3)"); - /* Open arp_fd */ - TFR(arp_fd = open ("/dev/tap", O_RDWR, 0)); - if (arp_fd < 0) - error_report("Can't open %s", "/dev/tap"); - - /* Set ifname to arp */ - strioc_if.ic_cmd = SIOCSLIFNAME; - strioc_if.ic_timout = 0; - strioc_if.ic_len = sizeof(ifr); - strioc_if.ic_dp = (char *)𝔦 - if (ioctl(arp_fd, I_STR, &strioc_if) < 0){ - error_report("Can't set ifname to arp"); - } - - if((ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0){ - error_setg(errp, "Can't link TAP device to IP"); - return -1; - } - - if ((arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0) - error_report("Can't link TAP device to ARP"); - - close (if_fd); - - memset(&ifr, 0x0, sizeof(ifr)); - pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name); - ifr.lifr_ip_muxid = ip_muxid; - ifr.lifr_arp_muxid = arp_muxid; - - if (ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0) - { - ioctl (ip_fd, I_PUNLINK , arp_muxid); - ioctl (ip_fd, I_PUNLINK, ip_muxid); - error_report("Can't set multiplexor id"); - } - - snprintf(dev, dev_size, "tap%d", ppa); - return tap_fd; -} - -int tap_open(char *ifname, int ifname_size, int *vnet_hdr, - int vnet_hdr_required, int mq_required, Error **errp) -{ - char dev[10]=""; - int fd; - - fd = tap_alloc(dev, sizeof(dev), errp); - if (fd < 0) { - return -1; - } - pstrcpy(ifname, ifname_size, dev); - if (*vnet_hdr) { - /* Solaris doesn't have IFF_VNET_HDR */ - *vnet_hdr = 0; - - if (vnet_hdr_required && !*vnet_hdr) { - error_setg(errp, "vnet_hdr=1 requested, but no kernel " - "support for IFF_VNET_HDR available"); - close(fd); - return -1; - } - } - fcntl(fd, F_SETFL, O_NONBLOCK); - return fd; -} - -void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp) -{ -} - -int tap_probe_vnet_hdr(int fd) -{ - return 0; -} - -int tap_probe_has_ufo(int fd) -{ - return 0; -} - -int tap_probe_vnet_hdr_len(int fd, int len) -{ - return 0; -} - -void tap_fd_set_vnet_hdr_len(int fd, int len) -{ -} - -int tap_fd_set_vnet_le(int fd, int is_le) -{ - return -EINVAL; -} - -int tap_fd_set_vnet_be(int fd, int is_be) -{ - return -EINVAL; -} - -void tap_fd_set_offload(int fd, int csum, int tso4, - int tso6, int ecn, int ufo) -{ -} - -int tap_fd_enable(int fd) -{ - return -1; -} - -int tap_fd_disable(int fd) -{ - return -1; -} - -int tap_fd_get_ifname(int fd, char *ifname) -{ - return -1; -} diff --git a/qemu/net/tap-win32.c b/qemu/net/tap-win32.c deleted file mode 100644 index f1e142ace..000000000 --- a/qemu/net/tap-win32.c +++ /dev/null @@ -1,820 +0,0 @@ -/* - * TAP-Win32 -- A kernel driver to provide virtual tap device functionality - * on Windows. Originally derived from the CIPE-Win32 - * project by Damion K. Wilson, with extensive modifications by - * James Yonan. - * - * All source code which derives from the CIPE-Win32 project is - * Copyright (C) Damion K. Wilson, 2003, and is released under the - * GPL version 2 (see below). - * - * All other source code is Copyright (C) James Yonan, 2003-2004, - * and is released under the GPL version 2 (see below). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "tap_int.h" - -#include "qemu-common.h" -#include "clients.h" /* net_init_tap */ -#include "net/net.h" -#include "net/tap.h" /* tap_has_ufo, ... */ -#include "sysemu/sysemu.h" -#include "qemu/error-report.h" -#include <windows.h> -#include <winioctl.h> - -//============= -// TAP IOCTLs -//============= - -#define TAP_CONTROL_CODE(request,method) \ - CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) - -#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED) -#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED) -#define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE (3, METHOD_BUFFERED) -#define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE (4, METHOD_BUFFERED) -#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED) -#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED) -#define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE (7, METHOD_BUFFERED) -#define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE (8, METHOD_BUFFERED) -#define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE (9, METHOD_BUFFERED) - -//================= -// Registry keys -//================= - -#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" - -#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" - -//====================== -// Filesystem prefixes -//====================== - -#define USERMODEDEVICEDIR "\\\\.\\Global\\" -#define TAPSUFFIX ".tap" - - -//====================== -// Compile time configuration -//====================== - -//#define DEBUG_TAP_WIN32 - -/* FIXME: The asynch write path appears to be broken at - * present. WriteFile() ignores the lpNumberOfBytesWritten parameter - * for overlapped writes, with the result we return zero bytes sent, - * and after handling a single packet, receive is disabled for this - * interface. */ -/* #define TUN_ASYNCHRONOUS_WRITES 1 */ - -#define TUN_BUFFER_SIZE 1560 -#define TUN_MAX_BUFFER_COUNT 32 - -/* - * The data member "buffer" must be the first element in the tun_buffer - * structure. See the function, tap_win32_free_buffer. - */ -typedef struct tun_buffer_s { - unsigned char buffer [TUN_BUFFER_SIZE]; - unsigned long read_size; - struct tun_buffer_s* next; -} tun_buffer_t; - -typedef struct tap_win32_overlapped { - HANDLE handle; - HANDLE read_event; - HANDLE write_event; - HANDLE output_queue_semaphore; - HANDLE free_list_semaphore; - HANDLE tap_semaphore; - CRITICAL_SECTION output_queue_cs; - CRITICAL_SECTION free_list_cs; - OVERLAPPED read_overlapped; - OVERLAPPED write_overlapped; - tun_buffer_t buffers[TUN_MAX_BUFFER_COUNT]; - tun_buffer_t* free_list; - tun_buffer_t* output_queue_front; - tun_buffer_t* output_queue_back; -} tap_win32_overlapped_t; - -static tap_win32_overlapped_t tap_overlapped; - -static tun_buffer_t* get_buffer_from_free_list(tap_win32_overlapped_t* const overlapped) -{ - tun_buffer_t* buffer = NULL; - WaitForSingleObject(overlapped->free_list_semaphore, INFINITE); - EnterCriticalSection(&overlapped->free_list_cs); - buffer = overlapped->free_list; -// assert(buffer != NULL); - overlapped->free_list = buffer->next; - LeaveCriticalSection(&overlapped->free_list_cs); - buffer->next = NULL; - return buffer; -} - -static void put_buffer_on_free_list(tap_win32_overlapped_t* const overlapped, tun_buffer_t* const buffer) -{ - EnterCriticalSection(&overlapped->free_list_cs); - buffer->next = overlapped->free_list; - overlapped->free_list = buffer; - LeaveCriticalSection(&overlapped->free_list_cs); - ReleaseSemaphore(overlapped->free_list_semaphore, 1, NULL); -} - -static tun_buffer_t* get_buffer_from_output_queue(tap_win32_overlapped_t* const overlapped, const int block) -{ - tun_buffer_t* buffer = NULL; - DWORD result, timeout = block ? INFINITE : 0L; - - // Non-blocking call - result = WaitForSingleObject(overlapped->output_queue_semaphore, timeout); - - switch (result) - { - // The semaphore object was signaled. - case WAIT_OBJECT_0: - EnterCriticalSection(&overlapped->output_queue_cs); - - buffer = overlapped->output_queue_front; - overlapped->output_queue_front = buffer->next; - - if(overlapped->output_queue_front == NULL) { - overlapped->output_queue_back = NULL; - } - - LeaveCriticalSection(&overlapped->output_queue_cs); - break; - - // Semaphore was nonsignaled, so a time-out occurred. - case WAIT_TIMEOUT: - // Cannot open another window. - break; - } - - return buffer; -} - -static tun_buffer_t* get_buffer_from_output_queue_immediate (tap_win32_overlapped_t* const overlapped) -{ - return get_buffer_from_output_queue(overlapped, 0); -} - -static void put_buffer_on_output_queue(tap_win32_overlapped_t* const overlapped, tun_buffer_t* const buffer) -{ - EnterCriticalSection(&overlapped->output_queue_cs); - - if(overlapped->output_queue_front == NULL && overlapped->output_queue_back == NULL) { - overlapped->output_queue_front = overlapped->output_queue_back = buffer; - } else { - buffer->next = NULL; - overlapped->output_queue_back->next = buffer; - overlapped->output_queue_back = buffer; - } - - LeaveCriticalSection(&overlapped->output_queue_cs); - - ReleaseSemaphore(overlapped->output_queue_semaphore, 1, NULL); -} - - -static int is_tap_win32_dev(const char *guid) -{ - HKEY netcard_key; - LONG status; - DWORD len; - int i = 0; - - status = RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - ADAPTER_KEY, - 0, - KEY_READ, - &netcard_key); - - if (status != ERROR_SUCCESS) { - return FALSE; - } - - for (;;) { - char enum_name[256]; - char unit_string[256]; - HKEY unit_key; - char component_id_string[] = "ComponentId"; - char component_id[256]; - char net_cfg_instance_id_string[] = "NetCfgInstanceId"; - char net_cfg_instance_id[256]; - DWORD data_type; - - len = sizeof (enum_name); - status = RegEnumKeyEx( - netcard_key, - i, - enum_name, - &len, - NULL, - NULL, - NULL, - NULL); - - if (status == ERROR_NO_MORE_ITEMS) - break; - else if (status != ERROR_SUCCESS) { - return FALSE; - } - - snprintf (unit_string, sizeof(unit_string), "%s\\%s", - ADAPTER_KEY, enum_name); - - status = RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - unit_string, - 0, - KEY_READ, - &unit_key); - - if (status != ERROR_SUCCESS) { - return FALSE; - } else { - len = sizeof (component_id); - status = RegQueryValueEx( - unit_key, - component_id_string, - NULL, - &data_type, - (LPBYTE)component_id, - &len); - - if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) { - len = sizeof (net_cfg_instance_id); - status = RegQueryValueEx( - unit_key, - net_cfg_instance_id_string, - NULL, - &data_type, - (LPBYTE)net_cfg_instance_id, - &len); - - if (status == ERROR_SUCCESS && data_type == REG_SZ) { - if (/* !strcmp (component_id, TAP_COMPONENT_ID) &&*/ - !strcmp (net_cfg_instance_id, guid)) { - RegCloseKey (unit_key); - RegCloseKey (netcard_key); - return TRUE; - } - } - } - RegCloseKey (unit_key); - } - ++i; - } - - RegCloseKey (netcard_key); - return FALSE; -} - -static int get_device_guid( - char *name, - int name_size, - char *actual_name, - int actual_name_size) -{ - LONG status; - HKEY control_net_key; - DWORD len; - int i = 0; - int stop = 0; - - status = RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - NETWORK_CONNECTIONS_KEY, - 0, - KEY_READ, - &control_net_key); - - if (status != ERROR_SUCCESS) { - return -1; - } - - while (!stop) - { - char enum_name[256]; - char connection_string[256]; - HKEY connection_key; - char name_data[256]; - DWORD name_type; - const char name_string[] = "Name"; - - len = sizeof (enum_name); - status = RegEnumKeyEx( - control_net_key, - i, - enum_name, - &len, - NULL, - NULL, - NULL, - NULL); - - if (status == ERROR_NO_MORE_ITEMS) - break; - else if (status != ERROR_SUCCESS) { - return -1; - } - - snprintf(connection_string, - sizeof(connection_string), - "%s\\%s\\Connection", - NETWORK_CONNECTIONS_KEY, enum_name); - - status = RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - connection_string, - 0, - KEY_READ, - &connection_key); - - if (status == ERROR_SUCCESS) { - len = sizeof (name_data); - status = RegQueryValueEx( - connection_key, - name_string, - NULL, - &name_type, - (LPBYTE)name_data, - &len); - - if (status != ERROR_SUCCESS || name_type != REG_SZ) { - ++i; - continue; - } - else { - if (is_tap_win32_dev(enum_name)) { - snprintf(name, name_size, "%s", enum_name); - if (actual_name) { - if (strcmp(actual_name, "") != 0) { - if (strcmp(name_data, actual_name) != 0) { - RegCloseKey (connection_key); - ++i; - continue; - } - } - else { - snprintf(actual_name, actual_name_size, "%s", name_data); - } - } - stop = 1; - } - } - - RegCloseKey (connection_key); - } - ++i; - } - - RegCloseKey (control_net_key); - - if (stop == 0) - return -1; - - return 0; -} - -static int tap_win32_set_status(HANDLE handle, int status) -{ - unsigned long len = 0; - - return DeviceIoControl(handle, TAP_IOCTL_SET_MEDIA_STATUS, - &status, sizeof (status), - &status, sizeof (status), &len, NULL); -} - -static void tap_win32_overlapped_init(tap_win32_overlapped_t* const overlapped, const HANDLE handle) -{ - overlapped->handle = handle; - - overlapped->read_event = CreateEvent(NULL, FALSE, FALSE, NULL); - overlapped->write_event = CreateEvent(NULL, FALSE, FALSE, NULL); - - overlapped->read_overlapped.Offset = 0; - overlapped->read_overlapped.OffsetHigh = 0; - overlapped->read_overlapped.hEvent = overlapped->read_event; - - overlapped->write_overlapped.Offset = 0; - overlapped->write_overlapped.OffsetHigh = 0; - overlapped->write_overlapped.hEvent = overlapped->write_event; - - InitializeCriticalSection(&overlapped->output_queue_cs); - InitializeCriticalSection(&overlapped->free_list_cs); - - overlapped->output_queue_semaphore = CreateSemaphore( - NULL, // default security attributes - 0, // initial count - TUN_MAX_BUFFER_COUNT, // maximum count - NULL); // unnamed semaphore - - if(!overlapped->output_queue_semaphore) { - fprintf(stderr, "error creating output queue semaphore!\n"); - } - - overlapped->free_list_semaphore = CreateSemaphore( - NULL, // default security attributes - TUN_MAX_BUFFER_COUNT, // initial count - TUN_MAX_BUFFER_COUNT, // maximum count - NULL); // unnamed semaphore - - if(!overlapped->free_list_semaphore) { - fprintf(stderr, "error creating free list semaphore!\n"); - } - - overlapped->free_list = overlapped->output_queue_front = overlapped->output_queue_back = NULL; - - { - unsigned index; - for(index = 0; index < TUN_MAX_BUFFER_COUNT; index++) { - tun_buffer_t* element = &overlapped->buffers[index]; - element->next = overlapped->free_list; - overlapped->free_list = element; - } - } - /* To count buffers, initially no-signal. */ - overlapped->tap_semaphore = CreateSemaphore(NULL, 0, TUN_MAX_BUFFER_COUNT, NULL); - if(!overlapped->tap_semaphore) - fprintf(stderr, "error creating tap_semaphore.\n"); -} - -static int tap_win32_write(tap_win32_overlapped_t *overlapped, - const void *buffer, unsigned long size) -{ - unsigned long write_size; - BOOL result; - DWORD error; - -#ifdef TUN_ASYNCHRONOUS_WRITES - result = GetOverlappedResult( overlapped->handle, &overlapped->write_overlapped, - &write_size, FALSE); - - if (!result && GetLastError() == ERROR_IO_INCOMPLETE) - WaitForSingleObject(overlapped->write_event, INFINITE); -#endif - - result = WriteFile(overlapped->handle, buffer, size, - &write_size, &overlapped->write_overlapped); - -#ifdef TUN_ASYNCHRONOUS_WRITES - /* FIXME: we can't sensibly set write_size here, without waiting - * for the IO to complete! Moreover, we can't return zero, - * because that will disable receive on this interface, and we - * also can't assume it will succeed and return the full size, - * because that will result in the buffer being reclaimed while - * the IO is in progress. */ -#error Async writes are broken. Please disable TUN_ASYNCHRONOUS_WRITES. -#else /* !TUN_ASYNCHRONOUS_WRITES */ - if (!result) { - error = GetLastError(); - if (error == ERROR_IO_PENDING) { - result = GetOverlappedResult(overlapped->handle, - &overlapped->write_overlapped, - &write_size, TRUE); - } - } -#endif - - if (!result) { -#ifdef DEBUG_TAP_WIN32 - LPTSTR msgbuf; - error = GetLastError(); - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, - NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - &msgbuf, 0, NULL); - fprintf(stderr, "Tap-Win32: Error WriteFile %d - %s\n", error, msgbuf); - LocalFree(msgbuf); -#endif - return 0; - } - - return write_size; -} - -static DWORD WINAPI tap_win32_thread_entry(LPVOID param) -{ - tap_win32_overlapped_t *overlapped = (tap_win32_overlapped_t*)param; - unsigned long read_size; - BOOL result; - DWORD dwError; - tun_buffer_t* buffer = get_buffer_from_free_list(overlapped); - - - for (;;) { - result = ReadFile(overlapped->handle, - buffer->buffer, - sizeof(buffer->buffer), - &read_size, - &overlapped->read_overlapped); - if (!result) { - dwError = GetLastError(); - if (dwError == ERROR_IO_PENDING) { - WaitForSingleObject(overlapped->read_event, INFINITE); - result = GetOverlappedResult( overlapped->handle, &overlapped->read_overlapped, - &read_size, FALSE); - if (!result) { -#ifdef DEBUG_TAP_WIN32 - LPVOID lpBuffer; - dwError = GetLastError(); - FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) & lpBuffer, 0, NULL ); - fprintf(stderr, "Tap-Win32: Error GetOverlappedResult %d - %s\n", dwError, lpBuffer); - LocalFree( lpBuffer ); -#endif - } - } else { -#ifdef DEBUG_TAP_WIN32 - LPVOID lpBuffer; - FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) & lpBuffer, 0, NULL ); - fprintf(stderr, "Tap-Win32: Error ReadFile %d - %s\n", dwError, lpBuffer); - LocalFree( lpBuffer ); -#endif - } - } - - if(read_size > 0) { - buffer->read_size = read_size; - put_buffer_on_output_queue(overlapped, buffer); - ReleaseSemaphore(overlapped->tap_semaphore, 1, NULL); - buffer = get_buffer_from_free_list(overlapped); - } - } - - return 0; -} - -static int tap_win32_read(tap_win32_overlapped_t *overlapped, - uint8_t **pbuf, int max_size) -{ - int size = 0; - - tun_buffer_t* buffer = get_buffer_from_output_queue_immediate(overlapped); - - if(buffer != NULL) { - *pbuf = buffer->buffer; - size = (int)buffer->read_size; - if(size > max_size) { - size = max_size; - } - } - - return size; -} - -static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped, - uint8_t *pbuf) -{ - tun_buffer_t* buffer = (tun_buffer_t*)pbuf; - put_buffer_on_free_list(overlapped, buffer); -} - -static int tap_win32_open(tap_win32_overlapped_t **phandle, - const char *preferred_name) -{ - char device_path[256]; - char device_guid[0x100]; - int rc; - HANDLE handle; - BOOL bret; - char name_buffer[0x100] = {0, }; - struct { - unsigned long major; - unsigned long minor; - unsigned long debug; - } version; - DWORD version_len; - DWORD idThread; - - if (preferred_name != NULL) { - snprintf(name_buffer, sizeof(name_buffer), "%s", preferred_name); - } - - rc = get_device_guid(device_guid, sizeof(device_guid), name_buffer, sizeof(name_buffer)); - if (rc) - return -1; - - snprintf (device_path, sizeof(device_path), "%s%s%s", - USERMODEDEVICEDIR, - device_guid, - TAPSUFFIX); - - handle = CreateFile ( - device_path, - GENERIC_READ | GENERIC_WRITE, - 0, - 0, - OPEN_EXISTING, - FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, - 0 ); - - if (handle == INVALID_HANDLE_VALUE) { - return -1; - } - - bret = DeviceIoControl(handle, TAP_IOCTL_GET_VERSION, - &version, sizeof (version), - &version, sizeof (version), &version_len, NULL); - - if (bret == FALSE) { - CloseHandle(handle); - return -1; - } - - if (!tap_win32_set_status(handle, TRUE)) { - return -1; - } - - tap_win32_overlapped_init(&tap_overlapped, handle); - - *phandle = &tap_overlapped; - - CreateThread(NULL, 0, tap_win32_thread_entry, - (LPVOID)&tap_overlapped, 0, &idThread); - return 0; -} - -/********************************************/ - - typedef struct TAPState { - NetClientState nc; - tap_win32_overlapped_t *handle; - } TAPState; - -static void tap_cleanup(NetClientState *nc) -{ - TAPState *s = DO_UPCAST(TAPState, nc, nc); - - qemu_del_wait_object(s->handle->tap_semaphore, NULL, NULL); - - /* FIXME: need to kill thread and close file handle: - tap_win32_close(s); - */ -} - -static ssize_t tap_receive(NetClientState *nc, const uint8_t *buf, size_t size) -{ - TAPState *s = DO_UPCAST(TAPState, nc, nc); - - return tap_win32_write(s->handle, buf, size); -} - -static void tap_win32_send(void *opaque) -{ - TAPState *s = opaque; - uint8_t *buf; - int max_size = 4096; - int size; - - size = tap_win32_read(s->handle, &buf, max_size); - if (size > 0) { - qemu_send_packet(&s->nc, buf, size); - tap_win32_free_buffer(s->handle, buf); - } -} - -static bool tap_has_ufo(NetClientState *nc) -{ - return false; -} - -static bool tap_has_vnet_hdr(NetClientState *nc) -{ - return false; -} - -int tap_probe_vnet_hdr_len(int fd, int len) -{ - return 0; -} - -void tap_fd_set_vnet_hdr_len(int fd, int len) -{ -} - -int tap_fd_set_vnet_le(int fd, int is_le) -{ - return -EINVAL; -} - -int tap_fd_set_vnet_be(int fd, int is_be) -{ - return -EINVAL; -} - -static void tap_using_vnet_hdr(NetClientState *nc, bool using_vnet_hdr) -{ -} - -static void tap_set_offload(NetClientState *nc, int csum, int tso4, - int tso6, int ecn, int ufo) -{ -} - -struct vhost_net *tap_get_vhost_net(NetClientState *nc) -{ - return NULL; -} - -static bool tap_has_vnet_hdr_len(NetClientState *nc, int len) -{ - return false; -} - -static void tap_set_vnet_hdr_len(NetClientState *nc, int len) -{ - abort(); -} - -static NetClientInfo net_tap_win32_info = { - .type = NET_CLIENT_OPTIONS_KIND_TAP, - .size = sizeof(TAPState), - .receive = tap_receive, - .cleanup = tap_cleanup, - .has_ufo = tap_has_ufo, - .has_vnet_hdr = tap_has_vnet_hdr, - .has_vnet_hdr_len = tap_has_vnet_hdr_len, - .using_vnet_hdr = tap_using_vnet_hdr, - .set_offload = tap_set_offload, - .set_vnet_hdr_len = tap_set_vnet_hdr_len, -}; - -static int tap_win32_init(NetClientState *peer, const char *model, - const char *name, const char *ifname) -{ - NetClientState *nc; - TAPState *s; - tap_win32_overlapped_t *handle; - - if (tap_win32_open(&handle, ifname) < 0) { - printf("tap: Could not open '%s'\n", ifname); - return -1; - } - - nc = qemu_new_net_client(&net_tap_win32_info, peer, model, name); - - s = DO_UPCAST(TAPState, nc, nc); - - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "tap: ifname=%s", ifname); - - s->handle = handle; - - qemu_add_wait_object(s->handle->tap_semaphore, tap_win32_send, s); - - return 0; -} - -int net_init_tap(const NetClientOptions *opts, const char *name, - NetClientState *peer, Error **errp) -{ - /* FIXME error_setg(errp, ...) on failure */ - const NetdevTapOptions *tap; - - assert(opts->type == NET_CLIENT_OPTIONS_KIND_TAP); - tap = opts->u.tap.data; - - if (!tap->has_ifname) { - error_report("tap: no interface name"); - return -1; - } - - if (tap_win32_init(peer, "tap", name, tap->ifname) == -1) { - return -1; - } - - return 0; -} - -int tap_enable(NetClientState *nc) -{ - abort(); -} - -int tap_disable(NetClientState *nc) -{ - abort(); -} diff --git a/qemu/net/tap.c b/qemu/net/tap.c deleted file mode 100644 index 740e8a261..000000000 --- a/qemu/net/tap.c +++ /dev/null @@ -1,931 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * Copyright (c) 2009 Red Hat, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "tap_int.h" - - -#include <sys/ioctl.h> -#include <sys/wait.h> -#include <sys/socket.h> -#include <net/if.h> - -#include "net/net.h" -#include "clients.h" -#include "monitor/monitor.h" -#include "sysemu/sysemu.h" -#include "qapi/error.h" -#include "qemu-common.h" -#include "qemu/cutils.h" -#include "qemu/error-report.h" - -#include "net/tap.h" - -#include "net/vhost_net.h" - -typedef struct TAPState { - NetClientState nc; - int fd; - char down_script[1024]; - char down_script_arg[128]; - uint8_t buf[NET_BUFSIZE]; - bool read_poll; - bool write_poll; - bool using_vnet_hdr; - bool has_ufo; - bool enabled; - VHostNetState *vhost_net; - unsigned host_vnet_hdr_len; -} TAPState; - -static void launch_script(const char *setup_script, const char *ifname, - int fd, Error **errp); - -static void tap_send(void *opaque); -static void tap_writable(void *opaque); - -static void tap_update_fd_handler(TAPState *s) -{ - qemu_set_fd_handler(s->fd, - s->read_poll && s->enabled ? tap_send : NULL, - s->write_poll && s->enabled ? tap_writable : NULL, - s); -} - -static void tap_read_poll(TAPState *s, bool enable) -{ - s->read_poll = enable; - tap_update_fd_handler(s); -} - -static void tap_write_poll(TAPState *s, bool enable) -{ - s->write_poll = enable; - tap_update_fd_handler(s); -} - -static void tap_writable(void *opaque) -{ - TAPState *s = opaque; - - tap_write_poll(s, false); - - qemu_flush_queued_packets(&s->nc); -} - -static ssize_t tap_write_packet(TAPState *s, const struct iovec *iov, int iovcnt) -{ - ssize_t len; - - do { - len = writev(s->fd, iov, iovcnt); - } while (len == -1 && errno == EINTR); - - if (len == -1 && errno == EAGAIN) { - tap_write_poll(s, true); - return 0; - } - - return len; -} - -static ssize_t tap_receive_iov(NetClientState *nc, const struct iovec *iov, - int iovcnt) -{ - TAPState *s = DO_UPCAST(TAPState, nc, nc); - const struct iovec *iovp = iov; - struct iovec iov_copy[iovcnt + 1]; - struct virtio_net_hdr_mrg_rxbuf hdr = { }; - - if (s->host_vnet_hdr_len && !s->using_vnet_hdr) { - iov_copy[0].iov_base = &hdr; - iov_copy[0].iov_len = s->host_vnet_hdr_len; - memcpy(&iov_copy[1], iov, iovcnt * sizeof(*iov)); - iovp = iov_copy; - iovcnt++; - } - - return tap_write_packet(s, iovp, iovcnt); -} - -static ssize_t tap_receive_raw(NetClientState *nc, const uint8_t *buf, size_t size) -{ - TAPState *s = DO_UPCAST(TAPState, nc, nc); - struct iovec iov[2]; - int iovcnt = 0; - struct virtio_net_hdr_mrg_rxbuf hdr = { }; - - if (s->host_vnet_hdr_len) { - iov[iovcnt].iov_base = &hdr; - iov[iovcnt].iov_len = s->host_vnet_hdr_len; - iovcnt++; - } - - iov[iovcnt].iov_base = (char *)buf; - iov[iovcnt].iov_len = size; - iovcnt++; - - return tap_write_packet(s, iov, iovcnt); -} - -static ssize_t tap_receive(NetClientState *nc, const uint8_t *buf, size_t size) -{ - TAPState *s = DO_UPCAST(TAPState, nc, nc); - struct iovec iov[1]; - - if (s->host_vnet_hdr_len && !s->using_vnet_hdr) { - return tap_receive_raw(nc, buf, size); - } - - iov[0].iov_base = (char *)buf; - iov[0].iov_len = size; - - return tap_write_packet(s, iov, 1); -} - -#ifndef __sun__ -ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen) -{ - return read(tapfd, buf, maxlen); -} -#endif - -static void tap_send_completed(NetClientState *nc, ssize_t len) -{ - TAPState *s = DO_UPCAST(TAPState, nc, nc); - tap_read_poll(s, true); -} - -static void tap_send(void *opaque) -{ - TAPState *s = opaque; - int size; - int packets = 0; - - while (true) { - uint8_t *buf = s->buf; - - size = tap_read_packet(s->fd, s->buf, sizeof(s->buf)); - if (size <= 0) { - break; - } - - if (s->host_vnet_hdr_len && !s->using_vnet_hdr) { - buf += s->host_vnet_hdr_len; - size -= s->host_vnet_hdr_len; - } - - size = qemu_send_packet_async(&s->nc, buf, size, tap_send_completed); - if (size == 0) { - tap_read_poll(s, false); - break; - } else if (size < 0) { - break; - } - - /* - * When the host keeps receiving more packets while tap_send() is - * running we can hog the QEMU global mutex. Limit the number of - * packets that are processed per tap_send() callback to prevent - * stalling the guest. - */ - packets++; - if (packets >= 50) { - break; - } - } -} - -static bool tap_has_ufo(NetClientState *nc) -{ - TAPState *s = DO_UPCAST(TAPState, nc, nc); - - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); - - return s->has_ufo; -} - -static bool tap_has_vnet_hdr(NetClientState *nc) -{ - TAPState *s = DO_UPCAST(TAPState, nc, nc); - - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); - - return !!s->host_vnet_hdr_len; -} - -static bool tap_has_vnet_hdr_len(NetClientState *nc, int len) -{ - TAPState *s = DO_UPCAST(TAPState, nc, nc); - - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); - - return !!tap_probe_vnet_hdr_len(s->fd, len); -} - -static void tap_set_vnet_hdr_len(NetClientState *nc, int len) -{ - TAPState *s = DO_UPCAST(TAPState, nc, nc); - - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); - assert(len == sizeof(struct virtio_net_hdr_mrg_rxbuf) || - len == sizeof(struct virtio_net_hdr)); - - tap_fd_set_vnet_hdr_len(s->fd, len); - s->host_vnet_hdr_len = len; -} - -static void tap_using_vnet_hdr(NetClientState *nc, bool using_vnet_hdr) -{ - TAPState *s = DO_UPCAST(TAPState, nc, nc); - - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); - assert(!!s->host_vnet_hdr_len == using_vnet_hdr); - - s->using_vnet_hdr = using_vnet_hdr; -} - -static int tap_set_vnet_le(NetClientState *nc, bool is_le) -{ - TAPState *s = DO_UPCAST(TAPState, nc, nc); - - return tap_fd_set_vnet_le(s->fd, is_le); -} - -static int tap_set_vnet_be(NetClientState *nc, bool is_be) -{ - TAPState *s = DO_UPCAST(TAPState, nc, nc); - - return tap_fd_set_vnet_be(s->fd, is_be); -} - -static void tap_set_offload(NetClientState *nc, int csum, int tso4, - int tso6, int ecn, int ufo) -{ - TAPState *s = DO_UPCAST(TAPState, nc, nc); - if (s->fd < 0) { - return; - } - - tap_fd_set_offload(s->fd, csum, tso4, tso6, ecn, ufo); -} - -static void tap_cleanup(NetClientState *nc) -{ - TAPState *s = DO_UPCAST(TAPState, nc, nc); - Error *err = NULL; - - if (s->vhost_net) { - vhost_net_cleanup(s->vhost_net); - s->vhost_net = NULL; - } - - qemu_purge_queued_packets(nc); - - if (s->down_script[0]) { - launch_script(s->down_script, s->down_script_arg, s->fd, &err); - if (err) { - error_report_err(err); - } - } - - tap_read_poll(s, false); - tap_write_poll(s, false); - close(s->fd); - s->fd = -1; -} - -static void tap_poll(NetClientState *nc, bool enable) -{ - TAPState *s = DO_UPCAST(TAPState, nc, nc); - tap_read_poll(s, enable); - tap_write_poll(s, enable); -} - -int tap_get_fd(NetClientState *nc) -{ - TAPState *s = DO_UPCAST(TAPState, nc, nc); - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); - return s->fd; -} - -/* fd support */ - -static NetClientInfo net_tap_info = { - .type = NET_CLIENT_OPTIONS_KIND_TAP, - .size = sizeof(TAPState), - .receive = tap_receive, - .receive_raw = tap_receive_raw, - .receive_iov = tap_receive_iov, - .poll = tap_poll, - .cleanup = tap_cleanup, - .has_ufo = tap_has_ufo, - .has_vnet_hdr = tap_has_vnet_hdr, - .has_vnet_hdr_len = tap_has_vnet_hdr_len, - .using_vnet_hdr = tap_using_vnet_hdr, - .set_offload = tap_set_offload, - .set_vnet_hdr_len = tap_set_vnet_hdr_len, - .set_vnet_le = tap_set_vnet_le, - .set_vnet_be = tap_set_vnet_be, -}; - -static TAPState *net_tap_fd_init(NetClientState *peer, - const char *model, - const char *name, - int fd, - int vnet_hdr) -{ - NetClientState *nc; - TAPState *s; - - nc = qemu_new_net_client(&net_tap_info, peer, model, name); - - s = DO_UPCAST(TAPState, nc, nc); - - s->fd = fd; - s->host_vnet_hdr_len = vnet_hdr ? sizeof(struct virtio_net_hdr) : 0; - s->using_vnet_hdr = false; - s->has_ufo = tap_probe_has_ufo(s->fd); - s->enabled = true; - tap_set_offload(&s->nc, 0, 0, 0, 0, 0); - /* - * Make sure host header length is set correctly in tap: - * it might have been modified by another instance of qemu. - */ - if (tap_probe_vnet_hdr_len(s->fd, s->host_vnet_hdr_len)) { - tap_fd_set_vnet_hdr_len(s->fd, s->host_vnet_hdr_len); - } - tap_read_poll(s, true); - s->vhost_net = NULL; - return s; -} - -static void launch_script(const char *setup_script, const char *ifname, - int fd, Error **errp) -{ - int pid, status; - char *args[3]; - char **parg; - - /* try to launch network script */ - pid = fork(); - if (pid < 0) { - error_setg_errno(errp, errno, "could not launch network script %s", - setup_script); - return; - } - if (pid == 0) { - int open_max = sysconf(_SC_OPEN_MAX), i; - - for (i = 3; i < open_max; i++) { - if (i != fd) { - close(i); - } - } - parg = args; - *parg++ = (char *)setup_script; - *parg++ = (char *)ifname; - *parg = NULL; - execv(setup_script, args); - _exit(1); - } else { - while (waitpid(pid, &status, 0) != pid) { - /* loop */ - } - - if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { - return; - } - error_setg(errp, "network script %s failed with status %d", - setup_script, status); - } -} - -static int recv_fd(int c) -{ - int fd; - uint8_t msgbuf[CMSG_SPACE(sizeof(fd))]; - struct msghdr msg = { - .msg_control = msgbuf, - .msg_controllen = sizeof(msgbuf), - }; - struct cmsghdr *cmsg; - struct iovec iov; - uint8_t req[1]; - ssize_t len; - - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); - msg.msg_controllen = cmsg->cmsg_len; - - iov.iov_base = req; - iov.iov_len = sizeof(req); - - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - len = recvmsg(c, &msg, 0); - if (len > 0) { - memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd)); - return fd; - } - - return len; -} - -static int net_bridge_run_helper(const char *helper, const char *bridge, - Error **errp) -{ - sigset_t oldmask, mask; - int pid, status; - char *args[5]; - char **parg; - int sv[2]; - - sigemptyset(&mask); - sigaddset(&mask, SIGCHLD); - sigprocmask(SIG_BLOCK, &mask, &oldmask); - - if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) { - error_setg_errno(errp, errno, "socketpair() failed"); - return -1; - } - - /* try to launch bridge helper */ - pid = fork(); - if (pid < 0) { - error_setg_errno(errp, errno, "Can't fork bridge helper"); - return -1; - } - if (pid == 0) { - int open_max = sysconf(_SC_OPEN_MAX), i; - char fd_buf[6+10]; - char br_buf[6+IFNAMSIZ] = {0}; - char helper_cmd[PATH_MAX + sizeof(fd_buf) + sizeof(br_buf) + 15]; - - for (i = 3; i < open_max; i++) { - if (i != sv[1]) { - close(i); - } - } - - snprintf(fd_buf, sizeof(fd_buf), "%s%d", "--fd=", sv[1]); - - if (strrchr(helper, ' ') || strrchr(helper, '\t')) { - /* assume helper is a command */ - - if (strstr(helper, "--br=") == NULL) { - snprintf(br_buf, sizeof(br_buf), "%s%s", "--br=", bridge); - } - - snprintf(helper_cmd, sizeof(helper_cmd), "%s %s %s %s", - helper, "--use-vnet", fd_buf, br_buf); - - parg = args; - *parg++ = (char *)"sh"; - *parg++ = (char *)"-c"; - *parg++ = helper_cmd; - *parg++ = NULL; - - execv("/bin/sh", args); - } else { - /* assume helper is just the executable path name */ - - snprintf(br_buf, sizeof(br_buf), "%s%s", "--br=", bridge); - - parg = args; - *parg++ = (char *)helper; - *parg++ = (char *)"--use-vnet"; - *parg++ = fd_buf; - *parg++ = br_buf; - *parg++ = NULL; - - execv(helper, args); - } - _exit(1); - - } else { - int fd; - int saved_errno; - - close(sv[1]); - - do { - fd = recv_fd(sv[0]); - } while (fd == -1 && errno == EINTR); - saved_errno = errno; - - close(sv[0]); - - while (waitpid(pid, &status, 0) != pid) { - /* loop */ - } - sigprocmask(SIG_SETMASK, &oldmask, NULL); - if (fd < 0) { - error_setg_errno(errp, saved_errno, - "failed to recv file descriptor"); - return -1; - } - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - error_setg(errp, "bridge helper failed"); - return -1; - } - return fd; - } -} - -int net_init_bridge(const NetClientOptions *opts, const char *name, - NetClientState *peer, Error **errp) -{ - const NetdevBridgeOptions *bridge; - const char *helper, *br; - TAPState *s; - int fd, vnet_hdr; - - assert(opts->type == NET_CLIENT_OPTIONS_KIND_BRIDGE); - bridge = opts->u.bridge.data; - - helper = bridge->has_helper ? bridge->helper : DEFAULT_BRIDGE_HELPER; - br = bridge->has_br ? bridge->br : DEFAULT_BRIDGE_INTERFACE; - - fd = net_bridge_run_helper(helper, br, errp); - if (fd == -1) { - return -1; - } - - fcntl(fd, F_SETFL, O_NONBLOCK); - vnet_hdr = tap_probe_vnet_hdr(fd); - s = net_tap_fd_init(peer, "bridge", name, fd, vnet_hdr); - - snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s,br=%s", helper, - br); - - return 0; -} - -static int net_tap_init(const NetdevTapOptions *tap, int *vnet_hdr, - const char *setup_script, char *ifname, - size_t ifname_sz, int mq_required, Error **errp) -{ - Error *err = NULL; - int fd, vnet_hdr_required; - - if (tap->has_vnet_hdr) { - *vnet_hdr = tap->vnet_hdr; - vnet_hdr_required = *vnet_hdr; - } else { - *vnet_hdr = 1; - vnet_hdr_required = 0; - } - - TFR(fd = tap_open(ifname, ifname_sz, vnet_hdr, vnet_hdr_required, - mq_required, errp)); - if (fd < 0) { - return -1; - } - - if (setup_script && - setup_script[0] != '\0' && - strcmp(setup_script, "no") != 0) { - launch_script(setup_script, ifname, fd, &err); - if (err) { - error_propagate(errp, err); - close(fd); - return -1; - } - } - - return fd; -} - -#define MAX_TAP_QUEUES 1024 - -static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, - const char *model, const char *name, - const char *ifname, const char *script, - const char *downscript, const char *vhostfdname, - int vnet_hdr, int fd, Error **errp) -{ - Error *err = NULL; - TAPState *s = net_tap_fd_init(peer, model, name, fd, vnet_hdr); - int vhostfd; - - tap_set_sndbuf(s->fd, tap, &err); - if (err) { - error_propagate(errp, err); - return; - } - - if (tap->has_fd || tap->has_fds) { - snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd); - } else if (tap->has_helper) { - snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s", - tap->helper); - } else { - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "ifname=%s,script=%s,downscript=%s", ifname, script, - downscript); - - if (strcmp(downscript, "no") != 0) { - snprintf(s->down_script, sizeof(s->down_script), "%s", downscript); - snprintf(s->down_script_arg, sizeof(s->down_script_arg), - "%s", ifname); - } - } - - if (tap->has_vhost ? tap->vhost : - vhostfdname || (tap->has_vhostforce && tap->vhostforce)) { - VhostNetOptions options; - - options.backend_type = VHOST_BACKEND_TYPE_KERNEL; - options.net_backend = &s->nc; - - if (vhostfdname) { - vhostfd = monitor_fd_param(cur_mon, vhostfdname, &err); - if (vhostfd == -1) { - error_propagate(errp, err); - return; - } - } else { - vhostfd = open("/dev/vhost-net", O_RDWR); - if (vhostfd < 0) { - error_setg_errno(errp, errno, - "tap: open vhost char device failed"); - return; - } - } - options.opaque = (void *)(uintptr_t)vhostfd; - - s->vhost_net = vhost_net_init(&options); - if (!s->vhost_net) { - error_setg(errp, - "vhost-net requested but could not be initialized"); - return; - } - } else if (vhostfdname) { - error_setg(errp, "vhostfd= is not valid without vhost"); - } -} - -static int get_fds(char *str, char *fds[], int max) -{ - char *ptr = str, *this; - size_t len = strlen(str); - int i = 0; - - while (i < max && ptr < str + len) { - this = strchr(ptr, ':'); - - if (this == NULL) { - fds[i] = g_strdup(ptr); - } else { - fds[i] = g_strndup(ptr, this - ptr); - } - - i++; - if (this == NULL) { - break; - } else { - ptr = this + 1; - } - } - - return i; -} - -int net_init_tap(const NetClientOptions *opts, const char *name, - NetClientState *peer, Error **errp) -{ - const NetdevTapOptions *tap; - int fd, vnet_hdr = 0, i = 0, queues; - /* for the no-fd, no-helper case */ - const char *script = NULL; /* suppress wrong "uninit'd use" gcc warning */ - const char *downscript = NULL; - Error *err = NULL; - const char *vhostfdname; - char ifname[128]; - - assert(opts->type == NET_CLIENT_OPTIONS_KIND_TAP); - tap = opts->u.tap.data; - queues = tap->has_queues ? tap->queues : 1; - vhostfdname = tap->has_vhostfd ? tap->vhostfd : NULL; - - /* QEMU vlans does not support multiqueue tap, in this case peer is set. - * For -netdev, peer is always NULL. */ - if (peer && (tap->has_queues || tap->has_fds || tap->has_vhostfds)) { - error_setg(errp, "Multiqueue tap cannot be used with QEMU vlans"); - return -1; - } - - if (tap->has_fd) { - if (tap->has_ifname || tap->has_script || tap->has_downscript || - tap->has_vnet_hdr || tap->has_helper || tap->has_queues || - tap->has_fds || tap->has_vhostfds) { - error_setg(errp, "ifname=, script=, downscript=, vnet_hdr=, " - "helper=, queues=, fds=, and vhostfds= " - "are invalid with fd="); - return -1; - } - - fd = monitor_fd_param(cur_mon, tap->fd, &err); - if (fd == -1) { - error_propagate(errp, err); - return -1; - } - - fcntl(fd, F_SETFL, O_NONBLOCK); - - vnet_hdr = tap_probe_vnet_hdr(fd); - - net_init_tap_one(tap, peer, "tap", name, NULL, - script, downscript, - vhostfdname, vnet_hdr, fd, &err); - if (err) { - error_propagate(errp, err); - return -1; - } - } else if (tap->has_fds) { - char *fds[MAX_TAP_QUEUES]; - char *vhost_fds[MAX_TAP_QUEUES]; - int nfds, nvhosts; - - if (tap->has_ifname || tap->has_script || tap->has_downscript || - tap->has_vnet_hdr || tap->has_helper || tap->has_queues || - tap->has_vhostfd) { - error_setg(errp, "ifname=, script=, downscript=, vnet_hdr=, " - "helper=, queues=, and vhostfd= " - "are invalid with fds="); - return -1; - } - - nfds = get_fds(tap->fds, fds, MAX_TAP_QUEUES); - if (tap->has_vhostfds) { - nvhosts = get_fds(tap->vhostfds, vhost_fds, MAX_TAP_QUEUES); - if (nfds != nvhosts) { - error_setg(errp, "The number of fds passed does not match " - "the number of vhostfds passed"); - return -1; - } - } - - for (i = 0; i < nfds; i++) { - fd = monitor_fd_param(cur_mon, fds[i], &err); - if (fd == -1) { - error_propagate(errp, err); - return -1; - } - - fcntl(fd, F_SETFL, O_NONBLOCK); - - if (i == 0) { - vnet_hdr = tap_probe_vnet_hdr(fd); - } else if (vnet_hdr != tap_probe_vnet_hdr(fd)) { - error_setg(errp, - "vnet_hdr not consistent across given tap fds"); - return -1; - } - - net_init_tap_one(tap, peer, "tap", name, ifname, - script, downscript, - tap->has_vhostfds ? vhost_fds[i] : NULL, - vnet_hdr, fd, &err); - if (err) { - error_propagate(errp, err); - return -1; - } - } - } else if (tap->has_helper) { - if (tap->has_ifname || tap->has_script || tap->has_downscript || - tap->has_vnet_hdr || tap->has_queues || tap->has_vhostfds) { - error_setg(errp, "ifname=, script=, downscript=, vnet_hdr=, " - "queues=, and vhostfds= are invalid with helper="); - return -1; - } - - fd = net_bridge_run_helper(tap->helper, DEFAULT_BRIDGE_INTERFACE, - errp); - if (fd == -1) { - return -1; - } - - fcntl(fd, F_SETFL, O_NONBLOCK); - vnet_hdr = tap_probe_vnet_hdr(fd); - - net_init_tap_one(tap, peer, "bridge", name, ifname, - script, downscript, vhostfdname, - vnet_hdr, fd, &err); - if (err) { - error_propagate(errp, err); - close(fd); - return -1; - } - } else { - if (tap->has_vhostfds) { - error_setg(errp, "vhostfds= is invalid if fds= wasn't specified"); - return -1; - } - script = tap->has_script ? tap->script : DEFAULT_NETWORK_SCRIPT; - downscript = tap->has_downscript ? tap->downscript : - DEFAULT_NETWORK_DOWN_SCRIPT; - - if (tap->has_ifname) { - pstrcpy(ifname, sizeof ifname, tap->ifname); - } else { - ifname[0] = '\0'; - } - - for (i = 0; i < queues; i++) { - fd = net_tap_init(tap, &vnet_hdr, i >= 1 ? "no" : script, - ifname, sizeof ifname, queues > 1, errp); - if (fd == -1) { - return -1; - } - - if (queues > 1 && i == 0 && !tap->has_ifname) { - if (tap_fd_get_ifname(fd, ifname)) { - error_setg(errp, "Fail to get ifname"); - close(fd); - return -1; - } - } - - net_init_tap_one(tap, peer, "tap", name, ifname, - i >= 1 ? "no" : script, - i >= 1 ? "no" : downscript, - vhostfdname, vnet_hdr, fd, &err); - if (err) { - error_propagate(errp, err); - close(fd); - return -1; - } - } - } - - return 0; -} - -VHostNetState *tap_get_vhost_net(NetClientState *nc) -{ - TAPState *s = DO_UPCAST(TAPState, nc, nc); - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP); - return s->vhost_net; -} - -int tap_enable(NetClientState *nc) -{ - TAPState *s = DO_UPCAST(TAPState, nc, nc); - int ret; - - if (s->enabled) { - return 0; - } else { - ret = tap_fd_enable(s->fd); - if (ret == 0) { - s->enabled = true; - tap_update_fd_handler(s); - } - return ret; - } -} - -int tap_disable(NetClientState *nc) -{ - TAPState *s = DO_UPCAST(TAPState, nc, nc); - int ret; - - if (s->enabled == 0) { - return 0; - } else { - ret = tap_fd_disable(s->fd); - if (ret == 0) { - qemu_purge_queued_packets(nc); - s->enabled = false; - tap_update_fd_handler(s); - } - return ret; - } -} diff --git a/qemu/net/tap_int.h b/qemu/net/tap_int.h deleted file mode 100644 index 2378021c4..000000000 --- a/qemu/net/tap_int.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * Copyright (c) 2009 Red Hat, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef QEMU_TAP_H -#define QEMU_TAP_H - -#include "qemu-common.h" -#include "qapi-types.h" - -int tap_open(char *ifname, int ifname_size, int *vnet_hdr, - int vnet_hdr_required, int mq_required, Error **errp); - -ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen); - -void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp); -int tap_probe_vnet_hdr(int fd); -int tap_probe_vnet_hdr_len(int fd, int len); -int tap_probe_has_ufo(int fd); -void tap_fd_set_offload(int fd, int csum, int tso4, int tso6, int ecn, int ufo); -void tap_fd_set_vnet_hdr_len(int fd, int len); -int tap_fd_set_vnet_le(int fd, int vnet_is_le); -int tap_fd_set_vnet_be(int fd, int vnet_is_be); -int tap_fd_enable(int fd); -int tap_fd_disable(int fd); -int tap_fd_get_ifname(int fd, char *ifname); - -#endif /* QEMU_TAP_H */ diff --git a/qemu/net/util.c b/qemu/net/util.c deleted file mode 100644 index 0b3dbfe5d..000000000 --- a/qemu/net/util.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "util.h" - -int net_parse_macaddr(uint8_t *macaddr, const char *p) -{ - int i; - char *last_char; - long int offset; - - errno = 0; - offset = strtol(p, &last_char, 0); - if (errno == 0 && *last_char == '\0' && - offset >= 0 && offset <= 0xFFFFFF) { - macaddr[3] = (offset & 0xFF0000) >> 16; - macaddr[4] = (offset & 0xFF00) >> 8; - macaddr[5] = offset & 0xFF; - return 0; - } - - for (i = 0; i < 6; i++) { - macaddr[i] = strtol(p, (char **)&p, 16); - if (i == 5) { - if (*p != '\0') { - return -1; - } - } else { - if (*p != ':' && *p != '-') { - return -1; - } - p++; - } - } - - return 0; -} diff --git a/qemu/net/util.h b/qemu/net/util.h deleted file mode 100644 index 60b73d372..000000000 --- a/qemu/net/util.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef QEMU_NET_UTIL_H -#define QEMU_NET_UTIL_H - - -int net_parse_macaddr(uint8_t *macaddr, const char *p); - -#endif /* QEMU_NET_UTIL_H */ diff --git a/qemu/net/vde.c b/qemu/net/vde.c deleted file mode 100644 index 9427eaa16..000000000 --- a/qemu/net/vde.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" - -#include <libvdeplug.h> - -#include "net/net.h" -#include "clients.h" -#include "qemu-common.h" -#include "qemu/option.h" -#include "qemu/main-loop.h" - -typedef struct VDEState { - NetClientState nc; - VDECONN *vde; -} VDEState; - -static void vde_to_qemu(void *opaque) -{ - VDEState *s = opaque; - uint8_t buf[NET_BUFSIZE]; - int size; - - size = vde_recv(s->vde, (char *)buf, sizeof(buf), 0); - if (size > 0) { - qemu_send_packet(&s->nc, buf, size); - } -} - -static ssize_t vde_receive(NetClientState *nc, const uint8_t *buf, size_t size) -{ - VDEState *s = DO_UPCAST(VDEState, nc, nc); - ssize_t ret; - - do { - ret = vde_send(s->vde, (const char *)buf, size, 0); - } while (ret < 0 && errno == EINTR); - - return ret; -} - -static void vde_cleanup(NetClientState *nc) -{ - VDEState *s = DO_UPCAST(VDEState, nc, nc); - qemu_set_fd_handler(vde_datafd(s->vde), NULL, NULL, NULL); - vde_close(s->vde); -} - -static NetClientInfo net_vde_info = { - .type = NET_CLIENT_OPTIONS_KIND_VDE, - .size = sizeof(VDEState), - .receive = vde_receive, - .cleanup = vde_cleanup, -}; - -static int net_vde_init(NetClientState *peer, const char *model, - const char *name, const char *sock, - int port, const char *group, int mode) -{ - NetClientState *nc; - VDEState *s; - VDECONN *vde; - char *init_group = (char *)group; - char *init_sock = (char *)sock; - - struct vde_open_args args = { - .port = port, - .group = init_group, - .mode = mode, - }; - - vde = vde_open(init_sock, (char *)"QEMU", &args); - if (!vde){ - return -1; - } - - nc = qemu_new_net_client(&net_vde_info, peer, model, name); - - snprintf(nc->info_str, sizeof(nc->info_str), "sock=%s,fd=%d", - sock, vde_datafd(vde)); - - s = DO_UPCAST(VDEState, nc, nc); - - s->vde = vde; - - qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s); - - return 0; -} - -int net_init_vde(const NetClientOptions *opts, const char *name, - NetClientState *peer, Error **errp) -{ - /* FIXME error_setg(errp, ...) on failure */ - const NetdevVdeOptions *vde; - - assert(opts->type == NET_CLIENT_OPTIONS_KIND_VDE); - vde = opts->u.vde.data; - - /* missing optional values have been initialized to "all bits zero" */ - if (net_vde_init(peer, "vde", name, vde->sock, vde->port, vde->group, - vde->has_mode ? vde->mode : 0700) == -1) { - return -1; - } - - return 0; -} diff --git a/qemu/net/vhost-user.c b/qemu/net/vhost-user.c deleted file mode 100644 index 1b9e73a2d..000000000 --- a/qemu/net/vhost-user.c +++ /dev/null @@ -1,331 +0,0 @@ -/* - * vhost-user.c - * - * Copyright (c) 2013 Virtual Open Systems Sarl. - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - */ - -#include "qemu/osdep.h" -#include "clients.h" -#include "net/vhost_net.h" -#include "net/vhost-user.h" -#include "sysemu/char.h" -#include "qemu/config-file.h" -#include "qemu/error-report.h" -#include "qmp-commands.h" -#include "trace.h" - -typedef struct VhostUserState { - NetClientState nc; - CharDriverState *chr; - VHostNetState *vhost_net; -} VhostUserState; - -typedef struct VhostUserChardevProps { - bool is_socket; - bool is_unix; -} VhostUserChardevProps; - -VHostNetState *vhost_user_get_vhost_net(NetClientState *nc) -{ - VhostUserState *s = DO_UPCAST(VhostUserState, nc, nc); - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER); - return s->vhost_net; -} - -static int vhost_user_running(VhostUserState *s) -{ - return (s->vhost_net) ? 1 : 0; -} - -static void vhost_user_stop(int queues, NetClientState *ncs[]) -{ - VhostUserState *s; - int i; - - for (i = 0; i < queues; i++) { - assert (ncs[i]->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER); - - s = DO_UPCAST(VhostUserState, nc, ncs[i]); - if (!vhost_user_running(s)) { - continue; - } - - if (s->vhost_net) { - vhost_net_cleanup(s->vhost_net); - s->vhost_net = NULL; - } - } -} - -static int vhost_user_start(int queues, NetClientState *ncs[]) -{ - VhostNetOptions options; - VhostUserState *s; - int max_queues; - int i; - - options.backend_type = VHOST_BACKEND_TYPE_USER; - - for (i = 0; i < queues; i++) { - assert (ncs[i]->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER); - - s = DO_UPCAST(VhostUserState, nc, ncs[i]); - if (vhost_user_running(s)) { - continue; - } - - options.net_backend = ncs[i]; - options.opaque = s->chr; - s->vhost_net = vhost_net_init(&options); - if (!s->vhost_net) { - error_report("failed to init vhost_net for queue %d", i); - goto err; - } - - if (i == 0) { - max_queues = vhost_net_get_max_queues(s->vhost_net); - if (queues > max_queues) { - error_report("you are asking more queues than supported: %d", - max_queues); - goto err; - } - } - } - - return 0; - -err: - vhost_user_stop(i + 1, ncs); - return -1; -} - -static ssize_t vhost_user_receive(NetClientState *nc, const uint8_t *buf, - size_t size) -{ - /* In case of RARP (message size is 60) notify backup to send a fake RARP. - This fake RARP will be sent by backend only for guest - without GUEST_ANNOUNCE capability. - */ - if (size == 60) { - VhostUserState *s = DO_UPCAST(VhostUserState, nc, nc); - int r; - static int display_rarp_failure = 1; - char mac_addr[6]; - - /* extract guest mac address from the RARP message */ - memcpy(mac_addr, &buf[6], 6); - - r = vhost_net_notify_migration_done(s->vhost_net, mac_addr); - - if ((r != 0) && (display_rarp_failure)) { - fprintf(stderr, - "Vhost user backend fails to broadcast fake RARP\n"); - fflush(stderr); - display_rarp_failure = 0; - } - } - - return size; -} - -static void vhost_user_cleanup(NetClientState *nc) -{ - VhostUserState *s = DO_UPCAST(VhostUserState, nc, nc); - - if (s->vhost_net) { - vhost_net_cleanup(s->vhost_net); - s->vhost_net = NULL; - } - - qemu_purge_queued_packets(nc); -} - -static bool vhost_user_has_vnet_hdr(NetClientState *nc) -{ - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER); - - return true; -} - -static bool vhost_user_has_ufo(NetClientState *nc) -{ - assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER); - - return true; -} - -static NetClientInfo net_vhost_user_info = { - .type = NET_CLIENT_OPTIONS_KIND_VHOST_USER, - .size = sizeof(VhostUserState), - .receive = vhost_user_receive, - .cleanup = vhost_user_cleanup, - .has_vnet_hdr = vhost_user_has_vnet_hdr, - .has_ufo = vhost_user_has_ufo, -}; - -static void net_vhost_user_event(void *opaque, int event) -{ - const char *name = opaque; - NetClientState *ncs[MAX_QUEUE_NUM]; - VhostUserState *s; - Error *err = NULL; - int queues; - - queues = qemu_find_net_clients_except(name, ncs, - NET_CLIENT_OPTIONS_KIND_NIC, - MAX_QUEUE_NUM); - assert(queues < MAX_QUEUE_NUM); - - s = DO_UPCAST(VhostUserState, nc, ncs[0]); - trace_vhost_user_event(s->chr->label, event); - switch (event) { - case CHR_EVENT_OPENED: - if (vhost_user_start(queues, ncs) < 0) { - exit(1); - } - qmp_set_link(name, true, &err); - break; - case CHR_EVENT_CLOSED: - qmp_set_link(name, false, &err); - vhost_user_stop(queues, ncs); - break; - } - - if (err) { - error_report_err(err); - } -} - -static int net_vhost_user_init(NetClientState *peer, const char *device, - const char *name, CharDriverState *chr, - int queues) -{ - NetClientState *nc; - VhostUserState *s; - int i; - - assert(name); - assert(queues > 0); - - for (i = 0; i < queues; i++) { - nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name); - - snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s", - i, chr->label); - - nc->queue_index = i; - - s = DO_UPCAST(VhostUserState, nc, nc); - s->chr = chr; - } - - qemu_chr_add_handlers(chr, NULL, NULL, net_vhost_user_event, nc[0].name); - - return 0; -} - -static int net_vhost_chardev_opts(void *opaque, - const char *name, const char *value, - Error **errp) -{ - VhostUserChardevProps *props = opaque; - - if (strcmp(name, "backend") == 0 && strcmp(value, "socket") == 0) { - props->is_socket = true; - } else if (strcmp(name, "path") == 0) { - props->is_unix = true; - } else if (strcmp(name, "server") == 0) { - } else { - error_setg(errp, - "vhost-user does not support a chardev with option %s=%s", - name, value); - return -1; - } - return 0; -} - -static CharDriverState *net_vhost_parse_chardev( - const NetdevVhostUserOptions *opts, Error **errp) -{ - CharDriverState *chr = qemu_chr_find(opts->chardev); - VhostUserChardevProps props; - - if (chr == NULL) { - error_setg(errp, "chardev \"%s\" not found", opts->chardev); - return NULL; - } - - /* inspect chardev opts */ - memset(&props, 0, sizeof(props)); - if (qemu_opt_foreach(chr->opts, net_vhost_chardev_opts, &props, errp)) { - return NULL; - } - - if (!props.is_socket || !props.is_unix) { - error_setg(errp, "chardev \"%s\" is not a unix socket", - opts->chardev); - return NULL; - } - - qemu_chr_fe_claim_no_fail(chr); - - return chr; -} - -static int net_vhost_check_net(void *opaque, QemuOpts *opts, Error **errp) -{ - const char *name = opaque; - const char *driver, *netdev; - const char virtio_name[] = "virtio-net-"; - - driver = qemu_opt_get(opts, "driver"); - netdev = qemu_opt_get(opts, "netdev"); - - if (!driver || !netdev) { - return 0; - } - - if (strcmp(netdev, name) == 0 && - strncmp(driver, virtio_name, strlen(virtio_name)) != 0) { - error_setg(errp, "vhost-user requires frontend driver virtio-net-*"); - return -1; - } - - return 0; -} - -int net_init_vhost_user(const NetClientOptions *opts, const char *name, - NetClientState *peer, Error **errp) -{ - int queues; - const NetdevVhostUserOptions *vhost_user_opts; - CharDriverState *chr; - - assert(opts->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER); - vhost_user_opts = opts->u.vhost_user.data; - - chr = net_vhost_parse_chardev(vhost_user_opts, errp); - if (!chr) { - return -1; - } - - /* verify net frontend */ - if (qemu_opts_foreach(qemu_find_opts("device"), net_vhost_check_net, - (char *)name, errp)) { - return -1; - } - - queues = vhost_user_opts->has_queues ? vhost_user_opts->queues : 1; - if (queues < 1 || queues > MAX_QUEUE_NUM) { - error_setg(errp, - "vhost-user number of queues must be in range [1, %d]", - MAX_QUEUE_NUM); - return -1; - } - - return net_vhost_user_init(peer, "vhost_user", name, chr, queues); -} |