virtio: refactor pci device code

Type: refactor

Change-Id: I7342178f9ab9adb99b91a4f984bc22bef2ce8021
Signed-off-by: Mohsin Kazmi <sykazmi@cisco.com>
diff --git a/src/vnet/CMakeLists.txt b/src/vnet/CMakeLists.txt
index a7f97be..168a35e 100644
--- a/src/vnet/CMakeLists.txt
+++ b/src/vnet/CMakeLists.txt
@@ -1097,12 +1097,14 @@
   devices/virtio/vhost_user_api.c
   devices/virtio/virtio.c
   devices/virtio/virtio_api.c
+  devices/virtio/virtio_pci_legacy.c
   devices/virtio/virtio_types_api.c
 )
 
 list(APPEND VNET_HEADERS
   devices/virtio/pci.h
   devices/virtio/virtio.h
+  devices/virtio/virtio_pci_legacy.h
   devices/virtio/vhost_user.h
   devices/virtio/virtio_types_api.h
 )
diff --git a/src/vnet/devices/virtio/cli.c b/src/vnet/devices/virtio/cli.c
index 1b37338..6d47bad 100644
--- a/src/vnet/devices/virtio/cli.c
+++ b/src/vnet/devices/virtio/cli.c
@@ -229,7 +229,7 @@
     {
       vif = pool_elt_at_index (vim->interfaces, hi->dev_instance);
       if (vif->type == VIRTIO_IF_TYPE_PCI)
-	debug_device_config_space (vm, vif);
+	vif->virtio_pci_func->device_debug_config_space (vm, vif);
     }
 
   virtio_show (vm, hw_if_indices, show_descr, VIRTIO_IF_TYPE_PCI);
diff --git a/src/vnet/devices/virtio/pci.c b/src/vnet/devices/virtio/pci.c
index d28c746..16c7f6d 100644
--- a/src/vnet/devices/virtio/pci.c
+++ b/src/vnet/devices/virtio/pci.c
@@ -36,9 +36,6 @@
 
 #define PCI_MSIX_ENABLE 0x8000
 
-#define PCI_CONFIG_SIZE(vif) ((vif->msix_enabled == VIRTIO_MSIX_ENABLED) ? \
-  24 : 20)
-
 static pci_device_id_t virtio_pci_device_ids[] = {
   {
    .vendor_id = PCI_VENDOR_ID_VIRTIO,
@@ -49,204 +46,6 @@
   {0},
 };
 
-static void
-virtio_pci_legacy_read_config (vlib_main_t * vm, virtio_if_t * vif, void *dst,
-			       int len, u32 addr)
-{
-  u32 size = 0;
-  vlib_pci_dev_handle_t h = vif->pci_dev_handle;
-
-  while (len > 0)
-    {
-      if (len >= 4)
-	{
-	  size = 4;
-	  vlib_pci_read_io_u32 (vm, h, PCI_CONFIG_SIZE (vif) + addr, dst);
-	}
-      else if (len >= 2)
-	{
-	  size = 2;
-	  vlib_pci_read_io_u16 (vm, h, PCI_CONFIG_SIZE (vif) + addr, dst);
-	}
-      else
-	{
-	  size = 1;
-	  vlib_pci_read_io_u8 (vm, h, PCI_CONFIG_SIZE (vif) + addr, dst);
-	}
-      dst = (u8 *) dst + size;
-      addr += size;
-      len -= size;
-    }
-}
-
-static void
-virtio_pci_legacy_write_config (vlib_main_t * vm, virtio_if_t * vif,
-				void *src, int len, u32 addr)
-{
-  u32 size = 0;
-  vlib_pci_dev_handle_t h = vif->pci_dev_handle;
-
-  while (len > 0)
-    {
-      if (len >= 4)
-	{
-	  size = 4;
-	  vlib_pci_write_io_u32 (vm, h, PCI_CONFIG_SIZE (vif) + addr, src);
-	}
-      else if (len >= 2)
-	{
-	  size = 2;
-	  vlib_pci_write_io_u16 (vm, h, PCI_CONFIG_SIZE (vif) + addr, src);
-	}
-      else
-	{
-	  size = 1;
-	  vlib_pci_write_io_u8 (vm, h, PCI_CONFIG_SIZE (vif) + addr, src);
-	}
-      src = (u8 *) src + size;
-      addr += size;
-      len -= size;
-    }
-}
-
-static u64
-virtio_pci_legacy_get_host_features (vlib_main_t * vm, virtio_if_t * vif)
-{
-  u32 features;
-  vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_HOST_FEATURES,
-			&features);
-  return features;
-}
-
-static u32
-virtio_pci_legacy_get_guest_features (vlib_main_t * vm, virtio_if_t * vif)
-{
-  u32 feature = 0;
-  vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_GUEST_FEATURES,
-			&feature);
-  vif->features = feature;
-  return feature;
-}
-
-static u32
-virtio_pci_legacy_set_guest_features (vlib_main_t * vm, virtio_if_t * vif,
-				      u64 features)
-{
-  if ((features >> 32) != 0)
-    {
-      clib_warning ("only 32 bit features are allowed for legacy virtio!");
-    }
-  u32 feature = 0, guest_features = (u32) features;
-  vlib_pci_write_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_GUEST_FEATURES,
-			 &guest_features);
-  vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_GUEST_FEATURES,
-			&feature);
-  return feature;
-}
-
-static u8
-virtio_pci_legacy_get_status (vlib_main_t * vm, virtio_if_t * vif)
-{
-  u8 status = 0;
-  vlib_pci_read_io_u8 (vm, vif->pci_dev_handle, VIRTIO_PCI_STATUS, &status);
-  return status;
-}
-
-static void
-virtio_pci_legacy_set_status (vlib_main_t * vm, virtio_if_t * vif, u8 status)
-{
-  if (status != VIRTIO_CONFIG_STATUS_RESET)
-    status |= virtio_pci_legacy_get_status (vm, vif);
-  vlib_pci_write_io_u8 (vm, vif->pci_dev_handle, VIRTIO_PCI_STATUS, &status);
-}
-
-static u8
-virtio_pci_legacy_reset (vlib_main_t * vm, virtio_if_t * vif)
-{
-  virtio_pci_legacy_set_status (vm, vif, VIRTIO_CONFIG_STATUS_RESET);
-  return virtio_pci_legacy_get_status (vm, vif);
-}
-
-static u8
-virtio_pci_legacy_get_isr (vlib_main_t * vm, virtio_if_t * vif)
-{
-  u8 isr = 0;
-  vlib_pci_read_io_u8 (vm, vif->pci_dev_handle, VIRTIO_PCI_ISR, &isr);
-  return isr;
-}
-
-static u16
-virtio_pci_legacy_get_queue_num (vlib_main_t * vm, virtio_if_t * vif,
-				 u16 queue_id)
-{
-  u16 queue_num = 0;
-  vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_SEL,
-			 &queue_id);
-  vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_NUM,
-			&queue_num);
-  return queue_num;
-}
-
-static int
-virtio_pci_legacy_setup_queue (vlib_main_t * vm, virtio_if_t * vif,
-			       u16 queue_id, void *p)
-{
-  u64 addr = vlib_physmem_get_pa (vm, p) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
-  u32 addr2 = 0;
-  vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_SEL,
-			 &queue_id);
-  vlib_pci_write_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_PFN,
-			 (u32 *) & addr);
-  vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_PFN,
-			&addr2);
-  if ((u32) addr == addr2)
-    return 0;
-  return 1;
-}
-
-static void
-virtio_pci_legacy_del_queue (vlib_main_t * vm, virtio_if_t * vif,
-			     u16 queue_id)
-{
-  u32 src = 0;
-  vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_SEL,
-			 &queue_id);
-  vlib_pci_write_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_PFN, &src);
-}
-
-inline void
-virtio_pci_legacy_notify_queue (vlib_main_t * vm, virtio_if_t * vif,
-				u16 queue_id)
-{
-  vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_NOTIFY,
-			 &queue_id);
-}
-
-/* Enable one vector (0) for Link State Intrerrupt */
-static u16
-virtio_pci_legacy_set_config_irq (vlib_main_t * vm, virtio_if_t * vif,
-				  u16 vec)
-{
-  vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_MSI_CONFIG_VECTOR,
-			 &vec);
-  vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_MSI_CONFIG_VECTOR,
-			&vec);
-  return vec;
-}
-
-static u16
-virtio_pci_legacy_set_queue_irq (vlib_main_t * vm, virtio_if_t * vif, u16 vec,
-				 u16 queue_id)
-{
-  vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_SEL,
-			 &queue_id);
-  vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_MSI_QUEUE_VECTOR,
-			 &vec);
-  vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_MSI_QUEUE_VECTOR,
-			&vec);
-  return vec;
-}
-
 static u32
 virtio_pci_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hw,
 			u32 flags)
