kvm tools: Add ivshmem device
[linux-2.6/next.git] / tools / kvm / net / uip / core.c
blob2e7603c3f9d4ec3312337a64bb273e93c4a9051c
1 #include "kvm/mutex.h"
2 #include "kvm/uip.h"
4 #include <linux/virtio_net.h>
5 #include <linux/kernel.h>
6 #include <linux/list.h>
8 int uip_tx(struct iovec *iov, u16 out, struct uip_info *info)
10 struct virtio_net_hdr *vnet;
11 struct uip_tx_arg arg;
12 int eth_len, vnet_len;
13 struct uip_eth *eth;
14 u8 *buf = NULL;
15 u16 proto;
16 int i;
19 * Buffer from guest to device
21 vnet_len = iov[0].iov_len;
22 vnet = iov[0].iov_base;
24 eth_len = iov[1].iov_len;
25 eth = iov[1].iov_base;
28 * In case, ethernet frame is in more than one iov entry.
29 * Copy iov buffer into one linear buffer.
31 if (out > 2) {
32 eth_len = 0;
33 for (i = 1; i < out; i++)
34 eth_len += iov[i].iov_len;
36 buf = malloc(eth_len);
37 if (!buf)
38 return -1;
40 eth = (struct uip_eth *)buf;
41 for (i = 1; i < out; i++) {
42 memcpy(buf, iov[i].iov_base, iov[i].iov_len);
43 buf += iov[i].iov_len;
47 memset(&arg, 0, sizeof(arg));
49 arg.vnet_len = vnet_len;
50 arg.eth_len = eth_len;
51 arg.info = info;
52 arg.vnet = vnet;
53 arg.eth = eth;
56 * Check package type
58 proto = ntohs(eth->type);
60 switch (proto) {
61 case UIP_ETH_P_ARP:
62 uip_tx_do_arp(&arg);
63 break;
64 case UIP_ETH_P_IP:
65 uip_tx_do_ipv4(&arg);
66 break;
67 default:
68 break;
71 if (out > 2 && buf)
72 free(eth);
74 return vnet_len + eth_len;
77 int uip_rx(struct iovec *iov, u16 in, struct uip_info *info)
79 struct virtio_net_hdr *vnet;
80 struct uip_eth *eth;
81 struct uip_buf *buf;
82 int vnet_len;
83 int eth_len;
84 char *p;
85 int len;
86 int cnt;
87 int i;
90 * Sleep until there is a buffer for guest
92 buf = uip_buf_get_used(info);
95 * Fill device to guest buffer, vnet hdr fisrt
97 vnet_len = iov[0].iov_len;
98 vnet = iov[0].iov_base;
99 if (buf->vnet_len > vnet_len) {
100 len = -1;
101 goto out;
103 memcpy(vnet, buf->vnet, buf->vnet_len);
106 * Then, the real eth data
107 * Note: Be sure buf->eth_len is not bigger than the buffer len that guest provides
109 cnt = buf->eth_len;
110 p = buf->eth;
111 for (i = 1; i < in; i++) {
112 eth_len = iov[i].iov_len;
113 eth = iov[i].iov_base;
114 if (cnt > eth_len) {
115 memcpy(eth, p, eth_len);
116 cnt -= eth_len;
117 p += eth_len;
118 } else {
119 memcpy(eth, p, cnt);
120 cnt -= cnt;
121 break;
125 if (cnt) {
126 pr_warning("uip_rx error");
127 len = -1;
128 goto out;
131 len = buf->vnet_len + buf->eth_len;
133 out:
134 uip_buf_set_free(info, buf);
135 return len;
138 int uip_init(struct uip_info *info)
140 struct list_head *udp_socket_head;
141 struct list_head *tcp_socket_head;
142 struct list_head *buf_head;
143 struct uip_buf *buf;
144 int buf_nr;
145 int i;
147 udp_socket_head = &info->udp_socket_head;
148 tcp_socket_head = &info->tcp_socket_head;
149 buf_head = &info->buf_head;
150 buf_nr = info->buf_nr;
152 INIT_LIST_HEAD(udp_socket_head);
153 INIT_LIST_HEAD(tcp_socket_head);
154 INIT_LIST_HEAD(buf_head);
156 pthread_mutex_init(&info->udp_socket_lock, NULL);
157 pthread_mutex_init(&info->tcp_socket_lock, NULL);
158 pthread_mutex_init(&info->buf_lock, NULL);
160 pthread_cond_init(&info->buf_used_cond, NULL);
161 pthread_cond_init(&info->buf_free_cond, NULL);
164 for (i = 0; i < buf_nr; i++) {
165 buf = malloc(sizeof(*buf));
166 memset(buf, 0, sizeof(*buf));
168 buf->status = UIP_BUF_STATUS_FREE;
169 buf->info = info;
170 buf->id = i;
171 list_add_tail(&buf->list, buf_head);
174 list_for_each_entry(buf, buf_head, list) {
175 buf->vnet = malloc(sizeof(struct virtio_net_hdr));
176 buf->vnet_len = sizeof(struct virtio_net_hdr);
177 buf->eth = malloc(1024*64 + sizeof(struct uip_pseudo_hdr));
178 buf->eth_len = 1024*64 + sizeof(struct uip_pseudo_hdr);
180 memset(buf->vnet, 0, buf->vnet_len);
181 memset(buf->eth, 0, buf->eth_len);
184 info->buf_free_nr = buf_nr;
185 info->buf_used_nr = 0;
187 uip_dhcp_get_dns(info);
189 return 0;