X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fdevices%2Flnx_virtio_nic.c;h=bb13a6959e54f553105c625f693c012c9d8a70ee;hb=dd1906aa28e83656da7025456e6f046bbe7712f4;hp=da6644ea753672fbbefcdd62b966c25f0a3afbcf;hpb=b349b55150ada21d3f973bf9a2571f7fd7312c4f;p=palacios.releases.git diff --git a/palacios/src/devices/lnx_virtio_nic.c b/palacios/src/devices/lnx_virtio_nic.c index da6644e..bb13a69 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 @@ -57,14 +58,15 @@ struct virtio_net_hdr_mrg_rxbuf { }; -#define TX_QUEUE_SIZE 64 -#define RX_QUEUE_SIZE 1024 +#define TX_QUEUE_SIZE 256 +#define RX_QUEUE_SIZE 4096 #define CTRL_QUEUE_SIZE 64 #define VIRTIO_NET_F_MRG_RXBUF 15 /* Host can merge receive buffers. */ #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,17 +97,22 @@ 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; + uint8_t tx_notify, rx_notify; + uint32_t tx_pkts, rx_pkts; + uint64_t past_ms; + void * backend_data; struct virtio_dev_state * virtio_dev; struct list_head dev_link; }; - static int virtio_init_state(struct virtio_net_state * virtio) { virtio->rx_vq.queue_size = RX_QUEUE_SIZE; @@ -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->rx_notify == 1){ + v3_interrupt_cpu(virtio->virtio_dev->vm, virtio->virtio_dev->vm->cores[0].cpu_id, 0); + } + return 0; err_exit: @@ -636,10 +650,12 @@ 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); + + if(virtio->tx_notify == 0){ + handle_pkt_tx(&(vm->cores[0]), virtio); + } } static int register_dev(struct virtio_dev_state * virtio, @@ -714,6 +730,61 @@ static int register_dev(struct virtio_dev_state * virtio, return 0; } +#define RATE_UPPER_THRESHOLD 10 /* 10000 pkts per second, around 100Mbits */ +#define RATE_LOWER_THRESHOLD 1 +#define PROFILE_PERIOD 50 /*50ms*/ + +/* 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; + + period_ms = cpu_cycles/cpu_freq; + net_state->past_ms += period_ms; + + if(net_state->past_ms > PROFILE_PERIOD){ + uint32_t tx_rate, rx_rate; + + tx_rate = (net_state->statistics.tx_pkts - net_state->tx_pkts)/net_state->past_ms; /* pkts/per ms */ + rx_rate = (net_state->statistics.rx_pkts - net_state->rx_pkts)/net_state->past_ms; + + net_state->tx_pkts = net_state->statistics.tx_pkts; + net_state->rx_pkts = net_state->statistics.rx_pkts; + + if(tx_rate > RATE_UPPER_THRESHOLD && net_state->tx_notify == 1){ + V3_Print("Virtio NIC: Switch TX to VMM driven mode\n"); + disable_cb(&(net_state->tx_vq)); + net_state->tx_notify = 0; + } + + if(tx_rate < RATE_LOWER_THRESHOLD && net_state->tx_notify == 0){ + V3_Print("Virtio NIC: Switch TX to Guest driven mode\n"); + enable_cb(&(net_state->tx_vq)); + net_state->tx_notify = 1; + } + + if(rx_rate > RATE_UPPER_THRESHOLD && net_state->rx_notify == 1){ + PrintDebug("Virtio NIC: Switch RX to VMM None notify mode\n"); + net_state->rx_notify = 0; + } + + if(rx_rate < RATE_LOWER_THRESHOLD && net_state->rx_notify == 0){ + PrintDebug("Virtio NIC: Switch RX to VMM notify mode\n"); + net_state->rx_notify = 1; + } + + net_state->past_ms = 0; + } +} + + +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 +799,10 @@ 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->tx_notify = 1; + net_state->rx_notify = 1; + + net_state->timer = v3_add_timer(&(info->cores[0]),&timer_ops,net_state); ops->recv = virtio_rx; ops->poll = virtio_nic_poll; @@ -742,7 +816,9 @@ static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) { struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus")); struct virtio_dev_state * virtio_state = NULL; char * dev_id = v3_cfg_val(cfg, "ID"); - char * macstr = v3_cfg_val(cfg, "mac"); + char macstr[128]; + char * str = v3_cfg_val(cfg, "mac"); + memcpy(macstr, str, strlen(str)); if (pci_bus == NULL) { PrintError("Virtio NIC: VirtIO devices require a PCI Bus"); @@ -758,6 +834,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);