@@ -257,17 +56,12 @@
 static clib_error_t *
 virtio_pci_get_max_virtqueue_pairs (vlib_main_t * vm, virtio_if_t * vif)
 {
-  virtio_net_config_t config;
   clib_error_t *error = 0;
   u16 max_queue_pairs = 1;
 
   if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MQ))
     {
-      virtio_pci_legacy_read_config (vm, vif, &config.max_virtqueue_pairs,
-				     sizeof (config.max_virtqueue_pairs),
-				     STRUCT_OFFSET_OF (virtio_net_config_t,
-						       max_virtqueue_pairs));
-      max_queue_pairs = config.max_virtqueue_pairs;
+      max_queue_pairs = vif->virtio_pci_func->get_max_queue_pairs (vm, vif);
     }
 
   virtio_log_debug (vif, "max queue pair is %x", max_queue_pairs);
@@ -283,8 +77,8 @@
 static void
 virtio_pci_set_mac (vlib_main_t * vm, virtio_if_t * vif)
 {
-  virtio_pci_legacy_write_config (vm, vif, vif->mac_addr,
-				  sizeof (vif->mac_addr), 0);
+  if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MAC))
+    vif->virtio_pci_func->set_mac (vm, vif);
 }
 
 static u32
@@ -292,8 +86,7 @@
 {
   if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MAC))
     {
-      virtio_pci_legacy_read_config (vm, vif, vif->mac_addr,
-				     sizeof (vif->mac_addr), 0);
+      vif->virtio_pci_func->get_mac (vm, vif);
       return 0;
     }
   return 1;
@@ -307,9 +100,7 @@
    */
   u16 status = 1;
   if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_STATUS))
-    virtio_pci_legacy_read_config (vm, vif, &status, sizeof (status),	/* mac */
-				   STRUCT_OFFSET_OF (virtio_net_config_t,
-						     status));
+    status = vif->virtio_pci_func->get_device_status (vm, vif);
   return status;
 }
 
@@ -358,7 +149,7 @@
   u8 isr = 0;
   u16 line = 0;
 
