From c1ff9f24a948f0f6c263176a4771e2e75f064c74 Mon Sep 17 00:00:00 2001 From: Asias He Date: Wed, 29 Jun 2011 16:47:06 +0800 Subject: [PATCH] kvm tools: Introduce ethernet frame buffer system for uip - uip_buf_get_free() Get a free buffer from buffer pool, sleep if there is no free buffer. - uip_buf_get_used() Get a used buffer from buffer pool, sleep if there is no used buffer. - uip_buf_set_free() Set a buffer as free, so it can be reused by the buffer producer. - uip_buf_set_used() Set a buffer as used, uip rx code will inject the ethernet frame in this buffer into guest. - uip_buf_clone() Get a free buffer, and clone data into it. Signed-off-by: Asias He Signed-off-by: Pekka Enberg --- tools/kvm/Makefile | 1 + tools/kvm/include/kvm/uip.h | 69 ++++++++++++++++++++++ tools/kvm/uip/buf.c | 114 ++++++++++++++++++++++++++++++++++++ 3 files changed, 184 insertions(+) create mode 100644 tools/kvm/include/kvm/uip.h create mode 100644 tools/kvm/uip/buf.c diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile index d368c2216b0a..91539de76234 100644 --- a/tools/kvm/Makefile +++ b/tools/kvm/Makefile @@ -45,6 +45,7 @@ OBJS += disk/qcow.o OBJS += disk/raw.o OBJS += ioeventfd.o OBJS += irq.o +OBJS += uip/buf.o OBJS += kvm-cmd.o OBJS += kvm-debug.o OBJS += kvm-help.o diff --git a/tools/kvm/include/kvm/uip.h b/tools/kvm/include/kvm/uip.h new file mode 100644 index 000000000000..32a5da365ad5 --- /dev/null +++ b/tools/kvm/include/kvm/uip.h @@ -0,0 +1,69 @@ +#ifndef KVM__UIP_H +#define KVM__UIP_H + +#include "linux/types.h" +#include "kvm/mutex.h" + +#include +#include + +#define UIP_BUF_STATUS_FREE 0 +#define UIP_BUF_STATUS_INUSE 1 +#define UIP_BUF_STATUS_USED 2 + +struct uip_eth_addr { + u8 addr[6]; +}; + +struct uip_eth { + struct uip_eth_addr dst; + struct uip_eth_addr src; + u16 type; +} __attribute__((packed)); + +struct uip_info { + struct list_head udp_socket_head; + struct list_head tcp_socket_head; + pthread_mutex_t udp_socket_lock; + pthread_mutex_t tcp_socket_lock; + struct uip_eth_addr guest_mac; + struct uip_eth_addr host_mac; + pthread_cond_t buf_free_cond; + pthread_cond_t buf_used_cond; + struct list_head buf_head; + pthread_mutex_t buf_lock; + pthread_t udp_thread; + int udp_epollfd; + int buf_free_nr; + int buf_used_nr; + u32 host_ip; + u32 buf_nr; +}; + +struct uip_buf { + struct list_head list; + struct uip_info *info; + u32 payload; + int vnet_len; + int eth_len; + int status; + char *vnet; + char *eth; + int id; +}; + +struct uip_tx_arg { + struct virtio_net_hdr *vnet; + struct uip_info *info; + struct uip_eth *eth; + int vnet_len; + int eth_len; +}; + +struct uip_buf *uip_buf_set_used(struct uip_info *info, struct uip_buf *buf); +struct uip_buf *uip_buf_set_free(struct uip_info *info, struct uip_buf *buf); +struct uip_buf *uip_buf_get_used(struct uip_info *info); +struct uip_buf *uip_buf_get_free(struct uip_info *info); +struct uip_buf *uip_buf_clone(struct uip_tx_arg *arg); + +#endif /* KVM__UIP_H */ diff --git a/tools/kvm/uip/buf.c b/tools/kvm/uip/buf.c new file mode 100644 index 000000000000..5e564a99eb6a --- /dev/null +++ b/tools/kvm/uip/buf.c @@ -0,0 +1,114 @@ +#include "kvm/uip.h" + +#include +#include + +struct uip_buf *uip_buf_get_used(struct uip_info *info) +{ + struct uip_buf *buf; + bool found = false; + + mutex_lock(&info->buf_lock); + + while (!(info->buf_used_nr > 0)) + pthread_cond_wait(&info->buf_used_cond, &info->buf_lock); + + list_for_each_entry(buf, &info->buf_head, list) { + if (buf->status == UIP_BUF_STATUS_USED) { + /* + * Set status to INUSE immediately to prevent + * someone from using this buf until we free it + */ + buf->status = UIP_BUF_STATUS_INUSE; + info->buf_used_nr--; + found = true; + break; + } + } + + mutex_unlock(&info->buf_lock); + + return found ? buf : NULL; +} + +struct uip_buf *uip_buf_get_free(struct uip_info *info) +{ + struct uip_buf *buf; + bool found = false; + + mutex_lock(&info->buf_lock); + + while (!(info->buf_free_nr > 0)) + pthread_cond_wait(&info->buf_free_cond, &info->buf_lock); + + list_for_each_entry(buf, &info->buf_head, list) { + if (buf->status == UIP_BUF_STATUS_FREE) { + /* + * Set status to INUSE immediately to prevent + * someone from using this buf until we free it + */ + buf->status = UIP_BUF_STATUS_INUSE; + info->buf_free_nr--; + found = true; + break; + } + } + + mutex_unlock(&info->buf_lock); + + return found ? buf : NULL; +} + +struct uip_buf *uip_buf_set_used(struct uip_info *info, struct uip_buf *buf) +{ + mutex_lock(&info->buf_lock); + + buf->status = UIP_BUF_STATUS_USED; + info->buf_used_nr++; + pthread_cond_signal(&info->buf_used_cond); + + mutex_unlock(&info->buf_lock); + + return buf; +} + +struct uip_buf *uip_buf_set_free(struct uip_info *info, struct uip_buf *buf) +{ + mutex_lock(&info->buf_lock); + + buf->status = UIP_BUF_STATUS_FREE; + info->buf_free_nr++; + pthread_cond_signal(&info->buf_free_cond); + + mutex_unlock(&info->buf_lock); + + return buf; +} + +struct uip_buf *uip_buf_clone(struct uip_tx_arg *arg) +{ + struct uip_buf *buf; + struct uip_eth *eth2; + struct uip_info *info; + + info = arg->info; + + /* + * Get buffer from device to guest + */ + buf = uip_buf_get_free(info); + + /* + * Clone buffer + */ + memcpy(buf->vnet, arg->vnet, arg->vnet_len); + memcpy(buf->eth, arg->eth, arg->eth_len); + buf->vnet_len = arg->vnet_len; + buf->eth_len = arg->eth_len; + + eth2 = (struct uip_eth *)buf->eth; + eth2->src = info->host_mac; + eth2->dst = arg->eth->src; + + return buf; +} -- 2.39.5