@@ -269,6 +269,7 @@ static inline u16 uip_eth_hdrlen(struct uip_eth *eth)
}
int uip_tx(struct iovec *iov, u16 out, struct uip_info *info);
+int uip_rx(struct iovec *iov, u16 in, struct uip_info *info);
int uip_init(struct uip_info *info);
int uip_tx_do_ipv4_icmp(struct uip_tx_arg *arg);
@@ -74,6 +74,67 @@ int uip_tx(struct iovec *iov, u16 out, struct uip_info *info)
return vnet_len + eth_len;
}
+int uip_rx(struct iovec *iov, u16 in, struct uip_info *info)
+{
+ struct virtio_net_hdr *vnet;
+ struct uip_eth *eth;
+ struct uip_buf *buf;
+ int vnet_len;
+ int eth_len;
+ char *p;
+ int len;
+ int cnt;
+ int i;
+
+ /*
+ * Sleep until there is a buffer for guest
+ */
+ buf = uip_buf_get_used(info);
+
+ /*
+ * Fill device to guest buffer, vnet hdr fisrt
+ */
+ vnet_len = iov[0].iov_len;
+ vnet = iov[0].iov_base;
+ if (buf->vnet_len > vnet_len) {
+ len = -1;
+ goto out;
+ }
+ memcpy(vnet, buf->vnet, buf->vnet_len);
+
+ /*
+ * Then, the real eth data
+ * Note: Be sure buf->eth_len is not bigger than the buffer len that guest provides
+ */
+ cnt = buf->eth_len;
+ p = buf->eth;
+ for (i = 1; i < in; i++) {
+ eth_len = iov[i].iov_len;
+ eth = iov[i].iov_base;
+ if (cnt > eth_len) {
+ memcpy(eth, p, eth_len);
+ cnt -= eth_len;
+ p += eth_len;
+ } else {
+ memcpy(eth, p, cnt);
+ cnt -= cnt;
+ break;
+ }
+ }
+
+ if (cnt) {
+ pr_warning("uip_rx error");
+ len = -1;
+ goto out;
+ }
+
+ len = buf->vnet_len + buf->eth_len;
+
+out:
+ uip_buf_set_free(info, buf);
+ return len;
+}
+
int uip_init(struct uip_info *info)
{
struct list_head *udp_socket_head;
This patch implement rx interface for uip. uip_rx() can be called in virtio_net_rx_thread(). It is a consumer of the ethernet used buffer. It sleeps until there is used buffer avaiable and copy ethernet data into virtio iov buffers which provided by virtio_net_rx_thread(). Signed-off-by: Asias He <asias.hejun@gmail.com> --- tools/kvm/include/kvm/uip.h | 1 + tools/kvm/uip/core.c | 61 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 0 deletions(-)