X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fvnet%2Fvnet_core.c;h=e7b37f9d86efc337e4343633b2655e929d1b8ace;hb=a2b48dd0c4f8ccfa633139bc2b9aa4ddf59eda5c;hp=b82c905b6aa1f8954a0c025e01dc3146c39d7d61;hpb=f1fa6648dfea31fe4261c8c2d329a68613739714;p=palacios.git diff --git a/palacios/src/vnet/vnet_core.c b/palacios/src/vnet/vnet_core.c index b82c905..e7b37f9 100644 --- a/palacios/src/vnet/vnet_core.c +++ b/palacios/src/vnet/vnet_core.c @@ -10,7 +10,7 @@ * Copyright (c) 2010, Lei Xia * Copyright (c) 2009, Yuan Tang * Copyright (c) 2009, The V3VEE Project - * All rights reserved. + * All rights reserved * * Author: Lei Xia * Yuan Tang @@ -24,6 +24,8 @@ #include #include +#include + #ifndef V3_CONFIG_DEBUG_VNET #undef Vnet_Debug #define Vnet_Debug(fmt, args...) @@ -43,6 +45,12 @@ struct vnet_dev { uint8_t mac_addr[ETH_ALEN]; struct v3_vm_info * vm; struct v3_vnet_dev_ops dev_ops; + + int poll; + +#define VNET_MAX_QUOTE 64 + int quote; + void * private_data; struct list_head node; @@ -88,13 +96,6 @@ struct queue_entry{ uint32_t size_alloc; }; -#define VNET_QUEUE_SIZE 1024 -struct vnet_queue { - struct queue_entry buf[VNET_QUEUE_SIZE]; - int head, tail; - int count; - vnet_lock_t lock; -}; static struct { struct list_head routes; @@ -112,9 +113,10 @@ static struct { vnet_lock_t lock; struct vnet_stat stats; - struct vnet_thread * pkt_flush_thread; + /* device queue that are waiting to be polled */ + struct v3_queue * poll_devs; - struct vnet_queue pkt_q; + struct vnet_thread * pkt_flush_thread; struct hashtable * route_cache; } vnet_state; @@ -211,10 +213,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; @@ -301,7 +302,7 @@ void v3_vnet_del_route(uint32_t route_idx){ 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); @@ -320,12 +321,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; + struct vnet_route_info * route, *tmp_route; unsigned long 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 && @@ -469,17 +470,17 @@ static struct route_list * match_route(const struct v3_vnet_pkt * pkt) { } -int vnet_tx_one_pkt(struct v3_vnet_pkt * pkt, void * private_data) { +int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data) { struct route_list * matched_routes = NULL; unsigned long 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); + 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); + v3_hexdump(pkt->data, pkt->size, NULL, 0); } flags = vnet_lock_irqsave(vnet_state.lock); @@ -546,66 +547,8 @@ int vnet_tx_one_pkt(struct v3_vnet_pkt * pkt, void * private_data) { } -static int vnet_pkt_enqueue(struct v3_vnet_pkt * pkt){ - unsigned long flags; - struct queue_entry * entry; - struct vnet_queue * q = &(vnet_state.pkt_q); - uint16_t num_pages; - - flags = vnet_lock_irqsave(q->lock); - - if (q->count >= VNET_QUEUE_SIZE){ - Vnet_Print(1, "VNET Queue overflow!\n"); - vnet_unlock_irqrestore(q->lock, flags); - return -1; - } - - q->count ++; - entry = &(q->buf[q->tail++]); - q->tail %= VNET_QUEUE_SIZE; - - vnet_unlock_irqrestore(q->lock, flags); - - /* this is ugly, but should happen very unlikely */ - while(entry->use); - - if(entry->size_alloc < pkt->size){ - if(entry->data != NULL){ - Vnet_FreePages(Vnet_PAddr(entry->data), (entry->size_alloc / PAGE_SIZE)); - entry->data = NULL; - } - - num_pages = 1 + (pkt->size / PAGE_SIZE); - entry->data = Vnet_VAddr(Vnet_AllocPages(num_pages)); - if(entry->data == NULL){ - return -1; - } - entry->size_alloc = PAGE_SIZE * num_pages; - } - - entry->pkt.data = entry->data; - memcpy(&(entry->pkt), pkt, sizeof(struct v3_vnet_pkt)); - memcpy(entry->data, pkt->data, pkt->size); - - entry->use = 1; - - return 0; -} - - -int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data, int synchronize) { - if(synchronize){ - vnet_tx_one_pkt(pkt, NULL); - }else { - vnet_pkt_enqueue(pkt); - Vnet_Print(2, "VNET/P Core: Put pkt into Queue: pkt size %d\n", pkt->size); - } - - return 0; -} - int v3_vnet_add_dev(struct v3_vm_info * vm, uint8_t * mac, - struct v3_vnet_dev_ops *ops, + struct v3_vnet_dev_ops * ops, int quote, int poll_state, void * priv_data){ struct vnet_dev * new_dev = NULL; unsigned long flags; @@ -619,9 +562,12 @@ int v3_vnet_add_dev(struct v3_vm_info * vm, uint8_t * mac, 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 = quotepoll = poll_state; flags = vnet_lock_irqsave(vnet_state.lock); @@ -629,6 +575,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 is already there\n"); } vnet_unlock_irqrestore(vnet_state.lock, flags); @@ -678,18 +630,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); @@ -758,35 +710,30 @@ void v3_vnet_del_bridge(uint8_t type) { } -static int vnet_tx_flush(void *args){ - unsigned long flags; - struct queue_entry * entry; - struct vnet_queue * q = &(vnet_state.pkt_q); +/* can be instanieoued to multiple threads + * that runs on multiple cores + * or it could be running on a dedicated side core + */ +static int vnet_tx_flush(void * args){ + struct vnet_dev * dev = NULL; + int ret; - Vnet_Print(0, "VNET/P Handing Pkt Thread Starting ....\n"); + Vnet_Print(0, "VNET/P Polling Thread Starting ....\n"); - /* we need thread sleep/wakeup in Palacios */ while(!vnet_thread_should_stop()){ - flags = vnet_lock_irqsave(q->lock); - - if (q->count <= 0){ - vnet_unlock_irqrestore(q->lock, flags); + 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); + + if (ret < 0){ + Vnet_Print(0, "VNET/P: poll from device %p error!\n", dev); + } + } + v3_enqueue(vnet_state.poll_devs, (addr_t)dev); + }else { /* no device needs to be polled */ + /* sleep here? */ Vnet_Yield(); - }else { - q->count --; - entry = &(q->buf[q->head++]); - q->head %= VNET_QUEUE_SIZE; - - vnet_unlock_irqrestore(q->lock, flags); - - /* this is ugly, but should happen very unlikely */ - while(!entry->use); - vnet_tx_one_pkt(&(entry->pkt), NULL); - - /* asynchronizely release allocated memory for buffer entry here */ - entry->use = 0; - - Vnet_Print(2, "vnet_tx_flush: pkt (size %d)\n", entry->pkt.size); } } @@ -803,20 +750,20 @@ int v3_init_vnet() { vnet_state.num_routes = 0; if (vnet_lock_init(&(vnet_state.lock)) == -1){ - PrintError("VNET/P Core: Fails to initiate lock\n"); + PrintError("VNET/P: Fails to initiate lock\n"); } vnet_state.route_cache = vnet_create_htable(0, &hash_fn, &hash_eq); if (vnet_state.route_cache == NULL) { - PrintError("VNET/P Core: Fails to initiate route cache\n"); + PrintError("VNET/P: Fails to initiate route cache\n"); return -1; } - vnet_lock_init(&(vnet_state.pkt_q.lock)); + vnet_state.poll_devs = v3_create_queue(); - vnet_state.pkt_flush_thread = vnet_start_thread(vnet_tx_flush, NULL, "VNET_Pkts"); + vnet_state.pkt_flush_thread = vnet_start_thread(vnet_tx_flush, NULL, "vnetd-1"); - Vnet_Debug("VNET/P Core is initiated\n"); + Vnet_Debug("VNET/P is initiated\n"); return 0; }