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.


initial implementation of hookable exits
[palacios.git] / palacios / src / vnet / vnet_core.c
index 4669029..3e4dee3 100644 (file)
 #include <palacios/vmm_queue.h>
 
 #ifndef V3_CONFIG_DEBUG_VNET
-#undef Vnet_Debug
-#define Vnet_Debug(fmt, args...)
+#undef PrintDebug
+#define PrintDebug(fmt, args...)
 #endif
 
+#define VNET_YIELD_USEC 1000
+
 int net_debug = 0;
 
 struct eth_hdr {
@@ -53,7 +55,7 @@ struct vnet_dev {
        
     void * private_data;
 
-    struct list_head node;\r
+    struct list_head node;
 } __attribute__((packed));
 
 
@@ -133,15 +135,15 @@ static void print_route(struct v3_vnet_route * route){
     char str[50];
 
     mac2str(route->src_mac, str);
-    Vnet_Debug("Src Mac (%s),  src_qual (%d)\n", 
+    PrintDebug("Src Mac (%s),  src_qual (%d)\n", 
               str, route->src_mac_qual);
     mac2str(route->dst_mac, str);
-    Vnet_Debug("Dst Mac (%s),  dst_qual (%d)\n", 
+    PrintDebug("Dst Mac (%s),  dst_qual (%d)\n", 
               str, route->dst_mac_qual);
-    Vnet_Debug("Src dev id (%d), src type (%d)", 
+    PrintDebug("Src dev id (%d), src type (%d)", 
               route->src_id, 
               route->src_type);
-    Vnet_Debug("Dst dev id (%d), dst type (%d)\n", 
+    PrintDebug("Dst dev id (%d), dst type (%d)\n", 
               route->dst_id, 
               route->dst_type);
 }
@@ -149,13 +151,13 @@ static void print_route(struct v3_vnet_route * route){
 static void dump_routes(){
     struct vnet_route_info *route;
 
-    Vnet_Debug("\n========Dump routes starts ============\n");
+    PrintDebug("\n========Dump routes starts ============\n");
     list_for_each_entry(route, &(vnet_state.routes), node) {
-       Vnet_Debug("\nroute %d:\n", route->idx);
+       PrintDebug("\nroute %d:\n", route->idx);
                
        print_route(&(route->route_def));
        if (route->route_def.dst_type == LINK_INTERFACE) {
-           Vnet_Debug("dst_dev (%p), dst_dev_id (%d), dst_dev_ops(%p), dst_dev_data (%p)\n",
+           PrintDebug("dst_dev (%p), dst_dev_id (%d), dst_dev_ops(%p), dst_dev_data (%p)\n",
                route->dst_dev,
                route->dst_dev->dev_id,
                (void *)&(route->dst_dev->dev_ops),
@@ -163,7 +165,7 @@ static void dump_routes(){
        }
     }
 
-    Vnet_Debug("\n========Dump routes end ============\n");
+    PrintDebug("\n========Dump routes end ============\n");
 }
 
 #endif
@@ -213,10 +215,9 @@ static struct vnet_dev * dev_by_id(int idx) {
     struct vnet_dev * dev = NULL; 
 
     list_for_each_entry(dev, &(vnet_state.devs), node) {
-       int dev_id = dev->dev_id;
-
-       if (dev_id == idx)
+       if (dev->dev_id == idx) {
            return dev;
+       }
     }
 
     return NULL;
@@ -250,13 +251,19 @@ int v3_vnet_find_dev(uint8_t  * mac) {
 
 int v3_vnet_add_route(struct v3_vnet_route route) {
     struct vnet_route_info * new_route = NULL;
-    unsigned long flags; 
+    vnet_intr_flags_t flags; 
 
     new_route = (struct vnet_route_info *)Vnet_Malloc(sizeof(struct vnet_route_info));
+
+    if (!new_route) {
+       PrintError("Cannot allocate new route\n");
+       return -1;
+    }
+
     memset(new_route, 0, sizeof(struct vnet_route_info));
 
 #ifdef V3_CONFIG_DEBUG_VNET
-    Vnet_Debug("VNET/P Core: add_route_entry:\n");
+    PrintDebug("VNET/P Core: add_route_entry:\n");
     print_route(&route);
 #endif
     
@@ -298,12 +305,12 @@ int v3_vnet_add_route(struct v3_vnet_route route) {
 
 void v3_vnet_del_route(uint32_t route_idx){
     struct vnet_route_info * route = NULL;
-    unsigned long flags; 
+    vnet_intr_flags_t flags; 
 
     flags = vnet_lock_irqsave(vnet_state.lock);
 
     list_for_each_entry(route, &(vnet_state.routes), node) {
-       V3_Print("v3_vnet_del_route, route idx: %d\n", route->idx);
+       Vnet_Print(0, "v3_vnet_del_route, route idx: %d\n", route->idx);
        if(route->idx == route_idx){
            list_del(&(route->node));
            Vnet_Free(route);
@@ -322,12 +329,12 @@ void v3_vnet_del_route(uint32_t route_idx){
 
 /* delete all route entries with specfied src or dst device id */ 
 static void inline del_routes_by_dev(int dev_id){
-    struct vnet_route_info * route = NULL;
-    unsigned long flags; 
+    struct vnet_route_info * route, *tmp_route;
+    vnet_intr_flags_t flags; 
 
     flags = vnet_lock_irqsave(vnet_state.lock);
 
-    list_for_each_entry(route, &(vnet_state.routes), node) {
+    list_for_each_entry_safe(route, tmp_route, &(vnet_state.routes), node) {
        if((route->route_def.dst_type == LINK_INTERFACE &&
             route->route_def.dst_id == dev_id) ||
             (route->route_def.src_type == LINK_INTERFACE &&
@@ -342,6 +349,9 @@ static void inline del_routes_by_dev(int dev_id){
     vnet_unlock_irqrestore(vnet_state.lock, flags);
 }
 
+
+
+
 /* At the end allocate a route_list
  * This list will be inserted into the cache so we don't need to free it
  */
@@ -362,7 +372,7 @@ static struct route_list * match_route(const struct v3_vnet_pkt * pkt) {
 
        mac2str(hdr->src_mac, src_str);  
        mac2str(hdr->dst_mac, dst_str);
-       Vnet_Debug("VNET/P Core: match_route. pkt: SRC(%s), DEST(%s)\n", src_str, dst_str);
+       PrintDebug("VNET/P Core: match_route. pkt: SRC(%s), DEST(%s)\n", src_str, dst_str);
     }
 #endif
 
@@ -449,15 +459,21 @@ static struct route_list * match_route(const struct v3_vnet_pkt * pkt) {
        }
     }
 
-    Vnet_Debug("VNET/P Core: match_route: Matches=%d\n", num_matches);
+    PrintDebug("VNET/P Core: match_route: Matches=%d\n", num_matches);
 
-    if (num_matches == 0) {
+    if (num_matches <= 0) {
        return NULL;
     }
 
     matches = (struct route_list *)Vnet_Malloc(sizeof(struct route_list) + 
                                               (sizeof(struct vnet_route_info *) * num_matches));
 
+
+    if (!matches) {
+       PrintError("VNET/P Core: Unable to allocate matches\n");
+       return NULL;
+    }
+
     matches->num_routes = num_matches;
 
     {
@@ -470,16 +486,108 @@ static struct route_list * match_route(const struct v3_vnet_pkt * pkt) {
     return matches;
 }
 
+int v3_vnet_query_header(uint8_t src_mac[6], 
+                        uint8_t dest_mac[6],
+                        int     recv,         // 0 = send, 1=recv
+                        struct v3_vnet_header *header)
+{
+    struct route_list *routes;
+    struct vnet_route_info *r;
+    struct v3_vnet_pkt p;
+
+    p.size=14;
+    p.data=p.header;
+    memcpy(p.header,dest_mac,6);
+    memcpy(p.header+6,src_mac,6);
+    memset(p.header+12,0,2);
+
+    p.src_type = LINK_EDGE;
+    p.src_id = 0;
+
+    memcpy(header->src_mac,src_mac,6);
+    memcpy(header->dst_mac,dest_mac,6);
+
+    
+    look_into_cache(&p,&routes);
+
+    if (!routes) { 
+       routes = match_route(&p);
+       if (!routes) { 
+           PrintError("Cannot match route\n");
+           header->header_type=VNET_HEADER_NOMATCH;
+           header->header_len=0;
+           return -1;
+       } else {
+           add_route_to_cache(&p,routes);
+       }
+    }
+    
+    if (routes->num_routes<1) { 
+       PrintError("Less than one route\n");
+       header->header_type=VNET_HEADER_NOMATCH;
+       header->header_len=0;
+       return -1;
+    }
+
+    if (routes->num_routes>1) { 
+       PrintError("More than one route, building header for the first one only\n");
+    }
+
+    r=routes->routes[0];
+
+    switch (r->route_def.dst_type) {
+       case LINK_EDGE: {
+           // switch based on the link type
+           // for mac-in-udp, we would want to generate a mac, ip, and udp header
+           // direct transmission
+
+           // for now we will say we have no encapsulation
+           //
+           header->header_type=VNET_HEADER_NONE;
+           header->header_len=0;
+           header->src_mac_qual=r->route_def.src_mac_qual;
+           header->dst_mac_qual=r->route_def.dst_mac_qual;
+           
+       }
+           
+           return 0;
+           break;
+           
+
+       case LINK_INTERFACE:
+           // direct transmission
+           // let's guess that it goes to the same interface...
+           header->header_type=VNET_HEADER_NONE;
+           header->header_len=0;
+           header->src_mac_qual=r->route_def.src_mac_qual;
+           header->dst_mac_qual=r->route_def.dst_mac_qual;
+
+           return 0;
+           break;
+
+       default:
+           PrintError("Unknown destination type\n");
+           return -1;
+           break;
+
+    }
+    
+}
+
+
+
 
 int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data) {
     struct route_list * matched_routes = NULL;
-    unsigned long flags;
+    vnet_intr_flags_t flags;
     int i;
 
     int cpu = V3_Get_CPU();
+
     Vnet_Print(2, "VNET/P Core: cpu %d: pkt (size %d, src_id:%d, src_type: %d, dst_id: %d, dst_type: %d)\n",
               cpu, pkt->size, pkt->src_id, 
               pkt->src_type, pkt->dst_id, pkt->dst_type);
+
     if(net_debug >= 4){
        v3_hexdump(pkt->data, pkt->size, NULL, 0);
     }
@@ -490,15 +598,16 @@ int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data) {
     vnet_state.stats.rx_pkts++;
 
     look_into_cache(pkt, &matched_routes);
+
     if (matched_routes == NULL) {  
-       Vnet_Debug("VNET/P Core: send pkt Looking into routing table\n");
+       PrintDebug("VNET/P Core: sending pkt - matching route\n");
        
        matched_routes = match_route(pkt);
        
        if (matched_routes) {
            add_route_to_cache(pkt, matched_routes);
        } else {
-           Vnet_Debug("VNET/P Core: Could not find route for packet... discards packet\n");
+           PrintDebug("VNET/P Core: Could not find route for packet... discarding packet\n");
            vnet_unlock_irqrestore(vnet_state.lock, flags);
            return 0; /* do we return -1 here?*/
        }
@@ -506,7 +615,7 @@ int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data) {
 
     vnet_unlock_irqrestore(vnet_state.lock, flags);
 
-    Vnet_Debug("VNET/P Core: send pkt route matches %d\n", matched_routes->num_routes);
+    PrintDebug("VNET/P Core: send pkt route matches %d\n", matched_routes->num_routes);
 
     for (i = 0; i < matched_routes->num_routes; i++) {
        struct vnet_route_info * route = matched_routes->routes[i];
@@ -549,24 +658,25 @@ int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data) {
 
 
 int v3_vnet_add_dev(struct v3_vm_info * vm, uint8_t * mac, 
-                   struct v3_vnet_dev_ops *ops, int quote, int poll_state,
+                   struct v3_vnet_dev_ops * ops, int quote, int poll_state,
                    void * priv_data){
     struct vnet_dev * new_dev = NULL;
-    unsigned long flags;
+    vnet_intr_flags_t flags;
 
     new_dev = (struct vnet_dev *)Vnet_Malloc(sizeof(struct vnet_dev)); 
 
     if (new_dev == NULL) {
-       Vnet_Print(0, "Malloc fails\n");
+       Vnet_Print(0, "VNET/P Core: Unable to allocate a new device\n");
        return -1;
     }
    
     memcpy(new_dev->mac_addr, mac, 6);
     new_dev->dev_ops.input = ops->input;
+    new_dev->dev_ops.poll = ops->poll;
     new_dev->private_data = priv_data;
     new_dev->vm = vm;
     new_dev->dev_id = 0;
-    new_dev->quote = quote<VNET_MAX_QUOTE?quote:VNET_MAX_QUOTE;
+    new_dev->quote = quote<VNET_MAX_QUOTE ? quote : VNET_MAX_QUOTE;
     new_dev->poll = poll_state;
 
     flags = vnet_lock_irqsave(vnet_state.lock);
@@ -575,6 +685,12 @@ int v3_vnet_add_dev(struct v3_vm_info * vm, uint8_t * mac,
        list_add(&(new_dev->node), &(vnet_state.devs));
        new_dev->dev_id = ++ vnet_state.dev_idx;
        vnet_state.num_devs ++;
+
+       if(new_dev->poll) {
+           v3_enqueue(vnet_state.poll_devs, (addr_t)new_dev);
+       }
+    } else {
+       PrintError("VNET/P: Device with the same MAC has already been added\n");
     }
 
     vnet_unlock_irqrestore(vnet_state.lock, flags);
@@ -585,7 +701,7 @@ int v3_vnet_add_dev(struct v3_vm_info * vm, uint8_t * mac,
        return -1;
     }
 
-    Vnet_Debug("VNET/P Core: Add Device: dev_id %d\n", new_dev->dev_id);
+    PrintDebug("VNET/P Core: Add Device: dev_id %d\n", new_dev->dev_id);
 
     return new_dev->dev_id;
 }
@@ -593,7 +709,7 @@ int v3_vnet_add_dev(struct v3_vm_info * vm, uint8_t * mac,
 
 int v3_vnet_del_dev(int dev_id){
     struct vnet_dev * dev = NULL;
-    unsigned long flags;
+    vnet_intr_flags_t flags;
 
     flags = vnet_lock_irqsave(vnet_state.lock);
        
@@ -608,7 +724,7 @@ int v3_vnet_del_dev(int dev_id){
 
     Vnet_Free(dev);
 
-    Vnet_Debug("VNET/P Core: Remove Device: dev_id %d\n", dev_id);
+    PrintDebug("VNET/P Core: Removed Device: dev_id %d\n", dev_id);
 
     return 0;
 }
@@ -624,18 +740,18 @@ int v3_vnet_stat(struct vnet_stat * stats){
 }
 
 static void deinit_devices_list(){
-    struct vnet_dev * dev = NULL; 
+    struct vnet_dev * dev, * tmp; 
 
-    list_for_each_entry(dev, &(vnet_state.devs), node) {
+    list_for_each_entry_safe(dev, tmp, &(vnet_state.devs), node) {
        list_del(&(dev->node));
        Vnet_Free(dev);
     }
 }
 
 static void deinit_routes_list(){
-    struct vnet_route_info * route = NULL; 
+    struct vnet_route_info * route, * tmp; 
 
-    list_for_each_entry(route, &(vnet_state.routes), node) {
+    list_for_each_entry_safe(route, tmp, &(vnet_state.routes), node) {
        list_del(&(route->node));
        list_del(&(route->match_node));
        Vnet_Free(route);
@@ -646,7 +762,7 @@ int v3_vnet_add_bridge(struct v3_vm_info * vm,
                       struct v3_vnet_bridge_ops * ops,
                       uint8_t type,
                       void * priv_data) {
-    unsigned long flags;
+    vnet_intr_flags_t flags;
     int bridge_free = 0;
     struct vnet_brg_dev * tmp_bridge = NULL;    
     
@@ -665,7 +781,7 @@ int v3_vnet_add_bridge(struct v3_vm_info * vm,
     tmp_bridge = (struct vnet_brg_dev *)Vnet_Malloc(sizeof(struct vnet_brg_dev));
 
     if (tmp_bridge == NULL) {
-       PrintError("Malloc Fails\n");
+       PrintError("VNET/P Core: Unable to allocate new bridge\n");
        vnet_state.bridge = NULL;
        return -1;
     }
@@ -686,14 +802,14 @@ int v3_vnet_add_bridge(struct v3_vm_info * vm,
 
 
 void v3_vnet_del_bridge(uint8_t type) {
-    unsigned long flags;
+    vnet_intr_flags_t flags;
     struct vnet_brg_dev * tmp_bridge = NULL;    
     
     flags = vnet_lock_irqsave(vnet_state.lock);
        
     if (vnet_state.bridge != NULL && vnet_state.bridge->type == type) {
        tmp_bridge = vnet_state.bridge;
-       vnet_state.bridge = NULL;
+       vnet_state.bridge = NULL;
     }
        
     vnet_unlock_irqrestore(vnet_state.lock, flags);
@@ -708,35 +824,72 @@ void v3_vnet_del_bridge(uint8_t type) {
   * that runs on multiple cores 
   * or it could be running on a dedicated side core
   */
-static int vnet_tx_flush(void *args){
+static int vnet_tx_flush(void * args){
     struct vnet_dev * dev = NULL;
-    int ret;
+    int more;
+    int rc;
 
     Vnet_Print(0, "VNET/P Polling Thread Starting ....\n");
 
-    /* we need thread sleep/wakeup in Palacios */
-    while(!vnet_thread_should_stop()){
-       dev = (struct vnet_dev *)v3_dequeue(vnet_state.poll_devs);
-       if(dev != NULL){
-           if(dev->poll && dev->dev_ops.poll != NULL){
-               ret = dev->dev_ops.poll(dev->vm, dev->quote, dev->private_data);
+    // since there are multiple instances of this thread, and only
+    // one queue of pollable devices, our model here will be to synchronize
+    // on that queue, removing devices as we go, and keeping them
+    // then putting them back on the queue when we are done
+    // in this way, multiple instances of this function will never
+    // be polling the same device at the same time
 
-               if (ret < 0){
-                   PrintDebug("VNET/P: poll from device %p error!\n", dev);
-               }
+    struct v3_queue * tq = v3_create_queue();
+
+    if (!tq) { 
+       PrintError("VNET/P polling thread cannot allocate queue\n");
+       return -1;
+    }
+
+
+    while (!vnet_thread_should_stop()) {
+
+       more=0; // will indicate if any device has more work for us to do
 
-               v3_enqueue(vnet_state.poll_devs, (addr_t)dev); 
+       while ((dev = (struct vnet_dev *)v3_dequeue(vnet_state.poll_devs))) { 
+           // we are handling this device
+           v3_enqueue(tq,(addr_t)dev);
+           
+           if (dev->poll && dev->dev_ops.poll) {
+               // The device's poll function MUST NOT BLOCK
+               rc = dev->dev_ops.poll(dev->vm, dev->quote, dev->private_data);
+
+               if (rc<0) { 
+                   Vnet_Print(0, "VNET/P: poll from device %p error (ignoring) !\n", dev);
+               } else {
+                   more |= rc;  
+               }
            }
-       }else { /* no device needs to be polled */
-          /* sleep here? */
-           Vnet_Yield();
        }
+       
+       while ((dev = (struct vnet_dev *)v3_dequeue(tq))) { 
+           // now someone else can handle it
+           v3_enqueue(vnet_state.poll_devs, (addr_t)dev); 
+       }
+
+       // Yield regardless of whether we handled any devices - need
+       // to allow other threads to run
+       if (more) { 
+           // we have more to do, so we want to get back asap
+           V3_Yield();
+       } else {
+           // put ourselves briefly to sleep if we we don't have more
+           V3_Yield_Timed(VNET_YIELD_USEC);
+       }
+
     }
 
+    Vnet_Free(tq);
+    
+    Vnet_Print(0, "VNET/P Polling Thread Done.\n");
+
     return 0;
 }
 
-
 int v3_init_vnet() {
     memset(&vnet_state, 0, sizeof(vnet_state));
        
@@ -758,9 +911,9 @@ int v3_init_vnet() {
 
     vnet_state.poll_devs = v3_create_queue();
 
-    vnet_state.pkt_flush_thread = vnet_start_thread(vnet_tx_flush, NULL, "vnetd");
+    vnet_state.pkt_flush_thread = vnet_start_thread(vnet_tx_flush, NULL, "vnetd-1");
 
-    Vnet_Debug("VNET/P is initiated\n");
+    PrintDebug("VNET/P is initiated\n");
 
     return 0;
 }
@@ -768,13 +921,37 @@ int v3_init_vnet() {
 
 void v3_deinit_vnet(){
 
-    vnet_lock_deinit(&(vnet_state.lock));
+    PrintDebug("Stopping flush thread\n");
+    // This will pause until the flush thread is gone
+    vnet_thread_stop(vnet_state.pkt_flush_thread);
+    // At this point there should be no lock-holder
+
+    Vnet_Free(vnet_state.poll_devs);
+
 
-    deinit_devices_list();
+    PrintDebug("Deiniting Device List\n");
+    // close any devices we have open
+    deinit_devices_list();  
+    
+    PrintDebug("Deiniting Route List\n");
+    // remove any routes we have
     deinit_routes_list();
 
+    PrintDebug("Freeing hash table\n");
+    // remove the hash table
     vnet_free_htable(vnet_state.route_cache, 1, 1);
-    Vnet_Free(vnet_state.bridge);
+
+    
+    PrintDebug("Removing Bridge\n");
+    // remove bridge if it was added
+    if (vnet_state.bridge) { 
+       Vnet_Free(vnet_state.bridge);
+    }
+
+    PrintDebug("Deleting lock\n");
+    // eliminate the lock
+    vnet_lock_deinit(&(vnet_state.lock));
+
 }