-  isr = virtio_pci_legacy_get_isr (vm, vif);
+  isr = vif->virtio_pci_func->get_isr (vm, vif);
 
   /*
    * If the lower bit is set: look through the used rings of
@@ -403,72 +194,6 @@
     }
 }
 
-inline void
-debug_device_config_space (vlib_main_t * vm, virtio_if_t * vif)
-{
-  u32 data_u32;
-  u16 data_u16;
-  u8 data_u8;
-  vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_HOST_FEATURES,
-			&data_u32);
-  vlib_cli_output (vm, "remote features 0x%lx", data_u32);
-  vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_GUEST_FEATURES,
-			&data_u32);
-  vlib_cli_output (vm, "guest features 0x%lx", data_u32);
-  vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_PFN,
-			&data_u32);
-  vlib_cli_output (vm, "queue address 0x%lx", data_u32);
-  vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_NUM,
-			&data_u16);
-  vlib_cli_output (vm, "queue size 0x%x", data_u16);
-  vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_SEL,
-			&data_u16);
-  vlib_cli_output (vm, "queue select 0x%x", data_u16);
-  vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_NOTIFY,
-			&data_u16);
-  vlib_cli_output (vm, "queue notify 0x%x", data_u16);
-  vlib_pci_read_io_u8 (vm, vif->pci_dev_handle, VIRTIO_PCI_STATUS, &data_u8);
-  vlib_cli_output (vm, "status 0x%x", data_u8);
-  vlib_pci_read_io_u8 (vm, vif->pci_dev_handle, VIRTIO_PCI_ISR, &data_u8);
-  vlib_cli_output (vm, "isr 0x%x", data_u8);
-
-  if (vif->msix_enabled == VIRTIO_MSIX_ENABLED)
-    {
-      vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_MSI_CONFIG_VECTOR,
-			    &data_u16);
-      vlib_cli_output (vm, "config vector 0x%x", data_u16);
-      u16 queue_id = 0;
-      vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_SEL,
-			     &queue_id);
-      vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_MSI_QUEUE_VECTOR,
-			    &data_u16);
-      vlib_cli_output (vm, "queue vector for queue (0) 0x%x", data_u16);
-    }
-
-  u8 mac[6];
-  virtio_pci_legacy_read_config (vm, vif, mac, sizeof (mac), 0);
-  vlib_cli_output (vm, "mac %U", format_ethernet_address, mac);
-  virtio_pci_legacy_read_config (vm, vif, &data_u16, sizeof (u16),	/* offset to status */
-				 6);
-  vlib_cli_output (vm, "link up/down status 0x%x", data_u16);
-  virtio_pci_legacy_read_config (vm, vif, &data_u16, sizeof (u16),
-				 /* offset to max_virtqueue */ 8);
-  vlib_cli_output (vm, "num of virtqueue 0x%x", data_u16);
-  virtio_pci_legacy_read_config (vm, vif, &data_u16, sizeof (u16),	/* offset to mtu */
-				 10);
-  vlib_cli_output (vm, "mtu 0x%x", data_u16);
-
-  u32 i = PCI_CONFIG_SIZE (vif) + 12, a = 4;
-  i += a;
-  i &= ~a;
-  for (; i < 64; i += 4)
-    {
-      u32 data = 0;
-      vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, i, &data);
-      vlib_cli_output (vm, "0x%lx", data);
-    }
-}
-
 struct virtio_ctrl_msg
 {
   struct virtio_net_ctrl_hdr ctrl;
@@ -587,8 +312,8 @@
   status =
     virtio_pci_send_ctrl_msg (vm, vif, &offload_hdr, sizeof (offloads));
   virtio_log_debug (vif, "disable offloads");
-  vif->remote_features = virtio_pci_legacy_get_host_features (vm, vif);
-  virtio_pci_legacy_get_guest_features (vm, vif);
+  vif->remote_features = vif->virtio_pci_func->get_device_features (vm, vif);
+  vif->virtio_pci_func->get_driver_features (vm, vif);
   return status;
 }
 
@@ -608,8 +333,8 @@
   status =
     virtio_pci_send_ctrl_msg (vm, vif, &csum_offload_hdr, sizeof (offloads));
   virtio_log_debug (vif, "enable checksum offload");
-  vif->remote_features = virtio_pci_legacy_get_host_features (vm, vif);
-  virtio_pci_legacy_get_guest_features (vm, vif);
+  vif->remote_features = vif->virtio_pci_func->get_device_features (vm, vif);
+  vif->features = vif->virtio_pci_func->get_driver_features (vm, vif);
   return status;
 }
 
@@ -629,8 +354,8 @@
 
   status = virtio_pci_send_ctrl_msg (vm, vif, &gso_hdr, sizeof (offloads));
   virtio_log_debug (vif, "enable gso");
-  vif->remote_features = virtio_pci_legacy_get_host_features (vm, vif);
-  virtio_pci_legacy_get_guest_features (vm, vif);
+  vif->remote_features = vif->virtio_pci_func->get_device_features (vm, vif);
+  vif->virtio_pci_func->get_driver_features (vm, vif);
   return status;
 }
 
@@ -733,7 +458,7 @@
   u32 i = 0;
   void *ptr = NULL;
 
-  queue_size = virtio_pci_legacy_get_queue_num (vm, vif, queue_num);
+  queue_size = vif->virtio_pci_func->get_queue_size (vm, vif, queue_num);
   if (!virtio_pci_queue_size_valid (queue_size))
     clib_warning ("queue size is not valid");
 
@@ -768,7 +493,7 @@
   vring->size = queue_size;
   virtio_log_debug (vif, "control-queue: number %u, size %u", queue_num,
 		    queue_size);
-  virtio_pci_legacy_setup_queue (vm, vif, queue_num, ptr);
+  vif->virtio_pci_func->setup_queue (vm, vif, queue_num, ptr);
   vring->kick_fd = -1;
 
   return error;
@@ -784,7 +509,7 @@
   u32 i = 0;
   void *ptr = NULL;
 
-  queue_size = virtio_pci_legacy_get_queue_num (vm, vif, queue_num);
+  queue_size = vif->virtio_pci_func->get_queue_size (vm, vif, queue_num);
   if (!virtio_pci_queue_size_valid (queue_size))
     clib_warning ("queue size is not valid");
 
@@ -840,7 +565,7 @@
 			queue_size);
     }
   vring->size = queue_size;
-  if (virtio_pci_legacy_setup_queue (vm, vif, queue_num, ptr))
+  if (vif->virtio_pci_func->setup_queue (vm, vif, queue_num, ptr))
     return clib_error_return (0, "error in queue address setup");
 
   vring->kick_fd = -1;
@@ -884,23 +609,21 @@
 
   if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MTU))
     {
-      virtio_net_config_t config;
-      virtio_pci_legacy_read_config (vm, vif, &config.mtu,
-				     sizeof (config.mtu),
-				     STRUCT_OFFSET_OF (virtio_net_config_t,
-						       mtu));
-      if (config.mtu < 64)
+      u16 mtu = 0;
+      mtu = vif->virtio_pci_func->get_mtu (vm, vif);
+
+      if (mtu < 64)
 	vif->features &= ~VIRTIO_FEATURE (VIRTIO_NET_F_MTU);
     }
 
