Define a netdev_dpdk_common structure that is a 1:1 copy of netdev_dpdk
at this point.

At this point of the changes, the "common" fields can be identified by
looking at common_construct() content.

Then move helpers that are not eth/vhost specific, and prefer
accessing common fields with a common-> pointer.

Signed-off-by: David Marchand <[email protected]>
---
 lib/automake.mk          |   4 +-
 lib/netdev-dpdk-common.c | 159 +++++++
 lib/netdev-dpdk-common.h | 228 +++++++++
 lib/netdev-dpdk.c        | 991 ++++++++++++++++++---------------------
 4 files changed, 859 insertions(+), 523 deletions(-)
 create mode 100644 lib/netdev-dpdk-common.c
 create mode 100644 lib/netdev-dpdk-common.h

diff --git a/lib/automake.mk b/lib/automake.mk
index 2dfca79da8..48b3288429 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -441,7 +441,9 @@ lib_libopenvswitch_la_SOURCES += \
        lib/dpif-offload-dpdk.c \
        lib/dpif-offload-dpdk-netdev.c \
        lib/dpif-offload-dpdk-private.h \
-       lib/netdev-dpdk.c
+       lib/netdev-dpdk.c \
+       lib/netdev-dpdk-common.c \
+       lib/netdev-dpdk-common.h
 else
 lib_libopenvswitch_la_SOURCES += \
        lib/dpdk-stub.c
diff --git a/lib/netdev-dpdk-common.c b/lib/netdev-dpdk-common.c
new file mode 100644
index 0000000000..e58f4049ab
--- /dev/null
+++ b/lib/netdev-dpdk-common.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2014, 2015, 2016, 2017 Nicira, Inc.
+ *
+ * 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 <config.h>
+
+#include "netdev-dpdk-common.h"
+#include "netdev-provider.h"
+#include "openvswitch/vlog.h"
+
+VLOG_DEFINE_THIS_MODULE(netdev_dpdk_common);
+
+void
+netdev_dpdk_common_update_ol_flags(struct netdev_dpdk_common *common)
+{
+    const struct {
+        enum dpdk_hw_ol_features hw_ol_feature;
+        enum netdev_ol_flags flag;
+    } ol_flags_map[] = {
+        { NETDEV_TX_IPV4_CKSUM_OFFLOAD, NETDEV_TX_OFFLOAD_IPV4_CKSUM },
+        { NETDEV_TX_TCP_CKSUM_OFFLOAD, NETDEV_TX_OFFLOAD_TCP_CKSUM },
+        { NETDEV_TX_UDP_CKSUM_OFFLOAD, NETDEV_TX_OFFLOAD_UDP_CKSUM },
+        { NETDEV_TX_SCTP_CKSUM_OFFLOAD, NETDEV_TX_OFFLOAD_SCTP_CKSUM },
+        { NETDEV_TX_TSO_OFFLOAD, NETDEV_TX_OFFLOAD_TCP_TSO },
+        { NETDEV_TX_VXLAN_TNL_TSO_OFFLOAD, NETDEV_TX_VXLAN_TNL_TSO },
+        { NETDEV_TX_GRE_TNL_TSO_OFFLOAD, NETDEV_TX_GRE_TNL_TSO },
+        { NETDEV_TX_GENEVE_TNL_TSO_OFFLOAD, NETDEV_TX_GENEVE_TNL_TSO },
+        { NETDEV_TX_OUTER_IP_CKSUM_OFFLOAD, NETDEV_TX_OFFLOAD_OUTER_IP_CKSUM },
+        { NETDEV_TX_OUTER_UDP_CKSUM_OFFLOAD,
+          NETDEV_TX_OFFLOAD_OUTER_UDP_CKSUM },
+    };
+    uint32_t hw_ol_features = common->hw_ol_features;
+    struct netdev *netdev = &common->up;
+
+    for (unsigned int i = 0; i < ARRAY_SIZE(ol_flags_map); i++) {
+        if (hw_ol_features & ol_flags_map[i].hw_ol_feature) {
+            netdev->ol_flags |= ol_flags_map[i].flag;
+        } else {
+            netdev->ol_flags &= ~ol_flags_map[i].flag;
+        }
+    }
+}
+
+int
+netdev_dpdk_common_get_numa_id(const struct netdev *netdev)
+{
+    const struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
+
+    return common->socket_id;
+}
+
+void
+netdev_dpdk_common_get_etheraddr(const struct netdev_dpdk_common *common,
+                                 struct eth_addr *mac)
+{
+    *mac = common->hwaddr;
+}
+
+void
+netdev_dpdk_common_get_mtu(const struct netdev_dpdk_common *common, int *mtup)
+{
+    *mtup = common->mtu;
+}
+
+int
+netdev_dpdk_common_get_ifindex(const struct netdev_dpdk_common *common)
+{
+    const struct netdev *netdev = &common->up;
+
+    /* Calculate hash from the netdev name. Ensure that ifindex is a 24-bit
+     * positive integer to meet RFC 2863 recommendations.
+     */
+    return hash_string(netdev->name, 0) % 0xfffffe + 1;
+}
+
+int
+netdev_dpdk_common_set_mtu(struct netdev_dpdk_common *common, int mtu)
+{
+    struct netdev *netdev = &common->up;
+
+    /* XXX: Ensure that the overall frame length of the requested MTU does not
+     * surpass the NETDEV_DPDK_MAX_PKT_LEN. DPDK device drivers differ in how
+     * the L2 frame length is calculated for a given MTU when
+     * rte_eth_dev_set_mtu(mtu) is called e.g. i40e driver includes 2 x vlan
+     * headers, the em driver includes 1 x vlan header, the ixgbe driver does
+     * not include vlan headers. As such we should use
+     * MTU_TO_MAX_FRAME_LEN(mtu) which includes an additional 2 x vlan headers
+     * (8 bytes) for comparison. This avoids a failure later with
+     * rte_eth_dev_set_mtu(). This approach should be used until DPDK provides
+     * a method to retrieve the upper bound MTU for a given device.
+     */
+    if (MTU_TO_MAX_FRAME_LEN(mtu) > NETDEV_DPDK_MAX_PKT_LEN
+        || mtu < RTE_ETHER_MIN_MTU) {
+        VLOG_WARN("%s: unsupported MTU %d\n", netdev->name, mtu);
+        return EINVAL;
+    }
+
+    if (common->requested_mtu != mtu) {
+        common->requested_mtu = mtu;
+        netdev_request_reconfigure(netdev);
+    }
+
+    return 0;
+}
+
+void
+netdev_dpdk_common_get_sw_custom_stats(struct netdev_dpdk_common *common,
+                                       struct netdev_custom_stats *stats)
+{
+    int i, n;
+
+#define SW_CSTATS                    \
+    SW_CSTAT(tx_retries)             \
+    SW_CSTAT(tx_failure_drops)       \
+    SW_CSTAT(tx_mtu_exceeded_drops)  \
+    SW_CSTAT(tx_qos_drops)           \
+    SW_CSTAT(rx_qos_drops)           \
+    SW_CSTAT(tx_invalid_hwol_drops)
+
+#define SW_CSTAT(NAME) + 1
+    stats->size = SW_CSTATS;
+#undef SW_CSTAT
+    stats->counters = xcalloc(stats->size, sizeof *stats->counters);
+
+    rte_spinlock_lock(&common->stats_lock);
+    i = 0;
+#define SW_CSTAT(NAME) \
+    stats->counters[i++].value = common->sw_stats->NAME;
+    SW_CSTATS;
+#undef SW_CSTAT
+    rte_spinlock_unlock(&common->stats_lock);
+
+    i = 0;
+    n = 0;
+#define SW_CSTAT(NAME) \
+    if (stats->counters[i].value != UINT64_MAX) {                \
+        ovs_strlcpy(stats->counters[n].name,                     \
+                    "ovs_"#NAME, NETDEV_CUSTOM_STATS_NAME_SIZE); \
+        stats->counters[n].value = stats->counters[i].value;     \
+        n++;                                                     \
+    }                                                            \
+    i++;
+    SW_CSTATS;
+#undef SW_CSTAT
+
+    stats->size = n;
+}
diff --git a/lib/netdev-dpdk-common.h b/lib/netdev-dpdk-common.h
new file mode 100644
index 0000000000..3e25558eb5
--- /dev/null
+++ b/lib/netdev-dpdk-common.h
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2014, 2015, 2016, 2017 Nicira, Inc.
+ *
+ * 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 NETDEV_DPDK_COMMON_H
+#define NETDEV_DPDK_COMMON_H
+
+#include <config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+
+#include "netdev-provider.h"
+#include "openvswitch/compiler.h"
+#include "ovs-thread.h"
+
+struct dpdk_tx_queue;
+struct ingress_policer;
+struct qos_conf;
+
+#define ETHER_HDR_MAX_LEN           (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN \
+                                     + (2 * VLAN_HEADER_LEN))
+#define MTU_TO_MAX_FRAME_LEN(mtu)   ((mtu) + ETHER_HDR_MAX_LEN)
+#define NETDEV_DPDK_MAX_PKT_LEN     9728
+
+/* Custom software stats for dpdk ports */
+struct netdev_dpdk_sw_stats {
+    /* No. of retries when unable to transmit. */
+    uint64_t tx_retries;
+    /* Packet drops when unable to transmit; Probably Tx queue is full. */
+    uint64_t tx_failure_drops;
+    /* Packet length greater than device MTU. */
+    uint64_t tx_mtu_exceeded_drops;
+    /* Packet drops in egress policer processing. */
+    uint64_t tx_qos_drops;
+    /* Packet drops in ingress policer processing. */
+    uint64_t rx_qos_drops;
+    /* Packet drops in HWOL processing. */
+    uint64_t tx_invalid_hwol_drops;
+};
+
+struct netdev_dpdk_common {
+    PADDED_MEMBERS_CACHELINE_MARKER(CACHE_LINE_SIZE, cacheline0,
+        uint16_t port_id;
+
+        /* If true, device was attached by rte_eth_dev_attach(). */
+        bool attached;
+        /* If true, rte_eth_dev_start() was successfully called. */
+        bool started;
+        /* If true, this is a port representor. */
+        bool is_representor;
+        struct eth_addr hwaddr;
+        /* 1 pad bytes here. */
+        int mtu;
+        int socket_id;
+        int buf_size;
+        int max_packet_len;
+        enum netdev_flags flags;
+        int link_reset_cnt;
+        union {
+            /* Device arguments for dpdk ports. */
+            char *devargs;
+            /* Identifier used to distinguish vhost devices from each other. */
+            char *vhost_id;
+        };
+        struct dpdk_tx_queue *tx_q;
+        struct rte_eth_link link;
+    );
+
+    PADDED_MEMBERS_CACHELINE_MARKER(CACHE_LINE_SIZE, cacheline1,
+        struct ovs_mutex mutex;
+        struct dpdk_mp *dpdk_mp;
+
+        /* virtio identifier for vhost devices */
+        ovsrcu_index vid;
+
+        /* True if vHost device is 'up' and has been reconfigured at least
+         * once */
+        bool vhost_reconfigured;
+
+        atomic_uint8_t vhost_tx_retries_max;
+
+        /* Flags for virtio features recovery mechanism. */
+        uint8_t virtio_features_state;
+
+        /* 1 pad byte here. */
+    );
+
+    PADDED_MEMBERS(CACHE_LINE_SIZE,
+        struct netdev up;
+        struct ovs_list list_node;
+
+        /* QoS configuration and lock for the device */
+        OVSRCU_TYPE(struct qos_conf *) qos_conf;
+
+        /* Ingress Policer */
+        OVSRCU_TYPE(struct ingress_policer *) ingress_policer;
+        uint32_t policer_rate;
+        uint32_t policer_burst;
+
+        /* Array of vhost rxq states, see vring_state_changed. */
+        bool *vhost_rxq_enabled;
+
+        /* Ensures that Rx metadata delivery is configured only once. */
+        bool rx_metadata_delivery_configured;
+    );
+
+    PADDED_MEMBERS(CACHE_LINE_SIZE,
+        struct netdev_stats stats;
+        struct netdev_dpdk_sw_stats *sw_stats;
+        /* Protects stats */
+        rte_spinlock_t stats_lock;
+        /* 36 pad bytes here. */
+    );
+
+    PADDED_MEMBERS(CACHE_LINE_SIZE,
+        /* The following properties cannot be changed when a device is running,
+         * so we remember the request and update them next time
+         * netdev_dpdk*_reconfigure() is called */
+        int requested_mtu;
+        int requested_n_txq;
+        /* User input for n_rxq (see dpdk_set_rxq_config). */
+        int user_n_rxq;
+        /* user_n_rxq + an optional rx steering queue (see
+         * netdev_dpdk_reconfigure). This field is different from the other
+         * requested_* fields as it may contain a different value than the user
+         * input. */
+        int requested_n_rxq;
+        int requested_rxq_size;
+        int requested_txq_size;
+
+        /* Number of rx/tx descriptors for physical devices */
+        int rxq_size;
+        int txq_size;
+
+        /* Socket ID detected when vHost device is brought up */
+        int requested_socket_id;
+
+        /* Ignored by DPDK for vhost-user backends, only for VDUSE. */
+        uint8_t vhost_max_queue_pairs;
+
+        /* Denotes whether vHost port is client/server mode */
+        uint64_t vhost_driver_flags;
+
+        /* DPDK-ETH Flow control */
+        struct rte_eth_fc_conf fc_conf;
+
+        /* DPDK-ETH hardware offload features,
+         * from the enum set 'dpdk_hw_ol_features' */
+        uint32_t hw_ol_features;
+
+        /* Properties for link state change detection mode.
+         * If lsc_interrupt_mode is set to false, poll mode is used,
+         * otherwise interrupt mode is used. */
+        bool requested_lsc_interrupt_mode;
+        bool lsc_interrupt_mode;
+
+        /* VF configuration. */
+        struct eth_addr requested_hwaddr;
+
+        /* Requested rx queue steering flags,
+         * from the enum set 'dpdk_rx_steer_flags'. */
+        uint64_t requested_rx_steer_flags;
+        uint64_t rx_steer_flags;
+        size_t rx_steer_flows_num;
+        struct rte_flow **rx_steer_flows;
+    );
+
+    PADDED_MEMBERS(CACHE_LINE_SIZE,
+        /* Names of all XSTATS counters */
+        struct rte_eth_xstat_name *rte_xstats_names;
+        int rte_xstats_names_size;
+        int rte_xstats_ids_size;
+        uint64_t *rte_xstats_ids;
+    );
+};
+
+static inline struct netdev_dpdk_common *
+netdev_dpdk_common_cast(const struct netdev *netdev)
+{
+    return CONTAINER_OF(netdev, struct netdev_dpdk_common, up);
+}
+
+enum dpdk_hw_ol_features {
+    NETDEV_RX_CHECKSUM_OFFLOAD = 1 << 0,
+    NETDEV_RX_HW_CRC_STRIP = 1 << 1,
+    NETDEV_RX_HW_SCATTER = 1 << 2,
+    NETDEV_TX_IPV4_CKSUM_OFFLOAD = 1 << 3,
+    NETDEV_TX_TCP_CKSUM_OFFLOAD = 1 << 4,
+    NETDEV_TX_UDP_CKSUM_OFFLOAD = 1 << 5,
+    NETDEV_TX_SCTP_CKSUM_OFFLOAD = 1 << 6,
+    NETDEV_TX_TSO_OFFLOAD = 1 << 7,
+    NETDEV_TX_VXLAN_TNL_TSO_OFFLOAD = 1 << 8,
+    NETDEV_TX_GENEVE_TNL_TSO_OFFLOAD = 1 << 9,
+    NETDEV_TX_OUTER_IP_CKSUM_OFFLOAD = 1 << 10,
+    NETDEV_TX_OUTER_UDP_CKSUM_OFFLOAD = 1 << 11,
+    NETDEV_TX_GRE_TNL_TSO_OFFLOAD = 1 << 12,
+};
+
+void netdev_dpdk_common_update_ol_flags(struct netdev_dpdk_common *common);
+
+int netdev_dpdk_common_get_numa_id(const struct netdev *netdev);
+void netdev_dpdk_common_get_etheraddr(const struct netdev_dpdk_common *common,
+                                     struct eth_addr *mac);
+void netdev_dpdk_common_get_mtu(const struct netdev_dpdk_common *common,
+                               int *mtup);
+int netdev_dpdk_common_get_ifindex(const struct netdev_dpdk_common *common);
+int netdev_dpdk_common_set_mtu(struct netdev_dpdk_common *common, int mtu);
+void
+netdev_dpdk_common_get_sw_custom_stats(struct netdev_dpdk_common *common,
+                                       struct netdev_custom_stats *stats);
+
+#endif /* NETDEV_DPDK_COMMON_H */
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index b63d6fa5d6..d6ba8f534c 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -52,6 +52,7 @@
 #include "fatal-signal.h"
 #include "if-notifier.h"
 #include "mpsc-queue.h"
