mirror of
https://github.com/clearlinux/kvmtool.git
synced 2026-09-05 05:01:33 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user