summaryrefslogtreecommitdiffstats
path: root/qemu/net/l2tpv3.c
diff options
context:
space:
mode:
authorRajithaY <rajithax.yerrumsetty@intel.com>2017-04-25 03:31:15 -0700
committerRajitha Yerrumchetty <rajithax.yerrumsetty@intel.com>2017-05-22 06:48:08 +0000
commitbb756eebdac6fd24e8919e2c43f7d2c8c4091f59 (patch)
treeca11e03542edf2d8f631efeca5e1626d211107e3 /qemu/net/l2tpv3.c
parenta14b48d18a9ed03ec191cf16b162206998a895ce (diff)
Adding qemu as a submodule of KVMFORNFV
This Patch includes the changes to add qemu as a submodule to kvmfornfv repo and make use of the updated latest qemu for the execution of all testcase Change-Id: I1280af507a857675c7f81d30c95255635667bdd7 Signed-off-by:RajithaY<rajithax.yerrumsetty@intel.com>
Diffstat (limited to 'qemu/net/l2tpv3.c')
-rw-r--r--qemu/net/l2tpv3.c744
1 files changed, 0 insertions, 744 deletions
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;
-}
-