+#include "netdev-dpdk-common.h"
 #include "netdev-provider.h"
 #include "netdev-vport.h"
 #include "odp-util.h"
@@ -100,15 +101,11 @@ static bool per_port_memory = false; /* Status of per 
port memory support */
  * The minimum mbuf size is limited to avoid scatter behaviour and drop in
  * performance for standard Ethernet MTU.
  */
-#define ETHER_HDR_MAX_LEN           (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN \
-                                     + (2 * VLAN_HEADER_LEN))
 #define MTU_TO_FRAME_LEN(mtu)       ((mtu) + RTE_ETHER_HDR_LEN + \
                                      RTE_ETHER_CRC_LEN)
-#define MTU_TO_MAX_FRAME_LEN(mtu)   ((mtu) + ETHER_HDR_MAX_LEN)
 #define FRAME_LEN_TO_MTU(frame_len) ((frame_len)                    \
                                      - RTE_ETHER_HDR_LEN - RTE_ETHER_CRC_LEN)
 #define NETDEV_DPDK_MBUF_ALIGN      1024
-#define NETDEV_DPDK_MAX_PKT_LEN     9728
 
 /* Max and min number of packets in the mempool. OVS tries to allocate a
  * mempool with MAX_NB_MBUF: if this fails (because the system doesn't have
@@ -194,22 +191,6 @@ static const struct rte_vhost_device_ops 
virtio_net_device_ops =
     .destroy_connection = destroy_connection,
 };
 
-/* Custom software stats for dpdk ports */
-struct netdev_dpdk_sw_stats {
-    /* No. of retries when unable to transmit. */
-    uint64_t tx_retries;
-    /* Packet drops when unable to transmit; Probably Tx queue is full. */
-    uint64_t tx_failure_drops;
-    /* Packet length greater than device MTU. */
-    uint64_t tx_mtu_exceeded_drops;
-    /* Packet drops in egress policer processing. */
-    uint64_t tx_qos_drops;
-    /* Packet drops in ingress policer processing. */
-    uint64_t rx_qos_drops;
-    /* Packet drops in HWOL processing. */
-    uint64_t tx_invalid_hwol_drops;
-};
-
 /* Quality of Service */
 
 /* An instance of a QoS configuration.  Always associated with a particular
@@ -397,22 +378,6 @@ struct ingress_policer {
     rte_spinlock_t policer_lock;
 };
 
-enum dpdk_hw_ol_features {
-    NETDEV_RX_CHECKSUM_OFFLOAD = 1 << 0,
-    NETDEV_RX_HW_CRC_STRIP = 1 << 1,
-    NETDEV_RX_HW_SCATTER = 1 << 2,
-    NETDEV_TX_IPV4_CKSUM_OFFLOAD = 1 << 3,
-    NETDEV_TX_TCP_CKSUM_OFFLOAD = 1 << 4,
-    NETDEV_TX_UDP_CKSUM_OFFLOAD = 1 << 5,
-    NETDEV_TX_SCTP_CKSUM_OFFLOAD = 1 << 6,
-    NETDEV_TX_TSO_OFFLOAD = 1 << 7,
-    NETDEV_TX_VXLAN_TNL_TSO_OFFLOAD = 1 << 8,
-    NETDEV_TX_GENEVE_TNL_TSO_OFFLOAD = 1 << 9,
-    NETDEV_TX_OUTER_IP_CKSUM_OFFLOAD = 1 << 10,
-    NETDEV_TX_OUTER_UDP_CKSUM_OFFLOAD = 1 << 11,
-    NETDEV_TX_GRE_TNL_TSO_OFFLOAD = 1 << 12,
-};
-
 enum dpdk_rx_steer_flags {
     DPDK_RX_STEER_LACP = 1 << 0,
 };
@@ -433,16 +398,18 @@ enum dpdk_rx_steer_flags {
  * In order to avoid confusion in variables names, following naming convention
  * should be used, if possible:
  *
- *     'struct netdev'          : 'netdev'
- *     'struct netdev_dpdk'     : 'dev'
- *     'struct netdev_rxq'      : 'rxq'
- *     'struct netdev_rxq_dpdk' : 'rx'
+ *     'struct netdev'            : 'netdev'
+ *     'struct netdev_dpdk_common': 'common'
+ *     'struct netdev_dpdk_eth'   : 'dev'
+ *     'struct netdev_dpdk_vhost' : 'dev'
+ *     'struct netdev_rxq'        : 'rxq'
+ *     'struct netdev_rxq_dpdk'   : 'rx'
  *
  * Example:
  *     struct netdev *netdev = netdev_from_name(name);
  *     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
  *
- *  Also, 'netdev' should be used instead of 'dev->up', where 'netdev' was
+ *  Also, 'netdev' should be used instead of 'common->up', where 'netdev' was
  *  already defined.
  */
 
@@ -591,8 +558,6 @@ static const struct netdev_class netdev_dpdk_class;
 static const struct netdev_class netdev_dpdk_vhost_class;
 static const struct netdev_class netdev_dpdk_vhost_client_class;
 
-static int netdev_dpdk_get_sw_custom_stats(const struct netdev *,
-                                           struct netdev_custom_stats *);
 static void netdev_dpdk_configure_xstats(struct netdev_dpdk *dev);
 static void netdev_dpdk_clear_xstats(struct netdev_dpdk *dev);
 
@@ -978,9 +943,8 @@ dpdk_mp_put(struct dpdk_mp *dmp)
  * requested_mtu. On success, a new configuration will be applied.
  * On error, device will be left unchanged. */
 static int
