]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
kvm tools: Introduce uip_tx() for uip
authorAsias He <asias.hejun@gmail.com>
Wed, 29 Jun 2011 08:47:27 +0000 (16:47 +0800)
committerPekka Enberg <penberg@kernel.org>
Thu, 30 Jun 2011 07:42:44 +0000 (10:42 +0300)
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>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
tools/kvm/include/kvm/uip.h
tools/kvm/uip/core.c

index c300de09c4b6626810049ed3f8a1336228bbd735..38ad386a8d623bc2f352ec51f80345df15d2e14c 100644 (file)
@@ -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);
index 58eba6bec43c6e10d2f35b0ef07af490c81f52b2..3a3754675ae82cf91e2d345f7ca8679b5caf8a28 100644 (file)
@@ -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;