diff mbox

[v2,22/31] kvm tools: Introduce uip_tx() for uip

Message ID 1309423279-3093-23-git-send-email-asias.hejun@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Asias He June 30, 2011, 8:41 a.m. UTC
This patch implement tx interface for uip. uip_tx() can be called in
virtio_net_tx_thread().

It dispatches ethernet frame to ARP or IP handling code.

Signed-off-by: Asias He <asias.hejun@gmail.com>
---
 tools/kvm/include/kvm/uip.h |    2 +
 tools/kvm/uip/core.c        |   69 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 71 insertions(+), 0 deletions(-)
diff mbox

Patch

diff --git a/tools/kvm/include/kvm/uip.h b/tools/kvm/include/kvm/uip.h
index c300de0..38ad386 100644
--- a/tools/kvm/include/kvm/uip.h
+++ b/tools/kvm/include/kvm/uip.h
@@ -12,6 +12,7 @@ 
 #define UIP_BUF_STATUS_USED	2
 
 #define UIP_ETH_P_IP		0X0800
+#define UIP_ETH_P_ARP		0X0806
 
 #define UIP_IP_VER_4		0X40
 #define UIP_IP_HDR_LEN		0X05
@@ -267,6 +268,7 @@  static inline u16 uip_eth_hdrlen(struct uip_eth *eth)
 	return sizeof(*eth);
 }
 
+int uip_tx(struct iovec *iov, u16 out, struct uip_info *info);
 int uip_init(struct uip_info *info);
 
 int uip_tx_do_ipv4_icmp(struct uip_tx_arg *arg);
diff --git a/tools/kvm/uip/core.c b/tools/kvm/uip/core.c
index 58eba6b..3a37546 100644
--- a/tools/kvm/uip/core.c
+++ b/tools/kvm/uip/core.c
@@ -5,6 +5,75 @@ 
 #include <linux/kernel.h>
 #include <linux/list.h>
 
+int uip_tx(struct iovec *iov, u16 out, struct uip_info *info)
+{
+	struct virtio_net_hdr *vnet;
+	struct uip_tx_arg arg;
+	int eth_len, vnet_len;
+	struct uip_eth *eth;
+	u8 *buf = NULL;
+	u16 proto;
+	int i;
+
+	/*
+	 * Buffer from guest to device
+	 */
+	vnet_len = iov[0].iov_len;
+	vnet	 = iov[0].iov_base;
+
+	eth_len	 = iov[1].iov_len;
+	eth	 = iov[1].iov_base;
+
+	/*
+	 * In case, ethernet frame is in more than one iov entry.
+	 * Copy iov buffer into one linear buffer.
+	 */
+	if (out > 2) {
+		eth_len = 0;
+		for (i = 1; i < out; i++)
+			eth_len += iov[i].iov_len;
+
+		buf = malloc(eth_len);
+		if (!buf)
+			return -1;
+
+		eth = (struct uip_eth *)buf;
+		for (i = 1; i < out; i++) {
+			memcpy(buf, iov[i].iov_base, iov[i].iov_len);
+			buf += iov[i].iov_len;
+		}
+	}
+
+	memset(&arg, 0, sizeof(arg));
+
+	arg.vnet_len = vnet_len;
+	arg.eth_len = eth_len;
+	arg.info = info;
+	arg.vnet = vnet;
+	arg.eth = eth;
+
+	/*
+	 * Check package type
+	 */
+	proto = ntohs(eth->type);
+
+	switch (proto) {
+	case UIP_ETH_P_ARP:
+		uip_tx_do_arp(&arg);
+		break;
+	case UIP_ETH_P_IP:
+		uip_tx_do_ipv4(&arg);
+		break;
+	default:
+		break;
+	}
+
+	if (out > 2 && buf)
+		free(eth);
+
+	return vnet_len + eth_len;
+}
+
 int uip_init(struct uip_info *info)
 {
 	struct list_head *udp_socket_head;