-netdev_dpdk_mempool_configure(struct netdev_dpdk *dev,
+netdev_dpdk_mempool_configure(struct netdev_dpdk_common *common,
                               struct dpdk_mp_config *cfg)
-    OVS_REQUIRES(dev->mutex)
 {
     struct dpdk_mp *dmp;
     int ret = 0;
@@ -988,8 +952,8 @@ netdev_dpdk_mempool_configure(struct netdev_dpdk *dev,
     /* With shared memory we do not need to configure a mempool if the MTU
      * and socket ID have not changed, the previous configuration is still
      * valid so return 0 */
-    if (!per_port_memory && dev->mtu == cfg->mtu
-        && dev->socket_id == cfg->socket_id) {
+    if (!per_port_memory && common->mtu == cfg->mtu
+        && common->socket_id == cfg->socket_id) {
         return ret;
     }
 
@@ -997,14 +961,14 @@ netdev_dpdk_mempool_configure(struct netdev_dpdk *dev,
     if (!dmp) {
         VLOG_ERR("Failed to create memory pool for netdev "
                  "%s, with MTU %d on socket %d: %s\n",
-                 dev->up.name, cfg->mtu, cfg->socket_id,
+                 common->up.name, cfg->mtu, cfg->socket_id,
                  rte_strerror(rte_errno));
         ret = rte_errno;
     } else {
         /* Check for any pre-existing dpdk_mp for the device before accessing
          * the associated mempool.
          */
-        if (dev->dpdk_mp != NULL) {
+        if (common->dpdk_mp != NULL) {
             /* A new MTU was requested, decrement the reference count for the
              * devices current dpdk_mp. This is required even if a pointer to
              * same dpdk_mp is returned by dpdk_mp_get. The refcount for dmp
@@ -1012,12 +976,12 @@ netdev_dpdk_mempool_configure(struct netdev_dpdk *dev,
              * must be decremented to keep an accurate refcount for the
              * dpdk_mp.
              */
-            dpdk_mp_put(dev->dpdk_mp);
+            dpdk_mp_put(common->dpdk_mp);
         }
-        dev->dpdk_mp = dmp;
-        dev->mtu = cfg->mtu;
-        dev->socket_id = cfg->socket_id;
-        dev->max_packet_len = MTU_TO_FRAME_LEN(dev->mtu);
+        common->dpdk_mp = dmp;
+        common->mtu = cfg->mtu;
+        common->socket_id = cfg->socket_id;
+        common->max_packet_len = MTU_TO_FRAME_LEN(common->mtu);
     }
 
     return ret;
@@ -1076,53 +1040,14 @@ dpdk_watchdog(void *dummy OVS_UNUSED)
     return NULL;
 }
 
-static void
-netdev_dpdk_update_netdev_flag(struct netdev_dpdk *dev,
-                               enum dpdk_hw_ol_features hw_ol_features,
-                               enum netdev_ol_flags flag)
-    OVS_REQUIRES(dev->mutex)
-{
-    struct netdev *netdev = &dev->up;
-
-    if (dev->hw_ol_features & hw_ol_features) {
-        netdev->ol_flags |= flag;
-    } else {
-        netdev->ol_flags &= ~flag;
-    }
-}
-
-static void
-netdev_dpdk_update_netdev_flags(struct netdev_dpdk *dev)
-    OVS_REQUIRES(dev->mutex)
-{
-    netdev_dpdk_update_netdev_flag(dev, NETDEV_TX_IPV4_CKSUM_OFFLOAD,
-                                   NETDEV_TX_OFFLOAD_IPV4_CKSUM);
-    netdev_dpdk_update_netdev_flag(dev, NETDEV_TX_TCP_CKSUM_OFFLOAD,
-                                   NETDEV_TX_OFFLOAD_TCP_CKSUM);
-    netdev_dpdk_update_netdev_flag(dev, NETDEV_TX_UDP_CKSUM_OFFLOAD,
-                                   NETDEV_TX_OFFLOAD_UDP_CKSUM);
-    netdev_dpdk_update_netdev_flag(dev, NETDEV_TX_SCTP_CKSUM_OFFLOAD,
-                                   NETDEV_TX_OFFLOAD_SCTP_CKSUM);
-    netdev_dpdk_update_netdev_flag(dev, NETDEV_TX_TSO_OFFLOAD,
-                                   NETDEV_TX_OFFLOAD_TCP_TSO);
-    netdev_dpdk_update_netdev_flag(dev, NETDEV_TX_VXLAN_TNL_TSO_OFFLOAD,
-                                   NETDEV_TX_VXLAN_TNL_TSO);
-    netdev_dpdk_update_netdev_flag(dev, NETDEV_TX_GRE_TNL_TSO_OFFLOAD,
-                                   NETDEV_TX_GRE_TNL_TSO);
-    netdev_dpdk_update_netdev_flag(dev, NETDEV_TX_GENEVE_TNL_TSO_OFFLOAD,
-                                   NETDEV_TX_GENEVE_TNL_TSO);
-    netdev_dpdk_update_netdev_flag(dev, NETDEV_TX_OUTER_IP_CKSUM_OFFLOAD,
-                                   NETDEV_TX_OFFLOAD_OUTER_IP_CKSUM);
-    netdev_dpdk_update_netdev_flag(dev, NETDEV_TX_OUTER_UDP_CKSUM_OFFLOAD,
-                                   NETDEV_TX_OFFLOAD_OUTER_UDP_CKSUM);
-}
-
 static int
 dpdk_eth_dev_port_config(struct netdev_dpdk *dev,
                          const struct rte_eth_dev_info *info,
                          int n_rxq, int n_txq)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(&dev->up);
     struct rte_eth_conf conf = port_conf;
+    struct netdev *netdev = &common->up;
     uint16_t conf_mtu;
     int diag = 0;
     int i;
@@ -1131,60 +1056,60 @@ dpdk_eth_dev_port_config(struct netdev_dpdk *dev,
      * scatter to support jumbo RX.
      * Setting scatter for the device is done after checking for
      * scatter support in the device capabilites. */
-    if (dev->mtu > RTE_ETHER_MTU) {
-        if (dev->hw_ol_features & NETDEV_RX_HW_SCATTER) {
+    if (common->mtu > RTE_ETHER_MTU) {
+        if (common->hw_ol_features & NETDEV_RX_HW_SCATTER) {
             conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_SCATTER;
         }
     }
 
     conf.intr_conf.lsc = dev->lsc_interrupt_mode;
 
-    if (dev->hw_ol_features & NETDEV_RX_CHECKSUM_OFFLOAD) {
+    if (common->hw_ol_features & NETDEV_RX_CHECKSUM_OFFLOAD) {
         conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_CHECKSUM;
     }
 
-    if (!(dev->hw_ol_features & NETDEV_RX_HW_CRC_STRIP)
+    if (!(common->hw_ol_features & NETDEV_RX_HW_CRC_STRIP)
         && info->rx_offload_capa & RTE_ETH_RX_OFFLOAD_KEEP_CRC) {
         conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_KEEP_CRC;
     }
 
-    if (dev->hw_ol_features & NETDEV_TX_IPV4_CKSUM_OFFLOAD) {
+    if (common->hw_ol_features & NETDEV_TX_IPV4_CKSUM_OFFLOAD) {
         conf.txmode.offloads |= RTE_ETH_TX_OFFLOAD_IPV4_CKSUM;
     }
 
-    if (dev->hw_ol_features & NETDEV_TX_TCP_CKSUM_OFFLOAD) {
+    if (common->hw_ol_features & NETDEV_TX_TCP_CKSUM_OFFLOAD) {
         conf.txmode.offloads |= RTE_ETH_TX_OFFLOAD_TCP_CKSUM;
     }
 
-    if (dev->hw_ol_features & NETDEV_TX_UDP_CKSUM_OFFLOAD) {
+    if (common->hw_ol_features & NETDEV_TX_UDP_CKSUM_OFFLOAD) {
         conf.txmode.offloads |= RTE_ETH_TX_OFFLOAD_UDP_CKSUM;
     }
 
-    if (dev->hw_ol_features & NETDEV_TX_SCTP_CKSUM_OFFLOAD) {
+    if (common->hw_ol_features & NETDEV_TX_SCTP_CKSUM_OFFLOAD) {
         conf.txmode.offloads |= RTE_ETH_TX_OFFLOAD_SCTP_CKSUM;
     }
 
-    if (dev->hw_ol_features & NETDEV_TX_TSO_OFFLOAD) {
+    if (common->hw_ol_features & NETDEV_TX_TSO_OFFLOAD) {
         conf.txmode.offloads |= RTE_ETH_TX_OFFLOAD_TCP_TSO;
     }
 
-    if (dev->hw_ol_features & NETDEV_TX_VXLAN_TNL_TSO_OFFLOAD) {
+    if (common->hw_ol_features & NETDEV_TX_VXLAN_TNL_TSO_OFFLOAD) {
         conf.txmode.offloads |= RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO;
     }
 
-    if (dev->hw_ol_features & NETDEV_TX_GENEVE_TNL_TSO_OFFLOAD) {
+    if (common->hw_ol_features & NETDEV_TX_GENEVE_TNL_TSO_OFFLOAD) {
         conf.txmode.offloads |= RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO;
     }
 
-    if (dev->hw_ol_features & NETDEV_TX_GRE_TNL_TSO_OFFLOAD) {
+    if (common->hw_ol_features & NETDEV_TX_GRE_TNL_TSO_OFFLOAD) {
         conf.txmode.offloads |= RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO;
     }
 
-    if (dev->hw_ol_features & NETDEV_TX_OUTER_IP_CKSUM_OFFLOAD) {
+    if (common->hw_ol_features & NETDEV_TX_OUTER_IP_CKSUM_OFFLOAD) {
         conf.txmode.offloads |= RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM;
     }
 
-    if (dev->hw_ol_features & NETDEV_TX_OUTER_UDP_CKSUM_OFFLOAD) {
+    if (common->hw_ol_features & NETDEV_TX_OUTER_UDP_CKSUM_OFFLOAD) {
         conf.txmode.offloads |= RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM;
     }
 
@@ -1210,11 +1135,11 @@ dpdk_eth_dev_port_config(struct netdev_dpdk *dev,
         diag = rte_eth_dev_configure(dev->port_id, n_rxq, n_txq, &conf);
         if (diag) {
             VLOG_WARN("Interface %s eth_dev setup error %s\n",
-                      dev->up.name, rte_strerror(-diag));
+                      netdev->name, rte_strerror(-diag));
             break;
         }
 
-        diag = rte_eth_dev_set_mtu(dev->port_id, dev->mtu);
+        diag = rte_eth_dev_set_mtu(dev->port_id, common->mtu);
         if (diag) {
             /* A device may not support rte_eth_dev_set_mtu, in this case
              * flag a warning to the user and include the devices configured
@@ -1223,20 +1148,20 @@ dpdk_eth_dev_port_config(struct netdev_dpdk *dev,
                 rte_eth_dev_get_mtu(dev->port_id, &conf_mtu);
                 VLOG_WARN("Interface %s does not support MTU configuration, "
                           "max packet size supported is %"PRIu16".",
-                          dev->up.name, conf_mtu);
+                          netdev->name, conf_mtu);
             } else {
                 VLOG_ERR("Interface %s MTU (%d) setup error: %s",
-                         dev->up.name, dev->mtu, rte_strerror(-diag));
+                         netdev->name, common->mtu, rte_strerror(-diag));
                 break;
             }
         }
 
         for (i = 0; i < n_txq; i++) {
             diag = rte_eth_tx_queue_setup(dev->port_id, i, dev->txq_size,
-                                          dev->socket_id, NULL);
+                                          common->socket_id, NULL);
             if (diag) {
                 VLOG_INFO("Interface %s unable to setup txq(%d): %s",
-                          dev->up.name, i, rte_strerror(-diag));
+                          netdev->name, i, rte_strerror(-diag));
                 break;
             }
         }
@@ -1249,11 +1174,11 @@ dpdk_eth_dev_port_config(struct netdev_dpdk *dev,
 
         for (i = 0; i < n_rxq; i++) {
             diag = rte_eth_rx_queue_setup(dev->port_id, i, dev->rxq_size,
-                                          dev->socket_id, NULL,
-                                          dev->dpdk_mp->mp);
+                                          common->socket_id, NULL,
+                                          common->dpdk_mp->mp);
             if (diag) {
                 VLOG_INFO("Interface %s unable to setup rxq(%d): %s",
-                          dev->up.name, i, rte_strerror(-diag));
+                          netdev->name, i, rte_strerror(-diag));
                 break;
             }
         }
@@ -1264,8 +1189,8 @@ dpdk_eth_dev_port_config(struct netdev_dpdk *dev,
             continue;
         }
 
-        dev->up.n_rxq = n_rxq;
-        dev->up.n_txq = n_txq;
+        netdev->n_rxq = n_rxq;
+        netdev->n_txq = n_txq;
 
         return 0;
     }
@@ -1285,6 +1210,7 @@ dpdk_eth_flow_ctrl_setup(struct netdev_dpdk *dev) 
OVS_REQUIRES(dev->mutex)
 static void
 dpdk_eth_dev_init_rx_metadata(struct netdev_dpdk *dev)
 {
+    struct netdev *netdev = &dev->up;
     uint64_t rx_metadata = 0;
     int ret;
 
@@ -1299,12 +1225,12 @@ dpdk_eth_dev_init_rx_metadata(struct netdev_dpdk *dev)
     if (ret == 0) {
         if (!(rx_metadata & RTE_ETH_RX_METADATA_USER_MARK)) {
             VLOG_DBG("%s: The NIC will not provide per-packet USER_MARK",
-                     netdev_get_name(&dev->up));
+                     netdev_get_name(netdev));
         }
     } else {
         VLOG(ret == -ENOTSUP ? VLL_DBG : VLL_WARN,
              "%s: Cannot negotiate Rx metadata: %s",
-             netdev_get_name(&dev->up), rte_strerror(-ret));
+             netdev_get_name(netdev), rte_strerror(-ret));
     }
 
     dev->rx_metadata_delivery_configured = true;
@@ -1314,7 +1240,9 @@ static int
 dpdk_eth_dev_init(struct netdev_dpdk *dev)
     OVS_REQUIRES(dev->mutex)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(&dev->up);
     struct rte_pktmbuf_pool_private *mbp_priv;
+    struct netdev *netdev = &common->up;
     struct rte_eth_dev_info info;
     struct rte_ether_addr eth_addr;
     int diag;
@@ -1338,7 +1266,7 @@ dpdk_eth_dev_init(struct netdev_dpdk *dev)
     diag = rte_eth_dev_info_get(dev->port_id, &info);
     if (diag < 0) {
         VLOG_ERR("Interface %s rte_eth_dev_info_get error: %s",
-                 dev->up.name, rte_strerror(-diag));
+                 netdev->name, rte_strerror(-diag));
         return -diag;
     }
 
@@ -1346,102 +1274,102 @@ dpdk_eth_dev_init(struct netdev_dpdk *dev)
 
     if (strstr(info.driver_name, "vf") != NULL) {
         VLOG_INFO("Virtual function detected, HW_CRC_STRIP will be enabled");
-        dev->hw_ol_features |= NETDEV_RX_HW_CRC_STRIP;
+        common->hw_ol_features |= NETDEV_RX_HW_CRC_STRIP;
     } else {
-        dev->hw_ol_features &= ~NETDEV_RX_HW_CRC_STRIP;
+        common->hw_ol_features &= ~NETDEV_RX_HW_CRC_STRIP;
     }
 
     if ((info.rx_offload_capa & rx_chksm_offload_capa) !=
             rx_chksm_offload_capa) {
         VLOG_WARN("Rx checksum offload is not supported on port "
                   DPDK_PORT_ID_FMT, dev->port_id);
-        dev->hw_ol_features &= ~NETDEV_RX_CHECKSUM_OFFLOAD;
+        common->hw_ol_features &= ~NETDEV_RX_CHECKSUM_OFFLOAD;
     } else {
-        dev->hw_ol_features |= NETDEV_RX_CHECKSUM_OFFLOAD;
+        common->hw_ol_features |= NETDEV_RX_CHECKSUM_OFFLOAD;
     }
 
     if (info.rx_offload_capa & RTE_ETH_RX_OFFLOAD_SCATTER) {
-        dev->hw_ol_features |= NETDEV_RX_HW_SCATTER;
+        common->hw_ol_features |= NETDEV_RX_HW_SCATTER;
     } else {
         /* Do not warn on lack of scatter support */
-        dev->hw_ol_features &= ~NETDEV_RX_HW_SCATTER;
+        common->hw_ol_features &= ~NETDEV_RX_HW_SCATTER;
     }
 
     if (info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_IPV4_CKSUM) {
-        dev->hw_ol_features |= NETDEV_TX_IPV4_CKSUM_OFFLOAD;
+        common->hw_ol_features |= NETDEV_TX_IPV4_CKSUM_OFFLOAD;
     } else {
-        dev->hw_ol_features &= ~NETDEV_TX_IPV4_CKSUM_OFFLOAD;
+        common->hw_ol_features &= ~NETDEV_TX_IPV4_CKSUM_OFFLOAD;
     }
 
     if (info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_TCP_CKSUM) {
-        dev->hw_ol_features |= NETDEV_TX_TCP_CKSUM_OFFLOAD;
+        common->hw_ol_features |= NETDEV_TX_TCP_CKSUM_OFFLOAD;
     } else {
-        dev->hw_ol_features &= ~NETDEV_TX_TCP_CKSUM_OFFLOAD;
+        common->hw_ol_features &= ~NETDEV_TX_TCP_CKSUM_OFFLOAD;
     }
 
     if (info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_UDP_CKSUM) {
-        dev->hw_ol_features |= NETDEV_TX_UDP_CKSUM_OFFLOAD;
+        common->hw_ol_features |= NETDEV_TX_UDP_CKSUM_OFFLOAD;
     } else {
-        dev->hw_ol_features &= ~NETDEV_TX_UDP_CKSUM_OFFLOAD;
+        common->hw_ol_features &= ~NETDEV_TX_UDP_CKSUM_OFFLOAD;
     }
 
     if (info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_SCTP_CKSUM) {
-        dev->hw_ol_features |= NETDEV_TX_SCTP_CKSUM_OFFLOAD;
+        common->hw_ol_features |= NETDEV_TX_SCTP_CKSUM_OFFLOAD;
     } else {
-        dev->hw_ol_features &= ~NETDEV_TX_SCTP_CKSUM_OFFLOAD;
+        common->hw_ol_features &= ~NETDEV_TX_SCTP_CKSUM_OFFLOAD;
     }
 
     if (info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM) {
-        dev->hw_ol_features |= NETDEV_TX_OUTER_IP_CKSUM_OFFLOAD;
+        common->hw_ol_features |= NETDEV_TX_OUTER_IP_CKSUM_OFFLOAD;
     } else {
-        dev->hw_ol_features &= ~NETDEV_TX_OUTER_IP_CKSUM_OFFLOAD;
+        common->hw_ol_features &= ~NETDEV_TX_OUTER_IP_CKSUM_OFFLOAD;
     }
 
     if (info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM) {
-        dev->hw_ol_features |= NETDEV_TX_OUTER_UDP_CKSUM_OFFLOAD;
+        common->hw_ol_features |= NETDEV_TX_OUTER_UDP_CKSUM_OFFLOAD;
     } else {
-        dev->hw_ol_features &= ~NETDEV_TX_OUTER_UDP_CKSUM_OFFLOAD;
+        common->hw_ol_features &= ~NETDEV_TX_OUTER_UDP_CKSUM_OFFLOAD;
     }
 
-    dev->hw_ol_features &= ~NETDEV_TX_TSO_OFFLOAD;
+    common->hw_ol_features &= ~NETDEV_TX_TSO_OFFLOAD;
     if (userspace_tso_enabled()) {
         if (info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_TCP_TSO) {
-            dev->hw_ol_features |= NETDEV_TX_TSO_OFFLOAD;
+            common->hw_ol_features |= NETDEV_TX_TSO_OFFLOAD;
         } else {
             VLOG_WARN("%s: Tx TSO offload is not supported.",
-                      netdev_get_name(&dev->up));
+                      netdev_get_name(netdev));
         }
 
         if (info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO) {
-            dev->hw_ol_features |= NETDEV_TX_VXLAN_TNL_TSO_OFFLOAD;
+            common->hw_ol_features |= NETDEV_TX_VXLAN_TNL_TSO_OFFLOAD;
         } else {
             VLOG_WARN("%s: Tx Vxlan tunnel TSO offload is not supported.",
-                      netdev_get_name(&dev->up));
+                      netdev_get_name(netdev));
         }
 
         if (info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO) {
-            dev->hw_ol_features |= NETDEV_TX_GENEVE_TNL_TSO_OFFLOAD;
+            common->hw_ol_features |= NETDEV_TX_GENEVE_TNL_TSO_OFFLOAD;
         } else {
             VLOG_WARN("%s: Tx Geneve tunnel TSO offload is not supported.",
-                      netdev_get_name(&dev->up));
+                      netdev_get_name(netdev));
         }
 
         if (info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO) {
-            dev->hw_ol_features |= NETDEV_TX_GRE_TNL_TSO_OFFLOAD;
+            common->hw_ol_features |= NETDEV_TX_GRE_TNL_TSO_OFFLOAD;
         } else {
             VLOG_WARN("%s: Tx GRE tunnel TSO offload is not supported.",
-                      netdev_get_name(&dev->up));
+                      netdev_get_name(netdev));
         }
     }
 
-    n_rxq = MIN(info.max_rx_queues, dev->up.n_rxq);
-    n_txq = MIN(info.max_tx_queues, dev->up.n_txq);
+    n_rxq = MIN(info.max_rx_queues, netdev->n_rxq);
+    n_txq = MIN(info.max_tx_queues, netdev->n_txq);
 
     diag = dpdk_eth_dev_port_config(dev, &info, n_rxq, n_txq);
     if (diag) {
         VLOG_ERR("Interface %s(rxq:%d txq:%d lsc interrupt mode:%s) "
                  "configure error: %s",
-                 dev->up.name, n_rxq, n_txq,
+                 netdev->name, n_rxq, n_txq,
                  dev->lsc_interrupt_mode ? "true" : "false",
                  rte_strerror(-diag));
         return -diag;
@@ -1449,7 +1377,7 @@ dpdk_eth_dev_init(struct netdev_dpdk *dev)
 
     diag = rte_eth_dev_start(dev->port_id);
     if (diag) {
-        VLOG_ERR("Interface %s start error: %s", dev->up.name,
+        VLOG_ERR("Interface %s start error: %s", netdev->name,
                  rte_strerror(-diag));
         return -diag;
     }
@@ -1465,13 +1393,13 @@ dpdk_eth_dev_init(struct netdev_dpdk *dev)
     VLOG_INFO_RL(&rl, "Port "DPDK_PORT_ID_FMT": "ETH_ADDR_FMT,
                  dev->port_id, ETH_ADDR_BYTES_ARGS(eth_addr.addr_bytes));
 
-    memcpy(dev->hwaddr.ea, eth_addr.addr_bytes, ETH_ADDR_LEN);
+    memcpy(common->hwaddr.ea, eth_addr.addr_bytes, ETH_ADDR_LEN);
     if (rte_eth_link_get_nowait(dev->port_id, &dev->link) < 0) {
         memset(&dev->link, 0, sizeof dev->link);
     }
 
-    mbp_priv = rte_mempool_get_priv(dev->dpdk_mp->mp);
-    dev->buf_size = mbp_priv->mbuf_data_room_size - RTE_PKTMBUF_HEADROOM;
+    mbp_priv = rte_mempool_get_priv(common->dpdk_mp->mp);
+    common->buf_size = mbp_priv->mbuf_data_room_size - RTE_PKTMBUF_HEADROOM;
     return 0;
 }
 
@@ -1524,50 +1452,51 @@ netdev_dpdk_vhost_alloc(void)
 }
 
 static void
-common_construct(struct netdev *netdev, int socket_id)
+common_construct(struct netdev_dpdk_common *common, int socket_id)
     OVS_REQUIRES(dpdk_mutex)
 {
-    struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+    struct netdev *netdev = &common->up;
 
-    ovs_mutex_init(&dev->mutex);
+    ovs_mutex_init(&common->mutex);
 
-    rte_spinlock_init(&dev->stats_lock);
+    rte_spinlock_init(&common->stats_lock);
 
     /* If the 'sid' is negative, it means that the kernel fails
      * to obtain the pci numa info.  In that situation, always
      * use 'SOCKET0'. */
-    dev->socket_id = socket_id < 0 ? SOCKET0 : socket_id;
-    dev->requested_socket_id = dev->socket_id;
-    dev->requested_mtu = RTE_ETHER_MTU;
-    dev->max_packet_len = MTU_TO_FRAME_LEN(dev->mtu);
+    common->socket_id = socket_id < 0 ? SOCKET0 : socket_id;
+    common->requested_socket_id = common->socket_id;
+    common->requested_mtu = RTE_ETHER_MTU;
+    common->max_packet_len = MTU_TO_FRAME_LEN(common->mtu);
 
-    ovsrcu_init(&dev->qos_conf, NULL);
+    ovsrcu_init(&common->qos_conf, NULL);
 
-    ovsrcu_init(&dev->ingress_policer, NULL);
-    dev->policer_rate = 0;
-    dev->policer_burst = 0;
+    ovsrcu_init(&common->ingress_policer, NULL);
+    common->policer_rate = 0;
+    common->policer_burst = 0;
 
     netdev->n_rxq = 0;
     netdev->n_txq = 0;
-    dev->requested_n_rxq = NR_QUEUE;
-    dev->requested_n_txq = NR_QUEUE;
+    common->requested_n_rxq = NR_QUEUE;
+    common->requested_n_txq = NR_QUEUE;
 
     /* Initilize the hardware offload flags to 0 */
-    dev->hw_ol_features = 0;
+    common->hw_ol_features = 0;
 
-    dev->flags = NETDEV_UP | NETDEV_PROMISC;
+    common->flags = NETDEV_UP | NETDEV_PROMISC;
 
-    ovs_list_push_back(&dpdk_list, &dev->list_node);
+    ovs_list_push_back(&dpdk_list, &common->list_node);
 
     netdev_request_reconfigure(netdev);
 
-    dev->sw_stats = xzalloc(sizeof *dev->sw_stats);
+    common->sw_stats = xzalloc(sizeof *common->sw_stats);
 }
 
 static int
 vhost_common_construct(struct netdev *netdev)
     OVS_REQUIRES(dpdk_mutex)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     int socket_id = rte_lcore_to_socket_id(rte_get_main_lcore());
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
 
@@ -1576,13 +1505,13 @@ vhost_common_construct(struct netdev *netdev)
     if (!dev->vhost_rxq_enabled) {
         return ENOMEM;
     }
-    dev->tx_q = netdev_dpdk_alloc_txq(OVS_VHOST_MAX_QUEUE_NUM);
-    if (!dev->tx_q) {
+    common->tx_q = netdev_dpdk_alloc_txq(OVS_VHOST_MAX_QUEUE_NUM);
+    if (!common->tx_q) {
         rte_free(dev->vhost_rxq_enabled);
         return ENOMEM;
     }
     for (unsigned i = 0; i < OVS_VHOST_MAX_QUEUE_NUM; i++) {
-        dev->tx_q[i].map = OVS_VHOST_QUEUE_MAP_UNKNOWN;
+        common->tx_q[i].map = OVS_VHOST_QUEUE_MAP_UNKNOWN;
     }
 
     ovsrcu_index_init(&dev->vid, -1);
@@ -1592,7 +1521,7 @@ vhost_common_construct(struct netdev *netdev)
 
     dev->vhost_max_queue_pairs = VHOST_MAX_QUEUE_PAIRS_DEF;
 
-    common_construct(netdev, socket_id);
+    common_construct(common, socket_id);
     return 0;
 }
 
@@ -1697,10 +1626,11 @@ netdev_dpdk_vhost_client_construct(struct netdev 
*netdev)
 static int
 netdev_dpdk_eth_construct(struct netdev *netdev)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
 
     ovs_mutex_lock(&dpdk_mutex);
-    common_construct(netdev, SOCKET0);
+    common_construct(common, SOCKET0);
 
     dev->port_id = DPDK_ETH_PORT_ID_INVALID;
     dev->attached = false;
@@ -1719,24 +1649,24 @@ netdev_dpdk_eth_construct(struct netdev *netdev)
     dev->rte_xstats_names_size = 0;
     dev->rte_xstats_ids = NULL;
     dev->rte_xstats_ids_size = 0;
-    dev->sw_stats->tx_retries = UINT64_MAX;
+    common->sw_stats->tx_retries = UINT64_MAX;
     ovs_mutex_unlock(&dpdk_mutex);
     return 0;
 }
 
 static void
-common_destruct(struct netdev_dpdk *dev)
+common_destruct(struct netdev_dpdk_common *common)
     OVS_REQUIRES(dpdk_mutex)
-    OVS_EXCLUDED(dev->mutex)
+    OVS_EXCLUDED(common->mutex)
 {
-    rte_free(dev->tx_q);
-    dpdk_mp_put(dev->dpdk_mp);
+    rte_free(common->tx_q);
+    dpdk_mp_put(common->dpdk_mp);
 
-    ovs_list_remove(&dev->list_node);
+    ovs_list_remove(&common->list_node);
     free(ovsrcu_get_protected(struct ingress_policer *,
-                              &dev->ingress_policer));
-    free(dev->sw_stats);
-    ovs_mutex_destroy(&dev->mutex);
+                              &common->ingress_policer));
+    free(common->sw_stats);
+    ovs_mutex_destroy(&common->mutex);
 }
 
 static void dpdk_rx_steer_unconfigure(struct netdev_dpdk *);
@@ -1744,6 +1674,7 @@ static void dpdk_rx_steer_unconfigure(struct netdev_dpdk 
*);
 static void
 netdev_dpdk_eth_destruct(struct netdev *netdev)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
 
     ovs_mutex_lock(&dpdk_mutex);
@@ -1815,7 +1746,7 @@ netdev_dpdk_eth_destruct(struct netdev *netdev)
 
     netdev_dpdk_clear_xstats(dev);
     free(dev->devargs);
-    common_destruct(dev);
+    common_destruct(common);
 
     ovs_mutex_unlock(&dpdk_mutex);
 }
@@ -1843,6 +1774,7 @@ dpdk_vhost_driver_unregister(struct netdev_dpdk *dev 
OVS_UNUSED,
 static void
 netdev_dpdk_vhost_destruct(struct netdev *netdev)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
     bool is_client_mode;
     char *vhost_id;
@@ -1863,7 +1795,7 @@ netdev_dpdk_vhost_destruct(struct netdev *netdev)
     dev->vhost_id = NULL;
     rte_free(dev->vhost_rxq_enabled);
 
-    common_destruct(dev);
+    common_destruct(common);
 
     ovs_mutex_unlock(&dpdk_mutex);
 
@@ -2190,10 +2122,12 @@ netdev_dpdk_eth_run(const struct netdev_class 
*netdev_class OVS_UNUSED)
             ovs_mutex_lock(&dpdk_mutex);
             dev = netdev_dpdk_lookup_by_port_id(port_id);
             if (dev) {
+                struct netdev *netdev = &dev->up;
+
                 ovs_mutex_lock(&dev->mutex);
-                netdev_request_reconfigure(&dev->up);
+                netdev_request_reconfigure(netdev);
                 VLOG_DBG_RL(&rl, "%s: Device reset requested.",
-                            netdev_get_name(&dev->up));
+                            netdev_get_name(netdev));
                 ovs_mutex_unlock(&dev->mutex);
             }
             ovs_mutex_unlock(&dpdk_mutex);
@@ -2314,6 +2248,7 @@ static int
 netdev_dpdk_eth_set_config(struct netdev *netdev, const struct smap *args,
                            char **errp)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
     bool rx_fc_en, tx_fc_en, autoneg, lsc_interrupt_mode;
     bool flow_control_requested = true;
@@ -2370,10 +2305,10 @@ netdev_dpdk_eth_set_config(struct netdev *netdev, const 
struct smap *args,
                 } else {
                     int sid = rte_eth_dev_socket_id(new_port_id);
 
-                    dev->requested_socket_id = sid < 0 ? SOCKET0 : sid;
+                    common->requested_socket_id = sid < 0 ? SOCKET0 : sid;
                     dev->devargs = xstrdup(new_devargs);
                     dev->port_id = new_port_id;
-                    netdev_request_reconfigure(&dev->up);
+                    netdev_request_reconfigure(netdev);
                     err = 0;
                 }
             }
@@ -2549,27 +2484,20 @@ netdev_dpdk_vhost_client_set_config(struct netdev 
*netdev,
     return 0;
 }
 
-static int
-netdev_dpdk_get_numa_id(const struct netdev *netdev)
-{
-    struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
-
-    return dev->socket_id;
-}
-
 /* Sets the number of tx queues for the dpdk interface. */
 static int
 netdev_dpdk_eth_set_tx_multiq(struct netdev *netdev, unsigned int n_txq)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
 
     ovs_mutex_lock(&dev->mutex);
 
-    if (dev->requested_n_txq == n_txq) {
+    if (common->requested_n_txq == n_txq) {
         goto out;
     }
 
-    dev->requested_n_txq = n_txq;
+    common->requested_n_txq = n_txq;
     netdev_request_reconfigure(netdev);
 
 out:
@@ -2663,10 +2591,12 @@ netdev_dpdk_batch_init_packet_fields(struct 
dp_packet_batch *batch)
 /* Prepare the packet for HWOL.
  * Return True if the packet is OK to continue. */
 static bool
-netdev_dpdk_prep_hwol_packet(struct netdev_dpdk *dev, struct rte_mbuf *mbuf)
+netdev_dpdk_prep_hwol_packet(struct netdev_dpdk_common *common,
+                             struct rte_mbuf *mbuf)
 {
     struct dp_packet *pkt = CONTAINER_OF(mbuf, struct dp_packet, mbuf);
     uint64_t unexpected = mbuf->ol_flags & RTE_MBUF_F_TX_OFFLOAD_MASK;
+    struct netdev *netdev = &common->up;
     const struct ip_header *ip;
     bool is_sctp;
     bool l3_csum;
@@ -2679,8 +2609,8 @@ netdev_dpdk_prep_hwol_packet(struct netdev_dpdk *dev, 
struct rte_mbuf *mbuf)
 
     if (OVS_UNLIKELY(unexpected)) {
         VLOG_WARN_RL(&rl, "%s: Unexpected Tx offload flags: %#"PRIx64,
-                     netdev_get_name(&dev->up), unexpected);
-        netdev_dpdk_mbuf_dump(netdev_get_name(&dev->up),
+                     netdev_get_name(netdev), unexpected);
+        netdev_dpdk_mbuf_dump(netdev_get_name(netdev),
                               "Packet with unexpected ol_flags", mbuf);
         return false;
     }
@@ -2781,11 +2711,12 @@ netdev_dpdk_prep_hwol_packet(struct netdev_dpdk *dev, 
struct rte_mbuf *mbuf)
             hdr_len += mbuf->outer_l2_len + mbuf->outer_l3_len;
         }
 
-        if (OVS_UNLIKELY((hdr_len + mbuf->tso_segsz) > dev->max_packet_len)) {
+        if (OVS_UNLIKELY((hdr_len + mbuf->tso_segsz)
+            > common->max_packet_len)) {
             VLOG_WARN_RL(&rl, "%s: Oversized TSO packet. hdr: %"PRIu32", "
                          "gso: %"PRIu32", max len: %"PRIu32"",
-                         dev->up.name, hdr_len, mbuf->tso_segsz,
-                         dev->max_packet_len);
+                         netdev->name, hdr_len, mbuf->tso_segsz,
+                         common->max_packet_len);
             return false;
         }
         mbuf->ol_flags |= RTE_MBUF_F_TX_TCP_SEG;
@@ -2802,8 +2733,8 @@ netdev_dpdk_prep_hwol_packet(struct netdev_dpdk *dev, 
struct rte_mbuf *mbuf)
 /* Prepare a batch for HWOL.
  * Return the number of good packets in the batch. */
 static int
-netdev_dpdk_prep_hwol_batch(struct netdev_dpdk *dev, struct rte_mbuf **pkts,
-                            int pkt_cnt)
+netdev_dpdk_prep_hwol_batch(struct netdev_dpdk_common *common,
+                            struct rte_mbuf **pkts, int pkt_cnt)
 {
     int i = 0;
     int cnt = 0;
@@ -2812,7 +2743,7 @@ netdev_dpdk_prep_hwol_batch(struct netdev_dpdk *dev, 
struct rte_mbuf **pkts,
     /* Prepare and filter bad HWOL packets. */
     for (i = 0; i < pkt_cnt; i++) {
         pkt = pkts[i];
-        if (!netdev_dpdk_prep_hwol_packet(dev, pkt)) {
+        if (!netdev_dpdk_prep_hwol_packet(common, pkt)) {
             rte_pktmbuf_free(pkt);
             continue;
         }
@@ -2863,15 +2794,16 @@ static inline int
 netdev_dpdk_eth_tx_burst(struct netdev_dpdk *dev, int qid,
                          struct rte_mbuf **pkts, int cnt)
 {
+    struct netdev *netdev = &dev->up;
     uint32_t nb_tx = 0;
     uint16_t nb_tx_prep = cnt;
 
     nb_tx_prep = rte_eth_tx_prepare(dev->port_id, qid, pkts, cnt);
     if (nb_tx_prep != cnt) {
         VLOG_WARN_RL(&rl, "%s: Output batch contains invalid packets. "
-                     "Only %u/%u are valid: %s", netdev_get_name(&dev->up),
+                     "Only %u/%u are valid: %s", netdev_get_name(netdev),
                      nb_tx_prep, cnt, rte_strerror(rte_errno));
-        netdev_dpdk_mbuf_dump(netdev_get_name(&dev->up),
+        netdev_dpdk_mbuf_dump(netdev_get_name(netdev),
                               "First invalid packet", pkts[nb_tx_prep]);
     }
 
@@ -2964,6 +2896,7 @@ static int
 netdev_dpdk_vhost_rxq_recv(struct netdev_rxq *rxq,
                            struct dp_packet_batch *batch, int *qfill)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(rxq->netdev);
     struct netdev_dpdk *dev = netdev_dpdk_cast(rxq->netdev);
     struct ingress_policer *policer = netdev_dpdk_get_ingress_policer(dev);
     uint16_t nb_rx = 0;
@@ -2972,11 +2905,11 @@ netdev_dpdk_vhost_rxq_recv(struct netdev_rxq *rxq,
     int vid = netdev_dpdk_get_vid(dev);
 
     if (OVS_UNLIKELY(vid < 0 || !dev->vhost_reconfigured
-                     || !(dev->flags & NETDEV_UP))) {
+                     || !(common->flags & NETDEV_UP))) {
         return EAGAIN;
     }
 
-    nb_rx = rte_vhost_dequeue_burst(vid, qid, dev->dpdk_mp->mp,
+    nb_rx = rte_vhost_dequeue_burst(vid, qid, common->dpdk_mp->mp,
                                     (struct rte_mbuf **) batch->packets,
                                     NETDEV_MAX_BURST);
     if (!nb_rx) {
@@ -3002,10 +2935,10 @@ netdev_dpdk_vhost_rxq_recv(struct netdev_rxq *rxq,
     }
 
     if (OVS_UNLIKELY(qos_drops)) {
-        rte_spinlock_lock(&dev->stats_lock);
-        dev->stats.rx_dropped += qos_drops;
-        dev->sw_stats->rx_qos_drops += qos_drops;
-        rte_spinlock_unlock(&dev->stats_lock);
+        rte_spinlock_lock(&common->stats_lock);
+        common->stats.rx_dropped += qos_drops;
+        common->sw_stats->rx_qos_drops += qos_drops;
+        rte_spinlock_unlock(&common->stats_lock);
     }
 
     batch->count = nb_rx;
@@ -3026,13 +2959,14 @@ static int
 netdev_dpdk_eth_rxq_recv(struct netdev_rxq *rxq, struct dp_packet_batch *batch,
                          int *qfill)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(rxq->netdev);
     struct netdev_rxq_dpdk *rx = netdev_rxq_dpdk_cast(rxq);
     struct netdev_dpdk *dev = netdev_dpdk_cast(rxq->netdev);
     struct ingress_policer *policer = netdev_dpdk_get_ingress_policer(dev);
     int nb_rx;
     int dropped = 0;
 
-    if (OVS_UNLIKELY(!(dev->flags & NETDEV_UP))) {
+    if (OVS_UNLIKELY(!(common->flags & NETDEV_UP))) {
         return EAGAIN;
     }
 
@@ -3061,10 +2995,10 @@ netdev_dpdk_eth_rxq_recv(struct netdev_rxq *rxq, struct 
dp_packet_batch *batch,
 
     /* Update stats to reflect dropped packets */
     if (OVS_UNLIKELY(dropped)) {
-        rte_spinlock_lock(&dev->stats_lock);
-        dev->stats.rx_dropped += dropped;
-        dev->sw_stats->rx_qos_drops += dropped;
-        rte_spinlock_unlock(&dev->stats_lock);
+        rte_spinlock_lock(&common->stats_lock);
+        common->stats.rx_dropped += dropped;
+        common->sw_stats->rx_qos_drops += dropped;
+        rte_spinlock_unlock(&common->stats_lock);
     }
 
     batch->count = nb_rx;
@@ -3074,11 +3008,12 @@ netdev_dpdk_eth_rxq_recv(struct netdev_rxq *rxq, struct 
dp_packet_batch *batch,
 }
 
 static inline int
-netdev_dpdk_qos_run(struct netdev_dpdk *dev, struct rte_mbuf **pkts,
+netdev_dpdk_qos_run(struct netdev_dpdk_common *common, struct rte_mbuf **pkts,
                     int cnt, bool should_steal)
 {
-    struct qos_conf *qos_conf = ovsrcu_get(struct qos_conf *, &dev->qos_conf);
+    struct qos_conf *qos_conf;
 
+    qos_conf = ovsrcu_get(struct qos_conf *, &common->qos_conf);
     if (qos_conf) {
         rte_spinlock_lock(&qos_conf->lock);
         cnt = qos_conf->ops->qos_run(qos_conf, pkts, cnt, should_steal);
@@ -3089,8 +3024,8 @@ netdev_dpdk_qos_run(struct netdev_dpdk *dev, struct 
rte_mbuf **pkts,
 }
 
 static int
-netdev_dpdk_filter_packet_len(struct netdev_dpdk *dev, struct rte_mbuf **pkts,
-                              int pkt_cnt)
+netdev_dpdk_filter_packet_len(struct netdev_dpdk_common *common,
+                              struct rte_mbuf **pkts, int pkt_cnt)
 {
     int i = 0;
     int cnt = 0;
@@ -3100,11 +3035,11 @@ netdev_dpdk_filter_packet_len(struct netdev_dpdk *dev, 
struct rte_mbuf **pkts,
      * during the offloading preparation for performance reasons. */
     for (i = 0; i < pkt_cnt; i++) {
         pkt = pkts[i];
-        if (OVS_UNLIKELY((pkt->pkt_len > dev->max_packet_len)
+        if (OVS_UNLIKELY((pkt->pkt_len > common->max_packet_len)
             && !pkt->tso_segsz)) {
             VLOG_WARN_RL(&rl, "%s: Too big size %" PRIu32 " "
-                         "max_packet_len %d", dev->up.name, pkt->pkt_len,
-                         dev->max_packet_len);
+                         "max_packet_len %d", common->up.name, pkt->pkt_len,
+                         common->max_packet_len);
             rte_pktmbuf_free(pkt);
             continue;
         }
@@ -3275,7 +3210,7 @@ dpdk_copy_dp_packet_to_mbuf(struct rte_mempool *mp, 
struct dp_packet *pkt_orig)
 static size_t
 dpdk_copy_batch_to_mbuf(struct netdev *netdev, struct dp_packet_batch *batch)
 {
-    struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     size_t i, size = dp_packet_batch_size(batch);
     struct dp_packet *packet;
 
@@ -3285,7 +3220,7 @@ dpdk_copy_batch_to_mbuf(struct netdev *netdev, struct 
dp_packet_batch *batch)
         } else {
             struct dp_packet *pktcopy;
 
-            pktcopy = dpdk_copy_dp_packet_to_mbuf(dev->dpdk_mp->mp, packet);
+            pktcopy = dpdk_copy_dp_packet_to_mbuf(common->dpdk_mp->mp, packet);
             if (pktcopy) {
                 dp_packet_batch_add(batch, pktcopy);
             }
@@ -3298,12 +3233,13 @@ dpdk_copy_batch_to_mbuf(struct netdev *netdev, struct 
dp_packet_batch *batch)
 }
 
 static size_t
-netdev_dpdk_common_send(struct netdev *netdev, struct dp_packet_batch *batch,
+netdev_dpdk_common_send(struct netdev_dpdk_common *common,
+                        struct dp_packet_batch *batch,
                         struct netdev_dpdk_sw_stats *stats)
 {
     struct rte_mbuf **pkts = (struct rte_mbuf **) batch->packets;
-    struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
     size_t cnt, pkt_cnt = dp_packet_batch_size(batch);
+    struct netdev *netdev = &common->up;
     struct dp_packet *packet;
     bool need_copy = false;
 
@@ -3324,19 +3260,19 @@ netdev_dpdk_common_send(struct netdev *netdev, struct 
dp_packet_batch *batch,
     }
 
     /* Drop oversized packets. */
-    cnt = netdev_dpdk_filter_packet_len(dev, pkts, pkt_cnt);
+    cnt = netdev_dpdk_filter_packet_len(common, pkts, pkt_cnt);
     stats->tx_mtu_exceeded_drops += pkt_cnt - cnt;
     pkt_cnt = cnt;
 
     if (netdev->ol_flags) {
         /* Prepare each mbuf for hardware offloading. */
-        cnt = netdev_dpdk_prep_hwol_batch(dev, pkts, pkt_cnt);
+        cnt = netdev_dpdk_prep_hwol_batch(common, pkts, pkt_cnt);
         stats->tx_invalid_hwol_drops += pkt_cnt - cnt;
         pkt_cnt = cnt;
     }
 
     /* Apply Quality of Service policy. */
-    cnt = netdev_dpdk_qos_run(dev, pkts, pkt_cnt, true);
+    cnt = netdev_dpdk_qos_run(common, pkts, pkt_cnt, true);
     stats->tx_qos_drops += pkt_cnt - cnt;
 
     return cnt;
@@ -3347,6 +3283,7 @@ netdev_dpdk_vhost_send(struct netdev *netdev, int qid,
                        struct dp_packet_batch *batch,
                        bool concurrent_txq OVS_UNUSED)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
     int max_retries = VHOST_ENQ_RETRY_MIN;
     int cnt, batch_cnt, vhost_batch_cnt;
@@ -3357,22 +3294,22 @@ netdev_dpdk_vhost_send(struct netdev *netdev, int qid,
     int retries;
 
     batch_cnt = cnt = dp_packet_batch_size(batch);
-    qid = dev->tx_q[qid % netdev->n_txq].map;
+    qid = common->tx_q[qid % netdev->n_txq].map;
     if (OVS_UNLIKELY(vid < 0 || !dev->vhost_reconfigured || qid < 0
-                     || !(dev->flags & NETDEV_UP))) {
-        rte_spinlock_lock(&dev->stats_lock);
-        dev->stats.tx_dropped += cnt;
-        rte_spinlock_unlock(&dev->stats_lock);
+                     || !(common->flags & NETDEV_UP))) {
+        rte_spinlock_lock(&common->stats_lock);
+        common->stats.tx_dropped += cnt;
+        rte_spinlock_unlock(&common->stats_lock);
         dp_packet_delete_batch(batch, true);
         return 0;
     }
 
-    if (OVS_UNLIKELY(!rte_spinlock_trylock(&dev->tx_q[qid].tx_lock))) {
+    if (OVS_UNLIKELY(!rte_spinlock_trylock(&common->tx_q[qid].tx_lock))) {
         COVERAGE_INC(vhost_tx_contention);
-        rte_spinlock_lock(&dev->tx_q[qid].tx_lock);
+        rte_spinlock_lock(&common->tx_q[qid].tx_lock);
     }
 
-    cnt = netdev_dpdk_common_send(netdev, batch, &stats);
+    cnt = netdev_dpdk_common_send(common, batch, &stats);
     dropped = batch_cnt - cnt;
 
     pkts = (struct rte_mbuf **) batch->packets;
@@ -3408,23 +3345,23 @@ netdev_dpdk_vhost_send(struct netdev *netdev, int qid,
         }
     } while (cnt && (retries++ < max_retries));
 
-    rte_spinlock_unlock(&dev->tx_q[qid].tx_lock);
+    rte_spinlock_unlock(&common->tx_q[qid].tx_lock);
 
     stats.tx_failure_drops += cnt;
     dropped += cnt;
     stats.tx_retries = MIN(retries, max_retries);
 
     if (OVS_UNLIKELY(dropped || stats.tx_retries)) {
-        struct netdev_dpdk_sw_stats *sw_stats = dev->sw_stats;
+        struct netdev_dpdk_sw_stats *sw_stats = common->sw_stats;
 
-        rte_spinlock_lock(&dev->stats_lock);
-        dev->stats.tx_dropped += dropped;
+        rte_spinlock_lock(&common->stats_lock);
+        common->stats.tx_dropped += dropped;
         sw_stats->tx_retries += stats.tx_retries;
         sw_stats->tx_failure_drops += stats.tx_failure_drops;
         sw_stats->tx_mtu_exceeded_drops += stats.tx_mtu_exceeded_drops;
         sw_stats->tx_qos_drops += stats.tx_qos_drops;
         sw_stats->tx_invalid_hwol_drops += stats.tx_invalid_hwol_drops;
-        rte_spinlock_unlock(&dev->stats_lock);
+        rte_spinlock_unlock(&common->stats_lock);
     }
 
     pkts = (struct rte_mbuf **) batch->packets;
@@ -3437,44 +3374,45 @@ static int
 netdev_dpdk_eth_send(struct netdev *netdev, int qid,
                      struct dp_packet_batch *batch, bool concurrent_txq)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     struct rte_mbuf **pkts = (struct rte_mbuf **) batch->packets;
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
     int batch_cnt = dp_packet_batch_size(batch);
     struct netdev_dpdk_sw_stats stats;
     int cnt, dropped;
 
-    if (OVS_UNLIKELY(!(dev->flags & NETDEV_UP))) {
-        rte_spinlock_lock(&dev->stats_lock);
-        dev->stats.tx_dropped += dp_packet_batch_size(batch);
-        rte_spinlock_unlock(&dev->stats_lock);
+    if (OVS_UNLIKELY(!(common->flags & NETDEV_UP))) {
+        rte_spinlock_lock(&common->stats_lock);
+        common->stats.tx_dropped += dp_packet_batch_size(batch);
+        rte_spinlock_unlock(&common->stats_lock);
         dp_packet_delete_batch(batch, true);
         return 0;
     }
 
     if (OVS_UNLIKELY(concurrent_txq)) {
-        qid = qid % dev->up.n_txq;
-        rte_spinlock_lock(&dev->tx_q[qid].tx_lock);
+        qid = qid % netdev->n_txq;
+        rte_spinlock_lock(&common->tx_q[qid].tx_lock);
     }
 
-    cnt = netdev_dpdk_common_send(netdev, batch, &stats);
+    cnt = netdev_dpdk_common_send(common, batch, &stats);
 
     dropped = netdev_dpdk_eth_tx_burst(dev, qid, pkts, cnt);
     stats.tx_failure_drops += dropped;
     dropped += batch_cnt - cnt;
     if (OVS_UNLIKELY(dropped)) {
-        struct netdev_dpdk_sw_stats *sw_stats = dev->sw_stats;
+        struct netdev_dpdk_sw_stats *sw_stats = common->sw_stats;
 
-        rte_spinlock_lock(&dev->stats_lock);
-        dev->stats.tx_dropped += dropped;
+        rte_spinlock_lock(&common->stats_lock);
+        common->stats.tx_dropped += dropped;
         sw_stats->tx_failure_drops += stats.tx_failure_drops;
         sw_stats->tx_mtu_exceeded_drops += stats.tx_mtu_exceeded_drops;
         sw_stats->tx_qos_drops += stats.tx_qos_drops;
         sw_stats->tx_invalid_hwol_drops += stats.tx_invalid_hwol_drops;
-        rte_spinlock_unlock(&dev->stats_lock);
+        rte_spinlock_unlock(&common->stats_lock);
     }
 
     if (OVS_UNLIKELY(concurrent_txq)) {
-        rte_spinlock_unlock(&dev->tx_q[qid].tx_lock);
+        rte_spinlock_unlock(&common->tx_q[qid].tx_lock);
     }
 
     return 0;
@@ -3485,16 +3423,17 @@ netdev_dpdk_eth_set_etheraddr__(struct netdev_dpdk *dev,
                                 const struct eth_addr mac)
     OVS_REQUIRES(dev->mutex)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(&dev->up);
     struct rte_ether_addr ea;
     int err;
 
     memcpy(ea.addr_bytes, mac.ea, ETH_ADDR_LEN);
     err = -rte_eth_dev_default_mac_addr_set(dev->port_id, &ea);
     if (!err) {
-        dev->hwaddr = mac;
+        common->hwaddr = mac;
     } else {
         VLOG_WARN("%s: Failed to set requested mac("ETH_ADDR_FMT"): %s",
-                  netdev_get_name(&dev->up), ETH_ADDR_ARGS(mac),
+                  netdev_get_name(&common->up), ETH_ADDR_ARGS(mac),
                   rte_strerror(err));
     }
 
@@ -3504,11 +3443,12 @@ netdev_dpdk_eth_set_etheraddr__(struct netdev_dpdk *dev,
 static int
 netdev_dpdk_eth_set_etheraddr(struct netdev *netdev, const struct eth_addr mac)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
     int err = 0;
 
     ovs_mutex_lock(&dev->mutex);
-    if (!eth_addr_equals(dev->hwaddr, mac)) {
+    if (!eth_addr_equals(common->hwaddr, mac)) {
         err = netdev_dpdk_eth_set_etheraddr__(dev, mac);
         if (!err) {
             netdev_change_seq_changed(netdev);
@@ -3523,11 +3463,12 @@ static int
 netdev_dpdk_vhost_set_etheraddr(struct netdev *netdev,
                                 const struct eth_addr mac)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
 
     ovs_mutex_lock(&dev->mutex);
-    if (!eth_addr_equals(dev->hwaddr, mac)) {
-        dev->hwaddr = mac;
+    if (!eth_addr_equals(common->hwaddr, mac)) {
+        common->hwaddr = mac;
         netdev_change_seq_changed(netdev);
     }
     ovs_mutex_unlock(&dev->mutex);
@@ -3539,10 +3480,11 @@ static int
 netdev_dpdk_eth_get_etheraddr(const struct netdev *netdev,
                               struct eth_addr *mac)
 {
+    const struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
 
     ovs_mutex_lock(&dev->mutex);
-    *mac = dev->hwaddr;
+    netdev_dpdk_common_get_etheraddr(common, mac);
     ovs_mutex_unlock(&dev->mutex);
 
     return 0;
@@ -3552,63 +3494,75 @@ static int
 netdev_dpdk_vhost_get_etheraddr(const struct netdev *netdev,
                                 struct eth_addr *mac)
 {
+    const struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
 
     ovs_mutex_lock(&dev->mutex);
-    *mac = dev->hwaddr;
+    netdev_dpdk_common_get_etheraddr(common, mac);
     ovs_mutex_unlock(&dev->mutex);
 
     return 0;
 }
 
 static int
-netdev_dpdk_get_mtu(const struct netdev *netdev, int *mtup)
+netdev_dpdk_eth_get_mtu(const struct netdev *netdev, int *mtup)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
 
     ovs_mutex_lock(&dev->mutex);
-    *mtup = dev->mtu;
+    netdev_dpdk_common_get_mtu(common, mtup);
     ovs_mutex_unlock(&dev->mutex);
 
     return 0;
 }
 
 static int
-netdev_dpdk_set_mtu(struct netdev *netdev, int mtu)
+netdev_dpdk_vhost_get_mtu(const struct netdev *netdev, int *mtup)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
 
-    /* XXX: Ensure that the overall frame length of the requested MTU does not
-     * surpass the NETDEV_DPDK_MAX_PKT_LEN. DPDK device drivers differ in how
-     * the L2 frame length is calculated for a given MTU when
-     * rte_eth_dev_set_mtu(mtu) is called e.g. i40e driver includes 2 x vlan
-     * headers, the em driver includes 1 x vlan header, the ixgbe driver does
-     * not include vlan headers. As such we should use
-     * MTU_TO_MAX_FRAME_LEN(mtu) which includes an additional 2 x vlan headers
-     * (8 bytes) for comparison. This avoids a failure later with
-     * rte_eth_dev_set_mtu(). This approach should be used until DPDK provides
-     * a method to retrieve the upper bound MTU for a given device.
-     */
-    if (MTU_TO_MAX_FRAME_LEN(mtu) > NETDEV_DPDK_MAX_PKT_LEN
-        || mtu < RTE_ETHER_MIN_MTU) {
-        VLOG_WARN("%s: unsupported MTU %d\n", dev->up.name, mtu);
-        return EINVAL;
-    }
-
     ovs_mutex_lock(&dev->mutex);
-    if (dev->requested_mtu != mtu) {
-        dev->requested_mtu = mtu;
-        netdev_request_reconfigure(netdev);
-    }
+    netdev_dpdk_common_get_mtu(common, mtup);
     ovs_mutex_unlock(&dev->mutex);
 
     return 0;
 }
 
+static int
+netdev_dpdk_eth_set_mtu(struct netdev *netdev, int mtu)
+{
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
+    struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+    int ret;
+
+    ovs_mutex_lock(&dev->mutex);
+    ret = netdev_dpdk_common_set_mtu(common, mtu);
+    ovs_mutex_unlock(&dev->mutex);
+
+    return ret;
+}
+
+static int
+netdev_dpdk_vhost_set_mtu(struct netdev *netdev, int mtu)
+{
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
+    struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+    int ret;
+
+    ovs_mutex_lock(&dev->mutex);
+    ret = netdev_dpdk_common_set_mtu(common, mtu);
+    ovs_mutex_unlock(&dev->mutex);
+
+    return ret;
+}
+
 static int
 netdev_dpdk_vhost_get_stats(const struct netdev *netdev,
                             struct netdev_stats *stats)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     struct rte_vhost_stat_name *vhost_stats_names = NULL;
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
     struct rte_vhost_stat *vhost_stats = NULL;
@@ -3659,11 +3613,11 @@ netdev_dpdk_vhost_get_stats(const struct netdev *netdev,
     VHOST_RXQ_STAT(rx_1024_to_1522_packets, "size_1024_1518_packets") \
     VHOST_RXQ_STAT(rx_1523_to_max_packets,  "size_1519_max_packets")
 
-#define VHOST_RXQ_STAT(MEMBER, NAME) dev->stats.MEMBER = 0;
+#define VHOST_RXQ_STAT(MEMBER, NAME) common->stats.MEMBER = 0;
     VHOST_RXQ_STATS;
 #undef VHOST_RXQ_STAT
 
-    for (int q = 0; q < dev->up.n_rxq; q++) {
+    for (int q = 0; q < common->up.n_rxq; q++) {
         qid = q * VIRTIO_QNUM + VIRTIO_TXQ;
 
         err = rte_vhost_vring_stats_get(vid, qid, vhost_stats,
@@ -3676,7 +3630,7 @@ netdev_dpdk_vhost_get_stats(const struct netdev *netdev,
         for (int i = 0; i < vhost_stats_count; i++) {
 #define VHOST_RXQ_STAT(MEMBER, NAME)                                 \
             if (string_ends_with(vhost_stats_names[i].name, NAME)) { \
-                dev->stats.MEMBER += vhost_stats[i].value;           \
+                common->stats.MEMBER += vhost_stats[i].value;        \
                 continue;                                            \
             }
             VHOST_RXQ_STATS;
@@ -3688,11 +3642,11 @@ netdev_dpdk_vhost_get_stats(const struct netdev *netdev,
      * Since vhost only reports good packets and has no error counter,
      * rx_undersized_errors is highjacked (see above) to retrieve
      * "undersize_packets". */
-    dev->stats.rx_1_to_64_packets += dev->stats.rx_undersized_errors;
-    memset(&dev->stats.rx_undersized_errors, 0xff,
-           sizeof dev->stats.rx_undersized_errors);
+    common->stats.rx_1_to_64_packets += common->stats.rx_undersized_errors;
+    memset(&common->stats.rx_undersized_errors, 0xff,
+           sizeof common->stats.rx_undersized_errors);
 
-#define VHOST_RXQ_STAT(MEMBER, NAME) stats->MEMBER = dev->stats.MEMBER;
+#define VHOST_RXQ_STAT(MEMBER, NAME) stats->MEMBER = common->stats.MEMBER;
     VHOST_RXQ_STATS;
 #undef VHOST_RXQ_STAT
 
@@ -3734,11 +3688,11 @@ netdev_dpdk_vhost_get_stats(const struct netdev *netdev,
     VHOST_TXQ_STAT(tx_1024_to_1522_packets, "size_1024_1518_packets") \
     VHOST_TXQ_STAT(tx_1523_to_max_packets,  "size_1519_max_packets")
 
-#define VHOST_TXQ_STAT(MEMBER, NAME) dev->stats.MEMBER = 0;
+#define VHOST_TXQ_STAT(MEMBER, NAME) common->stats.MEMBER = 0;
     VHOST_TXQ_STATS;
 #undef VHOST_TXQ_STAT
 
-    for (int q = 0; q < dev->up.n_txq; q++) {
+    for (int q = 0; q < common->up.n_txq; q++) {
         qid = q * VIRTIO_QNUM;
 
         err = rte_vhost_vring_stats_get(vid, qid, vhost_stats,
@@ -3751,7 +3705,7 @@ netdev_dpdk_vhost_get_stats(const struct netdev *netdev,
         for (int i = 0; i < vhost_stats_count; i++) {
 #define VHOST_TXQ_STAT(MEMBER, NAME)                                 \
             if (string_ends_with(vhost_stats_names[i].name, NAME)) { \
-                dev->stats.MEMBER += vhost_stats[i].value;           \
+                common->stats.MEMBER += vhost_stats[i].value;        \
                 continue;                                            \
             }
             VHOST_TXQ_STATS;
@@ -3761,18 +3715,18 @@ netdev_dpdk_vhost_get_stats(const struct netdev *netdev,
 
     /* OVS reports 64 bytes and smaller packets into "tx_1_to_64_packets".
      * Same as for rx, rx_undersized_errors is highjacked. */
-    dev->stats.tx_1_to_64_packets += dev->stats.rx_undersized_errors;
-    memset(&dev->stats.rx_undersized_errors, 0xff,
-           sizeof dev->stats.rx_undersized_errors);
+    common->stats.tx_1_to_64_packets += common->stats.rx_undersized_errors;
+    memset(&common->stats.rx_undersized_errors, 0xff,
+           sizeof common->stats.rx_undersized_errors);
 
-#define VHOST_TXQ_STAT(MEMBER, NAME) stats->MEMBER = dev->stats.MEMBER;
+#define VHOST_TXQ_STAT(MEMBER, NAME) stats->MEMBER = common->stats.MEMBER;
     VHOST_TXQ_STATS;
 #undef VHOST_TXQ_STAT
 
-    rte_spinlock_lock(&dev->stats_lock);
-    stats->rx_dropped = dev->stats.rx_dropped;
-    stats->tx_dropped = dev->stats.tx_dropped;
-    rte_spinlock_unlock(&dev->stats_lock);
+    rte_spinlock_lock(&common->stats_lock);
+    stats->rx_dropped = common->stats.rx_dropped;
+    stats->tx_dropped = common->stats.tx_dropped;
+    rte_spinlock_unlock(&common->stats_lock);
 
     err = 0;
 out:
@@ -3789,6 +3743,7 @@ static int
 netdev_dpdk_vhost_get_custom_stats(const struct netdev *netdev,
                                    struct netdev_custom_stats *custom_stats)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     struct rte_vhost_stat_name *vhost_stats_names = NULL;
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
     struct rte_vhost_stat *vhost_stats = NULL;
@@ -3799,7 +3754,7 @@ netdev_dpdk_vhost_get_custom_stats(const struct netdev 
*netdev,
     int qid;
     int vid;
 
-    netdev_dpdk_get_sw_custom_stats(netdev, custom_stats);
+    netdev_dpdk_common_get_sw_custom_stats(common, custom_stats);
     stat_offset = custom_stats->size;
 
     ovs_mutex_lock(&dev->mutex);
@@ -3824,8 +3779,8 @@ netdev_dpdk_vhost_get_custom_stats(const struct netdev 
*netdev,
     }
     vhost_txq_stats_count = err;
 
-    stat_offset += dev->up.n_rxq * vhost_rxq_stats_count;
-    stat_offset += dev->up.n_txq * vhost_txq_stats_count;
+    stat_offset += netdev->n_rxq * vhost_rxq_stats_count;
+    stat_offset += netdev->n_txq * vhost_txq_stats_count;
     custom_stats->counters = xrealloc(custom_stats->counters,
                                       stat_offset *
                                       sizeof *custom_stats->counters);
@@ -3835,7 +3790,7 @@ netdev_dpdk_vhost_get_custom_stats(const struct netdev 
*netdev,
                                 sizeof *vhost_stats_names);
     vhost_stats = xcalloc(vhost_rxq_stats_count, sizeof *vhost_stats);
 
-    for (int q = 0; q < dev->up.n_rxq; q++) {
+    for (int q = 0; q < netdev->n_rxq; q++) {
         qid = q * VIRTIO_QNUM + VIRTIO_TXQ;
 
         err = rte_vhost_vring_stats_get_names(vid, qid, vhost_stats_names,
@@ -3869,7 +3824,7 @@ netdev_dpdk_vhost_get_custom_stats(const struct netdev 
*netdev,
                                 sizeof *vhost_stats_names);
     vhost_stats = xcalloc(vhost_txq_stats_count, sizeof *vhost_stats);
 
-    for (int q = 0; q < dev->up.n_txq; q++) {
+    for (int q = 0; q < netdev->n_txq; q++) {
         qid = q * VIRTIO_QNUM;
 
         err = rte_vhost_vring_stats_get_names(vid, qid, vhost_stats_names,
@@ -3954,6 +3909,7 @@ static int
 netdev_dpdk_eth_get_stats(const struct netdev *netdev,
                           struct netdev_stats *stats)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
     struct rte_eth_stats rte_stats;
     bool gg;
@@ -4015,10 +3971,10 @@ out:
     stats->rx_errors = rte_stats.ierrors;
     stats->tx_errors = rte_stats.oerrors;
 
-    rte_spinlock_lock(&dev->stats_lock);
-    stats->tx_dropped = dev->stats.tx_dropped;
-    stats->rx_dropped = dev->stats.rx_dropped;
-    rte_spinlock_unlock(&dev->stats_lock);
+    rte_spinlock_lock(&common->stats_lock);
+    stats->tx_dropped = common->stats.tx_dropped;
+    stats->rx_dropped = common->stats.rx_dropped;
+    rte_spinlock_unlock(&common->stats_lock);
 
     /* These are the available DPDK counters for packets not received due to
      * local resource constraints in DPDK and NIC respectively. */
@@ -4035,11 +3991,12 @@ netdev_dpdk_eth_get_custom_stats(const struct netdev 
*netdev,
                                  struct netdev_custom_stats *custom_stats)
 {
 
-    uint32_t i;
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
     int rte_xstats_ret, sw_stats_size;
+    uint32_t i;
 
-    netdev_dpdk_get_sw_custom_stats(netdev, custom_stats);
+    netdev_dpdk_common_get_sw_custom_stats(common, custom_stats);
 
     ovs_mutex_lock(&dev->mutex);
 
@@ -4080,56 +4037,6 @@ netdev_dpdk_eth_get_custom_stats(const struct netdev 
*netdev,
     return 0;
 }
 
-static int
-netdev_dpdk_get_sw_custom_stats(const struct netdev *netdev,
-                                struct netdev_custom_stats *custom_stats)
-{
-    struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
-    int i, n;
-
-#define SW_CSTATS                    \
-    SW_CSTAT(tx_retries)             \
-    SW_CSTAT(tx_failure_drops)       \
-    SW_CSTAT(tx_mtu_exceeded_drops)  \
-    SW_CSTAT(tx_qos_drops)           \
-    SW_CSTAT(rx_qos_drops)           \
-    SW_CSTAT(tx_invalid_hwol_drops)
-
-#define SW_CSTAT(NAME) + 1
-    custom_stats->size = SW_CSTATS;
-#undef SW_CSTAT
-    custom_stats->counters = xcalloc(custom_stats->size,
-                                     sizeof *custom_stats->counters);
-
-    ovs_mutex_lock(&dev->mutex);
-
-    rte_spinlock_lock(&dev->stats_lock);
-    i = 0;
-#define SW_CSTAT(NAME) \
-    custom_stats->counters[i++].value = dev->sw_stats->NAME;
-    SW_CSTATS;
-#undef SW_CSTAT
-    rte_spinlock_unlock(&dev->stats_lock);
-
-    ovs_mutex_unlock(&dev->mutex);
-
-    i = 0;
-    n = 0;
-#define SW_CSTAT(NAME) \
-    if (custom_stats->counters[i].value != UINT64_MAX) {                   \
-        ovs_strlcpy(custom_stats->counters[n].name,                        \
-                    "ovs_"#NAME, NETDEV_CUSTOM_STATS_NAME_SIZE);           \
-        custom_stats->counters[n].value = custom_stats->counters[i].value; \
-        n++;                                                               \
-    }                                                                      \
-    i++;
-    SW_CSTATS;
-#undef SW_CSTAT
-
-    custom_stats->size = n;
-    return 0;
-}
-
 static int
 netdev_dpdk_eth_get_features(const struct netdev *netdev,
                              enum netdev_features *current,
@@ -4351,15 +4258,28 @@ netdev_dpdk_set_policing(struct netdev* netdev, 
uint32_t policer_rate,
 }
 
 static int
-netdev_dpdk_get_ifindex(const struct netdev *netdev)
+netdev_dpdk_eth_get_ifindex(const struct netdev *netdev)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+    int ifindex;
 
     ovs_mutex_lock(&dev->mutex);
-    /* Calculate hash from the netdev name. Ensure that ifindex is a 24-bit
-     * postive integer to meet RFC 2863 recommendations.
-     */
-    int ifindex = hash_string(netdev->name, 0) % 0xfffffe + 1;
+    ifindex = netdev_dpdk_common_get_ifindex(common);
+    ovs_mutex_unlock(&dev->mutex);
+
+    return ifindex;
+}
+
+static int
+netdev_dpdk_vhost_get_ifindex(const struct netdev *netdev)
+{
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
+    struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+    int ifindex;
+
+    ovs_mutex_lock(&dev->mutex);
+    ifindex = netdev_dpdk_common_get_ifindex(common);
     ovs_mutex_unlock(&dev->mutex);
 
     return ifindex;
@@ -4416,24 +4336,25 @@ netdev_dpdk_eth_update_flags__(struct netdev_dpdk *dev,
                                enum netdev_flags *old_flagsp)
     OVS_REQUIRES(dev->mutex)
 {
-    struct netdev *netdev = &dev->up;
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(&dev->up);
+    struct netdev *netdev = &common->up;
 
     if ((off | on) & ~(NETDEV_UP | NETDEV_PROMISC)) {
         return EINVAL;
     }
 
-    *old_flagsp = dev->flags;
-    dev->flags |= on;
-    dev->flags &= ~off;
+    *old_flagsp = common->flags;
+    common->flags |= on;
+    common->flags &= ~off;
 
-    if (dev->flags == *old_flagsp) {
+    if (common->flags == *old_flagsp) {
         return 0;
     }
 
-    if ((dev->flags ^ *old_flagsp) & NETDEV_UP) {
+    if ((common->flags ^ *old_flagsp) & NETDEV_UP) {
         int err;
 
-        if (dev->flags & NETDEV_UP) {
+        if (common->flags & NETDEV_UP) {
             err = rte_eth_dev_set_link_up(dev->port_id);
         } else {
             err = rte_eth_dev_set_link_down(dev->port_id);
@@ -4444,12 +4365,12 @@ netdev_dpdk_eth_update_flags__(struct netdev_dpdk *dev,
         } else if (err < 0) {
             VLOG_ERR("Interface %s link change error: %s",
                      netdev_get_name(netdev), rte_strerror(-err));
-            dev->flags = *old_flagsp;
+            common->flags = *old_flagsp;
             return -err;
         }
     }
 
-    if (dev->flags & NETDEV_PROMISC) {
+    if (common->flags & NETDEV_PROMISC) {
         rte_eth_promiscuous_enable(dev->port_id);
     }
 
@@ -4479,17 +4400,18 @@ netdev_dpdk_vhost_update_flags__(struct netdev_dpdk 
*dev,
                                  enum netdev_flags *old_flagsp)
     OVS_REQUIRES(dev->mutex)
 {
-    struct netdev *netdev = &dev->up;
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(&dev->up);
+    struct netdev *netdev = &common->up;
 
     if ((off | on) & ~(NETDEV_UP | NETDEV_PROMISC)) {
         return EINVAL;
     }
 
-    *old_flagsp = dev->flags;
-    dev->flags |= on;
-    dev->flags &= ~off;
+    *old_flagsp = common->flags;
+    common->flags |= on;
+    common->flags &= ~off;
 
-    if (dev->flags == *old_flagsp) {
+    if (common->flags == *old_flagsp) {
         return 0;
     }
 
@@ -4503,10 +4425,10 @@ netdev_dpdk_vhost_update_flags__(struct netdev_dpdk 
*dev,
 
         /* Clear statistics if device is getting up. */
         if (NETDEV_UP & on) {
-            rte_spinlock_lock(&dev->stats_lock);
-            memset(&dev->stats, 0, sizeof dev->stats);
-            memset(dev->sw_stats, 0, sizeof *dev->sw_stats);
-            rte_spinlock_unlock(&dev->stats_lock);
+            rte_spinlock_lock(&common->stats_lock);
+            memset(&common->stats, 0, sizeof common->stats);
+            memset(common->sw_stats, 0, sizeof *common->sw_stats);
+            rte_spinlock_unlock(&common->stats_lock);
         }
     }
 
@@ -4621,6 +4543,7 @@ netdev_dpdk_link_speed_to_str__(uint32_t link_speed)
 static int
 netdev_dpdk_eth_get_status(const struct netdev *netdev, struct smap *args)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
     struct rte_eth_dev_info dev_info;
     size_t rx_steer_flows_num;
@@ -4650,7 +4573,7 @@ netdev_dpdk_eth_get_status(const struct netdev *netdev, 
struct smap *args)
         smap_add_format(args, "driver_name", "%s", dev_info.driver_name);
         smap_add_format(args, "min_rx_bufsize", "%u", dev_info.min_rx_bufsize);
     }
-    smap_add_format(args, "max_rx_pktlen", "%u", dev->max_packet_len);
+    smap_add_format(args, "max_rx_pktlen", "%u", common->max_packet_len);
     if (!diag) {
         smap_add_format(args, "max_rx_queues", "%u", dev_info.max_rx_queues);
         smap_add_format(args, "max_tx_queues", "%u", dev_info.max_tx_queues);
@@ -4665,7 +4588,7 @@ netdev_dpdk_eth_get_status(const struct netdev *netdev, 
struct smap *args)
     smap_add_format(args, "n_txq", "%d", netdev->n_txq);
 
     smap_add(args, "rx_csum_offload",
-             dev->hw_ol_features & NETDEV_RX_CHECKSUM_OFFLOAD
+             common->hw_ol_features & NETDEV_RX_CHECKSUM_OFFLOAD
              ? "true" : "false");
 
     /* Querying the DPDK library for iftype may be done in future, pending
@@ -4693,7 +4616,7 @@ netdev_dpdk_eth_get_status(const struct netdev *netdev, 
struct smap *args)
 
     if (dev->is_representor) {
         smap_add_format(args, "dpdk-vf-mac", ETH_ADDR_FMT,
-                        ETH_ADDR_ARGS(dev->hwaddr));
+                        ETH_ADDR_ARGS(common->hwaddr));
     }
 
     if (rx_steer_flags && !rx_steer_flows_num) {
@@ -4894,16 +4817,17 @@ netdev_dpdk_get_mempool_info(struct unixctl_conn *conn,
     }
 
     if (netdev) {
+        struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
         struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
 
         ovs_mutex_lock(&dev->mutex);
         ovs_mutex_lock(&dpdk_mp_mutex);
 
-        if (dev->dpdk_mp) {
-            rte_mempool_dump(stream, dev->dpdk_mp->mp);
+        if (common->dpdk_mp) {
+            rte_mempool_dump(stream, common->dpdk_mp->mp);
             fprintf(stream, "    count: avail (%u), in use (%u)\n",
-                    rte_mempool_avail_count(dev->dpdk_mp->mp),
-                    rte_mempool_in_use_count(dev->dpdk_mp->mp));
+                    rte_mempool_avail_count(common->dpdk_mp->mp),
+                    rte_mempool_in_use_count(common->dpdk_mp->mp));
         } else {
             error = "Not allocated";
         }
@@ -4949,14 +4873,16 @@ static void
 netdev_dpdk_remap_txqs(struct netdev_dpdk *dev)
     OVS_REQUIRES(dev->mutex)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(&dev->up);
+    struct netdev *netdev = &common->up;
     int *enabled_queues, n_enabled = 0;
-    int i, k, total_txqs = dev->up.n_txq;
+    int i, k, total_txqs = netdev->n_txq;
 
     enabled_queues = xcalloc(total_txqs, sizeof *enabled_queues);
 
     for (i = 0; i < total_txqs; i++) {
         /* Enabled queues always mapped to themselves. */
-        if (dev->tx_q[i].map == i) {
+        if (common->tx_q[i].map == i) {
             enabled_queues[n_enabled++] = i;
         }
     }
@@ -4968,8 +4894,8 @@ netdev_dpdk_remap_txqs(struct netdev_dpdk *dev)
 
     k = 0;
     for (i = 0; i < total_txqs; i++) {
-        if (dev->tx_q[i].map != i) {
-            dev->tx_q[i].map = enabled_queues[k];
+        if (common->tx_q[i].map != i) {
+            common->tx_q[i].map = enabled_queues[k];
             k = (k + 1) % n_enabled;
         }
     }
@@ -4978,9 +4904,9 @@ netdev_dpdk_remap_txqs(struct netdev_dpdk *dev)
         struct ds mapping = DS_EMPTY_INITIALIZER;
 
         ds_put_format(&mapping, "TX queue mapping for port '%s':\n",
-                      netdev_get_name(&dev->up));
+                      netdev_get_name(netdev));
         for (i = 0; i < total_txqs; i++) {
-            ds_put_format(&mapping, "%2d --> %2d\n", i, dev->tx_q[i].map);
+            ds_put_format(&mapping, "%2d --> %2d\n", i, common->tx_q[i].map);
         }
 
         VLOG_DBG("%s", ds_cstr(&mapping));
@@ -5006,7 +4932,10 @@ new_device(int vid)
     ovs_mutex_lock(&dpdk_mutex);
     /* Add device to the vhost port with the same name as that passed down. */
     LIST_FOR_EACH(dev, list_node, &dpdk_list) {
-        if (!is_vhost_class(dev->up.netdev_class)) {
+        struct netdev_dpdk_common *common = netdev_dpdk_common_cast(&dev->up);
+        struct netdev *netdev = &common->up;
+
+        if (!is_vhost_class(netdev->netdev_class)) {
             continue;
         }
         ovs_mutex_lock(&dev->mutex);
@@ -5021,19 +4950,19 @@ new_device(int vid)
                 VLOG_INFO("Error getting NUMA info for vHost Device '%s'",
                           ifname);
 #endif
-                newnode = dev->socket_id;
+                newnode = common->socket_id;
             }
 
             dev->virtio_features_state |= OVS_VIRTIO_F_NEGOTIATED;
 
-            if (dev->requested_n_txq < qp_num
-                || dev->requested_n_rxq < qp_num
-                || dev->requested_socket_id != newnode
-                || dev->dpdk_mp == NULL) {
-                dev->requested_socket_id = newnode;
-                dev->requested_n_rxq = qp_num;
-                dev->requested_n_txq = qp_num;
-                netdev_request_reconfigure(&dev->up);
+            if (common->requested_n_txq < qp_num
+                || common->requested_n_rxq < qp_num
+                || common->requested_socket_id != newnode
+                || common->dpdk_mp == NULL) {
+                common->requested_socket_id = newnode;
+                common->requested_n_rxq = qp_num;
+                common->requested_n_txq = qp_num;
+                netdev_request_reconfigure(netdev);
             } else {
                 /* Reconfiguration not required. */
                 dev->vhost_reconfigured = true;
@@ -5044,13 +4973,13 @@ new_device(int vid)
                           "vHost Device '%s'", dev->vhost_id);
             } else {
                 if (features & (1ULL << VIRTIO_NET_F_GUEST_CSUM)) {
-                    dev->hw_ol_features |= NETDEV_TX_TCP_CKSUM_OFFLOAD;
-                    dev->hw_ol_features |= NETDEV_TX_UDP_CKSUM_OFFLOAD;
-                    dev->hw_ol_features |= NETDEV_TX_SCTP_CKSUM_OFFLOAD;
+                    common->hw_ol_features |= NETDEV_TX_TCP_CKSUM_OFFLOAD;
+                    common->hw_ol_features |= NETDEV_TX_UDP_CKSUM_OFFLOAD;
+                    common->hw_ol_features |= NETDEV_TX_SCTP_CKSUM_OFFLOAD;
 
                     /* There is no support in virtio net to offload IPv4 csum,
                      * but the vhost library handles IPv4 csum offloading. */
-                    dev->hw_ol_features |= NETDEV_TX_IPV4_CKSUM_OFFLOAD;
+                    common->hw_ol_features |= NETDEV_TX_IPV4_CKSUM_OFFLOAD;
                 }
 
                 if (userspace_tso_enabled()
@@ -5059,24 +4988,24 @@ new_device(int vid)
                     if (features & (1ULL << VIRTIO_NET_F_GUEST_TSO4)
                         && features & (1ULL << VIRTIO_NET_F_GUEST_TSO6)) {
 
-                        dev->hw_ol_features |= NETDEV_TX_TSO_OFFLOAD;
+                        common->hw_ol_features |= NETDEV_TX_TSO_OFFLOAD;
                         VLOG_DBG("%s: TSO enabled on vhost port",
-                                 netdev_get_name(&dev->up));
+                                 netdev_get_name(netdev));
                     } else {
                         VLOG_WARN("%s: Tx TSO offload is not supported.",
-                                  netdev_get_name(&dev->up));
+                                  netdev_get_name(netdev));
                     }
                 }
             }
 
-            netdev_dpdk_update_netdev_flags(dev);
+            netdev_dpdk_common_update_ol_flags(common);
 
             ovsrcu_index_set(&dev->vid, vid);
             exists = true;
 
             /* Disable notifications. */
             set_irq_status(vid);
-            netdev_change_seq_changed(&dev->up);
+            netdev_change_seq_changed(netdev);
             ovs_mutex_unlock(&dev->mutex);
             break;
         }
@@ -5101,10 +5030,11 @@ static void
 netdev_dpdk_txq_map_clear(struct netdev_dpdk *dev)
     OVS_REQUIRES(dev->mutex)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(&dev->up);
     int i;
 
-    for (i = 0; i < dev->up.n_txq; i++) {
-        dev->tx_q[i].map = OVS_VHOST_QUEUE_MAP_UNKNOWN;
+    for (i = 0; i < common->up.n_txq; i++) {
+        common->tx_q[i].map = OVS_VHOST_QUEUE_MAP_UNKNOWN;
     }
 }
 
@@ -5125,7 +5055,10 @@ destroy_device(int vid)
 
     ovs_mutex_lock(&dpdk_mutex);
     LIST_FOR_EACH (dev, list_node, &dpdk_list) {
-        if (!is_vhost_class(dev->up.netdev_class)) {
+        struct netdev_dpdk_common *common = netdev_dpdk_common_cast(&dev->up);
+        struct netdev *netdev = &common->up;
+
+        if (!is_vhost_class(netdev->netdev_class)) {
             continue;
         }
         if (netdev_dpdk_get_vid(dev) == vid) {
@@ -5134,14 +5067,14 @@ destroy_device(int vid)
             dev->vhost_reconfigured = false;
             ovsrcu_index_set(&dev->vid, -1);
             memset(dev->vhost_rxq_enabled, 0,
-                   dev->up.n_rxq * sizeof *dev->vhost_rxq_enabled);
+                   netdev->n_rxq * sizeof *dev->vhost_rxq_enabled);
             netdev_dpdk_txq_map_clear(dev);
 
             /* Clear offload capabilities before next new_device. */
-            dev->hw_ol_features = 0;
-            netdev_dpdk_update_netdev_flags(dev);
+            common->hw_ol_features = 0;
+            netdev_dpdk_common_update_ol_flags(common);
 
-            netdev_change_seq_changed(&dev->up);
+            netdev_change_seq_changed(netdev);
             ovs_mutex_unlock(&dev->mutex);
             exists = true;
             break;
@@ -5188,7 +5121,10 @@ vring_state_changed__(struct vhost_state_change *sc)
 
     ovs_mutex_lock(&dpdk_mutex);
     LIST_FOR_EACH (dev, list_node, &dpdk_list) {
-        if (!is_vhost_class(dev->up.netdev_class)) {
+        struct netdev_dpdk_common *common = netdev_dpdk_common_cast(&dev->up);
+        struct netdev *netdev = &common->up;
+
+        if (!is_vhost_class(netdev->netdev_class)) {
             continue;
         }
         ovs_mutex_lock(&dev->mutex);
@@ -5198,13 +5134,13 @@ vring_state_changed__(struct vhost_state_change *sc)
 
                 dev->vhost_rxq_enabled[qid] = sc->enable != 0;
                 if (old_state != dev->vhost_rxq_enabled[qid]) {
-                    netdev_change_seq_changed(&dev->up);
+                    netdev_change_seq_changed(netdev);
                 }
             } else {
                 if (sc->enable) {
-                    dev->tx_q[qid].map = qid;
+                    common->tx_q[qid].map = qid;
                 } else {
-                    dev->tx_q[qid].map = OVS_VHOST_QUEUE_DISABLED;
+                    common->tx_q[qid].map = OVS_VHOST_QUEUE_DISABLED;
                 }
                 netdev_dpdk_remap_txqs(dev);
             }
@@ -5297,7 +5233,10 @@ destroy_connection(int vid)
 
     ovs_mutex_lock(&dpdk_mutex);
     LIST_FOR_EACH (dev, list_node, &dpdk_list) {
-        if (!is_vhost_class(dev->up.netdev_class)) {
+        struct netdev_dpdk_common *common = netdev_dpdk_common_cast(&dev->up);
+        struct netdev *netdev = &common->up;
+
+        if (!is_vhost_class(netdev->netdev_class)) {
             continue;
         }
         ovs_mutex_lock(&dev->mutex);
@@ -5310,11 +5249,11 @@ destroy_connection(int vid)
             }
 
             /* Restore the number of queue pairs to default. */
-            if (dev->requested_n_txq != qp_num
-                || dev->requested_n_rxq != qp_num) {
-                dev->requested_n_rxq = qp_num;
-                dev->requested_n_txq = qp_num;
-                netdev_request_reconfigure(&dev->up);
+            if (common->requested_n_txq != qp_num
+                || common->requested_n_rxq != qp_num) {
+                common->requested_n_rxq = qp_num;
+                common->requested_n_txq = qp_num;
+                netdev_request_reconfigure(netdev);
             }
 
             if (!(dev->virtio_features_state & OVS_VIRTIO_F_NEGOTIATED)) {
@@ -5351,7 +5290,7 @@ destroy_connection(int vid)
                 }
                 if (!(dev->virtio_features_state & OVS_VIRTIO_F_NEGOTIATED)) {
                     dev->virtio_features_state |= OVS_VIRTIO_F_RECONF_PENDING;
-                    netdev_request_reconfigure(&dev->up);
+                    netdev_request_reconfigure(netdev);
                 }
             }
 
@@ -6159,12 +6098,13 @@ dpdk_rx_steer_add_flow(struct netdev_dpdk *dev,
                       const struct rte_flow_item items[],
                       const char *desc)
 {
+    struct netdev *netdev = &dev->up;
     const struct rte_flow_attr attr = { .ingress = 1 };
     const struct rte_flow_action actions[] = {
         {
             .type = RTE_FLOW_ACTION_TYPE_QUEUE,
             .conf = &(const struct rte_flow_action_queue) {
-                .index = dev->up.n_rxq - 1,
+                .index = netdev->n_rxq - 1,
             },
         },
         { .type = RTE_FLOW_ACTION_TYPE_END },
@@ -6178,7 +6118,7 @@ dpdk_rx_steer_add_flow(struct netdev_dpdk *dev,
     err = rte_flow_validate(dev->port_id, &attr, items, actions, &error);
     if (err) {
         VLOG_WARN("%s: rx-steering: device does not support %s flow: %s",
-                  netdev_get_name(&dev->up), desc,
+                  netdev_get_name(netdev), desc,
                   error.message ? error.message : "");
         goto out;
     }
@@ -6187,7 +6127,7 @@ dpdk_rx_steer_add_flow(struct netdev_dpdk *dev,
     flow = rte_flow_create(dev->port_id, &attr, items, actions, &error);
     if (flow == NULL) {
         VLOG_WARN("%s: rx-steering: failed to add %s flow: %s",
-                  netdev_get_name(&dev->up), desc,
+                  netdev_get_name(netdev), desc,
                   error.message ? error.message : "");
         err = rte_errno;
         goto out;
@@ -6199,7 +6139,7 @@ dpdk_rx_steer_add_flow(struct netdev_dpdk *dev,
     dev->rx_steer_flows_num = num;
 
     VLOG_INFO("%s: rx-steering: redirected %s traffic to rx queue %d",
-              netdev_get_name(&dev->up), desc, dev->up.n_rxq - 1);
+              netdev_get_name(netdev), desc, netdev->n_rxq - 1);
 out:
     return err;
 }
@@ -6210,13 +6150,14 @@ static int
 dpdk_rx_steer_rss_configure(struct netdev_dpdk *dev, int rss_n_rxq)
 {
     struct rte_eth_rss_reta_entry64 reta_conf[RETA_CONF_SIZE];
+    struct netdev *netdev = &dev->up;
     struct rte_eth_dev_info info;
     int err;
 
     err = rte_eth_dev_info_get(dev->port_id, &info);
     if (err < 0) {
         VLOG_WARN("%s: failed to query RSS info: %s",
-                  netdev_get_name(&dev->up), rte_strerror(-err));
+                  netdev_get_name(netdev), rte_strerror(-err));
         goto error;
     }
 
@@ -6261,7 +6202,7 @@ dpdk_rx_steer_rss_configure(struct netdev_dpdk *dev, int 
rss_n_rxq)
     err = rte_eth_dev_rss_reta_update(dev->port_id, reta_conf, info.reta_size);
     if (err < 0) {
         VLOG_WARN("%s: failed to configure RSS redirection table: err=%d",
-                  netdev_get_name(&dev->up), err);
+                  netdev_get_name(netdev), err);
     }
 
 error:
@@ -6271,12 +6212,13 @@ error:
 static int
 dpdk_rx_steer_configure(struct netdev_dpdk *dev)
 {
+    struct netdev *netdev = &dev->up;
     int err = 0;
 
-    if (dev->up.n_rxq < 2) {
+    if (netdev->n_rxq < 2) {
         err = ENOTSUP;
         VLOG_WARN("%s: rx-steering: not enough available rx queues",
-                  netdev_get_name(&dev->up));
+                  netdev_get_name(netdev));
         goto out;
     }
 
@@ -6301,16 +6243,16 @@ dpdk_rx_steer_configure(struct netdev_dpdk *dev)
 
     if (dev->rx_steer_flows_num) {
         /* Reconfigure RSS reta in all but the rx steering queue. */
-        err = dpdk_rx_steer_rss_configure(dev, dev->up.n_rxq - 1);
+        err = dpdk_rx_steer_rss_configure(dev, netdev->n_rxq - 1);
         if (err) {
             goto out;
         }
-        if (dev->up.n_rxq == 2) {
+        if (netdev->n_rxq == 2) {
             VLOG_INFO("%s: rx-steering: redirected other traffic to "
-                      "rx queue 0", netdev_get_name(&dev->up));
+                      "rx queue 0", netdev_get_name(netdev));
         } else {
             VLOG_INFO("%s: rx-steering: applied rss on rx queues 0-%u",
-                      netdev_get_name(&dev->up), dev->up.n_rxq - 2);
+                      netdev_get_name(netdev), netdev->n_rxq - 2);
         }
     }
 
@@ -6321,19 +6263,20 @@ out:
 static void
 dpdk_rx_steer_unconfigure(struct netdev_dpdk *dev)
 {
+    struct netdev *netdev = &dev->up;
     struct rte_flow_error error;
 
     if (!dev->rx_steer_flows_num) {
         return;
     }
 
-    VLOG_DBG("%s: rx-steering: reset flows", netdev_get_name(&dev->up));
+    VLOG_DBG("%s: rx-steering: reset flows", netdev_get_name(netdev));
 
     for (int i = 0; i < dev->rx_steer_flows_num; i++) {
         set_error(&error, RTE_FLOW_ERROR_TYPE_NONE);
         if (rte_flow_destroy(dev->port_id, dev->rx_steer_flows[i], &error)) {
             VLOG_WARN("%s: rx-steering: failed to destroy flow: %s",
-                      netdev_get_name(&dev->up),
+                      netdev_get_name(netdev),
                       error.message ? error.message : "");
         }
     }
@@ -6350,6 +6293,7 @@ dpdk_rx_steer_unconfigure(struct netdev_dpdk *dev)
 static int
 netdev_dpdk_eth_reconfigure(struct netdev *netdev)
 {
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(netdev);
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
     struct dpdk_mp_config mp_cfg;
     bool pending_reset;
@@ -6359,23 +6303,23 @@ netdev_dpdk_eth_reconfigure(struct netdev *netdev)
     ovs_mutex_lock(&dev->mutex);
 
     try_rx_steer = dev->requested_rx_steer_flags != 0;
-    dev->requested_n_rxq = dev->user_n_rxq;
+    common->requested_n_rxq = dev->user_n_rxq;
     if (try_rx_steer) {
-        dev->requested_n_rxq += 1;
+        common->requested_n_rxq += 1;
     }
 
     atomic_read_relaxed(&netdev_dpdk_pending_reset[dev->port_id],
                         &pending_reset);
 
-    if (netdev->n_txq == dev->requested_n_txq
-        && netdev->n_rxq == dev->requested_n_rxq
+    if (netdev->n_txq == common->requested_n_txq
+        && netdev->n_rxq == common->requested_n_rxq
         && dev->rx_steer_flags == dev->requested_rx_steer_flags
-        && dev->mtu == dev->requested_mtu
+        && common->mtu == common->requested_mtu
         && dev->lsc_interrupt_mode == dev->requested_lsc_interrupt_mode
         && dev->rxq_size == dev->requested_rxq_size
         && dev->txq_size == dev->requested_txq_size
-        && eth_addr_equals(dev->hwaddr, dev->requested_hwaddr)
-        && dev->socket_id == dev->requested_socket_id
+        && eth_addr_equals(common->hwaddr, dev->requested_hwaddr)
+        && common->socket_id == common->requested_socket_id
         && dev->started && !pending_reset) {
         /* Reconfiguration is unnecessary */
 
@@ -6400,31 +6344,31 @@ retry:
     dev->started = false;
 
     mp_cfg = (struct dpdk_mp_config){
-        .name = dev->up.name,
-        .mtu = dev->requested_mtu,
-        .socket_id = dev->requested_socket_id,
-        .n_rxq = dev->requested_n_rxq,
+        .name = common->up.name,
+        .mtu = common->requested_mtu,
+        .socket_id = common->requested_socket_id,
+        .n_rxq = common->requested_n_rxq,
         .rxq_size = dev->requested_rxq_size,
-        .n_txq = dev->requested_n_txq,
+        .n_txq = common->requested_n_txq,
         .txq_size = dev->requested_txq_size,
     };
-    err = netdev_dpdk_mempool_configure(dev, &mp_cfg);
+    err = netdev_dpdk_mempool_configure(common, &mp_cfg);
     if (err && err != EEXIST) {
         goto out;
     }
 
     dev->lsc_interrupt_mode = dev->requested_lsc_interrupt_mode;
 
-    netdev->n_txq = dev->requested_n_txq;
-    netdev->n_rxq = dev->requested_n_rxq;
+    netdev->n_txq = common->requested_n_txq;
+    netdev->n_rxq = common->requested_n_rxq;
 
     dev->rxq_size = dev->requested_rxq_size;
     dev->txq_size = dev->requested_txq_size;
 
-    rte_free(dev->tx_q);
-    dev->tx_q = NULL;
+    rte_free(common->tx_q);
+    common->tx_q = NULL;
 
-    if (!eth_addr_equals(dev->hwaddr, dev->requested_hwaddr)) {
+    if (!eth_addr_equals(common->hwaddr, dev->requested_hwaddr)) {
         err = netdev_dpdk_eth_set_etheraddr__(dev, dev->requested_hwaddr);
         if (err) {
             goto out;
@@ -6435,7 +6379,7 @@ retry:
     if (err) {
         goto out;
     }
-    netdev_dpdk_update_netdev_flags(dev);
+    netdev_dpdk_common_update_ol_flags(common);
 
     /* If both requested and actual hwaddr were previously
      * unset (initialized to 0), then first device init above
@@ -6447,7 +6391,7 @@ retry:
      * configured by the user, as netdev_dpdk_eth_set_etheraddr__()
      * will have succeeded to get to this point.
      */
-    dev->requested_hwaddr = dev->hwaddr;
+    dev->requested_hwaddr = common->hwaddr;
 
     if (try_rx_steer) {
         err = dpdk_rx_steer_configure(dev);
@@ -6458,16 +6402,16 @@ retry:
              * The extra queue must be explicitly removed here to ensure that
              * it is unconfigured immediately.
              */
-            dev->requested_n_rxq = dev->user_n_rxq;
+            common->requested_n_rxq = dev->user_n_rxq;
             goto retry;
         }
     } else {
-        VLOG_INFO("%s: rx-steering: default rss", netdev_get_name(&dev->up));
+        VLOG_INFO("%s: rx-steering: default rss", netdev_get_name(netdev));
     }
     dev->rx_steer_flags = dev->requested_rx_steer_flags;
 
-    dev->tx_q = netdev_dpdk_alloc_txq(netdev->n_txq);
-    if (!dev->tx_q) {
+    common->tx_q = netdev_dpdk_alloc_txq(netdev->n_txq);
+    if (!common->tx_q) {
         err = ENOMEM;
     }
 
@@ -6482,41 +6426,44 @@ static int
 dpdk_vhost_reconfigure_helper(struct netdev_dpdk *dev)
     OVS_REQUIRES(dev->mutex)
 {
-    dev->up.n_txq = dev->requested_n_txq;
-    dev->up.n_rxq = dev->requested_n_rxq;
+    struct netdev_dpdk_common *common = netdev_dpdk_common_cast(&dev->up);
+    struct netdev *netdev = &common->up;
+
+    netdev->n_txq = common->requested_n_txq;
+    netdev->n_rxq = common->requested_n_rxq;
 
     /* Always keep RX queue 0 enabled for implementations that won't
      * report vring states. */
     dev->vhost_rxq_enabled[0] = true;
 
     /* Enable TX queue 0 by default if it wasn't disabled. */
-    if (dev->tx_q[0].map == OVS_VHOST_QUEUE_MAP_UNKNOWN) {
-        dev->tx_q[0].map = 0;
+    if (common->tx_q[0].map == OVS_VHOST_QUEUE_MAP_UNKNOWN) {
+        common->tx_q[0].map = 0;
     }
 
-    rte_spinlock_lock(&dev->stats_lock);
-    memset(&dev->stats, 0, sizeof dev->stats);
-    memset(dev->sw_stats, 0, sizeof *dev->sw_stats);
-    rte_spinlock_unlock(&dev->stats_lock);
+    rte_spinlock_lock(&common->stats_lock);
+    memset(&common->stats, 0, sizeof common->stats);
+    memset(common->sw_stats, 0, sizeof *common->sw_stats);
+    rte_spinlock_unlock(&common->stats_lock);
 
     netdev_dpdk_remap_txqs(dev);
 
     if (netdev_dpdk_get_vid(dev) >= 0) {
         struct dpdk_mp_config mp_cfg = {
-            .name = dev->up.name,
-            .mtu = dev->requested_mtu,
-            .socket_id = dev->requested_socket_id,
-            .n_rxq = dev->requested_n_rxq,
+            .name = common->up.name,
+            .mtu = common->requested_mtu,
+            .socket_id = common->requested_socket_id,
+            .n_rxq = common->requested_n_rxq,
             .rxq_size = NIC_PORT_DEFAULT_RXQ_SIZE,
-            .n_txq = dev->requested_n_txq,
+            .n_txq = common->requested_n_txq,
             .txq_size = NIC_PORT_DEFAULT_TXQ_SIZE,
         };
         int err;
 
-        err = netdev_dpdk_mempool_configure(dev, &mp_cfg);
+        err = netdev_dpdk_mempool_configure(common, &mp_cfg);
         if (!err) {
             /* A new mempool was created or re-used. */
-            netdev_change_seq_changed(&dev->up);
+            netdev_change_seq_changed(netdev);
         } else if (err != EEXIST) {
             return err;
         }
@@ -6524,11 +6471,11 @@ dpdk_vhost_reconfigure_helper(struct netdev_dpdk *dev)
         if (dev->vhost_reconfigured == false) {
             dev->vhost_reconfigured = true;
             /* Carrier status may need updating. */
-            netdev_change_seq_changed(&dev->up);
+            netdev_change_seq_changed(netdev);
         }
     }
 
-    netdev_dpdk_update_netdev_flags(dev);
+    netdev_dpdk_common_update_ol_flags(common);
 
     return 0;
 }
@@ -6627,14 +6574,14 @@ netdev_dpdk_vhost_client_reconfigure(struct netdev 
*netdev)
             dev->vhost_driver_flags |= vhost_flags;
             VLOG_INFO("vHost User device '%s' created in 'client' mode, "
                       "using client socket '%s'",
-                      dev->up.name, dev->vhost_id);
+                      netdev->name, dev->vhost_id);
         }
 
         err = rte_vhost_driver_callback_register(dev->vhost_id,
                                                  &virtio_net_device_ops);
         if (err) {
             VLOG_ERR("rte_vhost_driver_callback_register failed for "
-                     "vhost user client port: %s\n", dev->up.name);
+                     "vhost user client port: %s\n", netdev->name);
             goto unlock;
         }
 
@@ -6642,7 +6589,7 @@ netdev_dpdk_vhost_client_reconfigure(struct netdev 
*netdev)
             virtio_unsup_features = 1ULL << VIRTIO_NET_F_HOST_ECN
                                     | 1ULL << VIRTIO_NET_F_HOST_UFO;
             VLOG_DBG("%s: TSO enabled on vhost port",
-                     netdev_get_name(&dev->up));
+                     netdev_get_name(netdev));
         } else {
             /* Advertise checksum offloading to the guest, but explicitly
              * disable TSO and friends.
@@ -6657,7 +6604,7 @@ netdev_dpdk_vhost_client_reconfigure(struct netdev 
*netdev)
                                                 virtio_unsup_features);
         if (err) {
             VLOG_ERR("rte_vhost_driver_disable_features failed for "
-                     "vhost user client port: %s\n", dev->up.name);
+                     "vhost user client port: %s\n", netdev->name);
             goto unlock;
         }
 
@@ -6668,7 +6615,7 @@ netdev_dpdk_vhost_client_reconfigure(struct netdev 
*netdev)
             err = rte_vhost_driver_set_max_queue_num(dev->vhost_id, max_qp);
             if (err) {
                 VLOG_ERR("rte_vhost_driver_set_max_queue_num failed for "
-                         "vhost-user client port: %s\n", dev->up.name);
+                         "vhost-user client port: %s\n", netdev->name);
                 goto unlock;
             }
         }
@@ -6676,7 +6623,7 @@ netdev_dpdk_vhost_client_reconfigure(struct netdev 
*netdev)
         err = rte_vhost_driver_start(dev->vhost_id);
         if (err) {
             VLOG_ERR("rte_vhost_driver_start failed for vhost user "
-                     "client port: %s\n", dev->up.name);
+                     "client port: %s\n", netdev->name);
             goto unlock;
         }
     }
@@ -6928,14 +6875,14 @@ static const struct netdev_class netdev_dpdk_class = {
     .dealloc = netdev_dpdk_eth_dealloc,
     .get_config = netdev_dpdk_eth_get_config,
     .set_config = netdev_dpdk_eth_set_config,
-    .get_numa_id = netdev_dpdk_get_numa_id,
+    .get_numa_id = netdev_dpdk_common_get_numa_id,
     .set_tx_multiq = netdev_dpdk_eth_set_tx_multiq,
     .send = netdev_dpdk_eth_send,
     .set_etheraddr = netdev_dpdk_eth_set_etheraddr,
     .get_etheraddr = netdev_dpdk_eth_get_etheraddr,
-    .get_mtu = netdev_dpdk_get_mtu,
-    .set_mtu = netdev_dpdk_set_mtu,
-    .get_ifindex = netdev_dpdk_get_ifindex,
+    .get_mtu = netdev_dpdk_eth_get_mtu,
+    .set_mtu = netdev_dpdk_eth_set_mtu,
+    .get_ifindex = netdev_dpdk_eth_get_ifindex,
     .get_carrier = netdev_dpdk_eth_get_carrier,
     .get_carrier_resets = netdev_dpdk_eth_get_carrier_resets,
     .get_stats = netdev_dpdk_eth_get_stats,
@@ -6972,13 +6919,13 @@ static const struct netdev_class 
netdev_dpdk_vhost_class = {
     .construct = netdev_dpdk_vhost_construct,
     .destruct = netdev_dpdk_vhost_destruct,
     .dealloc = netdev_dpdk_vhost_dealloc,
-    .get_numa_id = netdev_dpdk_get_numa_id,
+    .get_numa_id = netdev_dpdk_common_get_numa_id,
     .send = netdev_dpdk_vhost_send,
     .set_etheraddr = netdev_dpdk_vhost_set_etheraddr,
     .get_etheraddr = netdev_dpdk_vhost_get_etheraddr,
-    .get_mtu = netdev_dpdk_get_mtu,
-    .set_mtu = netdev_dpdk_set_mtu,
-    .get_ifindex = netdev_dpdk_get_ifindex,
+    .get_mtu = netdev_dpdk_vhost_get_mtu,
+    .set_mtu = netdev_dpdk_vhost_set_mtu,
+    .get_ifindex = netdev_dpdk_vhost_get_ifindex,
     .get_carrier = netdev_dpdk_vhost_get_carrier,
     .get_stats = netdev_dpdk_vhost_get_stats,
     .get_custom_stats = netdev_dpdk_vhost_get_custom_stats,
@@ -7014,13 +6961,13 @@ static const struct netdev_class 
netdev_dpdk_vhost_client_class = {
     .dealloc = netdev_dpdk_vhost_dealloc,
     .get_config = netdev_dpdk_vhost_client_get_config,
     .set_config = netdev_dpdk_vhost_client_set_config,
-    .get_numa_id = netdev_dpdk_get_numa_id,
+    .get_numa_id = netdev_dpdk_common_get_numa_id,
     .send = netdev_dpdk_vhost_send,
     .set_etheraddr = netdev_dpdk_vhost_set_etheraddr,
     .get_etheraddr = netdev_dpdk_vhost_get_etheraddr,
-    .get_mtu = netdev_dpdk_get_mtu,
-    .set_mtu = netdev_dpdk_set_mtu,
-    .get_ifindex = netdev_dpdk_get_ifindex,
+    .get_mtu = netdev_dpdk_vhost_get_mtu,
+    .set_mtu = netdev_dpdk_vhost_set_mtu,
+    .get_ifindex = netdev_dpdk_vhost_get_ifindex,
     .get_carrier = netdev_dpdk_vhost_get_carrier,
     .get_stats = netdev_dpdk_vhost_get_stats,
     .get_custom_stats = netdev_dpdk_vhost_get_custom_stats,
-- 
2.54.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to