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 dynamic VMM Driven/Guest Driven mode switch in VNET devices
Lei Xia [Tue, 12 Apr 2011 02:56:09 +0000 (21:56 -0500)]
palacios/include/palacios/vmm_dev_mgr.h
palacios/include/palacios/vmm_ethernet.h
palacios/include/palacios/vmm_vnet.h
palacios/src/devices/lnx_virtio_nic.c
palacios/src/devices/vnet_nic.c
palacios/src/palacios/vmm_vnet_core.c

index 383aebd..cd1d2ef 100644 (file)
@@ -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; 
index 06dde7b..e38e4a7 100644 (file)
@@ -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)
 {
index 1f83e54..1750fff 100644 (file)
@@ -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,
index da6644e..7746560 100644 (file)
@@ -30,6 +30,7 @@
 #include <palacios/vmm_util.h>
 #include <devices/pci.h>
 #include <palacios/vmm_ethernet.h>
+#include <palacios/vmm_time.h>
 
 
 #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);
index 1831270..0fdaaba 100644 (file)
@@ -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);
 }
 
 
index 6b86436..a2d06f2 100644 (file)
@@ -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));