-  vif->features =
-    virtio_pci_legacy_set_guest_features (vm, vif, vif->features);
+  vif->virtio_pci_func->set_driver_features (vm, vif, vif->features);
+  vif->features = vif->virtio_pci_func->get_driver_features (vm, vif);
 }
 
 void
 virtio_pci_read_device_feature (vlib_main_t * vm, virtio_if_t * vif)
 {
-  vif->remote_features = virtio_pci_legacy_get_host_features (vm, vif);
+  vif->remote_features = vif->virtio_pci_func->get_device_features (vm, vif);
 }
 
 int
@@ -911,22 +634,22 @@
   /*
    * Reset the device
    */
-  status = virtio_pci_legacy_reset (vm, vif);
+  status = vif->virtio_pci_func->device_reset (vm, vif);
 
   /*
    * Set the Acknowledge status bit
    */
-  virtio_pci_legacy_set_status (vm, vif, VIRTIO_CONFIG_STATUS_ACK);
+  vif->virtio_pci_func->set_status (vm, vif, VIRTIO_CONFIG_STATUS_ACK);
 
   /*
    * Set the Driver status bit
    */
-  virtio_pci_legacy_set_status (vm, vif, VIRTIO_CONFIG_STATUS_DRIVER);
+  vif->virtio_pci_func->set_status (vm, vif, VIRTIO_CONFIG_STATUS_DRIVER);
 
   /*
    * Read the status and verify it
    */
-  status = virtio_pci_legacy_get_status (vm, vif);
+  status = vif->virtio_pci_func->get_status (vm, vif);
   if (!
       ((status & VIRTIO_CONFIG_STATUS_ACK)
        && (status & VIRTIO_CONFIG_STATUS_DRIVER)))
@@ -1023,6 +746,8 @@
       pos = cap.cap_next;
     }
 
