From: Lei Xia Date: Tue, 12 Apr 2011 02:56:09 +0000 (-0500) Subject: Add dynamic VMM Driven/Guest Driven mode switch in VNET devices X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=commitdiff_plain;h=0a7690f54cb5bda83780dac26ce433ad24b1d766;p=palacios.git Add dynamic VMM Driven/Guest Driven mode switch in VNET devices --- diff --git a/palacios/include/palacios/vmm_dev_mgr.h b/palacios/include/palacios/vmm_dev_mgr.h index 383aebd..cd1d2ef 100644 --- a/palacios/include/palacios/vmm_dev_mgr.h +++ b/palacios/include/palacios/vmm_dev_mgr.h @@ -175,14 +175,10 @@ struct v3_dev_blk_ops { struct v3_dev_net_ops { /* Backend implemented functions */ int (*send)(uint8_t * buf, uint32_t count, void * private_data); - void (*start_rx)(void * back_data); - void (*stop_rx)(void * back_data); /* Frontend implemented functions */ int (*recv)(uint8_t * buf, uint32_t count, void * frnt_data); - void (*poll)(struct v3_vm_info * vm, void * frnt_data); - void (*start_tx)(void * frnt_data); - void (*stop_tx)(void * frnt_data); + void (*poll)(struct v3_vm_info * vm, int budget, void * frnt_data); /* This is ugly... */ void * frontend_data; diff --git a/palacios/include/palacios/vmm_ethernet.h b/palacios/include/palacios/vmm_ethernet.h index 06dde7b..e38e4a7 100644 --- a/palacios/include/palacios/vmm_ethernet.h +++ b/palacios/include/palacios/vmm_ethernet.h @@ -41,6 +41,8 @@ struct nic_statistics { uint32_t interrupts; }; + +typedef enum {VMM_DRIVERN = 1, GUEST_DRIVERN} nic_poll_type_t; static inline int is_multicast_ethaddr(const uint8_t * addr) { diff --git a/palacios/include/palacios/vmm_vnet.h b/palacios/include/palacios/vmm_vnet.h index 1f83e54..1750fff 100644 --- a/palacios/include/palacios/vmm_vnet.h +++ b/palacios/include/palacios/vmm_vnet.h @@ -106,19 +106,17 @@ int v3_vnet_stat(struct vnet_stat * stats); #ifdef __V3VEE__ -typedef enum {VMM_DRIVERN = 1, GUEST_DRIVERN} vnet_poll_type_t; - struct v3_vnet_dev_ops { int (*input)(struct v3_vm_info * vm, struct v3_vnet_pkt * pkt, void * dev_data); - void (*poll) (struct v3_vm_info * vm, void * dev_data); + void (*poll) (struct v3_vm_info * vm, int budget, void * dev_data); }; int v3_init_vnet(void); void v3_deinit_vnet(void); -void v3_vnet_poll(struct v3_vm_info * vm); +void v3_vnet_do_poll(struct v3_vm_info * vm); int v3_vnet_add_dev(struct v3_vm_info * info, uint8_t * mac, struct v3_vnet_dev_ops * ops, diff --git a/palacios/src/devices/lnx_virtio_nic.c b/palacios/src/devices/lnx_virtio_nic.c index da6644e..7746560 100644 --- a/palacios/src/devices/lnx_virtio_nic.c +++ b/palacios/src/devices/lnx_virtio_nic.c @@ -30,6 +30,7 @@ #include #include #include +#include #ifndef CONFIG_DEBUG_VIRTIO_NET @@ -65,6 +66,7 @@ struct virtio_net_hdr_mrg_rxbuf { #define VIRTIO_NET_F_MAC 5 /* Host has given MAC address. */ #define VIRTIO_NET_F_GSO 6 /* Host handles pkts w/ any GSO type */ #define VIRTIO_NET_F_HOST_TSO4 11 /* Host can handle TSOv4 in. */ +#define VIRTIO_NET_F_HOST_UFO 14 /* Host can handle UFO in. */ /* Port to get virtio config */ #define VIRTIO_NET_CONFIG 20 @@ -95,11 +97,16 @@ struct virtio_net_state { struct virtio_queue tx_vq; /* idx 1*/ struct virtio_queue ctrl_vq; /* idx 2*/ + struct v3_timer * timer; + struct nic_statistics statistics; struct v3_dev_net_ops * net_ops; v3_lock_t rx_lock, tx_lock; + nic_poll_type_t mode; + uint32_t tx_pkts, rx_pkts; + void * backend_data; struct virtio_dev_state * virtio_dev; struct list_head dev_link; @@ -132,7 +139,9 @@ static int virtio_init_state(struct virtio_net_state * virtio) virtio->virtio_cfg.pci_isr = 0; - virtio->virtio_cfg.host_features = 0 | (1 << VIRTIO_NET_F_MAC); + virtio->virtio_cfg.host_features = 0 | (1 << VIRTIO_NET_F_MAC) | + (1 << VIRTIO_NET_F_HOST_UFO) | + (1 << VIRTIO_NET_F_HOST_TSO4); if ((v3_lock_init(&(virtio->rx_lock)) == -1) || (v3_lock_init(&(virtio->tx_lock)) == -1)){ @@ -261,7 +270,7 @@ static int handle_pkt_tx(struct guest_info * core, desc_idx = hdr_desc->next; if(desc_cnt > 2){ - PrintError("VNIC: merged rx buffer not supported\n"); + PrintError("VNIC: merged rx buffer not supported, desc_cnt %d\n", desc_cnt); goto exit_error; } @@ -535,7 +544,7 @@ static int virtio_rx(uint8_t * buf, uint32_t size, void * private_data) { uint32_t offset = 0; unsigned long flags; -#ifndef CONFIG_DEBUG_VIRTIO_NET +#ifdef CONFIG_DEBUG_VIRTIO_NET PrintDebug("Virtio-NIC: virtio_rx: size: %d\n", size); v3_hexdump(buf, size, NULL, 0); #endif @@ -604,6 +613,11 @@ static int virtio_rx(uint8_t * buf, uint32_t size, void * private_data) { v3_unlock_irqrestore(virtio->rx_lock, flags); + /* notify guest if guest is running */ + if(virtio->mode == GUEST_DRIVERN){ + v3_interrupt_cpu(virtio->virtio_dev->vm, virtio->virtio_dev->vm->cores[0].cpu_id, 0); + } + return 0; err_exit: @@ -636,7 +650,7 @@ static struct v3_device_ops dev_ops = { }; -static void virtio_nic_poll(struct v3_vm_info * vm, void * data){ +static void virtio_nic_poll(struct v3_vm_info * vm, int budget, void * data){ struct virtio_net_state * virtio = (struct virtio_net_state *)data; handle_pkt_tx(&(vm->cores[0]), virtio); @@ -714,6 +728,49 @@ static int register_dev(struct virtio_dev_state * virtio, return 0; } +/* Timer Functions */ +static void virtio_nic_timer(struct guest_info * core, + uint64_t cpu_cycles, uint64_t cpu_freq, + void * priv_data) { + struct virtio_net_state * net_state = (struct virtio_net_state *)priv_data; + uint64_t period_ms; + uint32_t pkts_tx=0, pkts_rx=0; + uint32_t tx_rate, rx_rate; + + period_ms = (1000*cpu_cycles/cpu_freq); + + if(period_ms > 100){ + V3_Print("Virtio NIC timer: last tx %d, last rx: %d\n", pkts_tx, pkts_rx); + + pkts_tx = net_state->statistics.tx_pkts - net_state->tx_pkts; + pkts_rx = net_state->statistics.rx_pkts - net_state->rx_pkts; + net_state->tx_pkts = net_state->statistics.tx_pkts; + net_state->rx_pkts = net_state->statistics.rx_pkts; + + tx_rate = pkts_tx/period_ms; /* pkts/per ms */ + rx_rate = pkts_rx/period_ms; + + if(tx_rate > 100 && net_state->mode == GUEST_DRIVERN){ + V3_Print("Virtio NIC: Switch to VMM driven mode\n"); + disable_cb(&(net_state->tx_vq)); + net_state->mode = VMM_DRIVERN; + } + + if(tx_rate < 10 && net_state->mode == VMM_DRIVERN){ + V3_Print("Virtio NIC: Switch to Guest driven mode\n"); + enable_cb(&(net_state->tx_vq)); + net_state->mode = GUEST_DRIVERN; + } + } + + return; +} + +static struct v3_timer_ops timer_ops = { + .update_timer = virtio_nic_timer, +}; + + static int connect_fn(struct v3_vm_info * info, void * frontend_data, struct v3_dev_net_ops * ops, @@ -728,7 +785,8 @@ static int connect_fn(struct v3_vm_info * info, net_state->net_ops = ops; net_state->backend_data = private_data; net_state->virtio_dev = virtio; - + + net_state->timer = v3_add_timer(&(info->cores[0]),&timer_ops,net_state); ops->recv = virtio_rx; ops->poll = virtio_nic_poll; @@ -758,6 +816,12 @@ static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { if (macstr != NULL && !str2mac(macstr, virtio_state->mac)) { PrintDebug("Virtio NIC: Mac specified %s\n", macstr); + PrintDebug("MAC: %x:%x:%x:%x:%x:%x\n", virtio_state->mac[0], + virtio_state->mac[1], + virtio_state->mac[2], + virtio_state->mac[3], + virtio_state->mac[4], + virtio_state->mac[5]); }else { PrintDebug("Virtio NIC: MAC not specified\n"); random_ethaddr(virtio_state->mac); diff --git a/palacios/src/devices/vnet_nic.c b/palacios/src/devices/vnet_nic.c index 1831270..0fdaaba 100644 --- a/palacios/src/devices/vnet_nic.c +++ b/palacios/src/devices/vnet_nic.c @@ -79,10 +79,11 @@ static int virtio_input(struct v3_vm_info * info, /* poll data from front-end */ static void virtio_poll(struct v3_vm_info * info, + int budget, void * private_data){ struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data; - vnetnic->net_ops.poll(info, vnetnic->net_ops.frontend_data); + vnetnic->net_ops.poll(info, budget, vnetnic->net_ops.frontend_data); } diff --git a/palacios/src/palacios/vmm_vnet_core.c b/palacios/src/palacios/vmm_vnet_core.c index 6b86436..a2d06f2 100644 --- a/palacios/src/palacios/vmm_vnet_core.c +++ b/palacios/src/palacios/vmm_vnet_core.c @@ -46,7 +46,10 @@ struct vnet_dev { void * private_data; int active; - vnet_poll_type_t mode; //vmm_drivern or guest_drivern + nic_poll_type_t mode; /*vmm_drivern or guest_drivern */ + + uint64_t bytes_tx, bytes_rx; + uint32_t pkts_tx, pkt_rx; struct list_head node; } __attribute__((packed)); @@ -57,7 +60,7 @@ struct vnet_brg_dev { struct v3_vnet_bridge_ops brg_ops; uint8_t type; - vnet_poll_type_t mode; + nic_poll_type_t mode; int active; void * private_data; } __attribute__((packed)); @@ -90,7 +93,7 @@ static struct { int num_routes; int num_devs; - struct vnet_brg_dev *bridge; + struct vnet_brg_dev * bridge; v3_lock_t lock; struct vnet_stat stats; @@ -642,6 +645,20 @@ int v3_vnet_add_bridge(struct v3_vm_info * vm, } +void v3_vnet_do_poll(struct v3_vm_info * vm){ + struct vnet_dev * dev = NULL; + + /* TODO: run this on separate threads + * round-robin schedule, with maximal budget for each poll + */ + list_for_each_entry(dev, &(vnet_state.devs), node) { + if(dev->mode == VMM_DRIVERN){ + dev->dev_ops.poll(vm, -1, dev->private_data); + } + } +} + + int v3_init_vnet() { memset(&vnet_state, 0, sizeof(vnet_state));