X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=blobdiff_plain;f=linux_module%2Fpalacios-vnet-brg.c;h=abf4142dcd9dde14452275b96dd38adf1536d3a0;hp=7a605c7d16d3ac46c35d9ba9efe266494b3fc542;hb=c8b23e99efde3aa5a2c26d1b8e9bc7dc914e6113;hpb=020108512c01b113a5e8cca88a8facdc5ba5488a diff --git a/linux_module/palacios-vnet-brg.c b/linux_module/palacios-vnet-brg.c index 7a605c7..abf4142 100644 --- a/linux_module/palacios-vnet-brg.c +++ b/linux_module/palacios-vnet-brg.c @@ -19,12 +19,23 @@ #include #include +#include +#include +#include + #include #include #include "palacios-vnet.h" +#include "palacios.h" + + #define VNET_SERVER_PORT 9000 +#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; uint16_t dst_port; @@ -90,22 +101,22 @@ 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); - printk("VNET Bridge: Link deleted, ip 0x%x, port: %d, idx: %d\n", + INFO("VNET Bridge: Link deleted, ip 0x%x, port: %d, idx: %d\n", link->dst_ip, link->dst_port, link->idx); - kfree(link); + palacios_free(link); link = NULL; } @@ -118,9 +129,9 @@ void vnet_brg_delete_link(uint32_t idx){ } static void deinit_links_list(void){ - struct vnet_link * link; + struct vnet_link * link = NULL, * tmp_link = NULL; - list_for_each_entry(link, &(vnet_brg_s.link_list), node) { + list_for_each_entry_safe(link, tmp_link, &(vnet_brg_s.link_list), node) { _delete_link(link); } } @@ -139,34 +150,48 @@ static uint32_t _create_link(struct vnet_link * link) { break; default: - printk("Unsupported VNET Server Protocol\n"); + WARNING("Unsupported VNET Server Protocol\n"); return -1; } if ((err = sock_create(AF_INET, SOCK_DGRAM, protocol, &link->sock)) < 0) { - printk("Could not create socket for VNET Link, error %d\n", err); + WARNING("Could not create socket for VNET Link, error %d\n", err); 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)) { - printk("Could not connect to remote VNET Server, error %d\n", err); + + 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); - printk("VNET Bridge: Link created, ip 0x%x, port: %d, idx: %d, link: %p, protocol: %s\n", + INFO("VNET Bridge: Link created, ip 0x%x, port: %d, idx: %d, link: %p, protocol: %s\n", link->dst_ip, link->dst_port, link->idx, @@ -181,7 +206,7 @@ uint32_t vnet_brg_add_link(uint32_t ip, uint16_t port, vnet_brg_proto_t proto){ struct vnet_link * new_link = NULL; uint32_t idx; - new_link = kmalloc(sizeof(struct vnet_link), GFP_KERNEL); + new_link = palacios_alloc(sizeof(struct vnet_link)); if (!new_link) { return -1; } @@ -193,8 +218,8 @@ uint32_t vnet_brg_add_link(uint32_t ip, uint16_t port, vnet_brg_proto_t proto){ idx = _create_link(new_link); if (idx < 0) { - printk("Could not create link\n"); - kfree(new_link); + WARNING("Could not create link\n"); + palacios_free(new_link); return -1; } @@ -233,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(); @@ -254,8 +283,8 @@ _udp_send(struct socket * sock, static int _udp_recv(struct socket * sock, - struct sockaddr_in * addr, - unsigned char * buf, int len) { + struct sockaddr_in * addr, + unsigned char * buf, int len, int nonblocking) { struct msghdr msg; struct iovec iov; mm_segment_t oldfs; @@ -268,13 +297,17 @@ _udp_recv(struct socket * sock, iov.iov_base = buf; iov.iov_len = len; - msg.msg_flags = 0; + msg.msg_flags = MSG_NOSIGNAL | (nonblocking ? MSG_DONTWAIT : 0); 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),READ,&iov,1,0); +#endif msg.msg_control = NULL; oldfs = get_fs(); @@ -292,14 +325,16 @@ 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); pkt.data = buf; if(net_debug >= 2){ - printk("VNET Lnx Bridge: send pkt to VNET core (size: %d, src_id: %d, src_type: %d)\n", + DEBUG("VNET Lnx Bridge: send pkt to VNET core (size: %d, src_id: %d, src_type: %d)\n", pkt.size, pkt.src_id, pkt.src_type); if(net_debug >= 4){ print_hex_dump(NULL, "pkt_data: ", 0, 20, 20, pkt.data, pkt.size, 0); @@ -317,10 +352,10 @@ 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){ - printk("VNET Lnx Host Bridge: packet received from VNET Core ... pkt size: %d, link: %d\n", + DEBUG("VNET Lnx Host Bridge: packet received from VNET Core ... pkt size: %d, link: %d\n", pkt->size, pkt->dst_id); if(net_debug >= 4){ @@ -342,13 +377,13 @@ bridge_send_pkt(struct v3_vm_info * vm, break; default: - printk("VNET Server: Invalid Link Protocol\n"); + WARNING("VNET Server: Invalid Link Protocol\n"); vnet_brg_s.stats.pkt_drop_vmm ++; } link->stats.tx_bytes += pkt->size; link->stats.tx_pkts ++; } else { - printk("VNET Bridge Linux Host: wrong dst link, idx: %d, discards the packet\n", pkt->dst_id); + INFO("VNET Bridge Linux Host: wrong dst link, idx: %d, discarding the packet\n", pkt->dst_id); vnet_brg_s.stats.pkt_drop_vmm ++; } @@ -369,15 +404,27 @@ static int init_vnet_serv(void) { break; default: - printk("Unsupported VNET Server Protocol\n"); + WARNING("Unsupported VNET Server Protocol\n"); return -1; } if ((err = sock_create(AF_INET, SOCK_DGRAM, protocol, &vnet_brg_s.serv_sock)) < 0) { - printk("Could not create VNET server socket, error: %d\n", err); + WARNING("Could not create VNET server socket, error: %d\n", err); 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; @@ -385,19 +432,21 @@ static int init_vnet_serv(void) { vnet_brg_s.serv_addr.sin_port = htons(VNET_SERVER_PORT); if ((err = vnet_brg_s.serv_sock->ops->bind(vnet_brg_s.serv_sock, (struct sockaddr *)&(vnet_brg_s.serv_addr), sizeof(struct sockaddr))) < 0) { - printk("Could not bind VNET server socket to port %d, error: %d\n", VNET_SERVER_PORT, err); + WARNING("Could not bind VNET server socket to port %d, error: %d\n", VNET_SERVER_PORT, err); return -1; } - printk("VNET server bind to port: %d\n", VNET_SERVER_PORT); + INFO("VNET server bind to port: %d\n", VNET_SERVER_PORT); if(vnet_brg_s.serv_proto == TCP){ if((err = vnet_brg_s.serv_sock->ops->listen(vnet_brg_s.serv_sock, 32)) < 0){ - printk("VNET Server error listening on port %d, error %d\n", VNET_SERVER_PORT, err); + WARNING("VNET Server error listening on port %d, error %d\n", VNET_SERVER_PORT, err); return -1; } } + + return 0; } @@ -406,21 +455,68 @@ 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"); + + pkt = palacios_alloc(MAX_PACKET_LEN); + + if (!pkt) { + ERROR("Unable to allocate packet in VNET UDP Server\n"); + return -1; + } - printk("Palacios VNET Bridge: UDP receiving server ..... \n"); + + noprogress_count=0; - pkt = kmalloc(MAX_PACKET_LEN, GFP_KERNEL); while (!kthread_should_stop()) { + + // This is a NONBLOCKING receive + // If we block here, we will never detect that this thread + // is being signaled to stop, plus we might go uninterrupted on this core + // blocking out access to other threads - leave this NONBLOCKING + // unless you know what you are doing + len = _udp_recv(vnet_brg_s.serv_sock, &pkt_addr, pkt, MAX_PACKET_LEN, 1); + + + // 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) { + + // 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; + } - len = _udp_recv(vnet_brg_s.serv_sock, &pkt_addr, pkt, MAX_PACKET_LEN); + + // Something interesting has happened, therefore progress! + noprogress_count=0; + + if(len < 0) { - printk("Receive error: Could not get packet, error %d\n", len); + WARNING("Receive error: Could not get packet, error %d\n", len); continue; } link = _link_by_ip(pkt_addr.sin_addr.s_addr); + if (link == NULL){ - printk("VNET Server: No VNET Link match the src IP\n"); + WARNING("VNET Server: No VNET Link matches the src IP\n"); vnet_brg_s.stats.pkt_drop_phy ++; continue; } @@ -432,7 +528,9 @@ static int _udp_server(void * arg) { send_to_palacios(pkt, len, link->idx); } - kfree(pkt); + INFO("VNET Server: UDP thread exiting\n"); + + palacios_free(pkt); return 0; } @@ -446,8 +544,10 @@ static int _rx_server(void * arg) { //accept new connection //use select to receive pkt from physical network //or create new kthread to handle each connection? + WARNING("VNET Server: TCP is not currently supported\n"); + return -1; }else { - printk ("VNET Server: Unsupported Protocol\n"); + WARNING ("VNET Server: Unsupported Protocol\n"); return -1; } @@ -474,18 +574,18 @@ 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; vnet_brg_s.ip2link = vnet_create_htable(10, hash_fn, hash_eq); if(vnet_brg_s.ip2link == NULL){ - printk("Failure to initiate VNET link hashtable\n"); + WARNING("Failure to initiate VNET link hashtable\n"); return -1; } if(init_vnet_serv() < 0){ - printk("Failure to initiate VNET server\n"); + WARNING("Failure to initiate VNET server\n"); return -1; } @@ -495,10 +595,10 @@ int vnet_bridge_init(void) { bridge_ops.poll = NULL; if( v3_vnet_add_bridge(NULL, &bridge_ops, HOST_LNX_BRIDGE, NULL) < 0){ - printk("VNET LNX Bridge: Fails to register bridge to VNET core"); + WARNING("VNET LNX Bridge: Fails to register bridge to VNET core"); } - printk("VNET Linux Bridge initiated\n"); + INFO("VNET Linux Bridge initiated\n"); return 0; } @@ -506,16 +606,31 @@ int vnet_bridge_init(void) { void vnet_bridge_deinit(void){ + INFO("VNET LNX Bridge Deinit Started\n"); + v3_vnet_del_bridge(HOST_LNX_BRIDGE); + //DEBUG("Stopping bridge service thread\n"); + kthread_stop(vnet_brg_s.serv_thread); + + //DEBUG("Releasing bridee service socket\n"); + vnet_brg_s.serv_sock->ops->release(vnet_brg_s.serv_sock); + //DEBUG("Deiniting bridge links\n"); + deinit_links_list(); + //DEBUG("Freeing bridge hash tables\n"); + vnet_free_htable(vnet_brg_s.ip2link, 0, 0); vnet_brg_s.status = 0; + + palacios_spinlock_deinit(&(vnet_brg_s.lock)); + + INFO("VNET LNX Bridge Deinit Finished\n"); }