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 VNET bridge for Linux Host
Lei Xia [Tue, 9 Nov 2010 21:35:29 +0000 (15:35 -0600)]
palacios/src/devices/lnx_vnet_brg.c [new file with mode: 0644]

diff --git a/palacios/src/devices/lnx_vnet_brg.c b/palacios/src/devices/lnx_vnet_brg.c
new file mode 100644 (file)
index 0000000..366dc46
--- /dev/null
@@ -0,0 +1,255 @@
+/* 
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National 
+ * Science Foundation and the Department of Energy.  
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico.  You can find out more at 
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2010, Lei Xia <lxia@cs.northwestern.edu>
+ * Copyright (c) 2010, The V3VEE Project <http://www.v3vee.org> 
+ * All rights reserved.
+ *
+ * Author: Lei Xia <lxia@cs.northwestern.edu>
+ *
+ * This is free software.  You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+ /* VNET backend bridge for Linux host
+ */
+#include <palacios/vmm.h>
+#include <palacios/vmm_dev_mgr.h>
+#include <palacios/vm_guest_mem.h>
+#include <palacios/vmm_vnet.h>
+#include <palacios/vmm_sprintf.h>
+#include <palacios/vmm_socket.h>
+
+#ifndef CONFIG_DEBUG_VNET_LNX_BRIGE
+#undef PrintDebug
+#define PrintDebug(fmt, args...)
+#endif
+
+typedef enum {SOCK_UDP, SOCK_TCP, SOCK_OTHER} sock_type_t; 
+
+const uint16_t vnet_udp_port = 20003;
+
+struct vnet_link {
+    uint32_t dst_ip;
+    uint16_t dst_port;
+    
+    int socket;
+    sock_type_t type;
+    int link_idx;
+
+    struct list_head node;
+};
+
+struct vnet_brg_state {
+    uint32_t num_links; 
+
+    struct list_head link_list;
+
+    int serv_sock;
+    sock_type_t serv_sock_type;
+    int serv_port;
+    
+    /* The thread recving pkts from sockets. */
+    int serv_thread;
+
+    v3_lock_t lock;
+
+    unsigned long pkt_sent, pkt_recv, pkt_drop;
+};
+
+static struct vnet_brg_state lnxbrg_state;
+
+static int vnet_lnxbrg_reset(struct vnet_brg_state * state) {
+    memset(state, 0, sizeof(struct vnet_brg_state));
+
+    state->num_links = 0;
+    state->serv_sock = -1;
+    state->serv_port = vnet_udp_port;
+    state->serv_sock_type = SOCK_UDP;
+
+    if(v3_lock_init(&(state->lock)) < 0){
+       PrintError("VNET Linux Bridge: error to initiate vnet lock\n");
+    }
+
+    return 0;
+}
+
+
+struct vnet_link * link_by_ip(struct vnet_brg_state * state, uint32_t ip) {
+    struct vnet_link * link = NULL;
+
+    list_for_each_entry(link, &(state->link_list), node) {
+       if (link->dst_ip == ip) {
+           return link;
+       }
+    }
+
+    return NULL;
+}
+
+struct vnet_link * link_by_idx(struct vnet_brg_state * state, int idx) {
+    struct vnet_link * link = NULL;
+
+    list_for_each_entry(link, &(state->link_list), node) {
+       if (link->link_idx == idx) {
+           return link;
+       }
+    }
+    return NULL;
+}
+
+static int
+udp_send(int sockid, uint32_t dst_ip, 
+                       uint16_t dst_port, uchar_t * pkt, 
+                       uint16_t len){
+    if(dst_ip > 0 && dst_port > 0){
+       return V3_SendTo_IP(sockid, dst_ip, dst_port, pkt, len);
+    }
+
+    return V3_Send(sockid, pkt, len);
+}
+
+
+static int 
+udp_recv(int sockid, uint32_t * src_ip, 
+                       uint16_t * src_port, uchar_t *buf, 
+                       uint16_t len) {
+
+    return V3_Recv(sockid, buf, len);
+}
+
+
+
+static int 
+brg_send(struct vnet_brg_state * state,
+                       struct v3_vm_info * vm,  
+                       struct v3_vnet_pkt * vnet_pkt, 
+                       void * private_data){
+    struct vnet_link * link = NULL;
+       
+    #ifdef CONFIG_DEBUG_VNET_LNX_BRIGE
+    {
+       PrintDebug("vnet_brg_send... pkt size: %d, link: %d, struct len: %d\n",
+                       vnet_pkt->size,
+                       vnet_pkt->dst_id,
+                       sizeof(struct v3_vnet_pkt));
+    }
+    #endif
+
+    state->pkt_recv ++;
+    link = link_by_idx(vnet_pkt->dst_id);
+    if (link != NULL) {
+       if(link->type == SOCK_TCP){
+               
+       }else if(link->type == SOCK_UDP){
+           udp_send(link->socket, 0, 0, vnet_pkt->data, vnet_pkt->size);
+           state->pkt_sent ++;
+       }else {
+           PrintError("VNET Linux Bridge: wrong link type\n"); 
+           return -1;
+       }
+    } else {
+       PrintDebug("VNET Linux Bridge: wrong dst link, idx: %d, discards the packet\n", vnet_pkt->dst_id);
+       state->pkt_drop ++;
+    }
+
+    return 0;
+}
+
+
+static int init_serv(struct vnet_brg_state * state) {
+    int sock, err;
+
+    if(state->serv_sock_type == SOCK_UDP){
+       sock = V3_Create_UDP_Socket();
+       if (sock < 0) {
+           PrintError("Could not create socket, Initiate VNET server error\n");
+           return -1;
+       }
+
+       err = V3_Bind_Socket(sock, state->serv_port);
+       if(err < 0){
+           PrintError("Error to bind VNET Linux bridge receiving UDP socket\n");
+           return -1;
+       }
+       state->serv_sock = sock;
+    }
+
+    return 0;
+}
+
+static int vnet_server(void * arg) {
+    struct v3_vnet_pkt pkt;
+    struct vnet_link *link;
+    struct vnet_brg_state * state = (struct vnet_brg_state *)arg;
+    uchar_t buf[ETHERNET_MTU];
+    uint32_t ip = 0;
+    uint16_t port = 0;
+    int len;
+
+    while (1) {
+       len = udp_recv(state->serv_sock, &ip, &port, buf, ETHERNET_MTU);
+       if(len < 0) {
+           PrintError("VNET Linux Bridge: receive error\n");
+           continue;
+       }
+
+       link = link_by_ip(ip);
+       if (link != NULL) {
+           pkt.src_id= link->link_idx;
+       }
+       else { 
+           pkt.src_id= -1;
+       }
+
+       pkt.size = len;
+       pkt.src_type = LINK_EDGE;
+       memcpy(pkt.header, buf, ETHERNET_HEADER_LEN);
+       pkt.data = buf;
+       
+       #ifdef CONFIG_DEBUG_VNET_LNX_BRIGE
+       {
+           PrintDebug("VNET Linux Bridge: recv pkt size: %d, pkt src_id: %d\n", 
+                       len,  pkt.src_id);
+           v3_hexdump(buf, len, NULL, 0);
+       }
+       #endif
+
+       v3_vnet_send_pkt(&pkt, NULL);
+       
+       state->pkt_recv ++;
+    }
+
+    return 0;
+}
+
+
+static int vnet_lnxbrg_init() {
+    struct v3_vnet_bridge_ops brg_ops;
+    struct vnet_brg_state * state;
+       
+    state = (struct vnet_brg_state *)V3_Malloc(sizeof(struct vnet_brg_state));
+    V3_ASSERT(state != NULL);
+
+    vnet_lnxbrg_reset(state);
+
+    brg_ops.input = brg_send;
+
+    v3_vnet_add_bridge(NULL, &brg_ops, state);
+
+    init_serv();
+    V3_CREATE_THREAD(vnet_server, state, "VNET_LNX_BRIDGE");
+
+    PrintDebug("VNET Linux Bridge initiated\n");
+
+    return 0;
+}
+
+
+device_register("LNX_VNET_BRIDGE", vnet_lnxbrg_init)