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.


add missed file
[palacios.git] / linux_module / palacios-vnet-brg.c
diff --git a/linux_module/palacios-vnet-brg.c b/linux_module/palacios-vnet-brg.c
new file mode 100644 (file)
index 0000000..e87d422
--- /dev/null
@@ -0,0 +1,520 @@
+/* 
+   Palacios VNET Host Bridge
+   (c) Lei Xia, 2010
+ */
+#include <linux/spinlock.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#include <linux/inet.h>
+#include <linux/kthread.h>
+
+#include <linux/netdevice.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/net.h>
+#include <linux/string.h>
+#include <linux/preempt.h>
+#include <linux/sched.h>
+#include <asm/msr.h>
+
+#include <vnet/vnet.h>
+#include <vnet/vnet_hashtable.h>
+#include "palacios-vnet.h"
+
+#define VNET_SERVER_PORT 9000
+
+struct vnet_link {
+    uint32_t dst_ip;
+    uint16_t dst_port;
+    
+    struct socket * sock;
+    struct sockaddr_in sock_addr;
+    vnet_brg_proto_t sock_proto;
+
+    struct nic_statistics stats;
+
+    uint32_t idx;
+
+    struct list_head node;
+};
+
+
+struct vnet_brg_state {
+    uint8_t status;
+
+    uint32_t num_links;
+    uint32_t link_idx;
+    struct list_head link_list;
+    struct hashtable *ip2link;
+
+    spinlock_t lock;
+
+    struct socket * serv_sock;
+    struct sockaddr_in serv_addr;
+    vnet_brg_proto_t serv_proto;
+       
+    struct task_struct * serv_thread;
+
+    void * brg_data; /* private data from vnet_core */
+
+    struct vnet_brg_stats stats;
+};
+
+
+static struct vnet_brg_state vnet_brg_s;
+
+
+int vnet_brg_stats(struct vnet_brg_stats * stats){
+    memcpy(stats, &(vnet_brg_s.stats), sizeof(*stats));
+
+    return 0;
+}
+
+static inline struct vnet_link * _link_by_ip(uint32_t ip) {
+    return (struct vnet_link *)vnet_htable_search(vnet_brg_s.ip2link, (addr_t)&ip);
+}
+
+static inline struct vnet_link * _link_by_idx(int idx) {
+    struct vnet_link * link = NULL;
+
+    list_for_each_entry(link, &(vnet_brg_s.link_list), node) {
+               
+       if (link->idx == idx) {
+           return link;
+       }
+    }
+    return NULL;
+}
+
+
+static void _delete_link(struct vnet_link * link){
+    unsigned long flags;
+
+    link->sock->ops->release(link->sock);
+
+    spin_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);
+
+    printk("VNET Bridge: Link deleted, ip 0x%x, port: %d, idx: %d\n", 
+          link->dst_ip, 
+          link->dst_port, 
+          link->idx);
+
+    kfree(link);
+    link = NULL;
+}
+
+void vnet_brg_delete_link(uint32_t idx){
+    struct vnet_link * link = _link_by_idx(idx);
+
+    if(link){
+       _delete_link(link);
+    }
+}
+
+static void deinit_links_list(void){
+    struct vnet_link * link;
+
+    list_for_each_entry(link, &(vnet_brg_s.link_list), node) {
+       _delete_link(link);
+    }
+}
+
+static uint32_t _create_link(struct vnet_link * link) {
+    int err;
+    unsigned long flags;
+    int protocol;
+
+    switch(link->sock_proto){
+       case UDP:
+           protocol = IPPROTO_UDP;
+           break;
+       case TCP:
+           protocol = IPPROTO_TCP;
+           break;
+
+       default:
+           printk("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);
+       return -1;
+    }
+
+    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);
+       return -1;
+    }
+
+    spin_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);
+
+    printk("VNET Bridge: Link created, ip 0x%x, port: %d, idx: %d, link: %p, protocol: %s\n", 
+          link->dst_ip, 
+          link->dst_port, 
+          link->idx, 
+          link,
+          ((link->sock_proto==UDP)?"UDP":"TCP"));
+
+    return link->idx;
+}
+
+
+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);
+     if (!new_link) {
+       return -1;
+     }
+     memset(new_link, 0, sizeof(struct vnet_link));
+
+     new_link->dst_ip = ip;
+     new_link->dst_port = port;
+     new_link->sock_proto = proto;
+
+     idx = _create_link(new_link);
+     if (idx < 0) {
+       printk("Could not create link\n");
+       kfree(new_link);
+       return -1;
+     }
+
+     return idx;
+}
+
+
+int vnet_brg_link_stats(uint32_t link_idx, struct nic_statistics * stats){
+     struct vnet_link * link;
+
+     link = _link_by_idx(link_idx);
+     if(!link){
+        return -1;
+     }
+
+     memcpy(stats, &(link->stats), sizeof(*stats));
+
+     return 0;
+}
+     
+
+static int 
+_udp_send(struct socket * sock, 
+        struct sockaddr_in * addr,
+        unsigned char * buf,  int len) {
+    struct msghdr msg;
+    struct iovec iov;
+    mm_segment_t oldfs;
+    int size = 0;
+
+         
+    if (sock->sk == NULL) {
+       return 0;
+    }
+
+    iov.iov_base = buf;
+    iov.iov_len = len;
+
+    msg.msg_flags = 0;
+    msg.msg_name = addr;
+    msg.msg_namelen = sizeof(struct sockaddr_in);
+    msg.msg_control = NULL;
+    msg.msg_controllen = 0;
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+    msg.msg_control = NULL;
+
+    oldfs = get_fs();
+    set_fs(KERNEL_DS);
+    size = sock_sendmsg(sock, &msg, len);
+    set_fs(oldfs);
+
+    return size;
+}
+
+
+
+static int 
+_udp_recv(struct socket * sock, 
+        struct sockaddr_in * addr,
+        unsigned char * buf, int len) {
+    struct msghdr msg;
+    struct iovec iov;
+    mm_segment_t oldfs;
+    int size = 0;
+    
+    if (sock->sk == NULL) {
+       return 0;
+    }
+
+    iov.iov_base = buf;
+    iov.iov_len = len;
+    
+    msg.msg_flags = 0;
+    msg.msg_name = addr;
+    msg.msg_namelen = sizeof(struct sockaddr_in);
+    msg.msg_control = NULL;
+    msg.msg_controllen = 0;
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+    msg.msg_control = NULL;
+    
+    oldfs = get_fs();
+    set_fs(KERNEL_DS);
+    size = sock_recvmsg(sock, &msg, len, msg.msg_flags);
+       
+    set_fs(oldfs);
+    
+    return size;
+}
+
+/* send packets to VNET core */
+static int 
+send_to_palacios(unsigned char * buf, 
+                int len,
+                int link_id){
+    struct v3_vnet_pkt pkt;
+    pkt.size = len;
+    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", 
+                       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);
+       }
+    }
+
+    vnet_brg_s.stats.pkt_to_vmm ++;
+
+    return v3_vnet_send_pkt(&pkt, NULL, 1);
+}
+
+
+/* send packet to extern network */
+static int 
+bridge_send_pkt(struct v3_vm_info * vm, 
+               struct v3_vnet_pkt * pkt, 
+               void * private_data) {
+    struct vnet_link * link;
+
+    if(net_debug >= 2){
+       printk("VNET Lnx Host Bridge: packet received from VNET Core ... pkt size: %d, link: %d\n",
+                       pkt->size,
+                       pkt->dst_id);
+       if(net_debug >= 4){
+           print_hex_dump(NULL, "pkt_data: ", 0, 20, 20, pkt->data, pkt->size, 0);
+       }
+    }
+
+    vnet_brg_s.stats.pkt_from_vmm ++;
+
+    link = _link_by_idx(pkt->dst_id);
+    if (link != NULL) {
+       switch(link->sock_proto){
+           case UDP:
+               _udp_send(link->sock, &(link->sock_addr), pkt->data, pkt->size);
+               vnet_brg_s.stats.pkt_to_phy ++;
+               break;
+           case TCP:
+               vnet_brg_s.stats.pkt_to_phy ++;
+               break;  
+
+           default:
+               printk("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);
+       vnet_brg_s.stats.pkt_drop_vmm ++;
+    }
+
+    return 0;
+}
+
+
+static int init_vnet_serv(void) {
+    int protocol;
+    int err;
+
+    switch(vnet_brg_s.serv_proto){
+       case UDP:
+           protocol = IPPROTO_UDP;
+           break;
+       case TCP:
+           protocol = IPPROTO_TCP;
+           break;
+
+       default:
+           printk("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);
+       return -1;
+    }
+
+    memset(&vnet_brg_s.serv_addr, 0, sizeof(struct sockaddr));
+
+    vnet_brg_s.serv_addr.sin_family = AF_INET;
+    vnet_brg_s.serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+    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);
+       return -1;
+    }
+
+    printk("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);
+           return -1;
+       }
+    }
+
+    return 0;
+}
+
+static int _udp_server(void * arg) {
+    unsigned char * pkt;
+    struct sockaddr_in pkt_addr;
+    struct vnet_link * link = NULL;
+    int len;
+
+    printk("Palacios VNET Bridge: UDP receiving server ..... \n");
+
+    pkt = kmalloc(MAX_PACKET_LEN, GFP_KERNEL);
+    while (!kthread_should_stop()) {
+       
+       len = _udp_recv(vnet_brg_s.serv_sock, &pkt_addr, pkt, MAX_PACKET_LEN); 
+       if(len < 0) {
+           printk("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");
+           vnet_brg_s.stats.pkt_drop_phy ++;
+           continue;
+       }
+       
+       vnet_brg_s.stats.pkt_from_phy ++;
+       link->stats.rx_bytes += len;
+       link->stats.rx_pkts ++;
+
+       send_to_palacios(pkt, len, link->idx);
+    }
+
+    kfree(pkt);
+
+    return 0;
+}
+
+
+static int _rx_server(void * arg) {
+    
+    if(vnet_brg_s.serv_proto == UDP){
+       _udp_server(NULL);
+    }else if(vnet_brg_s.serv_proto == TCP) {
+       //accept new connection
+       //use select to receive pkt from physical network
+       //or create new kthread to handle each connection?
+    }else {
+       printk ("VNET Server: Unsupported Protocol\n");
+       return -1;
+    }
+
+    return 0;
+}
+
+static inline unsigned int hash_fn(addr_t hdr_ptr) {    
+    return vnet_hash_buffer((uint8_t *)hdr_ptr, sizeof(uint32_t));
+}
+
+static inline int hash_eq(addr_t key1, addr_t key2) {  
+    return (memcmp((uint8_t *)key1, (uint8_t *)key2, sizeof(uint32_t)) == 0);
+}
+
+
+int vnet_bridge_init(void) {
+    struct v3_vnet_bridge_ops bridge_ops;
+
+    if(vnet_brg_s.status != 0) {
+       return -1;
+    }  
+    vnet_brg_s.status = 1;     
+       
+    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));
+
+    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");
+       return -1;
+    }
+       
+    if(init_vnet_serv() < 0){
+       printk("Failure to initiate VNET server\n");
+       return -1;
+    }
+
+    vnet_brg_s.serv_thread = kthread_run(_rx_server, NULL, "vnet-server");
+
+    bridge_ops.input = bridge_send_pkt;
+    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");
+    }
+
+    printk("VNET Linux Bridge initiated\n");
+
+    return 0;
+}
+
+
+void vnet_bridge_deinit(void){
+
+    v3_vnet_del_bridge(HOST_LNX_BRIDGE);
+
+    kthread_stop(vnet_brg_s.serv_thread);
+    vnet_brg_s.serv_sock->ops->release(vnet_brg_s.serv_sock);
+
+    deinit_links_list();
+
+    vnet_free_htable(vnet_brg_s.ip2link, 0, 0);
+
+    vnet_brg_s.status = 0;
+}
+
+