+  vif->virtio_pci_func = &virtio_pci_legacy_func;
+
   if (common_cfg == 0 || notify_base == 0 || dev_cfg == 0 || isr == 0)
     {
       virtio_log_debug (vif, "legacy virtio pci device found");
@@ -1077,8 +802,9 @@
   /*
    * After FEATURE_OK, driver should not accept new feature bits
    */
-  virtio_pci_legacy_set_status (vm, vif, VIRTIO_CONFIG_STATUS_FEATURES_OK);
-  status = virtio_pci_legacy_get_status (vm, vif);
+  vif->virtio_pci_func->set_status (vm, vif,
+				    VIRTIO_CONFIG_STATUS_FEATURES_OK);
+  status = vif->virtio_pci_func->get_status (vm, vif);
   if (!(status & VIRTIO_CONFIG_STATUS_FEATURES_OK))
     {
       args->rv = VNET_API_ERROR_UNSUPPORTED;
@@ -1136,8 +862,10 @@
 	  args->rv = VNET_API_ERROR_INIT_FAILED;
 	  virtio_log_error (vif, "%s (%u) %s", "error in rxq-queue",
 			    RX_QUEUE (i), "initialization");
-	  clib_error_return (error, "%s (%u) %s", "error in rxq-queue",
-			     RX_QUEUE (i), "initialization");
+	  error =
+	    clib_error_return (error, "%s (%u) %s", "error in rxq-queue",
+			       RX_QUEUE (i), "initialization");
+	  goto err;
 	}
       else
 	{
@@ -1165,8 +893,10 @@
 	  args->rv = VNET_API_ERROR_INIT_FAILED;
 	  virtio_log_error (vif, "%s (%u) %s", "error in txq-queue",
 			    TX_QUEUE (i), "initialization");
-	  clib_error_return (error, "%s (%u) %s", "error in txq-queue",
-			     TX_QUEUE (i), "initialization");
+	  error =
+	    clib_error_return (error, "%s (%u) %s", "error in txq-queue",
+			       TX_QUEUE (i), "initialization");
+	  goto err;
 	}
       else
 	{
@@ -1197,7 +927,7 @@
   if (vif->msix_enabled == VIRTIO_MSIX_ENABLED)
     {
       int i, j;
-      if (virtio_pci_legacy_set_config_irq (vm, vif, 0) ==
+      if (vif->virtio_pci_func->set_config_irq (vm, vif, 0) ==
 	  VIRTIO_MSI_NO_VECTOR)
 	{
 	  virtio_log_warning (vif, "config vector 0 is not set");
@@ -1208,7 +938,8 @@
 	}
       for (i = 0, j = 1; i < vif->max_queue_pairs; i++, j++)
 	{
-	  if (virtio_pci_legacy_set_queue_irq (vm, vif, j, RX_QUEUE (i)) ==
+	  if (vif->virtio_pci_func->set_queue_irq (vm, vif, j,
+						   RX_QUEUE (i)) ==
 	      VIRTIO_MSI_NO_VECTOR)
 	    {
 	      virtio_log_warning (vif, "queue (%u) vector is not set at %u",
@@ -1225,8 +956,8 @@
   /*
    * set the driver status OK
    */
-  virtio_pci_legacy_set_status (vm, vif, VIRTIO_CONFIG_STATUS_DRIVER_OK);
-  vif->status = virtio_pci_legacy_get_status (vm, vif);
+  vif->virtio_pci_func->set_status (vm, vif, VIRTIO_CONFIG_STATUS_DRIVER_OK);
+  vif->status = vif->virtio_pci_func->get_status (vm, vif);
 err:
   return error;
 }
@@ -1431,14 +1162,14 @@
 
   for (i = 0; i < vif->max_queue_pairs; i++)
     {
-      virtio_pci_legacy_del_queue (vm, vif, RX_QUEUE (i));
-      virtio_pci_legacy_del_queue (vm, vif, TX_QUEUE (i));
+      vif->virtio_pci_func->del_queue (vm, vif, RX_QUEUE (i));
+      vif->virtio_pci_func->del_queue (vm, vif, TX_QUEUE (i));
     }
 
   if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ))
-    virtio_pci_legacy_del_queue (vm, vif, vif->max_queue_pairs * 2);
+    vif->virtio_pci_func->del_queue (vm, vif, vif->max_queue_pairs * 2);
 
-  virtio_pci_legacy_reset (vm, vif);
+  vif->virtio_pci_func->device_reset (vm, vif);
 
   if (vif->hw_if_index)
     {
diff --git a/src/vnet/devices/virtio/pci.h b/src/vnet/devices/virtio/pci.h
index 8ec1360..dfc0711 100644
--- a/src/vnet/devices/virtio/pci.h
+++ b/src/vnet/devices/virtio/pci.h
@@ -20,23 +20,6 @@
 #define VIRTIO_PCI_ABI_VERSION 0
 
 /*
- * VirtIO Header, located in BAR 0.
- */
-#define VIRTIO_PCI_HOST_FEATURES  0	/* host's supported features (32bit, RO) */
-#define VIRTIO_PCI_GUEST_FEATURES 4	/* guest's supported features (32, RW) */
-#define VIRTIO_PCI_QUEUE_PFN      8	/* physical address of VQ (32, RW) */
-#define VIRTIO_PCI_QUEUE_NUM      12	/* number of ring entries (16, RO) */
-#define VIRTIO_PCI_QUEUE_SEL      14	/* current VQ selection (16, RW) */
-#define VIRTIO_PCI_QUEUE_NOTIFY   16	/* notify host regarding VQ (16, RW) */
-#define VIRTIO_PCI_STATUS         18	/* device status register (8, RW) */
-#define VIRTIO_PCI_ISR            19	/* interrupt status register, reading
-					 * also clears the register (8, RO) */
-/* Only if MSIX is enabled: */
-#define VIRTIO_MSI_CONFIG_VECTOR  20	/* configuration change vector (16, RW) */
-#define VIRTIO_MSI_QUEUE_VECTOR   22	/* vector for selected VQ notifications
-					   (16, RW) */
-
-/*
  * Vector value used to disable MSI for queue.
  * define in include/linux/virtio_pci.h
  * #define VIRTIO_MSI_NO_VECTOR 0xFFFF
@@ -187,6 +170,14 @@
 
 typedef struct
 {
+  u8 mac[6];
+  u16 status;
+  u16 max_virtqueue_pairs;
+  u16 mtu;
+} virtio_net_config_t;
+
+typedef struct
+{
   u64 addr;
   u32 len;
   u16 flags;
@@ -215,6 +206,44 @@
   /* u16 avail_event; */
 } vring_used_t;
 
+typedef struct _virtio_pci_func
+{
+  void (*read_config) (vlib_main_t * vm, virtio_if_t * vif, void *dst,
+		       int len, u32 addr);
+  void (*write_config) (vlib_main_t * vm, virtio_if_t * vif, void *src,
+			int len, u32 addr);
+
+    u64 (*get_device_features) (vlib_main_t * vm, virtio_if_t * vif);
+    u64 (*get_driver_features) (vlib_main_t * vm, virtio_if_t * vif);
+  void (*set_driver_features) (vlib_main_t * vm, virtio_if_t * vif,
+			       u64 features);
+
+    u8 (*get_status) (vlib_main_t * vm, virtio_if_t * vif);
+  void (*set_status) (vlib_main_t * vm, virtio_if_t * vif, u8 status);
+    u8 (*device_reset) (vlib_main_t * vm, virtio_if_t * vif);
+
+    u8 (*get_isr) (vlib_main_t * vm, virtio_if_t * vif);
+
+    u16 (*get_queue_size) (vlib_main_t * vm, virtio_if_t * vif, u16 queue_id);
+  void (*set_queue_size) (vlib_main_t * vm, virtio_if_t * vif, u16 queue_id,
+			  u16 queue_size);
+    u8 (*setup_queue) (vlib_main_t * vm, virtio_if_t * vif, u16 queue_id,
+		       void *p);
+  void (*del_queue) (vlib_main_t * vm, virtio_if_t * vif, u16 queue_id);
+  void (*notify_queue) (vlib_main_t * vm, virtio_if_t * vif, u16 queue_id);
+
+    u16 (*set_config_irq) (vlib_main_t * vm, virtio_if_t * vif, u16 vec);
+    u16 (*set_queue_irq) (vlib_main_t * vm, virtio_if_t * vif, u16 vec,
+			  u16 queue_id);
+
+  void (*get_mac) (vlib_main_t * vm, virtio_if_t * vif);
+  void (*set_mac) (vlib_main_t * vm, virtio_if_t * vif);
+    u16 (*get_device_status) (vlib_main_t * vm, virtio_if_t * vif);
+    u16 (*get_max_queue_pairs) (vlib_main_t * vm, virtio_if_t * vif);
+    u16 (*get_mtu) (vlib_main_t * vm, virtio_if_t * vif);
+  void (*device_debug_config_space) (vlib_main_t * vm, virtio_if_t * vif);
+} virtio_pci_func_t;
+
 typedef struct
 {
   u32 addr;
@@ -229,7 +258,8 @@
   clib_error_t *error;
 } virtio_pci_create_if_args_t;
 
-extern void debug_device_config_space (vlib_main_t * vm, virtio_if_t * vif);
+extern const virtio_pci_func_t virtio_pci_legacy_func;
+
 extern void device_status (vlib_main_t * vm, virtio_if_t * vif);
 void virtio_pci_create_if (vlib_main_t * vm,
 			   virtio_pci_create_if_args_t * args);
diff --git a/src/vnet/devices/virtio/virtio.h b/src/vnet/devices/virtio/virtio.h
index b57c6eb..e1ba71d 100644
--- a/src/vnet/devices/virtio/virtio.h
+++ b/src/vnet/devices/virtio/virtio.h
@@ -70,9 +70,6 @@
 #undef _
 } virtio_if_flag_t;
 
-#define VIRTIO_NUM_RX_DESC 256
-#define VIRTIO_NUM_TX_DESC 256
-
 #define VIRTIO_FEATURE(X) (1ULL << X)
 
 #define TX_QUEUE(X) ((X*2) + 1)
@@ -80,6 +77,9 @@
 #define TX_QUEUE_ACCESS(X) (X/2)
 #define RX_QUEUE_ACCESS(X) (X/2)
 
+#define VIRTIO_NUM_RX_DESC 256
+#define VIRTIO_NUM_TX_DESC 256
+
 #define foreach_virtio_if_types \
   _ (TAP, 0)                    \
   _ (TUN, 1)                    \
@@ -93,15 +93,6 @@
     VIRTIO_IF_N_TYPES = (1 << 3),
 } virtio_if_type_t;
 
-
-typedef struct
-{
-  u8 mac[6];
-  u16 status;
-  u16 max_virtqueue_pairs;
-  u16 mtu;
-} virtio_net_config_t;
-
 #define VIRTIO_RING_FLAG_MASK_INT 1
 
 typedef struct
@@ -139,6 +130,8 @@
   u32 as_u32;
 } pci_addr_t;
 
+typedef struct _virtio_pci_func virtio_pci_func_t;
+
 typedef struct
 {
   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
@@ -197,6 +190,7 @@
   u32 tap_flags;
   int ifindex;
   virtio_vring_t *cxq_vring;
+  const virtio_pci_func_t *virtio_pci_func;
 } virtio_if_t;
 
 typedef struct
@@ -245,7 +239,6 @@
     }
 }
 
