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 <asias.hejun@gmail.com>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
Asias He
2015-06-01 16:39:45 +01:00
committed by Will Deacon
parent 6c8ca05340
commit 26570aaffb
3 changed files with 184 additions and 0 deletions
+1
View File
@@ -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
+69
View File
@@ -0,0 +1,69 @@
#ifndef KVM__UIP_H
#define KVM__UIP_H
#include "linux/types.h"
#include "kvm/mutex.h"
#include <netinet/in.h>
#include <sys/uio.h>
#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 */
+114
View File
@@ -0,0 +1,114 @@
#include "kvm/uip.h"
#include <linux/kernel.h>
#include <linux/list.h>
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;
}