Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Linux kernel compatability enhancements (through 3.19)
[palacios.git] / linux_module / palacios-vnet-brg.c
index efb7d18..abf4142 100644 (file)
 #include <linux/sched.h>
 #include <asm/msr.h>
 
+#include <linux/net.h>
+#include <linux/socket.h>
+#include <net/sock.h>
+
 #include <vnet/vnet.h>
 #include <vnet/vnet_hashtable.h>
 #include "palacios-vnet.h"
 #include "palacios.h"
 
 
+
 #define VNET_SERVER_PORT 9000
 
-#define VNET_YIELD_TIME_USEC 1000
+#define VNET_ADAPTIVE_BRIDGE  1      // set this to one to have bridge go to sleep if there nothing to do...
+#define VNET_NOPROGRESS_LIMIT 1000   // ... after this many iterations
+#define VNET_YIELD_TIME_USEC  1000   // ... and go to sleep for this long
 
 struct vnet_link {
     uint32_t dst_ip;
@@ -94,15 +101,15 @@ static inline struct vnet_link * _link_by_idx(int idx) {
 
 
 static void _delete_link(struct vnet_link * link){
-    unsigned long flags;
+    unsigned long flags = 0;
 
     link->sock->ops->release(link->sock);
 
-    spin_lock_irqsave(&(vnet_brg_s.lock), flags);
+    palacios_spinlock_lock_irqsave(&(vnet_brg_s.lock), flags);
     list_del(&(link->node));
     vnet_htable_remove(vnet_brg_s.ip2link, (addr_t)&(link->dst_ip), 0);
     vnet_brg_s.num_links --;
-    spin_unlock_irqrestore(&(vnet_brg_s.lock), flags);
+    palacios_spinlock_unlock_irqrestore(&(vnet_brg_s.lock), flags);
 
     INFO("VNET Bridge: Link deleted, ip 0x%x, port: %d, idx: %d\n", 
           link->dst_ip, 
@@ -122,7 +129,7 @@ void vnet_brg_delete_link(uint32_t idx){
 }
 
 static void deinit_links_list(void){
-    struct vnet_link * link, * tmp_link;
+    struct vnet_link * link = NULL, * tmp_link = NULL;
 
     list_for_each_entry_safe(link, tmp_link, &(vnet_brg_s.link_list), node) {
        _delete_link(link);
@@ -152,23 +159,37 @@ static uint32_t _create_link(struct vnet_link * link) {
        return -1;
     }
 
+    if (link->sock_proto == UDP) { 
+       // no UDP checksumming
+       lock_sock(link->sock->sk);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0)
+       link->sock->sk->sk_no_check = 1;
+#else
+       link->sock->sk->sk_no_check_tx = 1;
+       link->sock->sk->sk_no_check_rx = 1;
+#endif
+       release_sock(link->sock->sk);
+    }
+
     memset(&link->sock_addr, 0, sizeof(struct sockaddr));
 
     link->sock_addr.sin_family = AF_INET;
     link->sock_addr.sin_addr.s_addr = link->dst_ip;
     link->sock_addr.sin_port = htons(link->dst_port);
 
-    if ((err = link->sock->ops->connect(link->sock, (struct sockaddr *)&(link->sock_addr), sizeof(struct sockaddr), 0) < 0)) {
+
+    if ((err = link->sock->ops->connect(link->sock, (struct sockaddr *)&(link->sock_addr), sizeof(struct sockaddr), 0)) < 0) {
        WARNING("Could not connect to remote VNET Server, error %d\n", err);
        return -1;
     }
 
-    spin_lock_irqsave(&(vnet_brg_s.lock), flags);
+
+    palacios_spinlock_lock_irqsave(&(vnet_brg_s.lock), flags);
     list_add(&(link->node), &(vnet_brg_s.link_list));
     vnet_brg_s.num_links ++;
     link->idx = ++ vnet_brg_s.link_idx;
     vnet_htable_insert(vnet_brg_s.ip2link, (addr_t)&(link->dst_ip), (addr_t)link);
-    spin_unlock_irqrestore(&(vnet_brg_s.lock), flags);
+    palacios_spinlock_unlock_irqrestore(&(vnet_brg_s.lock), flags);
 
     INFO("VNET Bridge: Link created, ip 0x%x, port: %d, idx: %d, link: %p, protocol: %s\n", 
           link->dst_ip, 
@@ -237,13 +258,17 @@ _udp_send(struct socket * sock,
     iov.iov_base = buf;
     iov.iov_len = len;
 
-    msg.msg_flags = 0;
+    msg.msg_flags = MSG_NOSIGNAL;
     msg.msg_name = addr;
     msg.msg_namelen = sizeof(struct sockaddr_in);
     msg.msg_control = NULL;
     msg.msg_controllen = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
     msg.msg_iov = &iov;
     msg.msg_iovlen = 1;
+#else
+    iov_iter_init(&(msg.msg_iter),WRITE,&iov,1,0);
+#endif
     msg.msg_control = NULL;
 
     oldfs = get_fs();
@@ -277,8 +302,12 @@ _udp_recv(struct socket * sock,
     msg.msg_namelen = sizeof(struct sockaddr_in);
     msg.msg_control = NULL;
     msg.msg_controllen = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0)
     msg.msg_iov = &iov;
     msg.msg_iovlen = 1;
+#else
+    iov_iter_init(&(msg.msg_iter),READ,&iov,1,0);
+#endif
     msg.msg_control = NULL;
     
     oldfs = get_fs();
@@ -296,7 +325,9 @@ send_to_palacios(unsigned char * buf,
                 int len,
                 int link_id){
     struct v3_vnet_pkt pkt;
+    memset(&pkt,0,sizeof(struct v3_vnet_pkt));
     pkt.size = len;
+    pkt.dst_type = LINK_NOSET;
     pkt.src_type = LINK_EDGE;
     pkt.src_id = link_id;
     memcpy(pkt.header, buf, ETHERNET_HEADER_LEN);
@@ -321,7 +352,7 @@ static int
 bridge_send_pkt(struct v3_vm_info * vm, 
                struct v3_vnet_pkt * pkt, 
                void * private_data) {
-    struct vnet_link * link;
+    struct vnet_link * link = NULL;
 
     if(net_debug >= 2){
        DEBUG("VNET Lnx Host Bridge: packet received from VNET Core ... pkt size: %d, link: %d\n",
@@ -382,6 +413,18 @@ static int init_vnet_serv(void) {
        return -1;
     }
 
+    if (vnet_brg_s.serv_proto == UDP) { 
+       // No UDP checksumming is done
+       lock_sock(vnet_brg_s.serv_sock->sk);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0)
+       vnet_brg_s.serv_sock->sk->sk_no_check = 1;
+#else
+       vnet_brg_s.serv_sock->sk->sk_no_check_tx = 1;
+       vnet_brg_s.serv_sock->sk->sk_no_check_rx = 1;
+#endif
+       release_sock(vnet_brg_s.serv_sock->sk);
+    }
+
     memset(&vnet_brg_s.serv_addr, 0, sizeof(struct sockaddr));
 
     vnet_brg_s.serv_addr.sin_family = AF_INET;
@@ -402,6 +445,8 @@ static int init_vnet_serv(void) {
        }
     }
 
+
+
     return 0;
 }
 
@@ -410,6 +455,7 @@ static int _udp_server(void * arg) {
     struct sockaddr_in pkt_addr;
     struct vnet_link * link = NULL;
     int len;
+    uint64_t noprogress_count;
 
     INFO("Palacios VNET Bridge: UDP receiving server ..... \n");
 
@@ -420,6 +466,8 @@ static int _udp_server(void * arg) {
        return -1;
     }
 
+    
+    noprogress_count=0;
 
     while (!kthread_should_stop()) {
 
@@ -434,10 +482,32 @@ static int _udp_server(void * arg) {
        // If it would have blocked, we have no packet, and so
        // we will give other threads on this core a chance
        if (len==-EAGAIN || len==-EWOULDBLOCK || len==-EINTR) { 
-           palacios_yield_cpu_timed(VNET_YIELD_TIME_USEC);
+
+           // avoid rollover in the counter out of paranoia
+           if (! ((noprogress_count + 1) < noprogress_count)) { 
+               noprogress_count++;
+           }
+           
+           // adaptively select yielding strategy depending on
+           // whether we are making progress
+           if ((!VNET_ADAPTIVE_BRIDGE) || (noprogress_count < VNET_NOPROGRESS_LIMIT)) { 
+               // Likely making progress, do fast yield so we 
+               // come back immediately if there is no other action
+               palacios_yield_cpu();
+           } else {
+               // Likely not making progress, do potentially slow
+               // yield - we won't come back for until VNET_YIELD_TIME_USEC has passed
+               palacios_sleep_cpu(VNET_YIELD_TIME_USEC);
+           }
+
            continue;
        }
        
+
+       // Something interesting has happened, therefore progress!
+       noprogress_count=0;
+           
+
        if(len < 0) {
            WARNING("Receive error: Could not get packet, error %d\n", len);
            continue;
@@ -504,7 +574,7 @@ int vnet_bridge_init(void) {
     memset(&vnet_brg_s, 0, sizeof(struct vnet_brg_state));
 
     INIT_LIST_HEAD(&(vnet_brg_s.link_list));
-    spin_lock_init(&(vnet_brg_s.lock));
+    palacios_spinlock_init(&(vnet_brg_s.lock));
 
     vnet_brg_s.serv_proto = UDP;
 
@@ -558,6 +628,8 @@ void vnet_bridge_deinit(void){
 
     vnet_brg_s.status = 0;
 
+    palacios_spinlock_deinit(&(vnet_brg_s.lock));
+
     INFO("VNET LNX Bridge Deinit Finished\n");
 }