#include "unaligned.h"
#include "timeval.h"
#include "unixctl.h"
-#include "vlog.h"
+#include "openvswitch/vlog.h"
VLOG_DEFINE_THIS_MODULE(dpdk);
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
static struct ovs_mutex dpdk_mutex = OVS_MUTEX_INITIALIZER;
/* Contains all 'struct dpdk_dev's. */
-static struct list dpdk_list OVS_GUARDED_BY(dpdk_mutex)
- = LIST_INITIALIZER(&dpdk_list);
+static struct ovs_list dpdk_list OVS_GUARDED_BY(dpdk_mutex)
+ = OVS_LIST_INITIALIZER(&dpdk_list);
-static struct list dpdk_mp_list OVS_GUARDED_BY(dpdk_mutex)
- = LIST_INITIALIZER(&dpdk_mp_list);
+static struct ovs_list dpdk_mp_list OVS_GUARDED_BY(dpdk_mutex)
+ = OVS_LIST_INITIALIZER(&dpdk_mp_list);
/* This mutex must be used by non pmd threads when allocating or freeing
* mbufs through mempools. Since dpdk_queue_pkts() and dpdk_queue_flush() may
int mtu;
int socket_id;
int refcount;
- struct list list_node OVS_GUARDED_BY(dpdk_mutex);
+ struct ovs_list list_node OVS_GUARDED_BY(dpdk_mutex);
};
/* There should be one 'struct dpdk_tx_queue' created for
so we have to keep them around once they've been created
*/
-static struct list dpdk_ring_list OVS_GUARDED_BY(dpdk_mutex)
- = LIST_INITIALIZER(&dpdk_ring_list);
+static struct ovs_list dpdk_ring_list OVS_GUARDED_BY(dpdk_mutex)
+ = OVS_LIST_INITIALIZER(&dpdk_ring_list);
struct dpdk_ring {
/* For the client rings */
struct rte_ring *cring_rx;
int user_port_id; /* User given port no, parsed from port name */
int eth_port_id; /* ethernet device port id */
- struct list list_node OVS_GUARDED_BY(dpdk_mutex);
+ struct ovs_list list_node OVS_GUARDED_BY(dpdk_mutex);
};
struct netdev_dpdk {
int link_reset_cnt;
/* In dpdk_list. */
- struct list list_node OVS_GUARDED_BY(dpdk_mutex);
+ struct ovs_list list_node OVS_GUARDED_BY(dpdk_mutex);
+ rte_spinlock_t dpdkr_tx_lock;
};
struct netdev_rxq_dpdk {
OVS_REQUIRES(dpdk_mutex)
{
struct netdev_dpdk *netdev = netdev_dpdk_cast(netdev_);
+ int sid;
int err = 0;
ovs_mutex_init(&netdev->mutex);
ovs_mutex_lock(&netdev->mutex);
- netdev->socket_id = rte_eth_dev_socket_id(port_no);
+ /* If the 'sid' is negative, it means that the kernel fails
+ * to obtain the pci numa info. In that situation, always
+ * use 'SOCKET0'. */
+ sid = rte_eth_dev_socket_id(port_no);
+ netdev->socket_id = sid < 0 ? SOCKET0 : sid;
netdev_dpdk_alloc_txq(netdev, NR_QUEUE);
netdev->port_id = port_no;
netdev->flags = 0;
netdev->mtu = ETHER_MTU;
netdev->max_packet_len = MTU_TO_MAX_LEN(netdev->mtu);
+ rte_spinlock_init(&netdev->dpdkr_tx_lock);
netdev->dpdk_mp = dpdk_mp_get(netdev->socket_id, netdev->mtu);
if (!netdev->dpdk_mp) {
}
}
-static int
-netdev_dpdk_send(struct netdev *netdev, int qid, struct dpif_packet **pkts,
- int cnt, bool may_steal)
+static inline void
+netdev_dpdk_send__(struct netdev_dpdk *dev, int qid,
+ struct dpif_packet **pkts, int cnt, bool may_steal)
{
- struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
- int ret;
int i;
- if (!may_steal || pkts[0]->ofpbuf.source != OFPBUF_DPDK) {
+ if (OVS_UNLIKELY(!may_steal ||
+ pkts[0]->ofpbuf.source != OFPBUF_DPDK)) {
+ struct netdev *netdev = &dev->up;
+
dpdk_do_tx_copy(netdev, qid, pkts, cnt);
if (may_steal) {
ovs_mutex_unlock(&dev->mutex);
}
}
- ret = 0;
+}
+
+static int
+netdev_dpdk_eth_send(struct netdev *netdev, int qid,
+ struct dpif_packet **pkts, int cnt, bool may_steal)
+{
+ struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
- return ret;
+ netdev_dpdk_send__(dev, qid, pkts, cnt, may_steal);
+ return 0;
}
static int
return ENOMEM;
}
+ /* XXX: Add support for multiquque ring. */
err = snprintf(ring_name, 10, "%s_tx", dev_name);
if (err < 0) {
return -err;
}
- ivshmem->cring_tx = rte_ring_create(ring_name, DPDK_RING_SIZE, SOCKET0, 0);
+ /* Create single consumer/producer rings, netdev does explicit locking. */
+ ivshmem->cring_tx = rte_ring_create(ring_name, DPDK_RING_SIZE, SOCKET0,
+ RING_F_SP_ENQ | RING_F_SC_DEQ);
if (ivshmem->cring_tx == NULL) {
rte_free(ivshmem);
return ENOMEM;
return -err;
}
- ivshmem->cring_rx = rte_ring_create(ring_name, DPDK_RING_SIZE, SOCKET0, 0);
+ /* Create single consumer/producer rings, netdev does explicit locking. */
+ ivshmem->cring_rx = rte_ring_create(ring_name, DPDK_RING_SIZE, SOCKET0,
+ RING_F_SP_ENQ | RING_F_SC_DEQ);
if (ivshmem->cring_rx == NULL) {
rte_free(ivshmem);
return ENOMEM;
return dpdk_ring_create(dev_name, port_no, eth_port_id);
}
+static int
+netdev_dpdk_ring_send(struct netdev *netdev, int qid OVS_UNUSED,
+ struct dpif_packet **pkts, int cnt, bool may_steal)
+{
+ struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+
+ /* DPDK Rings have a single TX queue, Therefore needs locking. */
+ rte_spinlock_lock(&dev->dpdkr_tx_lock);
+ netdev_dpdk_send__(dev, 0, pkts, cnt, may_steal);
+ rte_spinlock_unlock(&dev->dpdkr_tx_lock);
+ return 0;
+}
+
static int
netdev_dpdk_ring_construct(struct netdev *netdev)
{
return err;
}
-#define NETDEV_DPDK_CLASS(NAME, INIT, CONSTRUCT, MULTIQ) \
+#define NETDEV_DPDK_CLASS(NAME, INIT, CONSTRUCT, MULTIQ, SEND) \
{ \
NAME, \
INIT, /* init */ \
netdev_dpdk_get_config, \
NULL, /* netdev_dpdk_set_config */ \
NULL, /* get_tunnel_config */ \
+ NULL, /* build header */ \
+ NULL, /* push header */ \
+ NULL, /* pop header */ \
netdev_dpdk_get_numa_id, /* get_numa_id */ \
MULTIQ, /* set_multiq */ \
\
- netdev_dpdk_send, /* send */ \
+ SEND, /* send */ \
NULL, /* send_wait */ \
\
netdev_dpdk_set_etheraddr, \
"dpdk",
dpdk_class_init,
netdev_dpdk_construct,
- netdev_dpdk_set_multiq);
+ netdev_dpdk_set_multiq,
+ netdev_dpdk_eth_send);
const struct netdev_class dpdk_ring_class =
NETDEV_DPDK_CLASS(
"dpdkr",
NULL,
netdev_dpdk_ring_construct,
- NULL);
+ NULL,
+ netdev_dpdk_ring_send);
void
netdev_dpdk_register(void)