-
 #define virtio_log_debug(vif, f, ...)				\
 {								\
   vlib_log(VLIB_LOG_LEVEL_DEBUG, virtio_main.log_default,	\
diff --git a/src/vnet/devices/virtio/virtio_pci_legacy.c b/src/vnet/devices/virtio/virtio_pci_legacy.c
new file mode 100644
index 0000000..f70776d
--- /dev/null
+++ b/src/vnet/devices/virtio/virtio_pci_legacy.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vlib/vlib.h>
+#include <vlib/pci/pci.h>
+#include <vnet/ethernet/ethernet.h>
+#include <vnet/ip/ip4_packet.h>
+#include <vnet/ip/ip6_packet.h>
+#include <vnet/devices/virtio/virtio.h>
+#include <vnet/devices/virtio/virtio_pci_legacy.h>
+#include <vnet/devices/virtio/pci.h>
+
+#define PCI_CONFIG_SIZE(vif) ((vif->msix_enabled == VIRTIO_MSIX_ENABLED) ? \
+  24 : 20)
+
+static void
+virtio_pci_legacy_read_config (vlib_main_t * vm, virtio_if_t * vif, void *dst,
+			       int len, u32 addr)
+{
+  u32 size = 0;
+  vlib_pci_dev_handle_t h = vif->pci_dev_handle;
+
+  while (len > 0)
+    {
+      if (len >= 4)
+	{
+	  size = 4;
+	  vlib_pci_read_io_u32 (vm, h, PCI_CONFIG_SIZE (vif) + addr, dst);
+	}
+      else if (len >= 2)
+	{
+	  size = 2;
+	  vlib_pci_read_io_u16 (vm, h, PCI_CONFIG_SIZE (vif) + addr, dst);
+	}
+      else
+	{
+	  size = 1;
+	  vlib_pci_read_io_u8 (vm, h, PCI_CONFIG_SIZE (vif) + addr, dst);
+	}
+      dst = (u8 *) dst + size;
+      addr += size;
+      len -= size;
+    }
+}
+
+static void
+virtio_pci_legacy_write_config (vlib_main_t * vm, virtio_if_t * vif,
+				void *src, int len, u32 addr)
+{
+  u32 size = 0;
+  vlib_pci_dev_handle_t h = vif->pci_dev_handle;
+
+  while (len > 0)
+    {
+      if (len >= 4)
+	{
+	  size = 4;
+	  vlib_pci_write_io_u32 (vm, h, PCI_CONFIG_SIZE (vif) + addr, src);
+	}
+      else if (len >= 2)
+	{
+	  size = 2;
+	  vlib_pci_write_io_u16 (vm, h, PCI_CONFIG_SIZE (vif) + addr, src);
+	}
+      else
+	{
+	  size = 1;
+	  vlib_pci_write_io_u8 (vm, h, PCI_CONFIG_SIZE (vif) + addr, src);
+	}
+      src = (u8 *) src + size;
+      addr += size;
+      len -= size;
+    }
+}
+
+static u64
+virtio_pci_legacy_get_host_features (vlib_main_t * vm, virtio_if_t * vif)
+{
+  u32 host_features;
+  vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_HOST_FEATURES,
+			&host_features);
+  return host_features;
+}
+
+static u64
+virtio_pci_legacy_get_guest_features (vlib_main_t * vm, virtio_if_t * vif)
+{
+  u32 guest_features = 0;
+  vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_GUEST_FEATURES,
+			&guest_features);
+  vif->features = guest_features;
+  return guest_features;
+}
+
+static void
+virtio_pci_legacy_set_guest_features (vlib_main_t * vm, virtio_if_t * vif,
+				      u64 guest_features)
+{
+  if ((guest_features >> 32) != 0)
+    {
+      clib_warning ("only 32 bit features are allowed for legacy virtio!");
+    }
+  u32 features = 0;
+  vlib_pci_write_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_GUEST_FEATURES,
+			 (u32 *) & guest_features);
+  vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_GUEST_FEATURES,
+			&features);
+  if (features != (u32) guest_features)
+    {
+      clib_warning ("legacy set guest features failed!");
+    }
+}
+
+static u8
+virtio_pci_legacy_get_status (vlib_main_t * vm, virtio_if_t * vif)
+{
+  u8 status = 0;
+  vlib_pci_read_io_u8 (vm, vif->pci_dev_handle, VIRTIO_PCI_STATUS, &status);
+  return status;
+}
+
+static void
+virtio_pci_legacy_set_status (vlib_main_t * vm, virtio_if_t * vif, u8 status)
+{
+  if (status != VIRTIO_CONFIG_STATUS_RESET)
+    status |= virtio_pci_legacy_get_status (vm, vif);
+  vlib_pci_write_io_u8 (vm, vif->pci_dev_handle, VIRTIO_PCI_STATUS, &status);
+}
+
+static u8
+virtio_pci_legacy_reset (vlib_main_t * vm, virtio_if_t * vif)
+{
+  virtio_pci_legacy_set_status (vm, vif, VIRTIO_CONFIG_STATUS_RESET);
+  return virtio_pci_legacy_get_status (vm, vif);
+}
+
+static u8
+virtio_pci_legacy_get_isr (vlib_main_t * vm, virtio_if_t * vif)
+{
+  u8 isr = 0;
+  vlib_pci_read_io_u8 (vm, vif->pci_dev_handle, VIRTIO_PCI_ISR, &isr);
+  return isr;
+}
+
+static u16
+virtio_pci_legacy_get_queue_num (vlib_main_t * vm, virtio_if_t * vif,
+				 u16 queue_id)
+{
+  u16 queue_num = 0;
+  vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_SEL,
+			 &queue_id);
+  vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_NUM,
+			&queue_num);
+  return queue_num;
+}
+
+static void
+virtio_pci_legacy_set_queue_num (vlib_main_t * vm, virtio_if_t * vif,
+				 u16 queue_id, u16 queue_size)
+{
+  /* do nothing */
+}
+
+static u8
+virtio_pci_legacy_setup_queue (vlib_main_t * vm, virtio_if_t * vif,
+			       u16 queue_id, void *p)
+{
+  u64 addr = vlib_physmem_get_pa (vm, p) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
+  u32 addr2 = 0;
+  vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_SEL,
+			 &queue_id);
+  vlib_pci_write_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_PFN,
+			 (u32 *) & addr);
+  vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_PFN,
+			&addr2);
+  if ((u32) addr == addr2)
+    return 0;
+
+  clib_warning ("legacy queue setup failed!");
+  return 1;
+}
+
+static void
+virtio_pci_legacy_del_queue (vlib_main_t * vm, virtio_if_t * vif,
+			     u16 queue_id)
+{
+  u32 src = 0;
+  vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_SEL,
+			 &queue_id);
+  vlib_pci_write_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_PFN, &src);
+}
+
+inline void
+virtio_pci_legacy_notify_queue (vlib_main_t * vm, virtio_if_t * vif,
+				u16 queue_id)
+{
+  vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_NOTIFY,
+			 &queue_id);
+}
+
+/* Enable one vector (0) for Link State Intrerrupt */
+static u16
+virtio_pci_legacy_set_config_irq (vlib_main_t * vm, virtio_if_t * vif,
+				  u16 vec)
+{
+  vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_MSI_CONFIG_VECTOR,
+			 &vec);
+  vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_MSI_CONFIG_VECTOR,
+			&vec);
+  return vec;
+}
+
+static u16
+virtio_pci_legacy_set_queue_irq (vlib_main_t * vm, virtio_if_t * vif, u16 vec,
+				 u16 queue_id)
+{
+  vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_SEL,
+			 &queue_id);
+  vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_MSI_QUEUE_VECTOR,
+			 &vec);
+  vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_MSI_QUEUE_VECTOR,
+			&vec);
+  return vec;
+}
+
+static void
+virtio_pci_legacy_get_mac (vlib_main_t * vm, virtio_if_t * vif)
+{
+  virtio_pci_legacy_read_config (vm, vif, vif->mac_addr,
+				 sizeof (vif->mac_addr), 0);
+}
+
+static void
+virtio_pci_legacy_set_mac (vlib_main_t * vm, virtio_if_t * vif)
+{
+  virtio_pci_legacy_write_config (vm, vif, vif->mac_addr,
+				  sizeof (vif->mac_addr), 0);
+}
+
+static u16
+virtio_pci_legacy_get_device_status (vlib_main_t * vm, virtio_if_t * vif)
+{
+  u16 status = 0;
+  virtio_pci_legacy_read_config (vm, vif, &status,
+				 sizeof (status),
+				 STRUCT_OFFSET_OF
+				 (virtio_net_config_t, status));
+  return status;
+}
+
+static u16
+virtio_pci_legacy_get_max_queue_pairs (vlib_main_t * vm, virtio_if_t * vif)
+{
+  virtio_net_config_t config;
+  virtio_pci_legacy_read_config (vm, vif, &config.max_virtqueue_pairs,
+				 sizeof (config.max_virtqueue_pairs),
+				 STRUCT_OFFSET_OF
+				 (virtio_net_config_t, max_virtqueue_pairs));
+  return config.max_virtqueue_pairs;
+}
+
+static u16
+virtio_pci_legacy_get_mtu (vlib_main_t * vm, virtio_if_t * vif)
+{
+  virtio_net_config_t config;
+  virtio_pci_legacy_read_config (vm, vif, &config.mtu,
+				 sizeof (config.mtu),
+				 STRUCT_OFFSET_OF (virtio_net_config_t, mtu));
+  return config.mtu;
+}
+
+
+static void
+virtio_pci_legacy_device_debug_config_space (vlib_main_t * vm,
+					     virtio_if_t * vif)
+{
+  u32 data_u32;
+  u16 data_u16;
+  u8 data_u8;
+  vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_HOST_FEATURES,
+			&data_u32);
+  vlib_cli_output (vm, "remote features 0x%lx", data_u32);
+  vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_GUEST_FEATURES,
+			&data_u32);
+  vlib_cli_output (vm, "guest features 0x%lx", data_u32);
+  vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_PFN,
+			&data_u32);
+  vlib_cli_output (vm, "queue address 0x%lx", data_u32);
+  vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_NUM,
+			&data_u16);
+  vlib_cli_output (vm, "queue size 0x%x", data_u16);
+  vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_SEL,
+			&data_u16);
+  vlib_cli_output (vm, "queue select 0x%x", data_u16);
+  vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_NOTIFY,
+			&data_u16);
+  vlib_cli_output (vm, "queue notify 0x%x", data_u16);
+  vlib_pci_read_io_u8 (vm, vif->pci_dev_handle, VIRTIO_PCI_STATUS, &data_u8);
+  vlib_cli_output (vm, "status 0x%x", data_u8);
+  vlib_pci_read_io_u8 (vm, vif->pci_dev_handle, VIRTIO_PCI_ISR, &data_u8);
+  vlib_cli_output (vm, "isr 0x%x", data_u8);
+
+  if (vif->msix_enabled == VIRTIO_MSIX_ENABLED)
+    {
+      vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_MSI_CONFIG_VECTOR,
+			    &data_u16);
+      vlib_cli_output (vm, "config vector 0x%x", data_u16);
+      u16 queue_id = 0;
+      vlib_pci_write_io_u16 (vm, vif->pci_dev_handle, VIRTIO_PCI_QUEUE_SEL,
+			     &queue_id);
+      vlib_pci_read_io_u16 (vm, vif->pci_dev_handle, VIRTIO_MSI_QUEUE_VECTOR,
+			    &data_u16);
+      vlib_cli_output (vm, "queue vector for queue (0) 0x%x", data_u16);
+    }
+
+  u8 mac[6];
+  virtio_pci_legacy_read_config (vm, vif, mac, sizeof (mac), 0);
+  vlib_cli_output (vm, "mac %U", format_ethernet_address, mac);
+  virtio_pci_legacy_read_config (vm, vif, &data_u16, sizeof (u16),	/* offset to status */
+				 6);
+  vlib_cli_output (vm, "link up/down status 0x%x", data_u16);
+  virtio_pci_legacy_read_config (vm, vif, &data_u16, sizeof (u16),
+				 /* offset to max_virtqueue */ 8);
+  vlib_cli_output (vm, "num of virtqueue 0x%x", data_u16);
+  virtio_pci_legacy_read_config (vm, vif, &data_u16, sizeof (u16),	/* offset to mtu */
+				 10);
+  vlib_cli_output (vm, "mtu 0x%x", data_u16);
+
+  u32 i = PCI_CONFIG_SIZE (vif) + 12, a = 4;
+  i += a;
+  i &= ~a;
+  for (; i < 64; i += 4)
+    {
+      u32 data = 0;
+      vlib_pci_read_io_u32 (vm, vif->pci_dev_handle, i, &data);
+      vlib_cli_output (vm, "0x%lx", data);
+    }
+}
+
+const virtio_pci_func_t virtio_pci_legacy_func = {
+  .read_config = virtio_pci_legacy_read_config,
+  .write_config = virtio_pci_legacy_write_config,
+  .get_device_features = virtio_pci_legacy_get_host_features,
+  .get_driver_features = virtio_pci_legacy_get_guest_features,
+  .set_driver_features = virtio_pci_legacy_set_guest_features,
+  .get_status = virtio_pci_legacy_get_status,
+  .set_status = virtio_pci_legacy_set_status,
+  .device_reset = virtio_pci_legacy_reset,
+  .get_isr = virtio_pci_legacy_get_isr,
+  .get_queue_size = virtio_pci_legacy_get_queue_num,
+  .set_queue_size = virtio_pci_legacy_set_queue_num,
+  .setup_queue = virtio_pci_legacy_setup_queue,
+  .del_queue = virtio_pci_legacy_del_queue,
+  .notify_queue = virtio_pci_legacy_notify_queue,
+  .set_config_irq = virtio_pci_legacy_set_config_irq,
+  .set_queue_irq = virtio_pci_legacy_set_queue_irq,
+  .get_mac = virtio_pci_legacy_get_mac,
+  .set_mac = virtio_pci_legacy_set_mac,
+  .get_device_status = virtio_pci_legacy_get_device_status,
+  .get_max_queue_pairs = virtio_pci_legacy_get_max_queue_pairs,
+  .get_mtu = virtio_pci_legacy_get_mtu,
+  .device_debug_config_space = virtio_pci_legacy_device_debug_config_space,
+};
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/devices/virtio/virtio_pci_legacy.h b/src/vnet/devices/virtio/virtio_pci_legacy.h
new file mode 100644
index 0000000..0db04c1
--- /dev/null
+++ b/src/vnet/devices/virtio/virtio_pci_legacy.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __included_virtio_pci_legacy_h__
+#define __included_virtio_pci_legacy_h__
+
+/*
+ * VirtIO Header, located in BAR 0.
+ */
+#define VIRTIO_PCI_HOST_FEATURES  0	/* host's supported features (32bit, RO) */
+#define VIRTIO_PCI_GUEST_FEATURES 4	/* guest's supported features (32, RW) */
+#define VIRTIO_PCI_QUEUE_PFN      8	/* physical address of VQ (32, RW) */
+#define VIRTIO_PCI_QUEUE_NUM      12	/* number of ring entries (16, RO) */
+#define VIRTIO_PCI_QUEUE_SEL      14	/* current VQ selection (16, RW) */
+#define VIRTIO_PCI_QUEUE_NOTIFY   16	/* notify host regarding VQ (16, RW) */
+#define VIRTIO_PCI_STATUS         18	/* device status register (8, RW) */
+#define VIRTIO_PCI_ISR            19	/* interrupt status register, reading
+					 * also clears the register (8, RO) */
+/* Only if MSIX is enabled: */
+#define VIRTIO_MSI_CONFIG_VECTOR  20	/* configuration change vector (16, RW) */
+#define VIRTIO_MSI_QUEUE_VECTOR   22	/* vector for selected VQ notifications
+					   (16, RW) */
+#define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12
+
+#endif /* __included_virtio_pci_legacy_h__ */
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */