* [PATCH 0/3] Improvements in packet timestamps support
From: Oleg Kuporosov @ 2016-10-13 14:35 UTC (permalink / raw)
To: dev
Hello DPDK Developers,
Financial Services Industry which is pretty eager for several DPDK
features especially low latency while high throughput. The major issue
so far for increasing DPDK adoption there is requirement for several
applications (capturers, some trading algorithms) to support of accurate
timestamping. The requirement mostly came from regulatory and customers
need strictly follow it.
Current state of timestamping support in DPDK looks pretty good:
- there is API to enable/disable timestamping acquisition by
rte_eth_timesync_enable/disable
- get timestamps itself by timesync_read_rx/tx_timestamp
- and even implementation of NTP IEEE 1588 for time synchronization
by rte_eth_timesync_adjust_read/write_time APIs.
But it misses the most important feature there – embedding timestamp
in rte_mbuf aligning it with packet.
We would like to change this to increase DPDK adoption for several new
DPDK-based applications for FSI segment. It also might be very
applicable for several RT media and debugging purposes of network
flows/streams in other segments like HPC.
There are several thoughts how to improve there:
- include uint64_t timestamp field into rte_mbuf with minimal impact
to throughput/latency. Keep it just simple uint64_t in ns (more than
580 years) would be enough for immediate needs while using full
struct timespec with twice bigger size would have much stronger
performance impact as missed cacheline0. It is possible as there is
6-bytes gap in 1st cacheline (fast path) and moving uint16_t
vlan_tci_outer field to 2nd cacheline.
- such move will only impact for pretty rare usable VLAN RX stripping
mode for outer TCI (it used only for one NIC i40e from the whole
set and keep minimal performance impact for timestamps.
- PMD can fill the field in their callback completion routines
depending on enabling this feature in runtime.
We evaluated other possible options but looks it will have even worse
performance impact.
Oleg Kuporosov (3):
mbuf: embedding timestamp into the packet
app/testpmd: enabled control for packet timestamps
net/mlx5: implementation of Rx packet timestamping support
app/test-pmd/cmdline.c | 122 +++++++++++++++
app/test-pmd/parameters.c | 4 +
app/test-pmd/testpmd.c | 5 +
app/test-pmd/testpmd.h | 1 +
doc/guides/testpmd_app_ug/run_app.rst | 4 +
doc/guides/testpmd_app_ug/testpmd_funcs.rst | 7 +
drivers/net/mlx5/mlx5.c | 7 +-
drivers/net/mlx5/mlx5.h | 10 +-
drivers/net/mlx5/mlx5_defs.h | 4 +
drivers/net/mlx5/mlx5_ethdev.c | 222 +++++++++++++++++++++++++++-
drivers/net/mlx5/mlx5_rxq.c | 2 +
drivers/net/mlx5/mlx5_rxtx.c | 19 ++-
drivers/net/mlx5/mlx5_rxtx.h | 7 +-
drivers/net/mlx5/mlx5_time.h | 53 +++++++
drivers/net/mlx5/mlx5_trigger.c | 1 +
lib/librte_eal/common/include/rte_time.h | 45 ++++++
lib/librte_mbuf/rte_mbuf.h | 6 +-
17 files changed, 507 insertions(+), 12 deletions(-)
create mode 100644 drivers/net/mlx5/mlx5_time.h
Thanks,
Oleg.
--
1.8.3.1
^ permalink raw reply
* [PATCH 1/3] mbuf: embedding timestamp into the packet
From: Oleg Kuporosov @ 2016-10-13 14:35 UTC (permalink / raw)
To: dev
In-Reply-To: <1476369308-17021-1-git-send-email-olegk@mellanox.com>
The hard requirement of financial services industry is accurate
timestamping aligned with the packet itself. This patch is to satisfy
this requirement:
- include uint64_t timestamp field into rte_mbuf with minimal impact to
throughput/latency. Keep it just simple uint64_t in ns (more than 580
years) would be enough for immediate needs while using full
struct timespec with twice bigger size would have much stronger
performance impact as missed cacheline0.
- it is possible as there is 6-bytes gap in 1st cacheline (fast path)
and moving uint16_t vlan_tci_outer field to 2nd cacheline.
- such move will only impact for pretty rare usable VLAN RX stripping
mode for outer TCI (it used only for one NIC i40e from the whole set and
allows to keep minimal performance impact for RX/TX timestamps.
Signed-off-by: Oleg Kuporosov <olegk@mellanox.com>
---
lib/librte_mbuf/rte_mbuf.h | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/lib/librte_mbuf/rte_mbuf.h b/lib/librte_mbuf/rte_mbuf.h
index 23b7bf8..1e1f2ed 100644
--- a/lib/librte_mbuf/rte_mbuf.h
+++ b/lib/librte_mbuf/rte_mbuf.h
@@ -851,8 +851,7 @@ struct rte_mbuf {
uint32_t seqn; /**< Sequence number. See also rte_reorder_insert() */
- /** Outer VLAN TCI (CPU order), valid if PKT_RX_QINQ_STRIPPED is set. */
- uint16_t vlan_tci_outer;
+ uint64_t timestamp; /**< Packet's timestamp, usually in ns */
/* second cache line - fields only used in slow path or on TX */
MARKER cacheline1 __rte_cache_min_aligned;
@@ -885,6 +884,9 @@ struct rte_mbuf {
};
};
+ /** Outer VLAN TCI (CPU order), valid if PKT_RX_QINQ_STRIPPED is set. */
+ uint16_t vlan_tci_outer;
+
/** Size of the application private data. In case of an indirect
* mbuf, it stores the direct mbuf private data size. */
uint16_t priv_size;
--
1.8.3.1
^ permalink raw reply related
* [PATCH 3/3] net/mlx5: implementation of Rx packet timestamping support
From: Oleg Kuporosov @ 2016-10-13 14:35 UTC (permalink / raw)
To: dev
In-Reply-To: <1476369308-17021-1-git-send-email-olegk@mellanox.com>
Accurate RX timestaping is minimal requirement for several important
financial services industry requirement for several applications like
packet capture.
Support of periodic time synchronization with system time and adjusting
clock deviation was also added. We assume the system is synchronized by
PTP itself, so there is no links to PTP client implementation in DPDK.
Time synchronization is run by control thread by rte_alarm for each 5
seconds. New synchronization object is copied to each configured RXQ
for TS calculation.
RX timestamp is calculated in nanoseconds and stored in rte_mbuf.
RX timestamp doesn't require additional API as simply can be
read from timestamp field of rte_mbuf.
TX timestamps were not added due to several reasons - there is no API yet,
issue with burst mode as TS will be provided only for the latest packet in
the burst and rte_mbuf will be discarded immediately after completion.
Enabling/disabling time synchronization DPDK API was added.
Signed-off-by: Oleg Kuporosov <olegk@mellanox.com>
---
drivers/net/mlx5/mlx5.c | 7 +-
drivers/net/mlx5/mlx5.h | 10 +-
drivers/net/mlx5/mlx5_defs.h | 4 +
drivers/net/mlx5/mlx5_ethdev.c | 222 ++++++++++++++++++++++++++++++-
drivers/net/mlx5/mlx5_rxq.c | 2 +
drivers/net/mlx5/mlx5_rxtx.c | 19 ++-
drivers/net/mlx5/mlx5_rxtx.h | 7 +-
drivers/net/mlx5/mlx5_time.h | 53 ++++++++
drivers/net/mlx5/mlx5_trigger.c | 1 +
lib/librte_eal/common/include/rte_time.h | 45 +++++++
10 files changed, 360 insertions(+), 10 deletions(-)
create mode 100644 drivers/net/mlx5/mlx5_time.h
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 83bdf65..64dab28 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -1,8 +1,8 @@
/*-
* BSD LICENSE
*
- * Copyright 2015 6WIND S.A.
- * Copyright 2015 Mellanox.
+ * Copyright 2015-2016 6WIND S.A.
+ * Copyright 2015-2016 Mellanox.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -122,6 +122,7 @@ mlx5_dev_close(struct rte_eth_dev *dev)
(void *)dev,
((priv->ctx != NULL) ? priv->ctx->device->name : ""));
/* In case mlx5_dev_stop() has not been called. */
+ mlx5_timesync_disable(dev);
priv_dev_interrupt_handler_uninstall(priv, dev);
priv_special_flow_disable_all(priv);
priv_mac_addrs_disable(priv);
@@ -219,6 +220,8 @@ static const struct eth_dev_ops mlx5_dev_ops = {
.rss_hash_update = mlx5_rss_hash_update,
.rss_hash_conf_get = mlx5_rss_hash_conf_get,
.filter_ctrl = mlx5_dev_filter_ctrl,
+ .timesync_enable = mlx5_timesync_enable,
+ .timesync_disable = mlx5_timesync_disable,
};
static struct {
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index d4fb5ff..49447c4 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -1,8 +1,8 @@
/*-
* BSD LICENSE
*
- * Copyright 2015 6WIND S.A.
- * Copyright 2015 Mellanox.
+ * Copyright 2015-2016 6WIND S.A.
+ * Copyright 2015-2016 Mellanox.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -54,6 +54,7 @@
#ifdef PEDANTIC
#pragma GCC diagnostic ignored "-pedantic"
#endif
+#include <rte_alarm.h>
#include <rte_ether.h>
#include <rte_ethdev.h>
#include <rte_spinlock.h>
@@ -64,6 +65,7 @@
#endif
#include "mlx5_utils.h"
+#include "mlx5_time.h"
#include "mlx5_rxtx.h"
#include "mlx5_autoconf.h"
#include "mlx5_defs.h"
@@ -113,6 +115,7 @@ struct priv {
unsigned int mps:1; /* Whether multi-packet send is supported. */
unsigned int cqe_comp:1; /* Whether CQE compression is enabled. */
unsigned int pending_alarm:1; /* An alarm is pending. */
+ unsigned int timesync_en:1; /* Timesync (timestamping) enabled */
unsigned int txq_inline; /* Maximum packet size for inlining. */
unsigned int txqs_inline; /* Queue number threshold for inlining. */
/* RX/TX queues. */
@@ -120,6 +123,7 @@ struct priv {
unsigned int txqs_n; /* TX queues array size. */
struct rxq *(*rxqs)[]; /* RX queues. */
struct txq *(*txqs)[]; /* TX queues. */
+ struct mlx5_timesync timesync; /* time synronization object */
/* Indirection tables referencing all RX WQs. */
struct ibv_exp_rwq_ind_table *(*ind_tables)[];
unsigned int ind_tables_n; /* Number of indirection tables. */
@@ -203,6 +207,8 @@ int mlx5_set_link_up(struct rte_eth_dev *dev);
struct priv *mlx5_secondary_data_setup(struct priv *priv);
void priv_select_tx_function(struct priv *);
void priv_select_rx_function(struct priv *);
+int mlx5_timesync_enable(struct rte_eth_dev *dev);
+int mlx5_timesync_disable(struct rte_eth_dev *dev);
/* mlx5_mac.c */
diff --git a/drivers/net/mlx5/mlx5_defs.h b/drivers/net/mlx5/mlx5_defs.h
index cc2a6f3..10b3f04 100644
--- a/drivers/net/mlx5/mlx5_defs.h
+++ b/drivers/net/mlx5/mlx5_defs.h
@@ -79,4 +79,8 @@
/* Alarm timeout. */
#define MLX5_ALARM_TIMEOUT_US 100000
+/* Clock deviation fix alarm timeout*/
+#define MLX5_ALARM_CLOCK_DEVIATION_US 5000000
+#define MLX5_CLOCK_DEVIATION_THRESHOLD 10
+
#endif /* RTE_PMD_MLX5_DEFS_H_ */
diff --git a/drivers/net/mlx5/mlx5_ethdev.c b/drivers/net/mlx5/mlx5_ethdev.c
index 264299a..16ba733 100644
--- a/drivers/net/mlx5/mlx5_ethdev.c
+++ b/drivers/net/mlx5/mlx5_ethdev.c
@@ -1,8 +1,8 @@
/*-
* BSD LICENSE
*
- * Copyright 2015 6WIND S.A.
- * Copyright 2015 Mellanox.
+ * Copyright 2015-2016 6WIND S.A.
+ * Copyright 2015-2016 Mellanox.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -59,6 +59,7 @@
#include <rte_interrupts.h>
#include <rte_alarm.h>
#include <rte_malloc.h>
+#include <rte_time.h>
#ifdef PEDANTIC
#pragma GCC diagnostic error "-pedantic"
#endif
@@ -1412,3 +1413,220 @@ priv_select_rx_function(struct priv *priv)
{
priv->dev->rx_pkt_burst = mlx5_rx_burst;
}
+
+/**
+ * Synchronize with system time. We get the best (min) from 10 attempts
+ * to minimize shift from sys time and HCA clocks.
+ *
+ * @param ibv_context
+ * Pointer to IB verbs context.
+ * @param st
+ * Pointer to store system time.
+ * @param st_ns
+ * Pointer to store system time represented in ns.
+ * @param hw_clock
+ * Pointer to store HCA HW clock.
+ *
+ * @return
+ * 0 on success, -1 value on failure.
+ */
+static int
+mlx5_sync_clocks(struct ibv_context *ibv_ctx, struct timespec *st,
+ volatile uint64_t *st_ns, volatile uint64_t *hw_clock)
+{
+ struct timespec st1, st2, diff, st_min = TIMESPEC_INITIALIZER;
+ struct ibv_exp_values query_val = {0};
+ int64_t interval, best_interval = 0;
+ uint64_t hw_clock_min = 0;
+
+ memset(&query_val, 0, sizeof(query_val));
+ query_val.comp_mask = IBV_EXP_VALUES_HW_CLOCK;
+ for (int i = 0 ; i < 10 ; ++i) {
+ clock_gettime(CLOCK_REALTIME, &st1);
+ if (ibv_exp_query_values(ibv_ctx, IBV_EXP_VALUES_HW_CLOCK,
+ &query_val) || !query_val.hwclock)
+ return -1;
+ clock_gettime(CLOCK_REALTIME, &st2);
+ interval = (st2.tv_sec - st1.tv_sec) * NSEC_PER_SEC +
+ (st2.tv_nsec - st1.tv_nsec);
+
+ if (!best_interval || interval < best_interval) {
+ best_interval = interval;
+ hw_clock_min = query_val.hwclock;
+
+ interval /= 2;
+ diff.tv_sec = interval / NSEC_PER_SEC;
+ diff.tv_nsec = interval - (diff.tv_sec * NSEC_PER_SEC);
+ rte_timespec_add(&st1, &diff, &st_min);
+ }
+ }
+ *st = st_min;
+ *st_ns = st->tv_sec * NSEC_PER_SEC + st->tv_nsec;
+ *hw_clock = hw_clock_min;
+ return 0;
+}
+
+/**
+ * Periodic function to run by rte_eal_alarm and to synchronize with system
+ * time and calculate HCA HW сlock deviation. The deviation will be included
+ * into timestamp calculation in RX/TX callbacks.
+ *
+ * @param arg
+ * Void pointer to struct priv.
+ *
+ */
+static void
+mlx5_fix_hw_clock_deviation_handler(void *arg)
+{
+ struct priv *pv = arg;
+ struct timespec current_time, diff_systime;
+ uint64_t diff_hw_clock, hw_clock, estimated_hw_clock;
+ uint64_t systime_ns, diff_systime_ns;
+ int64_t clock_deviation_hw;
+ volatile struct mlx5_timestamp_sync *ts = &pv->timesync.sync_timestamp;
+
+ if (!ts->port_clock_frequency)
+ return;
+ if (mlx5_sync_clocks(pv->ctx, ¤t_time, &systime_ns, &hw_clock))
+ return;
+ /* time between current and previous time sync */
+ rte_timespec_sub(¤t_time, &pv->timesync.sync_systime,
+ &diff_systime);
+ /* also clocks */
+ diff_hw_clock = hw_clock - ts->sync_hw_clock;
+ diff_systime_ns = rte_timespec_to_ns(&diff_systime);
+ estimated_hw_clock = (diff_systime.tv_sec * ts->port_clock_frequency) +
+ (diff_systime.tv_nsec * ts->port_clock_frequency /
+ NSEC_PER_SEC);
+ clock_deviation_hw = estimated_hw_clock - diff_hw_clock;
+ priv_lock(pv);
+ if (abs(clock_deviation_hw) >= MLX5_CLOCK_DEVIATION_THRESHOLD) {
+ ts->port_clock_frequency = (diff_hw_clock * NSEC_PER_SEC) /
+ diff_systime_ns;
+ ts->mskd_duration = (NSEC_PER_SEC << 30) /
+ ts->port_clock_frequency;
+ }
+ ts->sync_hw_clock = hw_clock;
+ ts->sync_time_ns = systime_ns;
+ pv->timesync.sync_systime = current_time;
+ DEBUG("%ld.%09ld since last fix, time_ns: %lu estimate_hw_clock = %ld,"
+ "diff_hw_clock = %ld, deviation = %ld, freq = %ld durat: %lu",
+ diff_systime.tv_sec, diff_systime.tv_nsec, systime_ns,
+ estimated_hw_clock, diff_hw_clock, clock_deviation_hw,
+ ts->port_clock_frequency, ts->mskd_duration);
+ /* update all queues */
+ for (uint32_t i = 0; i != pv->rxqs_n; i++) {
+ struct rxq *rxq = (*pv->rxqs)[i];
+
+ if (rxq == NULL)
+ continue;
+ rxq->timestamps_enabled = pv->timesync_en;
+ rxq->timesync = *ts;
+ }
+ priv_unlock(pv);
+ rte_eal_alarm_set(MLX5_ALARM_CLOCK_DEVIATION_US,
+ mlx5_fix_hw_clock_deviation_handler,
+ (void *)pv);
+}
+
+/**
+ * Return HCA port clock frequency in Hz.
+ *
+ * @param priv
+ * Pointer to private structure.
+ */
+static uint64_t
+mlx5_get_port_clock_frequency(struct priv *pv)
+{
+ struct ibv_exp_device_attr exp_device_attr;
+ exp_device_attr.comp_mask = IBV_EXP_DEVICE_ATTR_WITH_HCA_CORE_CLOCK;
+ if (ibv_exp_query_device(pv->ctx, &exp_device_attr)) {
+ ERROR("ibv_exp_query_device() failed");
+ return 0;
+ }
+ return exp_device_attr.hca_core_clock * 1000; /* orig in KHz */
+}
+
+/**
+ * DPDK callback to enable timestamping. rte_mbuf.timestamp will hold
+ * value of the packet in ns.
+ *
+ * @param dev
+ * Pointer to Ethernet device structure.
+ *
+ * @return
+ * 0 on success, errno value on failure.
+ */
+int
+mlx5_timesync_enable(struct rte_eth_dev *dev)
+{
+ struct priv *pv = dev->data->dev_private;
+ struct mlx5_timesync *tso = &pv->timesync;
+ volatile struct mlx5_timestamp_sync *sts = &tso->sync_timestamp;
+
+ priv_lock(pv);
+ sts->port_clock_frequency = mlx5_get_port_clock_frequency(pv);
+ if (!sts->port_clock_frequency) {
+ pv->timesync_en = 0;
+ INFO("Timesync disabled: %d as port clock frequency is 0",
+ pv->timesync_en);
+ priv_unlock(pv);
+ return -ENOTSUP;
+ }
+ INFO("port %u Clock frequency: %lu Hz", pv->port,
+ sts->port_clock_frequency);
+ if (mlx5_sync_clocks(pv->ctx, &tso->sync_systime, &sts->sync_time_ns,
+ &sts->sync_hw_clock)) {
+ pv->timesync_en = 0;
+ INFO("Timesync disabled: %d", pv->timesync_en);
+ priv_unlock(pv);
+ return -ENOTSUP;
+ }
+ sts->mskd_duration = (NSEC_PER_SEC << 30) / sts->port_clock_frequency;
+ pv->timesync_en = 1;
+ DEBUG("%p: Timesync enabled, masked duration: %lu", (void *)dev,
+ sts->mskd_duration);
+ rte_eal_alarm_set(1000,
+ mlx5_fix_hw_clock_deviation_handler,
+ pv);
+ DEBUG("%p: sync_systime: %lu.%lu, time_ns: %lu sync_hw_clock: %lu",
+ (void *)dev, tso->sync_systime.tv_sec,
+ tso->sync_systime.tv_nsec, sts->sync_time_ns, sts->sync_hw_clock);
+ /* update all queues */
+ for (uint32_t i = 0; i != pv->rxqs_n; i++) {
+ struct rxq *rxq = (*pv->rxqs)[i];
+
+ if (rxq == NULL)
+ continue;
+ rxq->timestamps_enabled = pv->timesync_en;
+ rxq->timesync = *sts;
+ }
+ priv_unlock(pv);
+ return 0;
+}
+
+/**
+ * DPDK callback to disable timestamping. Value of rte_mbuf.timestamp is
+ * undefined.
+ *
+ * @param dev
+ * Pointer to Ethernet device structure.
+ *
+ * @return
+ * 0 on success, errno value on failure.
+ */
+int
+mlx5_timesync_disable(struct rte_eth_dev *dev)
+{
+ struct priv *pv = dev->data->dev_private;
+
+ pv->timesync_en = 0;
+ rte_eal_alarm_cancel(mlx5_fix_hw_clock_deviation_handler, pv);
+ for (uint32_t i = 0; i != pv->rxqs_n; i++) {
+ struct rxq *rxq = (*pv->rxqs)[i];
+ if (rxq == NULL)
+ continue;
+ rxq->timestamps_enabled = pv->timesync_en;
+ }
+ return 0;
+}
diff --git a/drivers/net/mlx5/mlx5_rxq.c b/drivers/net/mlx5/mlx5_rxq.c
index d32ad68..b9a5fe6 100644
--- a/drivers/net/mlx5/mlx5_rxq.c
+++ b/drivers/net/mlx5/mlx5_rxq.c
@@ -1258,6 +1258,8 @@ mlx5_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
rte_free(rxq_ctrl);
else {
rxq_ctrl->rxq.stats.idx = idx;
+ rxq_ctrl->rxq.timestamps_enabled = priv->timesync_en;
+ rxq_ctrl->rxq.timesync = priv->timesync.sync_timestamp;
DEBUG("%p: adding RX queue %p to list",
(void *)dev, (void *)rxq_ctrl);
(*priv->rxqs)[idx] = &rxq_ctrl->rxq;
diff --git a/drivers/net/mlx5/mlx5_rxtx.c b/drivers/net/mlx5/mlx5_rxtx.c
index 91b0131..54f284d 100644
--- a/drivers/net/mlx5/mlx5_rxtx.c
+++ b/drivers/net/mlx5/mlx5_rxtx.c
@@ -1,8 +1,8 @@
/*-
* BSD LICENSE
*
- * Copyright 2015 6WIND S.A.
- * Copyright 2015 Mellanox.
+ * Copyright 2015-2016 6WIND S.A.
+ * Copyright 2015-2016 Mellanox.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -59,6 +59,7 @@
#include <rte_branch_prediction.h>
#include <rte_ether.h>
#include <rte_vect.h>
+#include <rte_time.h>
#ifdef PEDANTIC
#pragma GCC diagnostic error "-pedantic"
#endif
@@ -1385,6 +1386,20 @@ mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
len -= ETHER_CRC_LEN;
}
PKT_LEN(pkt) = len;
+ /* Calculate synchronized timestamp in ns */
+ if (unlikely(rxq->timestamps_enabled)) {
+ volatile struct mlx5_timestamp_sync *tso =
+ &rxq->timesync;
+ uint64_t clock_diff;
+ rte_prefetch0(tso);
+ clock_diff = ntohll(cqe->timestamp) -
+ tso->sync_hw_clock;
+ clock_diff = (clock_diff * tso->mskd_duration)
+ >> 30;
+ pkt->timestamp = tso->sync_time_ns +
+ clock_diff;
+ pkt->ol_flags |= PKT_RX_IEEE1588_TMST;
+ }
}
DATA_LEN(rep) = DATA_LEN(seg);
PKT_LEN(rep) = PKT_LEN(seg);
diff --git a/drivers/net/mlx5/mlx5_rxtx.h b/drivers/net/mlx5/mlx5_rxtx.h
index 844cabc..2ff873c 100644
--- a/drivers/net/mlx5/mlx5_rxtx.h
+++ b/drivers/net/mlx5/mlx5_rxtx.h
@@ -1,8 +1,8 @@
/*-
* BSD LICENSE
*
- * Copyright 2015 6WIND S.A.
- * Copyright 2015 Mellanox.
+ * Copyright 2015-2016 6WIND S.A.
+ * Copyright 2015-2016 Mellanox.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -60,6 +60,7 @@
#endif
#include "mlx5_utils.h"
+#include "mlx5_time.h"
#include "mlx5.h"
#include "mlx5_autoconf.h"
#include "mlx5_defs.h"
@@ -109,6 +110,7 @@ struct rxq {
unsigned int csum_l2tun:1; /* Same for L2 tunnels. */
unsigned int vlan_strip:1; /* Enable VLAN stripping. */
unsigned int crc_present:1; /* CRC must be subtracted. */
+ unsigned int timestamps_enabled:1; /* timestamping enabled */
unsigned int sges_n:2; /* Log 2 of SGEs (max buffers per packet). */
unsigned int cqe_n:4; /* Log 2 of CQ elements. */
unsigned int elts_n:4; /* Log 2 of Mbufs. */
@@ -125,6 +127,7 @@ struct rxq {
struct rte_mbuf *(*elts)[];
struct rte_mempool *mp;
struct mlx5_rxq_stats stats;
+ volatile struct mlx5_timestamp_sync timesync; /* per queue copy */
} __rte_cache_aligned;
/* RX queue control descriptor. */
diff --git a/drivers/net/mlx5/mlx5_time.h b/drivers/net/mlx5/mlx5_time.h
new file mode 100644
index 0000000..b44bcb1
--- /dev/null
+++ b/drivers/net/mlx5/mlx5_time.h
@@ -0,0 +1,53 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright 2016 Mellanox.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of 6WIND S.A. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RTE_PMD_MLX5_TIME_H_
+#define RTE_PMD_MLX5_TIME_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <limits.h>
+
+
+struct mlx5_timestamp_sync {
+ uint64_t sync_hw_clock; /* the last HW clocks */
+ uint64_t sync_time_ns; /* the last system time in ns */
+ uint64_t mskd_duration; /* adjusted masked duration */
+ uint64_t port_clock_frequency; /* in Hz */
+};
+
+struct mlx5_timesync {
+ volatile struct mlx5_timestamp_sync sync_timestamp;
+ struct timespec sync_systime; /* the last system time */
+};
+
+#endif /* RTE_PMD_MLX5_TIME_H_ */
diff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c
index e9b9a29..ff94e6b 100644
--- a/drivers/net/mlx5/mlx5_trigger.c
+++ b/drivers/net/mlx5/mlx5_trigger.c
@@ -116,6 +116,7 @@ mlx5_dev_stop(struct rte_eth_dev *dev)
return;
}
DEBUG("%p: cleaning up and destroying hash RX queues", (void *)dev);
+ mlx5_timesync_disable(dev);
priv_special_flow_disable_all(priv);
priv_mac_addrs_disable(priv);
priv_destroy_hash_rxqs(priv);
diff --git a/lib/librte_eal/common/include/rte_time.h b/lib/librte_eal/common/include/rte_time.h
index 28c6274..7fa8e64 100644
--- a/lib/librte_eal/common/include/rte_time.h
+++ b/lib/librte_eal/common/include/rte_time.h
@@ -37,6 +37,8 @@
#include <stdint.h>
#include <time.h>
+#define TIMESPEC_INITIALIZER {0, 0}
+
#define NSEC_PER_SEC 1000000000L
/**
@@ -127,4 +129,47 @@ rte_ns_to_timespec(uint64_t nsec)
return ts;
}
+/**
+ * Addition of two timespec times to result.
+ *
+ * @param a
+ * Pointer to the first time
+ * @param b
+ * Pointer to the second time
+ * @param res
+ * Pointer to result
+ *
+ */
+static inline void rte_timespec_add(struct timespec *a, struct timespec *b,
+ struct timespec *res)
+{
+ res->tv_sec = a->tv_sec + b->tv_sec;
+ res->tv_nsec = a->tv_nsec + b->tv_nsec;
+ if (res->tv_nsec >= NSEC_PER_SEC) {
+ ++res->tv_sec;
+ res->tv_nsec -= NSEC_PER_SEC;
+ }
+}
+
+/**
+ * Substruction of the first timespec by second to result.
+ *
+ * @param a
+ * Pointer to the first time
+ * @param b
+ * Pointer to the second time
+ * @param res
+ * Pointer to result
+ */
+static inline void rte_timespec_sub(struct timespec *a, struct timespec *b,
+ struct timespec *res)
+{
+ res->tv_sec = a->tv_sec - b->tv_sec;
+ res->tv_nsec = a->tv_nsec - b->tv_nsec;
+ if (res->tv_nsec < 0) {
+ --res->tv_sec;
+ res->tv_nsec += NSEC_PER_SEC;
+ }
+}
+
#endif /* _RTE_TIME_H_ */
--
1.8.3.1
^ permalink raw reply related
* [PATCH 2/3] app/testpmd: enabled control for packet timestamps
From: Oleg Kuporosov @ 2016-10-13 14:35 UTC (permalink / raw)
To: dev
In-Reply-To: <1476369308-17021-1-git-send-email-olegk@mellanox.com>
Implemented two methods of control
- by --enable-timestamps CL testpmd application we can enable timestamping
for all ports;
- in interactive mode port config <port> timestamps on|off is able to
configure timestamping per specific port.
The control doesn't interact with IEEE1588 PTP implementation there as
it is under macro compilation but can be extended in the future.
This feature is required for debugging/testing purposes for real time HW
packet timestamping.
Signed-off-by: Oleg Kuporosov <olegk@mellanox.com>
---
app/test-pmd/cmdline.c | 122 ++++++++++++++++++++++++++++
app/test-pmd/parameters.c | 4 +
app/test-pmd/testpmd.c | 5 ++
app/test-pmd/testpmd.h | 1 +
doc/guides/testpmd_app_ug/run_app.rst | 4 +
doc/guides/testpmd_app_ug/testpmd_funcs.rst | 7 ++
6 files changed, 143 insertions(+)
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 17d238f..9b202ce 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -561,6 +561,9 @@ static void cmd_help_long_parsed(void *parsed_result,
" Set crc-strip/scatter/rx-checksum/hardware-vlan/drop_en"
" for ports.\n\n"
+ "port config (port_id|all) timestamps (on|off)\n"
+ " Enable/disable packet timestamps.\n\n"
+
"port config all rss (all|ip|tcp|udp|sctp|ether|port|vxlan|geneve|nvgre|none)\n"
" Set the RSS mode.\n\n"
@@ -10188,6 +10191,123 @@ cmdline_parse_inst_t cmd_config_l2_tunnel_en_dis_specific = {
},
};
+/* Configure port timestamping */
+struct cmd_config_timestamps_result {
+ cmdline_fixed_string_t port;
+ cmdline_fixed_string_t config;
+ cmdline_fixed_string_t all;
+ uint8_t id;
+ cmdline_fixed_string_t timestamps;
+ cmdline_fixed_string_t mode;
+};
+
+cmdline_parse_token_string_t cmd_config_timestamps_port =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_timestamps_result,
+ port, "port");
+cmdline_parse_token_string_t cmd_config_timestamps_config =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_timestamps_result,
+ config, "config");
+cmdline_parse_token_string_t cmd_config_timestamps_all_str =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_timestamps_result,
+ all, "all");
+cmdline_parse_token_num_t cmd_config_timestamps_id =
+ TOKEN_NUM_INITIALIZER
+ (struct cmd_config_timestamps_result,
+ id, UINT8);
+cmdline_parse_token_string_t cmd_config_timestamps_ts_str =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_timestamps_result,
+ timestamps, "timestamps");
+cmdline_parse_token_string_t cmd_config_timestamps_path =
+ TOKEN_STRING_INITIALIZER
+ (struct cmd_config_timestamps_result,
+ mode, "on#off");
+
+/* enable/disable timestamps (on/off) for a port */
+static void
+cmd_config_timestamps_all_parsed(
+ void *parsed_result,
+ __attribute__((unused)) struct cmdline *cl,
+ __attribute__((unused)) void *data)
+{
+ struct cmd_config_timestamps_result *res = parsed_result;
+ portid_t pid;
+ uint8_t mode = 0;
+
+ if (!strcmp("on", res->mode))
+ mode = 1;
+ else if (!strcmp("off", res->mode))
+ mode = 0;
+ else {
+ printf("Unknown timestamps mode parameter\n");
+ return;
+ }
+ FOREACH_PORT(pid, ports) {
+ if (mode)
+ rte_eth_timesync_enable(pid);
+ else
+ rte_eth_timesync_disable(pid);
+ }
+}
+
+cmdline_parse_inst_t cmd_config_timestamps_all = {
+ .f = cmd_config_timestamps_all_parsed,
+ .data = NULL,
+ .help_str = "port config all timestamps on|off",
+ .tokens = {
+ (void *)&cmd_config_timestamps_port,
+ (void *)&cmd_config_timestamps_config,
+ (void *)&cmd_config_timestamps_all_str,
+ (void *)&cmd_config_timestamps_ts_str,
+ (void *)&cmd_config_timestamps_path,
+ NULL,
+ },
+};
+
+/* enable/disable timestamps (rx/tx/both) for a port */
+static void
+cmd_config_timestamps_specific_parsed(
+ void *parsed_result,
+ __attribute__((unused)) struct cmdline *cl,
+ __attribute__((unused)) void *data)
+{
+ struct cmd_config_timestamps_result *res =
+ parsed_result;
+ uint8_t mode = 0;
+
+ if (port_id_is_invalid(res->id, ENABLED_WARN))
+ return;
+ if (!strcmp("on", res->mode))
+ mode = 1;
+ else if (!strcmp("off", res->mode))
+ mode = 0;
+ else {
+ printf("Unknown timestamps mode parameter\n");
+ return;
+ }
+ if (mode)
+ rte_eth_timesync_enable(res->id);
+ else
+ rte_eth_timesync_disable(res->id);
+}
+
+cmdline_parse_inst_t cmd_config_timestamps_specific = {
+ .f = cmd_config_timestamps_specific_parsed,
+ .data = NULL,
+ .help_str = "port config <port> timestamps on|off",
+ .tokens = {
+ (void *)&cmd_config_timestamps_port,
+ (void *)&cmd_config_timestamps_config,
+ (void *)&cmd_config_timestamps_id,
+ (void *)&cmd_config_timestamps_ts_str,
+ (void *)&cmd_config_timestamps_path,
+ NULL,
+ },
+};
+
/* E-tag configuration */
/* Common result structure for all E-tag configuration */
@@ -10739,6 +10859,8 @@ cmdline_parse_ctx_t main_ctx[] = {
(cmdline_parse_inst_t *)&cmd_config_e_tag_forwarding_en_dis,
(cmdline_parse_inst_t *)&cmd_config_e_tag_filter_add,
(cmdline_parse_inst_t *)&cmd_config_e_tag_filter_del,
+ (cmdline_parse_inst_t *)&cmd_config_timestamps_all,
+ (cmdline_parse_inst_t *)&cmd_config_timestamps_specific,
NULL,
};
diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c
index 6a6a07e..f15cd5a 100644
--- a/app/test-pmd/parameters.c
+++ b/app/test-pmd/parameters.c
@@ -150,6 +150,7 @@ usage(char* progname)
"By default drop-queue=127.\n");
printf(" --crc-strip: enable CRC stripping by hardware.\n");
printf(" --enable-rx-cksum: enable rx hardware checksum offload.\n");
+ printf(" --enable-timestamps: enable rx hardware timestamp.\n");
printf(" --disable-hw-vlan: disable hardware vlan.\n");
printf(" --disable-hw-vlan-filter: disable hardware vlan filter.\n");
printf(" --disable-hw-vlan-strip: disable hardware vlan strip.\n");
@@ -525,6 +526,7 @@ launch_args_parse(int argc, char** argv)
{ "pkt-filter-drop-queue", 1, 0, 0 },
{ "crc-strip", 0, 0, 0 },
{ "enable-rx-cksum", 0, 0, 0 },
+ { "enable-timestamps", 0, 0, 0 },
{ "enable-scatter", 0, 0, 0 },
{ "disable-hw-vlan", 0, 0, 0 },
{ "disable-hw-vlan-filter", 0, 0, 0 },
@@ -768,6 +770,8 @@ launch_args_parse(int argc, char** argv)
rx_mode.enable_scatter = 1;
if (!strcmp(lgopts[opt_idx].name, "enable-rx-cksum"))
rx_mode.hw_ip_checksum = 1;
+ if (!strcmp(lgopts[opt_idx].name, "enable-timestamps"))
+ timestamps_enabled = 1;
if (!strcmp(lgopts[opt_idx].name, "disable-hw-vlan")) {
rx_mode.hw_vlan_filter = 0;
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index e2403c3..ee76282 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -189,6 +189,8 @@ uint8_t dcb_config = 0;
/* Whether the dcb is in testing status */
uint8_t dcb_test = 0;
+/**< Enabling runtime packet timestamps by CL: --enable-timestamps */
+uint8_t timestamps_enabled = 0;
/*
* Configurable number of RX/TX queues.
*/
@@ -1851,6 +1853,9 @@ init_port_config(void)
rte_eth_macaddr_get(pid, &port->eth_addr);
+ if (timestamps_enabled)
+ rte_eth_timesync_enable(pid);
+
map_port_queue_stats_mapping_registers(pid, port);
#ifdef RTE_NIC_BYPASS
rte_eth_dev_bypass_init(pid);
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 2b281cc..489661e 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -353,6 +353,7 @@ extern int32_t txq_flags;
extern uint8_t dcb_config;
extern uint8_t dcb_test;
+extern uint8_t timestamps_enabled; /**< Timestamps by --enable-timestamps */
extern enum dcb_queue_mapping_mode dcb_q_mapping;
extern uint16_t mbuf_data_size; /**< Mbuf data space size. */
diff --git a/doc/guides/testpmd_app_ug/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst
index 7712bd2..fb56846 100644
--- a/doc/guides/testpmd_app_ug/run_app.rst
+++ b/doc/guides/testpmd_app_ug/run_app.rst
@@ -313,6 +313,10 @@ The commandline options are:
Enable per-queue packet drop for packets with no descriptors.
+* ``--enable-timestamps``
+
+ Enable timesync and per packet timestamping for all ports.
+
* ``--disable-rss``
Disable RSS (Receive Side Scaling).
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index f87e0c2..ed84c6d 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -1312,6 +1312,13 @@ Set the DCB mode for an individual port::
The traffic class should be 4 or 8.
+port config - Timesync/timestamping
+~~~~~~~~~~~~~~~~~~~
+
+Enable/disable time synhronzation/packet timestamping for specific port or all ports::
+
+ testpmd> port config (port_id|all) timestamps (on|off)
+
port config - Burst
~~~~~~~~~~~~~~~~~~~
--
1.8.3.1
^ permalink raw reply related
* Re: 17.02 Roadmap
From: Thomas Monjalon @ 2016-10-13 14:39 UTC (permalink / raw)
To: Hunt, David; +Cc: O'Driscoll, Tim, dev
In-Reply-To: <c92322c9-a8a4-8a9b-54b9-6fc1b403f986@intel.com>
2016-10-13 15:18, Hunt, David:
> Hi Thomas,
>
> On 10/10/2016 9:42 PM, Thomas Monjalon wrote:
> > 2016-10-10 16:13, O'Driscoll, Tim:
> >> Packet Distributor Enhancements: Enhancements will be made to the Packet Distributor library to improve performance:
> >> 1. Introduce burst functionality to allow batches of packets to be sent to workers.
> >> 2. Improve the performance of the flow/core affinity through the use of SSE/AVX instructions.
> >
> > The packet distributor looks more and more like a DPDK application
> > at the same level of BESS, VPP, OVS, etc.
>
> Lets discuss this further. Would you see other libraries heading in
> this direction also (reorder, acl, hash, etc)?
Not so easy to put things in a category.
> Do you think it would be an idea to add as an item of discussion for the
> technical steering group when we're all at Userspace next week?
If others are interested to discuss about libraries categories and growth,
yes I'll jump in.
^ permalink raw reply
* Re: [PATCH v6] drivers/net:new PMD using tun/tap host interface
From: Ferruh Yigit @ 2016-10-13 14:41 UTC (permalink / raw)
To: Keith Wiles, dev; +Cc: pmatilai, yuanhan.liu
In-Reply-To: <1476305658-27986-1-git-send-email-keith.wiles@intel.com>
On 10/12/2016 9:54 PM, Keith Wiles wrote:
> The rte_eth_tap.c PMD creates a device using TUN/TAP interfaces
> on the local host. The PMD allows for DPDK and the host to
> communicate using a raw device interface on the host and in
> the DPDK application. The device created is a Tap device with
> a L2 packet header.
>
> v6 - fixed the checkpatch issues
> v5 - merge in changes from list review see related emails
> fixed many minor edits
> v4 - merge with latest driver changes
> v3 - fix includes by removing ifdef for other type besides Linux
> Fix the copyright notice in the Makefile
> v2 - merge all of the patches into one patch
> Fix a typo on naming the tap device
> Update the maintainers list
>
> Signed-off-by: Keith Wiles <keith.wiles@intel.com>
> ---
<...>
> diff --git a/config/common_base b/config/common_base
...
> +
> +#
> +# Set TAP PMD to 'n' as it is only supported in Linux for now.
> +#
In final .config file, this comment says TAP PMD set to "n", but it is
set to "y"
Also this behavior is not unique to this config option, many config
items used as described in the comment, and they don't have same comment.
<...>
> diff --git a/doc/guides/nics/tap.rst b/doc/guides/nics/tap.rst
...
> +
> + Also the speed of the interface can be changed from 10G to whatever number
> + needed, but the interface does not enforce that speed.
> + e.g. --vdev=eth_tap,iface=foo0,speed=25000
Same comment with previous review, eth_tap should be net_tap, for all
occurrences in this document
<...>
> diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
...
> +struct tap_info {
> + char name[RTE_ETH_NAME_MAX_LEN]; /* Interface name supplied/given */
> + int speed; /* Speed of interface */
> +};
Same comment with previous review, this struct is not used at all.
<...>
> +static int
> +eth_dev_tap_create(const char *name, char *tap_name)
...
> + dev->data = data;
> + dev->dev_ops = &ops;
> + dev->driver = NULL;
> + dev->rx_pkt_burst = pmd_rx_burst;
> + dev->tx_pkt_burst = pmd_tx_burst;
> + snprintf(dev->data->name, sizeof(dev->data->name), "%s", tap_name);
[1]
<...>
> + */
> +static int
> +rte_pmd_tap_remove(const char *name)
...
> +
> + /* find the ethdev entry */
> + eth_dev = rte_eth_dev_allocated(name);
This still won't work, please see [1], dev->name overwritten by
tap_name, and this function does simply a strcmp with name and dev->name.
<...>
Thanks,
ferruh
^ permalink raw reply
* Re: [PATCH v2 12/12] virtio: add Tso support
From: Olivier MATZ @ 2016-10-13 14:52 UTC (permalink / raw)
To: Yuanhan Liu
Cc: dev, konstantin.ananyev, sugesh.chandran, bruce.richardson,
jianfeng.tan, helin.zhang, adrien.mazarguil, stephen, dprovan,
xiao.w.wang
In-Reply-To: <20161013141654.GW16751@yliu-dev.sh.intel.com>
On 10/13/2016 04:16 PM, Yuanhan Liu wrote:
> On Thu, Oct 13, 2016 at 04:02:49PM +0200, Olivier MATZ wrote:
>>
>>
>> On 10/13/2016 10:18 AM, Yuanhan Liu wrote:
>>> On Mon, Oct 03, 2016 at 11:00:23AM +0200, Olivier Matz wrote:
>>>> +/* When doing TSO, the IP length is not included in the pseudo header
>>>> + * checksum of the packet given to the PMD, but for virtio it is
>>>> + * expected.
>>>> + */
>>>> +static void
>>>> +virtio_tso_fix_cksum(struct rte_mbuf *m)
>>>> +{
>>>> + /* common case: header is not fragmented */
>>>> + if (likely(rte_pktmbuf_data_len(m) >= m->l2_len + m->l3_len +
>>>> + m->l4_len)) {
>>> ...
>>>> + /* replace it in the packet */
>>>> + th->cksum = new_cksum;
>>>> + } else {
>>> ...
>>>> + /* replace it in the packet */
>>>> + *rte_pktmbuf_mtod_offset(m, uint8_t *,
>>>> + m->l2_len + m->l3_len + 16) = new_cksum.u8[0];
>>>> + *rte_pktmbuf_mtod_offset(m, uint8_t *,
>>>> + m->l2_len + m->l3_len + 17) = new_cksum.u8[1];
>>>> + }
>>>
>>> The tcp header will always be in the mbuf, right? Otherwise, you can't
>>> update the cksum field here. What's the point of introducing the "else
>>> clause" then?
>>
>> Sorry, I don't see the problem you're pointing out here.
>>
>> What I want to solve here is to support the cases where the mbuf is
>> segmented in the middle of the network header (which is probably a rare
>> case).
>
> How it's gonna segmented?
The mbuf is given by the application. So if the application generates a
segmented mbuf, it should work.
This could happen for instance if the application uses mbuf clones to
share the IP/TCP/data part of the mbuf and prepend a specific
Ethernet/vlan for different destination.
>> In the "else" part, I only access the mbuf byte by byte using the
>> rte_pktmbuf_mtod_offset() accessor. An alternative would have been to copy
>> the header in a linear buffer, fix the checksum, then copy it again in the
>> packet, but there is no mbuf helpers to do these copies for now.
>
> In the "else" clause, the ip header is still in the mbuf, right?
> Why do you have to access it the way like:
>
> ip_version = *rte_pktmbuf_mtod_offset(m, uint8_t *,
> m->l2_len) >> 4;
>
> Why can't you just use
>
> iph = rte_pktmbuf_mtod_offset(m, struct ipv4_hdr *, m->l2_len);
> iph->version_ihl ....;
AFAIK, there is no requirement that each network header has to be
contiguous in a mbuf segment.
Of course, a split in the middle of a network header probably never
happens... but we never knows, as it is not forbidden. I think the code
should be robust enough to avoid accesses to wrong addresses.
Hope it's clear enough :)
Thanks
Olivier
^ permalink raw reply
* Re: [PATCH v2 12/12] virtio: add Tso support
From: Yuanhan Liu @ 2016-10-13 15:01 UTC (permalink / raw)
To: Olivier MATZ
Cc: dev, konstantin.ananyev, sugesh.chandran, bruce.richardson,
jianfeng.tan, helin.zhang, adrien.mazarguil, stephen, dprovan,
xiao.w.wang
In-Reply-To: <57FF9FA9.8020403@6wind.com>
On Thu, Oct 13, 2016 at 04:52:25PM +0200, Olivier MATZ wrote:
>
>
> On 10/13/2016 04:16 PM, Yuanhan Liu wrote:
> >On Thu, Oct 13, 2016 at 04:02:49PM +0200, Olivier MATZ wrote:
> >>
> >>
> >>On 10/13/2016 10:18 AM, Yuanhan Liu wrote:
> >>>On Mon, Oct 03, 2016 at 11:00:23AM +0200, Olivier Matz wrote:
> >>>>+/* When doing TSO, the IP length is not included in the pseudo header
> >>>>+ * checksum of the packet given to the PMD, but for virtio it is
> >>>>+ * expected.
> >>>>+ */
> >>>>+static void
> >>>>+virtio_tso_fix_cksum(struct rte_mbuf *m)
> >>>>+{
> >>>>+ /* common case: header is not fragmented */
> >>>>+ if (likely(rte_pktmbuf_data_len(m) >= m->l2_len + m->l3_len +
> >>>>+ m->l4_len)) {
> >>>...
> >>>>+ /* replace it in the packet */
> >>>>+ th->cksum = new_cksum;
> >>>>+ } else {
> >>>...
> >>>>+ /* replace it in the packet */
> >>>>+ *rte_pktmbuf_mtod_offset(m, uint8_t *,
> >>>>+ m->l2_len + m->l3_len + 16) = new_cksum.u8[0];
> >>>>+ *rte_pktmbuf_mtod_offset(m, uint8_t *,
> >>>>+ m->l2_len + m->l3_len + 17) = new_cksum.u8[1];
> >>>>+ }
> >>>
> >>>The tcp header will always be in the mbuf, right? Otherwise, you can't
> >>>update the cksum field here. What's the point of introducing the "else
> >>>clause" then?
> >>
> >>Sorry, I don't see the problem you're pointing out here.
> >>
> >>What I want to solve here is to support the cases where the mbuf is
> >>segmented in the middle of the network header (which is probably a rare
> >>case).
> >
> >How it's gonna segmented?
>
> The mbuf is given by the application. So if the application generates a
> segmented mbuf, it should work.
>
> This could happen for instance if the application uses mbuf clones to share
> the IP/TCP/data part of the mbuf and prepend a specific Ethernet/vlan for
> different destination.
>
>
> >>In the "else" part, I only access the mbuf byte by byte using the
> >>rte_pktmbuf_mtod_offset() accessor. An alternative would have been to copy
> >>the header in a linear buffer, fix the checksum, then copy it again in the
> >>packet, but there is no mbuf helpers to do these copies for now.
> >
> >In the "else" clause, the ip header is still in the mbuf, right?
> >Why do you have to access it the way like:
> >
> > ip_version = *rte_pktmbuf_mtod_offset(m, uint8_t *,
> > m->l2_len) >> 4;
> >
> >Why can't you just use
> >
> > iph = rte_pktmbuf_mtod_offset(m, struct ipv4_hdr *, m->l2_len);
> > iph->version_ihl ....;
>
> AFAIK, there is no requirement that each network header has to be contiguous
> in a mbuf segment.
>
> Of course, a split in the middle of a network header probably never
> happens... but we never knows, as it is not forbidden. I think the code
> should be robust enough to avoid accesses to wrong addresses.
>
> Hope it's clear enough :)
Thanks, but not really. Maybe let me ask this way: what wrong would
happen if we use
iph = rte_pktmbuf_mtod_offset(m, struct ipv4_hdr *, m->l2_len);
to access the IP header? Is it about the endian?
--yliu
^ permalink raw reply
* Re: [PATCH v2 12/12] virtio: add Tso support
From: Yuanhan Liu @ 2016-10-13 15:04 UTC (permalink / raw)
To: Olivier MATZ
Cc: dev, konstantin.ananyev, sugesh.chandran, bruce.richardson,
jianfeng.tan, helin.zhang, adrien.mazarguil, stephen, dprovan,
xiao.w.wang
In-Reply-To: <57FF9FA9.8020403@6wind.com>
On Thu, Oct 13, 2016 at 04:52:25PM +0200, Olivier MATZ wrote:
> >In the "else" clause, the ip header is still in the mbuf, right?
> >Why do you have to access it the way like:
> >
> > ip_version = *rte_pktmbuf_mtod_offset(m, uint8_t *,
> > m->l2_len) >> 4;
> >
> >Why can't you just use
> >
> > iph = rte_pktmbuf_mtod_offset(m, struct ipv4_hdr *, m->l2_len);
> > iph->version_ihl ....;
>
> AFAIK, there is no requirement that each network header has to be contiguous
> in a mbuf segment.
>
> Of course, a split in the middle of a network header probably never
> happens... but we never knows, as it is not forbidden. I think the code
> should be robust enough to avoid accesses to wrong addresses.
One more question is do you have any case to trigger the "else" clause?
--yliu
^ permalink raw reply
* Re: [PATCH] mempool: fix search of maximum contiguous pages
From: Olivier MATZ @ 2016-10-13 15:05 UTC (permalink / raw)
To: Ananyev, Konstantin, Dai, Wei, dev@dpdk.org,
Gonzalez Monroy, Sergio, Tan, Jianfeng
In-Reply-To: <2601191342CEEE43887BDE71AB9772583F0C12EF@irsmsx105.ger.corp.intel.com>
Hi Wei,
On 10/13/2016 02:31 PM, Ananyev, Konstantin wrote:
>
>>
>>>>> diff --git a/lib/librte_mempool/rte_mempool.c
>>>>> b/lib/librte_mempool/rte_mempool.c
>>>>> index 71017e1..e3e254a 100644
>>>>> --- a/lib/librte_mempool/rte_mempool.c
>>>>> +++ b/lib/librte_mempool/rte_mempool.c
>>>>> @@ -426,9 +426,12 @@ rte_mempool_populate_phys_tab(struct
>>>>> rte_mempool *mp, char *vaddr,
>>>>>
>>>>> for (i = 0; i < pg_num && mp->populated_size < mp->size; i += n) {
>>>>>
>>>>> + phys_addr_t paddr_next;
>>>>> + paddr_next = paddr[i] + pg_sz;
>>>>> +
>>>>> /* populate with the largest group of contiguous pages */
>>>>> for (n = 1; (i + n) < pg_num &&
>>>>> - paddr[i] + pg_sz == paddr[i+n]; n++)
>>>>> + paddr_next == paddr[i+n]; n++, paddr_next += pg_sz)
>>>>> ;
>>>>
>>>> Good catch.
>>>> Why not just paddr[i + n - 1] != paddr[i + n]?
>>>
>>> Sorry, I meant 'paddr[i + n - 1] + pg_sz == paddr[i+n]' off course.
>>>
>>>> Then you don't need extra variable (paddr_next) here.
>>>> Konstantin
>>
>> Thank you, Konstantin
>> 'paddr[i + n - 1] + pg_sz = paddr[i + n]' also can fix it and have straight meaning.
>> But I assume that my revision with paddr_next += pg_sz may have a bit better performance.
>
> I don't think there would be any real difference, again it is not performance critical code-path.
>
>> By the way, paddr[i] + n * pg_sz = paddr[i + n] can also resolve it.
>
> Yes, that's one seems even better for me - make things more clear.
Thank you for fixing this.
My vote would go for "addr[i + n - 1] + pg_sz == paddr[i + n]"
If you feel "paddr[i] + n * pg_sz = paddr[i + n]" is clearer, I have no
problem with it either.
Regards,
Olivier
^ permalink raw reply
* [PATCH] doc: add note on primary process dependency
From: Reshma Pattan @ 2016-10-13 15:09 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
The note i.e. "The dpdk-pdump tool can only be used in
conjunction with a primary process which has the packet
capture framework initialized already" is added to
doc/guides/sample_app_ug/pdump.rst to facilitate
easy understanding on the usage of the tool.
Suggested-by: Jianfeng Tan <jianfeng.tan@intel.com>
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
doc/guides/sample_app_ug/pdump.rst | 2 ++
1 file changed, 2 insertions(+)
diff --git a/doc/guides/sample_app_ug/pdump.rst b/doc/guides/sample_app_ug/pdump.rst
index ac0e7c9..4098e50 100644
--- a/doc/guides/sample_app_ug/pdump.rst
+++ b/doc/guides/sample_app_ug/pdump.rst
@@ -37,6 +37,8 @@ The ``dpdk-pdump`` tool is a Data Plane Development Kit (DPDK) tool that runs as
a DPDK secondary process and is capable of enabling packet capture on dpdk ports.
.. Note::
+ * The ``dpdk-pdump`` tool can only be used in conjunction with a primary
+ application which has the packet capture framework initialized already.
* The ``dpdk-pdump`` tool depends on libpcap based PMD which is disabled
by default in the build configuration files,
--
2.7.4
^ permalink raw reply related
* Re: [PATCH v2] app/testpmd: fix DCB config issue
From: Thomas Monjalon @ 2016-10-13 15:14 UTC (permalink / raw)
To: Lu, Wenzhuo; +Cc: dev, Iremonger, Bernard, De Lara Guarch, Pablo
In-Reply-To: <8CEF83825BEC744B83065625E567D7C21A08F248@IRSMSX108.ger.corp.intel.com>
> > An issue is found that DCB cannot be configured on ixgbe NICs. It's said the
> > TX queue number is not right.
> > On ixgbe the max TX queue number is not fixed, it depends on the multi-
> > queue mode.
> >
> > This patch adds the device configuration before getting info in the DCB
> > configuration process. So the right info can be got depending on the
> > configuration.
> >
> > Fixes: 1a572499beb6 (app/testpmd: setup DCB forwarding based on traffic
> > class)
> > Signed-off-by: Wenzhuo Lu <wenzhuo.lu@intel.com>
>
> Acked-by: Bernard Iremonger <Bernard.iremonger@intel.com>
Applied, thanks
^ permalink raw reply
* Re: [PATCH v2 12/12] virtio: add Tso support
From: Olivier MATZ @ 2016-10-13 15:15 UTC (permalink / raw)
To: Yuanhan Liu
Cc: dev, konstantin.ananyev, sugesh.chandran, bruce.richardson,
jianfeng.tan, helin.zhang, adrien.mazarguil, stephen, dprovan,
xiao.w.wang
In-Reply-To: <20161013150107.GX16751@yliu-dev.sh.intel.com>
On 10/13/2016 05:01 PM, Yuanhan Liu wrote:
> On Thu, Oct 13, 2016 at 04:52:25PM +0200, Olivier MATZ wrote:
>>
>>
>> On 10/13/2016 04:16 PM, Yuanhan Liu wrote:
>>> On Thu, Oct 13, 2016 at 04:02:49PM +0200, Olivier MATZ wrote:
>>>>
>>>>
>>>> On 10/13/2016 10:18 AM, Yuanhan Liu wrote:
>>>>> On Mon, Oct 03, 2016 at 11:00:23AM +0200, Olivier Matz wrote:
>>>>>> +/* When doing TSO, the IP length is not included in the pseudo header
>>>>>> + * checksum of the packet given to the PMD, but for virtio it is
>>>>>> + * expected.
>>>>>> + */
>>>>>> +static void
>>>>>> +virtio_tso_fix_cksum(struct rte_mbuf *m)
>>>>>> +{
>>>>>> + /* common case: header is not fragmented */
>>>>>> + if (likely(rte_pktmbuf_data_len(m) >= m->l2_len + m->l3_len +
>>>>>> + m->l4_len)) {
>>>>> ...
>>>>>> + /* replace it in the packet */
>>>>>> + th->cksum = new_cksum;
>>>>>> + } else {
>>>>> ...
>>>>>> + /* replace it in the packet */
>>>>>> + *rte_pktmbuf_mtod_offset(m, uint8_t *,
>>>>>> + m->l2_len + m->l3_len + 16) = new_cksum.u8[0];
>>>>>> + *rte_pktmbuf_mtod_offset(m, uint8_t *,
>>>>>> + m->l2_len + m->l3_len + 17) = new_cksum.u8[1];
>>>>>> + }
>>>>>
>>>>> The tcp header will always be in the mbuf, right? Otherwise, you can't
>>>>> update the cksum field here. What's the point of introducing the "else
>>>>> clause" then?
>>>>
>>>> Sorry, I don't see the problem you're pointing out here.
>>>>
>>>> What I want to solve here is to support the cases where the mbuf is
>>>> segmented in the middle of the network header (which is probably a rare
>>>> case).
>>>
>>> How it's gonna segmented?
>>
>> The mbuf is given by the application. So if the application generates a
>> segmented mbuf, it should work.
>>
>> This could happen for instance if the application uses mbuf clones to share
>> the IP/TCP/data part of the mbuf and prepend a specific Ethernet/vlan for
>> different destination.
>>
>>
>>>> In the "else" part, I only access the mbuf byte by byte using the
>>>> rte_pktmbuf_mtod_offset() accessor. An alternative would have been to copy
>>>> the header in a linear buffer, fix the checksum, then copy it again in the
>>>> packet, but there is no mbuf helpers to do these copies for now.
>>>
>>> In the "else" clause, the ip header is still in the mbuf, right?
>>> Why do you have to access it the way like:
>>>
>>> ip_version = *rte_pktmbuf_mtod_offset(m, uint8_t *,
>>> m->l2_len) >> 4;
>>>
>>> Why can't you just use
>>>
>>> iph = rte_pktmbuf_mtod_offset(m, struct ipv4_hdr *, m->l2_len);
>>> iph->version_ihl ....;
>>
>> AFAIK, there is no requirement that each network header has to be contiguous
>> in a mbuf segment.
>>
>> Of course, a split in the middle of a network header probably never
>> happens... but we never knows, as it is not forbidden. I think the code
>> should be robust enough to avoid accesses to wrong addresses.
>>
>> Hope it's clear enough :)
>
> Thanks, but not really. Maybe let me ask this way: what wrong would
> happen if we use
> iph = rte_pktmbuf_mtod_offset(m, struct ipv4_hdr *, m->l2_len);
> to access the IP header? Is it about the endian?
If you have a packet split like this:
mbuf segment 1 mbuf segment 2
---------------------------- ------------------------------
| Ethernet header | IP hea| |der | TCP header | data
---------------------------- ------------------------------
^
iph
The IP header is not contiguous. So accessing to the end of the
structure will access to a wrong location.
> One more question is do you have any case to trigger the "else" clause?
No, but I think it may happen.
Olivier
^ permalink raw reply
* Re: [PATCH] app/testpmd: configure flowgen packet size though --txpkts
From: Thomas Monjalon @ 2016-10-13 15:24 UTC (permalink / raw)
To: maciej.czekaj; +Cc: dev, De Lara Guarch, Pablo
In-Reply-To: <E115CCD9D858EF4F90C690B0DCB4D8973C9FBBF8@IRSMSX108.ger.corp.intel.com>
> > "flowgen" forwarding mode has fixed packet size (300).
> > Let it re-use --txpkts option for specifying generated packet size.
> >
> > Signed-off-by: Maciej Czekaj <maciej.czekaj@caviumnetworks.com>
>
> Acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
Applied, thanks
^ permalink raw reply
* Re: [PATCH v2] app/testpmd: add support to configure 25G and 50G speeds
From: Thomas Monjalon @ 2016-10-13 15:27 UTC (permalink / raw)
To: Ajit Khaparde; +Cc: dev, Pablo de Lara
In-Reply-To: <20161012212631.GA14658@C02PT1RBG8WP.broadcom.com>
2016-10-12 16:26, Ajit Khaparde:
> Support to configure 25G and 50G speeds is missing from testpmd.
> This patch also updates the testpmd user guide accordingly.
>
> Signed-off-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
> --
> v2: shorten lines > 80 character limit
> ---
Applied, thanks
^ permalink raw reply
* Re: [PATCH v2 12/12] virtio: add Tso support
From: Yuanhan Liu @ 2016-10-13 15:29 UTC (permalink / raw)
To: Olivier MATZ
Cc: dev, konstantin.ananyev, sugesh.chandran, bruce.richardson,
jianfeng.tan, helin.zhang, adrien.mazarguil, stephen, dprovan,
xiao.w.wang
In-Reply-To: <57FFA50C.6030805@6wind.com>
On Thu, Oct 13, 2016 at 05:15:24PM +0200, Olivier MATZ wrote:
>
>
> On 10/13/2016 05:01 PM, Yuanhan Liu wrote:
> >On Thu, Oct 13, 2016 at 04:52:25PM +0200, Olivier MATZ wrote:
> >>
> >>
> >>On 10/13/2016 04:16 PM, Yuanhan Liu wrote:
> >>>On Thu, Oct 13, 2016 at 04:02:49PM +0200, Olivier MATZ wrote:
> >>>>
> >>>>
> >>>>On 10/13/2016 10:18 AM, Yuanhan Liu wrote:
> >>>>>On Mon, Oct 03, 2016 at 11:00:23AM +0200, Olivier Matz wrote:
> >>>>>>+/* When doing TSO, the IP length is not included in the pseudo header
> >>>>>>+ * checksum of the packet given to the PMD, but for virtio it is
> >>>>>>+ * expected.
> >>>>>>+ */
> >>>>>>+static void
> >>>>>>+virtio_tso_fix_cksum(struct rte_mbuf *m)
> >>>>>>+{
> >>>>>>+ /* common case: header is not fragmented */
> >>>>>>+ if (likely(rte_pktmbuf_data_len(m) >= m->l2_len + m->l3_len +
> >>>>>>+ m->l4_len)) {
> >>>>>...
> >>>>>>+ /* replace it in the packet */
> >>>>>>+ th->cksum = new_cksum;
> >>>>>>+ } else {
> >>>>>...
> >>>>>>+ /* replace it in the packet */
> >>>>>>+ *rte_pktmbuf_mtod_offset(m, uint8_t *,
> >>>>>>+ m->l2_len + m->l3_len + 16) = new_cksum.u8[0];
> >>>>>>+ *rte_pktmbuf_mtod_offset(m, uint8_t *,
> >>>>>>+ m->l2_len + m->l3_len + 17) = new_cksum.u8[1];
> >>>>>>+ }
> >>>>>
> >>>>>The tcp header will always be in the mbuf, right? Otherwise, you can't
> >>>>>update the cksum field here. What's the point of introducing the "else
> >>>>>clause" then?
> >>>>
> >>>>Sorry, I don't see the problem you're pointing out here.
> >>>>
> >>>>What I want to solve here is to support the cases where the mbuf is
> >>>>segmented in the middle of the network header (which is probably a rare
> >>>>case).
> >>>
> >>>How it's gonna segmented?
> >>
> >>The mbuf is given by the application. So if the application generates a
> >>segmented mbuf, it should work.
> >>
> >>This could happen for instance if the application uses mbuf clones to share
> >>the IP/TCP/data part of the mbuf and prepend a specific Ethernet/vlan for
> >>different destination.
> >>
> >>
> >>>>In the "else" part, I only access the mbuf byte by byte using the
> >>>>rte_pktmbuf_mtod_offset() accessor. An alternative would have been to copy
> >>>>the header in a linear buffer, fix the checksum, then copy it again in the
> >>>>packet, but there is no mbuf helpers to do these copies for now.
> >>>
> >>>In the "else" clause, the ip header is still in the mbuf, right?
> >>>Why do you have to access it the way like:
> >>>
> >>> ip_version = *rte_pktmbuf_mtod_offset(m, uint8_t *,
> >>> m->l2_len) >> 4;
> >>>
> >>>Why can't you just use
> >>>
> >>> iph = rte_pktmbuf_mtod_offset(m, struct ipv4_hdr *, m->l2_len);
> >>> iph->version_ihl ....;
> >>
> >>AFAIK, there is no requirement that each network header has to be contiguous
> >>in a mbuf segment.
> >>
> >>Of course, a split in the middle of a network header probably never
> >>happens... but we never knows, as it is not forbidden. I think the code
> >>should be robust enough to avoid accesses to wrong addresses.
> >>
> >>Hope it's clear enough :)
> >
> >Thanks, but not really. Maybe let me ask this way: what wrong would
> >happen if we use
> > iph = rte_pktmbuf_mtod_offset(m, struct ipv4_hdr *, m->l2_len);
> >to access the IP header? Is it about the endian?
>
> If you have a packet split like this:
>
> mbuf segment 1 mbuf segment 2
> ---------------------------- ------------------------------
> | Ethernet header | IP hea| |der | TCP header | data
> ---------------------------- ------------------------------
> ^
> iph
Thanks, that's clear. How could you be able to access the tcp header
from the first mbuf then? I mean, how is the following code supposed
to work?
prev_cksum.u8[0] = *rte_pktmbuf_mtod_offset(m, uint8_t *,
m->l2_len + m->l3_len + 16);
> The IP header is not contiguous. So accessing to the end of the structure
> will access to a wrong location.
>
> >One more question is do you have any case to trigger the "else" clause?
>
> No, but I think it may happen.
A piece of untest code is not trusted though ...
--yliu
^ permalink raw reply
* [PATCH v7] drivers/net:new PMD using tun/tap host interface
From: Keith Wiles @ 2016-10-13 15:36 UTC (permalink / raw)
To: dev; +Cc: pmatilai, yuanhan.liu, ferruh.yigit
In-Reply-To: <1474423220-10207-1-git-send-email-keith.wiles@intel.com>
The rte_eth_tap.c PMD creates a device using TUN/TAP interfaces
on the local host. The PMD allows for DPDK and the host to
communicate using a raw device interface on the host and in
the DPDK application. The device created is a Tap device with
a L2 packet header.
v7 - Reword the comment in common_base and fix the data->name issue
v6 - fixed the checkpatch issues
v5 - merge in changes from list review see related emails
fixed many minor edits
v4 - merge with latest driver changes
v3 - fix includes by removing ifdef for other type besides Linux
Fix the copyright notice in the Makefile
v2 - merge all of the patches into one patch
Fix a typo on naming the tap device
Update the maintainers list
Signed-off-by: Keith Wiles <keith.wiles@intel.com>
---
MAINTAINERS | 5 +
config/common_base | 9 +
config/common_linuxapp | 1 +
doc/guides/nics/tap.rst | 138 ++++++
drivers/net/Makefile | 1 +
drivers/net/tap/Makefile | 57 +++
drivers/net/tap/rte_eth_tap.c | 754 ++++++++++++++++++++++++++++++++
drivers/net/tap/rte_pmd_tap_version.map | 4 +
mk/rte.app.mk | 1 +
9 files changed, 970 insertions(+)
create mode 100644 doc/guides/nics/tap.rst
create mode 100644 drivers/net/tap/Makefile
create mode 100644 drivers/net/tap/rte_eth_tap.c
create mode 100644 drivers/net/tap/rte_pmd_tap_version.map
diff --git a/MAINTAINERS b/MAINTAINERS
index cd8d167..f905709 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -394,6 +394,11 @@ F: doc/guides/nics/pcap_ring.rst
F: app/test/test_pmd_ring.c
F: app/test/test_pmd_ring_perf.c
+Tap PMD
+M: Keith Wiles <keith.wiles@intel.com>
+F: drivers/net/tap
+F: doc/guides/nics/tap.rst
+
Null Networking PMD
M: Tetsuya Mukawa <mtetsuyah@gmail.com>
F: drivers/net/null/
diff --git a/config/common_base b/config/common_base
index f5d2eff..47ef843 100644
--- a/config/common_base
+++ b/config/common_base
@@ -592,3 +592,12 @@ CONFIG_RTE_APP_TEST_RESOURCE_TAR=n
CONFIG_RTE_TEST_PMD=y
CONFIG_RTE_TEST_PMD_RECORD_CORE_CYCLES=n
CONFIG_RTE_TEST_PMD_RECORD_BURST_STATS=n
+
+#
+# Compile the TAP PMD
+#
+# The TAP PMD is currently only built for Linux and the
+# option is enabled by default in common_linuxapp file,
+# set to 'n' in the common_base file.
+#
+CONFIG_RTE_LIBRTE_PMD_TAP=n
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 2483dfa..782b503 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -44,3 +44,4 @@ CONFIG_RTE_LIBRTE_PMD_VHOST=y
CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
CONFIG_RTE_LIBRTE_POWER=y
CONFIG_RTE_VIRTIO_USER=y
+CONFIG_RTE_LIBRTE_PMD_TAP=y
diff --git a/doc/guides/nics/tap.rst b/doc/guides/nics/tap.rst
new file mode 100644
index 0000000..bffc649
--- /dev/null
+++ b/doc/guides/nics/tap.rst
@@ -0,0 +1,138 @@
+.. BSD LICENSE
+ Copyright(c) 2016 Intel Corporation. All rights reserved.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Tun/Tap Poll Mode Driver
+========================================
+
+The rte_eth_tap.c PMD creates a device using TUN/TAP interfaces on the local
+host. The PMD allows for DPDK and the host to communicate using a raw device
+interface on the host and in the DPDK application.
+
+The device created is a TAP device, which sends/receives packet in a raw format
+with a L2 header. The usage for a TAP PMD is for connectivity to the local host
+using a TAP interface. When the TAP PMD is initialized it will create a number
+of tap devices in the host accessed via 'ifconfig -a' or 'ip' command. The
+commands can be used to assign and query the virtual like device.
+
+These TAP interfaces can be used with wireshark or tcpdump or Pktgen-DPDK along
+with being able to be used as a network connection to the DPDK application. The
+method enable one or more interfaces is to use the --vdev=net_tap option on the
+DPDK application command line. Each --vdev=net_tap option give will create an
+interface named dtap0, dtap1, ... and so forth.
+
+.. code-block:: console
+
+ The interfaced name can be changed by adding the iface=foo0
+ e.g. --vdev=net_tap,iface=foo0 --vdev=net_tap,iface=foo1, ...
+
+.. code-block:: console
+
+ Also the speed of the interface can be changed from 10G to whatever number
+ needed, but the interface does not enforce that speed.
+ e.g. --vdev=net_tap,iface=foo0,speed=25000
+
+After the DPDK application is started you can send and receive packets on the
+interface using the standard rx_burst/tx_burst APIs in DPDK. From the host point
+of view you can use any host tool like tcpdump, wireshark, ping, Pktgen and
+others to communicate with the DPDK application. The DPDK application may not
+understand network protocols like IPv4/6, UDP or TCP unless the application has
+been written to understand these protocols.
+
+If you need the interface as a real network interface meaning running and has
+a valid IP address then you can do this with the following commands:
+
+.. code-block:: console
+
+ sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
+ sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
+
+Please change the IP addresses as you see fit.
+
+If routing is enabled on the host you can also communicate with the DPDK App
+over the internet via a standard socket layer application as long as you account
+for the protocol handing in the application.
+
+If you have a Network Stack in your DPDK application or something like it you
+can utilize that stack to handle the network protocols. Plus you would be able
+to address the interface using an IP address assigned to the internal interface.
+
+A very crude test you can do the following:
+
+Apply the patch below and make sure you have socat installed on your system.
+
+Build DPDK, then pull down Pktgen and build pktgen using the DPDK SDK/Target
+used to build the dpdk you pulled down.
+
+Run pktgen from the pktgen repo directory in an xterm:
+ Note: change the -b options to blacklist all of your physical ports. The
+ following command line is all one line.
+
+.. code-block:: console
+
+ sudo ./app/app/x86_64-native-linuxapp-gcc/app/pktgen -l 1-5 -n 4 \
+ --proc-type auto --log-level 8 --socket-mem 512,512 --file-prefix pg \
+ --vdev=net_tap --vdev=net_tap -b 05:00.0 -b 05:00.1 \
+ -b 04:00.0 -b 04:00.1 -b 04:00.2 -b 04:00.3 \
+ -b 81:00.0 -b 81:00.1 -b 81:00.2 -b 81:00.3 \
+ -b 82:00.0 -b 83:00.0 -- -T -P -m [2:3].0 -m [4:5].1 \
+ -f themes/black-yellow.theme
+
+I normally put the line above into a file called doit.sh, just to allow for a
+simple execution of the line above.
+
+You can leave the -f themes/black-yellow.theme off if the colors does not work
+for your system configuration.
+
+Verify with 'ifconfig -a' command in a different xterm window, should have a
+dtap0 and dtap1 interfaces created.
+
+Next set the links for the two interfaces to up via the commands below.
+
+.. code-block:: console
+
+ sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
+ sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
+
+Then use socat to create a loopback for the two interfaces.
+
+.. code-block:: console
+
+ sudo socat interface:dtap0 interface:dtap1
+
+Then on the Pktgen command line interface you can start sending packets using
+the commands 'start 0' and 'start 1' or you can start both at the same time
+with 'start all'. The command 'str' is an alias for 'start all' and 'stp' is
+an alias for 'stop all'.
+
+While running you should see the 64 byte counters increasing to verify the
+traffic is being looped back. You can use 'set all size XXX' to change the
+size of the packets after you stop the traffic. Use the pktgen 'help' command
+to see a list of all commands. You can also use the '-f' option to load commands
+at startup.
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index bc93230..e366a85 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -51,6 +51,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PMD_PCAP) += pcap
DIRS-$(CONFIG_RTE_LIBRTE_QEDE_PMD) += qede
DIRS-$(CONFIG_RTE_LIBRTE_PMD_RING) += ring
DIRS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += szedata2
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += tap
DIRS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += thunderx
DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio
DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += vmxnet3
diff --git a/drivers/net/tap/Makefile b/drivers/net/tap/Makefile
new file mode 100644
index 0000000..e18f30c
--- /dev/null
+++ b/drivers/net/tap/Makefile
@@ -0,0 +1,57 @@
+# BSD LICENSE
+#
+# Copyright(c) 2016 Intel Corporation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_tap.a
+
+EXPORT_MAP := rte_pmd_tap_version.map
+
+LIBABIVER := 1
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += rte_eth_tap.c
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_mempool
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_kvargs
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
new file mode 100644
index 0000000..9e0258b
--- /dev/null
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -0,0 +1,754 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_vdev.h>
+#include <rte_kvargs.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <poll.h>
+#include <arpa/inet.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <linux/if_ether.h>
+#include <fcntl.h>
+
+/* Linux based path to the TUN device */
+#define TUN_TAP_DEV_PATH "/dev/net/tun"
+#define DEFAULT_TAP_NAME "dtap"
+
+#define ETH_TAP_IFACE_ARG "iface"
+#define ETH_TAP_SPEED_ARG "speed"
+
+#define RTE_PMD_TAP_MAX_QUEUES 32
+
+static const char *valid_arguments[] = {
+ ETH_TAP_IFACE_ARG,
+ ETH_TAP_SPEED_ARG,
+ NULL
+};
+
+static const char *drivername = "Tap PMD";
+static int tap_unit;
+
+static struct rte_eth_link pmd_link = {
+ .link_speed = ETH_SPEED_NUM_10G,
+ .link_duplex = ETH_LINK_FULL_DUPLEX,
+ .link_status = ETH_LINK_DOWN,
+ .link_autoneg = ETH_LINK_SPEED_AUTONEG
+};
+
+struct pkt_stats {
+ uint64_t opackets; /* Number of output packets */
+ uint64_t ipackets; /* Number of input packets */
+ uint64_t obytes; /* Number of bytes on output */
+ uint64_t ibytes; /* Number of bytes on input */
+ uint64_t errs; /* Number of error packets */
+};
+
+struct rx_queue {
+ struct rte_mempool *mp; /* Mempool for RX packets */
+ uint16_t in_port; /* Port ID */
+ int fd;
+
+ struct pkt_stats stats; /* Stats for this RX queue */
+};
+
+struct tx_queue {
+ int fd;
+ struct pkt_stats stats; /* Stats for this TX queue */
+};
+
+struct pmd_internals {
+ char name[RTE_ETH_NAME_MAX_LEN]; /* Internal Tap device name */
+ uint16_t nb_queues; /* Number of queues supported */
+ struct ether_addr eth_addr; /* Mac address of the device port */
+
+ int if_index; /* IF_INDEX for the port */
+ int fds[RTE_PMD_TAP_MAX_QUEUES]; /* List of all file descriptors */
+
+ struct rx_queue rxq[RTE_PMD_TAP_MAX_QUEUES]; /* List of RX queues */
+ struct tx_queue txq[RTE_PMD_TAP_MAX_QUEUES]; /* List of TX queues */
+};
+
+/* Tun/Tap allocation routine
+ *
+ * name is the number of the interface to use, unless NULL to take the host
+ * supplied name.
+ */
+static int
+tun_alloc(char *name)
+{
+ struct ifreq ifr;
+ unsigned int features;
+ int fd;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (name && name[0])
+ strncpy(ifr.ifr_name, name, IFNAMSIZ);
+
+ fd = open(TUN_TAP_DEV_PATH, O_RDWR);
+ if (fd < 0) {
+ RTE_LOG(ERR, PMD, "Unable to create TAP interface");
+ goto error;
+ }
+
+ /* Grab the TUN features to verify we can work */
+ if (ioctl(fd, TUNGETFEATURES, &features) < 0) {
+ RTE_LOG(ERR, PMD, "Unable to get TUN/TAP features\n");
+ goto error;
+ }
+ RTE_LOG(DEBUG, PMD, "TUN/TAP Features %08x\n", features);
+
+ if (!(features & IFF_MULTI_QUEUE) && (RTE_PMD_TAP_MAX_QUEUES > 1)) {
+ RTE_LOG(DEBUG, PMD, "TUN/TAP device only one queue\n");
+ goto error;
+ } else if ((features & IFF_ONE_QUEUE) &&
+ (RTE_PMD_TAP_MAX_QUEUES == 1)) {
+ ifr.ifr_flags |= IFF_ONE_QUEUE;
+ RTE_LOG(DEBUG, PMD, "Single queue only support\n");
+ } else {
+ ifr.ifr_flags |= IFF_MULTI_QUEUE;
+ RTE_LOG(DEBUG, PMD, "Multi-queue support for %d queues\n",
+ RTE_PMD_TAP_MAX_QUEUES);
+ }
+
+ /* Set the TUN/TAP configuration and get the name if needed */
+ if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) {
+ RTE_LOG(ERR, PMD, "Unable to set TUNSETIFF for %s\n",
+ ifr.ifr_name);
+ perror("TUNSETIFF");
+ goto error;
+ }
+
+ /* Always set the file descriptor to non-blocking */
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
+ RTE_LOG(ERR, PMD, "Unable to set to nonblocking\n");
+ perror("F_SETFL, NONBLOCK");
+ goto error;
+ }
+
+ /* If the name is different that new name as default */
+ if (name && strcmp(name, ifr.ifr_name))
+ snprintf(name, RTE_ETH_NAME_MAX_LEN - 1, "%s", ifr.ifr_name);
+
+ return fd;
+
+error:
+ if (fd > 0)
+ close(fd);
+ return -1;
+}
+
+/* Callback to handle the rx burst of packets to the correct interface and
+ * file descriptor(s) in a multi-queue setup.
+ */
+static uint16_t
+pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+ int len;
+ struct rte_mbuf *mbuf;
+ struct rx_queue *rxq = queue;
+ uint16_t num_rx;
+ unsigned long num_rx_bytes = 0;
+
+ for (num_rx = 0; num_rx < nb_pkts; ) {
+ /* allocate the next mbuf */
+ mbuf = rte_pktmbuf_alloc(rxq->mp);
+ if (unlikely(!mbuf)) {
+ RTE_LOG(WARNING, PMD, "Unable to allocate mbuf\n");
+ break;
+ }
+
+ len = read(rxq->fd, rte_pktmbuf_mtod(mbuf, char *),
+ rte_pktmbuf_tailroom(mbuf));
+ if (len <= 0) {
+ rte_pktmbuf_free(mbuf);
+ break;
+ }
+
+ mbuf->data_len = len;
+ mbuf->pkt_len = len;
+ mbuf->port = rxq->in_port;
+
+ /* account for the receive frame */
+ bufs[num_rx++] = mbuf;
+ num_rx_bytes += mbuf->pkt_len;
+ }
+ rxq->stats.ipackets += num_rx;
+ rxq->stats.ibytes += num_rx_bytes;
+
+ return num_rx;
+}
+
+/* Callback to handle sending packets from the tap interface
+ */
+static uint16_t
+pmd_tx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+ struct rte_mbuf *mbuf;
+ struct tx_queue *txq = queue;
+ struct pollfd pfd;
+ uint16_t num_tx = 0;
+ unsigned long num_tx_bytes = 0;
+ int i, n;
+
+ if (unlikely(nb_pkts == 0))
+ return 0;
+
+ pfd.events = POLLOUT;
+ pfd.fd = txq->fd;
+ for (i = 0; i < nb_pkts; i++) {
+ n = poll(&pfd, 1, 0);
+
+ if (n <= 0)
+ break;
+
+ if (pfd.revents & POLLOUT) {
+ /* copy the tx frame data */
+ mbuf = bufs[num_tx];
+ n = write(pfd.fd, rte_pktmbuf_mtod(mbuf, void*),
+ rte_pktmbuf_pkt_len(mbuf));
+ if (n <= 0)
+ break;
+
+ num_tx++;
+ num_tx_bytes += mbuf->pkt_len;
+ rte_pktmbuf_free(mbuf);
+ }
+ }
+
+ txq->stats.opackets += num_tx;
+ txq->stats.errs += nb_pkts - num_tx;
+ txq->stats.obytes += num_tx_bytes;
+
+ return num_tx;
+}
+
+static int
+tap_dev_start(struct rte_eth_dev *dev)
+{
+ /* Force the Link up */
+ dev->data->dev_link.link_status = ETH_LINK_UP;
+
+ return 0;
+}
+
+/* This function gets called when the current port gets stopped.
+ */
+static void
+tap_dev_stop(struct rte_eth_dev *dev)
+{
+ int i;
+ struct pmd_internals *internals = dev->data->dev_private;
+
+ for (i = 0; i < internals->nb_queues; i++)
+ if (internals->fds[i] != -1)
+ close(internals->fds[i]);
+
+ dev->data->dev_link.link_status = ETH_LINK_DOWN;
+}
+
+static int
+tap_dev_configure(struct rte_eth_dev *dev __rte_unused)
+{
+ return 0;
+}
+
+static void
+tap_dev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
+{
+ struct pmd_internals *internals = dev->data->dev_private;
+
+ dev_info->driver_name = drivername;
+ dev_info->if_index = internals->if_index;
+ dev_info->max_mac_addrs = 1;
+ dev_info->max_rx_pktlen = (uint32_t)ETHER_MAX_VLAN_FRAME_LEN;
+ dev_info->max_rx_queues = internals->nb_queues;
+ dev_info->max_tx_queues = internals->nb_queues;
+ dev_info->min_rx_bufsize = 0;
+ dev_info->pci_dev = NULL;
+}
+
+static void
+tap_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *tap_stats)
+{
+ unsigned int i, imax;
+ unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
+ unsigned long rx_bytes_total = 0, tx_bytes_total = 0;
+ const struct pmd_internals *pmd = dev->data->dev_private;
+
+ imax = (pmd->nb_queues < RTE_ETHDEV_QUEUE_STAT_CNTRS) ?
+ pmd->nb_queues : RTE_ETHDEV_QUEUE_STAT_CNTRS;
+
+ for (i = 0; i < imax; i++) {
+ tap_stats->q_ipackets[i] = pmd->rxq[i].stats.ipackets;
+ tap_stats->q_ibytes[i] = pmd->rxq[i].stats.ibytes;
+ rx_total += tap_stats->q_ipackets[i];
+ rx_bytes_total += tap_stats->q_ibytes[i];
+ }
+
+ for (i = 0; i < imax; i++) {
+ tap_stats->q_opackets[i] = pmd->txq[i].stats.opackets;
+ tap_stats->q_errors[i] = pmd->txq[i].stats.errs;
+ tap_stats->q_obytes[i] = pmd->txq[i].stats.obytes;
+ tx_total += tap_stats->q_opackets[i];
+ tx_err_total += tap_stats->q_errors[i];
+ tx_bytes_total += tap_stats->q_obytes[i];
+ }
+
+ tap_stats->ipackets = rx_total;
+ tap_stats->ibytes = rx_bytes_total;
+ tap_stats->opackets = tx_total;
+ tap_stats->oerrors = tx_err_total;
+ tap_stats->obytes = tx_bytes_total;
+}
+
+static void
+tap_stats_reset(struct rte_eth_dev *dev)
+{
+ int i;
+ struct pmd_internals *pmd = dev->data->dev_private;
+
+ for (i = 0; i < pmd->nb_queues; i++) {
+ pmd->rxq[i].stats.ipackets = 0;
+ pmd->rxq[i].stats.ibytes = 0;
+ }
+
+ for (i = 0; i < pmd->nb_queues; i++) {
+ pmd->txq[i].stats.opackets = 0;
+ pmd->txq[i].stats.errs = 0;
+ pmd->txq[i].stats.obytes = 0;
+ }
+}
+
+static void
+tap_dev_close(struct rte_eth_dev *dev __rte_unused)
+{
+}
+
+static void
+tap_rx_queue_release(void *queue)
+{
+ struct rx_queue *rxq = queue;
+
+ if (rxq && (rxq->fd > 0)) {
+ close(rxq->fd);
+ rxq->fd = -1;
+ }
+}
+
+static void
+tap_tx_queue_release(void *queue)
+{
+ struct tx_queue *txq = queue;
+
+ if (txq && (txq->fd > 0)) {
+ close(txq->fd);
+ txq->fd = -1;
+ }
+}
+
+static int
+tap_link_update(struct rte_eth_dev *dev __rte_unused,
+ int wait_to_complete __rte_unused)
+{
+ return 0;
+}
+
+static int
+tap_setup_queue(struct rte_eth_dev *dev,
+ struct pmd_internals *internals,
+ uint16_t qid)
+{
+ struct rx_queue *rx = &internals->rxq[qid];
+ struct tx_queue *tx = &internals->txq[qid];
+ int fd;
+
+ fd = rx->fd;
+ if (fd < 0) {
+ fd = tx->fd;
+ if (fd < 0) {
+ RTE_LOG(INFO, PMD, "Add queue to TAP %s for qid %d\n",
+ dev->data->name, qid);
+ fd = tun_alloc(dev->data->name);
+ if (fd < 0) {
+ RTE_LOG(ERR, PMD, "tun_alloc(%s) failed\n",
+ dev->data->name);
+ return -1;
+ }
+ }
+ }
+ dev->data->rx_queues[qid] = rx;
+ dev->data->tx_queues[qid] = tx;
+
+ rx->fd = fd;
+ tx->fd = fd;
+
+ return fd;
+}
+
+static int
+tap_rx_queue_setup(struct rte_eth_dev *dev,
+ uint16_t rx_queue_id,
+ uint16_t nb_rx_desc __rte_unused,
+ unsigned int socket_id __rte_unused,
+ const struct rte_eth_rxconf *rx_conf __rte_unused,
+ struct rte_mempool *mp)
+{
+ struct pmd_internals *internals = dev->data->dev_private;
+ uint16_t buf_size;
+ int fd;
+
+ if ((rx_queue_id >= internals->nb_queues) || !mp) {
+ RTE_LOG(ERR, PMD, "nb_queues %d mp %p\n",
+ internals->nb_queues, mp);
+ return -1;
+ }
+
+ internals->rxq[rx_queue_id].mp = mp;
+ internals->rxq[rx_queue_id].in_port = dev->data->port_id;
+
+ /* Now get the space available for data in the mbuf */
+ buf_size = (uint16_t)(rte_pktmbuf_data_room_size(mp) -
+ RTE_PKTMBUF_HEADROOM);
+
+ if (buf_size < ETH_FRAME_LEN) {
+ RTE_LOG(ERR, PMD,
+ "%s: %d bytes will not fit in mbuf (%d bytes)\n",
+ dev->data->name, ETH_FRAME_LEN, buf_size);
+ return -ENOMEM;
+ }
+
+ fd = tap_setup_queue(dev, internals, rx_queue_id);
+ if (fd == -1)
+ return -1;
+
+ internals->fds[rx_queue_id] = fd;
+ RTE_LOG(INFO, PMD, "RX TAP device name %s, qid %d on fd %d\n",
+ dev->data->name, rx_queue_id, internals->rxq[rx_queue_id].fd);
+
+ return 0;
+}
+
+static int
+tap_tx_queue_setup(struct rte_eth_dev *dev,
+ uint16_t tx_queue_id,
+ uint16_t nb_tx_desc __rte_unused,
+ unsigned int socket_id __rte_unused,
+ const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+ struct pmd_internals *internals = dev->data->dev_private;
+ int ret = -1;
+
+ if (tx_queue_id >= internals->nb_queues)
+ return -1;
+
+ ret = tap_setup_queue(dev, internals, tx_queue_id);
+
+ RTE_LOG(INFO, PMD, "TX TAP device name %s, qid %d on fd %d\n",
+ dev->data->name, tx_queue_id, internals->txq[tx_queue_id].fd);
+
+ return ret;
+}
+
+static const struct eth_dev_ops ops = {
+ .dev_start = tap_dev_start,
+ .dev_stop = tap_dev_stop,
+ .dev_close = tap_dev_close,
+ .dev_configure = tap_dev_configure,
+ .dev_infos_get = tap_dev_info,
+ .rx_queue_setup = tap_rx_queue_setup,
+ .tx_queue_setup = tap_tx_queue_setup,
+ .rx_queue_release = tap_rx_queue_release,
+ .tx_queue_release = tap_tx_queue_release,
+ .link_update = tap_link_update,
+ .stats_get = tap_stats_get,
+ .stats_reset = tap_stats_reset,
+};
+
+static int
+pmd_mac_address(int fd, struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+ struct ifreq ifr;
+
+ if ((fd <= 0) || !dev || !addr)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) {
+ RTE_LOG(ERR, PMD, "ioctl failed (SIOCGIFHWADDR) (%s)\n",
+ ifr.ifr_name);
+ return -1;
+ }
+
+ /* Set the host based MAC address to this special MAC format */
+ ifr.ifr_hwaddr.sa_data[0] = 'T';
+ ifr.ifr_hwaddr.sa_data[1] = 'a';
+ ifr.ifr_hwaddr.sa_data[2] = 'p';
+ ifr.ifr_hwaddr.sa_data[3] = '-';
+ ifr.ifr_hwaddr.sa_data[4] = dev->data->port_id;
+ ifr.ifr_hwaddr.sa_data[5] = dev->data->numa_node;
+ if (ioctl(fd, SIOCSIFHWADDR, &ifr) == -1) {
+ RTE_LOG(ERR, PMD, "%s: ioctl failed (SIOCSIFHWADDR) (%s)\n",
+ dev->data->name, ifr.ifr_name);
+ return -1;
+ }
+
+ /* Set the local application MAC address, needs to be different then
+ * the host based MAC address.
+ */
+ ifr.ifr_hwaddr.sa_data[0] = 'd';
+ ifr.ifr_hwaddr.sa_data[1] = 'n';
+ ifr.ifr_hwaddr.sa_data[2] = 'e';
+ ifr.ifr_hwaddr.sa_data[3] = 't';
+ ifr.ifr_hwaddr.sa_data[4] = dev->data->port_id;
+ ifr.ifr_hwaddr.sa_data[5] = dev->data->numa_node;
+ rte_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ return 0;
+}
+
+static int
+eth_dev_tap_create(const char *name, char *tap_name)
+{
+ int numa_node = rte_socket_id();
+ struct rte_eth_dev *dev = NULL;
+ struct pmd_internals *pmd = NULL;
+ struct rte_eth_dev_data *data = NULL;
+ int i, fd = -1;
+
+ RTE_LOG(INFO, PMD,
+ "%s: Create TAP Ethernet device with %d queues on numa %u\n",
+ name, RTE_PMD_TAP_MAX_QUEUES, rte_socket_id());
+
+ data = rte_zmalloc_socket(tap_name, sizeof(*data), 0, numa_node);
+ if (!data)
+ goto error_exit;
+
+ pmd = rte_zmalloc_socket(tap_name, sizeof(*pmd), 0, numa_node);
+ if (!pmd)
+ goto error_exit;
+
+ /* Use the name and not the tap_name */
+ dev = rte_eth_dev_allocate(name);
+ if (!dev)
+ goto error_exit;
+
+ snprintf(pmd->name, sizeof(pmd->name), "%s", tap_name);
+
+ pmd->nb_queues = RTE_PMD_TAP_MAX_QUEUES;
+
+ /* Setup some default values */
+ data->dev_private = pmd;
+ data->port_id = dev->data->port_id;
+ data->dev_flags = RTE_ETH_DEV_DETACHABLE;
+ data->kdrv = RTE_KDRV_NONE;
+ data->drv_name = drivername;
+ data->numa_node = numa_node;
+
+ data->dev_link = pmd_link;
+ data->mac_addrs = &pmd->eth_addr;
+ data->nb_rx_queues = pmd->nb_queues;
+ data->nb_tx_queues = pmd->nb_queues;
+ data->drv_name = drivername;
+
+ dev->data = data;
+ dev->dev_ops = &ops;
+ dev->driver = NULL;
+ dev->rx_pkt_burst = pmd_rx_burst;
+ dev->tx_pkt_burst = pmd_tx_burst;
+ snprintf(dev->data->name, sizeof(dev->data->name), "%s", name);
+
+ /* Create the first Tap device */
+ fd = tun_alloc(tap_name);
+ if (fd < 0)
+ goto error_exit;
+
+ /* Presetup the fds to -1 as being not working */
+ for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
+ pmd->fds[i] = -1;
+ pmd->rxq[i].fd = -1;
+ pmd->txq[i].fd = -1;
+ }
+
+ /* Take the TUN/TAP fd and place in the first location */
+ pmd->rxq[0].fd = fd;
+ pmd->txq[0].fd = fd;
+ pmd->fds[0] = fd;
+
+ if (pmd_mac_address(fd, dev, &pmd->eth_addr) < 0)
+ goto error_exit;
+
+ return 0;
+
+error_exit:
+ RTE_PMD_DEBUG_TRACE("Unable to initialize %s\n", name);
+
+ rte_free(data);
+ rte_free(pmd);
+
+ rte_eth_dev_release_port(dev);
+
+ return -EINVAL;
+}
+
+static int
+set_interface_name(const char *key __rte_unused,
+ const char *value,
+ void *extra_args)
+{
+ char *name = (char *)extra_args;
+
+ if (value)
+ snprintf(name, RTE_ETH_NAME_MAX_LEN - 1, "%s", value);
+ else
+ snprintf(name, RTE_ETH_NAME_MAX_LEN - 1, "%s%d",
+ DEFAULT_TAP_NAME, (tap_unit - 1));
+
+ return 0;
+}
+
+static int
+set_interface_speed(const char *key __rte_unused,
+ const char *value,
+ void *extra_args)
+{
+ *(int *)extra_args = (value) ? atoi(value) : ETH_SPEED_NUM_10G;
+
+ return 0;
+}
+
+/* Open a TAP interface device.
+ */
+static int
+rte_pmd_tap_probe(const char *name, const char *params)
+{
+ int ret;
+ struct rte_kvargs *kvlist = NULL;
+ int speed;
+ char tap_name[RTE_ETH_NAME_MAX_LEN];
+
+ speed = ETH_SPEED_NUM_10G;
+ snprintf(tap_name, sizeof(tap_name), "%s%d",
+ DEFAULT_TAP_NAME, tap_unit++);
+
+ RTE_LOG(INFO, PMD, "Initializing pmd_tap for %s as %s\n",
+ name, tap_name);
+
+ if (params && (params[0] != '\0')) {
+ RTE_LOG(INFO, PMD, "paramaters (%s)\n", params);
+
+ kvlist = rte_kvargs_parse(params, valid_arguments);
+ if (kvlist) {
+ if (rte_kvargs_count(kvlist, ETH_TAP_SPEED_ARG) == 1) {
+ ret = rte_kvargs_process(kvlist,
+ ETH_TAP_SPEED_ARG,
+ &set_interface_speed,
+ &speed);
+ if (ret == -1)
+ goto leave;
+ }
+
+ if (rte_kvargs_count(kvlist, ETH_TAP_IFACE_ARG) == 1) {
+ ret = rte_kvargs_process(kvlist,
+ ETH_TAP_IFACE_ARG,
+ &set_interface_name,
+ tap_name);
+ if (ret == -1)
+ goto leave;
+ }
+ }
+ }
+ pmd_link.link_speed = speed;
+
+ ret = eth_dev_tap_create(name, tap_name);
+
+leave:
+ if (ret == -1) {
+ RTE_LOG(INFO, PMD, "Failed to create pmd_tap for %s as %s\n",
+ name, tap_name);
+ tap_unit--; /* Restore the unit number */
+ }
+ rte_kvargs_free(kvlist);
+
+ return ret;
+}
+
+/* detach a TAP device.
+ */
+static int
+rte_pmd_tap_remove(const char *name)
+{
+ struct rte_eth_dev *eth_dev = NULL;
+ struct pmd_internals *internals;
+ int i;
+
+ RTE_LOG(INFO, PMD, "Closing TUN/TAP Ethernet device on numa %u\n",
+ rte_socket_id());
+
+ /* find the ethdev entry */
+ eth_dev = rte_eth_dev_allocated(name);
+ if (!eth_dev)
+ return 0;
+
+ internals = eth_dev->data->dev_private;
+ for (i = 0; i < internals->nb_queues; i++)
+ if (internals->fds[i] != -1)
+ close(internals->fds[i]);
+
+ rte_free(eth_dev->data->dev_private);
+ rte_free(eth_dev->data);
+
+ rte_eth_dev_release_port(eth_dev);
+
+ return 0;
+}
+
+static struct rte_vdev_driver pmd_tap_drv = {
+ .probe = rte_pmd_tap_probe,
+ .remove = rte_pmd_tap_remove,
+};
+
+DRIVER_REGISTER_VDEV(net_tap, pmd_tap_drv);
+DRIVER_REGISTER_PARAM_STRING(net_tap, "iface=<string>,speed=N");
diff --git a/drivers/net/tap/rte_pmd_tap_version.map b/drivers/net/tap/rte_pmd_tap_version.map
new file mode 100644
index 0000000..61463bf
--- /dev/null
+++ b/drivers/net/tap/rte_pmd_tap_version.map
@@ -0,0 +1,4 @@
+DPDK_16.11 {
+
+ local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index ac50a21..40d16f7 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -123,6 +123,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_PCAP) += -lrte_pmd_pcap -lpcap
_LDLIBS-$(CONFIG_RTE_LIBRTE_QEDE_PMD) += -lrte_pmd_qede -lz
_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_RING) += -lrte_pmd_ring
_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += -lrte_pmd_szedata2 -lsze2
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += -lrte_pmd_tap
_LDLIBS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += -lrte_pmd_thunderx_nicvf -lm
_LDLIBS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += -lrte_pmd_virtio
ifeq ($(CONFIG_RTE_LIBRTE_VHOST),y)
--
2.8.0.GIT
^ permalink raw reply related
* Re: [PATCH] eal: avoid unnecessary conflicts over rte_config file
From: John Ousterhout @ 2016-10-13 15:42 UTC (permalink / raw)
To: Ananyev, Konstantin; +Cc: thomas.monjalon@6wind.com, dev@dpdk.org
In-Reply-To: <2601191342CEEE43887BDE71AB9772583F0C1256@irsmsx105.ger.corp.intel.com>
It's true that users can patch around this problem (and I started off doing
just that), but why impose this inconvenience on users when DPDK can just
"do the right thing" to begin with? For example, it took me several hours
to figure out why the problem was occurring and then to hunt down the
--file-prefix solution. Is there some reason why it would be a bad idea to
fix this in DPDK?
-John-
On Thu, Oct 13, 2016 at 3:53 AM, Ananyev, Konstantin <
konstantin.ananyev@intel.com> wrote:
>
> Hi John,
>
> > Before this patch, DPDK used the file ~/.rte_config as a lock to detect
> > potential interference between multiple DPDK applications running on the
> > same machine. However, if a single user ran DPDK applications
> concurrently
> > on several different machines, and if the user's home directory was
> shared
> > between the machines via NFS, DPDK would incorrectly detect conflicts
> > for all but the first application and abort them. This patch fixes the
> > problem by incorporating the machine name into the config file name
> (e.g.,
> > ~/.rte_hostname_config).
> >
> > Signed-off-by: John Ousterhout <ouster@cs.stanford.edu>
> > ---
> > doc/guides/prog_guide/multi_proc_support.rst | 11 +++++++----
> > lib/librte_eal/common/eal_common_proc.c | 8 ++------
> > lib/librte_eal/common/eal_filesystem.h | 15 +++++++++++++--
> > 3 files changed, 22 insertions(+), 12 deletions(-)
> >
> > diff --git a/doc/guides/prog_guide/multi_proc_support.rst
> b/doc/guides/prog_guide/multi_proc_support.rst
> > index badd102..a54fa1c 100644
> > --- a/doc/guides/prog_guide/multi_proc_support.rst
> > +++ b/doc/guides/prog_guide/multi_proc_support.rst
> > @@ -129,10 +129,13 @@ Support for this usage scenario is provided using
> the ``--file-prefix`` paramete
> >
> > By default, the EAL creates hugepage files on each hugetlbfs filesystem
> using the rtemap_X filename,
> > where X is in the range 0 to the maximum number of hugepages -1.
> > -Similarly, it creates shared configuration files, memory mapped in each
> process, using the /var/run/.rte_config filename,
> > -when run as root (or $HOME/.rte_config when run as a non-root user;
> > -if filesystem and device permissions are set up to allow this).
> > -The rte part of the filenames of each of the above is configurable
> using the file-prefix parameter.
> > +Similarly, it creates shared configuration files, memory mapped in each
> process.
> > +When run as root, the name of the configuration file will be
> > +/var/run/.rte_*host*_config, where *host* is the name of the machine.
> > +When run as a non-root user, the the name of the configuration file
> will be
> > +$HOME/.rte_*host*_config (if filesystem and device permissions are set
> up to allow this).
> > +If the ``--file-prefix`` parameter has been specified, its value will
> be used
> > +in place of "rte" in the file names.
>
> I am not sure that we need to handle all such cases inside EAL.
> User can easily overcome that problem by just adding something like:
> --file-prefix=`uname -n`
> to his command-line.
> Konstantin
>
> >
> > In addition to specifying the file-prefix parameter,
> > any DPDK applications that are to be run side-by-side must explicitly
> limit their memory use.
> > diff --git a/lib/librte_eal/common/eal_common_proc.c
> b/lib/librte_eal/common/eal_common_proc.c
> > index 12e0fca..517aa0c 100644
> > --- a/lib/librte_eal/common/eal_common_proc.c
> > +++ b/lib/librte_eal/common/eal_common_proc.c
> > @@ -45,12 +45,8 @@ rte_eal_primary_proc_alive(const char
> *config_file_path)
> >
> > if (config_file_path)
> > config_fd = open(config_file_path, O_RDONLY);
> > - else {
> > - char default_path[PATH_MAX+1];
> > - snprintf(default_path, PATH_MAX, RUNTIME_CONFIG_FMT,
> > - default_config_dir, "rte");
> > - config_fd = open(default_path, O_RDONLY);
> > - }
> > + else
> > + config_fd = open(eal_runtime_config_path(), O_RDONLY);
> > if (config_fd < 0)
> > return 0;
> >
> > diff --git a/lib/librte_eal/common/eal_filesystem.h
> b/lib/librte_eal/common/eal_filesystem.h
> > index fdb4a70..4929aa3 100644
> > --- a/lib/librte_eal/common/eal_filesystem.h
> > +++ b/lib/librte_eal/common/eal_filesystem.h
> > @@ -41,7 +41,7 @@
> > #define EAL_FILESYSTEM_H
> >
> > /** Path of rte config file. */
> > -#define RUNTIME_CONFIG_FMT "%s/.%s_config"
> > +#define RUNTIME_CONFIG_FMT "%s/.%s_%s_config"
> >
> > #include <stdint.h>
> > #include <limits.h>
> > @@ -59,11 +59,22 @@ eal_runtime_config_path(void)
> > static char buffer[PATH_MAX]; /* static so auto-zeroed */
> > const char *directory = default_config_dir;
> > const char *home_dir = getenv("HOME");
> > + static char nameBuffer[1000];
> > + int result;
> >
> > if (getuid() != 0 && home_dir != NULL)
> > directory = home_dir;
> > +
> > + /*
> > + * Include the name of the host in the config file path. Otherwise,
> > + * if DPDK applications run on different hosts but share a home
> > + * directory (e.g. via NFS), they will choose the same config
> > + * file and conflict unnecessarily.
> > + */
> > + result = gethostname(nameBuffer, sizeof(nameBuffer)-1);
> > snprintf(buffer, sizeof(buffer) - 1, RUNTIME_CONFIG_FMT, directory,
> > - internal_config.hugefile_prefix);
> > + internal_config.hugefile_prefix,
> > + (result == 0) ? nameBuffer : "unknown-host");
> > return buffer;
> > }
> >
> > --
> > 2.8.3
>
>
^ permalink raw reply
* Re: [PATCH v2 12/12] virtio: add Tso support
From: Olivier Matz @ 2016-10-13 15:45 UTC (permalink / raw)
To: Yuanhan Liu
Cc: dev, konstantin.ananyev, sugesh.chandran, bruce.richardson,
jianfeng.tan, helin.zhang, adrien.mazarguil, stephen, dprovan,
xiao.w.wang
In-Reply-To: <20161013152935.GZ16751@yliu-dev.sh.intel.com>
Le 13 octobre 2016 17:29:35 CEST, Yuanhan Liu <yuanhan.liu@linux.intel.com> a écrit :
>On Thu, Oct 13, 2016 at 05:15:24PM +0200, Olivier MATZ wrote:
>>
>>
>> On 10/13/2016 05:01 PM, Yuanhan Liu wrote:
>> >On Thu, Oct 13, 2016 at 04:52:25PM +0200, Olivier MATZ wrote:
>> >>
>> >>
>> >>On 10/13/2016 04:16 PM, Yuanhan Liu wrote:
>> >>>On Thu, Oct 13, 2016 at 04:02:49PM +0200, Olivier MATZ wrote:
>> >>>>
>> >>>>
>> >>>>On 10/13/2016 10:18 AM, Yuanhan Liu wrote:
>> >>>>>On Mon, Oct 03, 2016 at 11:00:23AM +0200, Olivier Matz wrote:
>> >>>>>>+/* When doing TSO, the IP length is not included in the pseudo
>header
>> >>>>>>+ * checksum of the packet given to the PMD, but for virtio it
>is
>> >>>>>>+ * expected.
>> >>>>>>+ */
>> >>>>>>+static void
>> >>>>>>+virtio_tso_fix_cksum(struct rte_mbuf *m)
>> >>>>>>+{
>> >>>>>>+ /* common case: header is not fragmented */
>> >>>>>>+ if (likely(rte_pktmbuf_data_len(m) >= m->l2_len + m->l3_len +
>> >>>>>>+ m->l4_len)) {
>> >>>>>...
>> >>>>>>+ /* replace it in the packet */
>> >>>>>>+ th->cksum = new_cksum;
>> >>>>>>+ } else {
>> >>>>>...
>> >>>>>>+ /* replace it in the packet */
>> >>>>>>+ *rte_pktmbuf_mtod_offset(m, uint8_t *,
>> >>>>>>+ m->l2_len + m->l3_len + 16) = new_cksum.u8[0];
>> >>>>>>+ *rte_pktmbuf_mtod_offset(m, uint8_t *,
>> >>>>>>+ m->l2_len + m->l3_len + 17) = new_cksum.u8[1];
>> >>>>>>+ }
>> >>>>>
>> >>>>>The tcp header will always be in the mbuf, right? Otherwise, you
>can't
>> >>>>>update the cksum field here. What's the point of introducing the
>"else
>> >>>>>clause" then?
>> >>>>
>> >>>>Sorry, I don't see the problem you're pointing out here.
>> >>>>
>> >>>>What I want to solve here is to support the cases where the mbuf
>is
>> >>>>segmented in the middle of the network header (which is probably
>a rare
>> >>>>case).
>> >>>
>> >>>How it's gonna segmented?
>> >>
>> >>The mbuf is given by the application. So if the application
>generates a
>> >>segmented mbuf, it should work.
>> >>
>> >>This could happen for instance if the application uses mbuf clones
>to share
>> >>the IP/TCP/data part of the mbuf and prepend a specific
>Ethernet/vlan for
>> >>different destination.
>> >>
>> >>
>> >>>>In the "else" part, I only access the mbuf byte by byte using the
>> >>>>rte_pktmbuf_mtod_offset() accessor. An alternative would have
>been to copy
>> >>>>the header in a linear buffer, fix the checksum, then copy it
>again in the
>> >>>>packet, but there is no mbuf helpers to do these copies for now.
>> >>>
>> >>>In the "else" clause, the ip header is still in the mbuf, right?
>> >>>Why do you have to access it the way like:
>> >>>
>> >>> ip_version = *rte_pktmbuf_mtod_offset(m, uint8_t *,
>> >>> m->l2_len) >> 4;
>> >>>
>> >>>Why can't you just use
>> >>>
>> >>> iph = rte_pktmbuf_mtod_offset(m, struct ipv4_hdr *, m->l2_len);
>> >>> iph->version_ihl ....;
>> >>
>> >>AFAIK, there is no requirement that each network header has to be
>contiguous
>> >>in a mbuf segment.
>> >>
>> >>Of course, a split in the middle of a network header probably never
>> >>happens... but we never knows, as it is not forbidden. I think the
>code
>> >>should be robust enough to avoid accesses to wrong addresses.
>> >>
>> >>Hope it's clear enough :)
>> >
>> >Thanks, but not really. Maybe let me ask this way: what wrong would
>> >happen if we use
>> > iph = rte_pktmbuf_mtod_offset(m, struct ipv4_hdr *, m->l2_len);
>> >to access the IP header? Is it about the endian?
>>
>> If you have a packet split like this:
>>
>> mbuf segment 1 mbuf segment 2
>> ---------------------------- ------------------------------
>> | Ethernet header | IP hea| |der | TCP header | data
>> ---------------------------- ------------------------------
>> ^
>> iph
>
>Thanks, that's clear. How could you be able to access the tcp header
>from the first mbuf then? I mean, how is the following code supposed
>to work?
>
> prev_cksum.u8[0] = *rte_pktmbuf_mtod_offset(m, uint8_t *,
> m->l2_len + m->l3_len + 16);
>
Oh I see... Sorry there was a confusion on my side with another (internal) macro that browses the segments if the offset ils not in the first one.
If you agree, let's add the code without the else part, I'll fix it for the rc2.
>> The IP header is not contiguous. So accessing to the end of the
>structure
>> will access to a wrong location.
>>
>> >One more question is do you have any case to trigger the "else"
>clause?
>>
>> No, but I think it may happen.
>
>A piece of untest code is not trusted though ...
>
> --yliu
^ permalink raw reply
* Re: [PATCH v2 12/12] virtio: add Tso support
From: Yuanhan Liu @ 2016-10-13 16:01 UTC (permalink / raw)
To: Olivier Matz
Cc: dev, konstantin.ananyev, sugesh.chandran, bruce.richardson,
jianfeng.tan, helin.zhang, adrien.mazarguil, stephen, dprovan,
xiao.w.wang, thoams
In-Reply-To: <3DAA9259-3C5F-43C3-B843-1270EDB09F33@6wind.com>
On Thu, Oct 13, 2016 at 05:45:21PM +0200, Olivier Matz wrote:
> >> If you have a packet split like this:
> >>
> >> mbuf segment 1 mbuf segment 2
> >> ---------------------------- ------------------------------
> >> | Ethernet header | IP hea| |der | TCP header | data
> >> ---------------------------- ------------------------------
> >> ^
> >> iph
> >
> >Thanks, that's clear. How could you be able to access the tcp header
> >from the first mbuf then? I mean, how is the following code supposed
> >to work?
> >
> > prev_cksum.u8[0] = *rte_pktmbuf_mtod_offset(m, uint8_t *,
> > m->l2_len + m->l3_len + 16);
> >
>
> Oh I see... Sorry there was a confusion on my side with another (internal) macro that browses the segments if the offset ils not in the first one.
>
> If you agree, let's add the code without the else part, I'll fix it for the rc2.
Good. That's okay to me.
--yliu
^ permalink raw reply
* Re: [PATCH v3 12/12] net/virtio: add Tso support
From: Yuanhan Liu @ 2016-10-13 16:05 UTC (permalink / raw)
To: Olivier Matz, Thomas Monjalon
Cc: dev, konstantin.ananyev, sugesh.chandran, bruce.richardson,
jianfeng.tan, helin.zhang, adrien.mazarguil, stephen, dprovan,
xiao.w.wang, maxime.coquelin
In-Reply-To: <1476368171-18176-13-git-send-email-olivier.matz@6wind.com>
On Thu, Oct 13, 2016 at 04:16:11PM +0200, Olivier Matz wrote:
> +/* When doing TSO, the IP length is not included in the pseudo header
> + * checksum of the packet given to the PMD, but for virtio it is
> + * expected.
> + */
> +static void
> +virtio_tso_fix_cksum(struct rte_mbuf *m)
> +{
> + /* common case: header is not fragmented */
> + if (likely(rte_pktmbuf_data_len(m) >= m->l2_len + m->l3_len +
> + m->l4_len)) {
> + struct ipv4_hdr *iph;
> + struct ipv6_hdr *ip6h;
> + struct tcp_hdr *th;
> + uint16_t prev_cksum, new_cksum, ip_len, ip_paylen;
> + uint32_t tmp;
...
> + } else {
As discussed just now, if you drop the else part, you could add my
ACK for the whole virtio changes, and Review-ed by for all mbuf and
other changes.
Thoams, please pick them by youself directly: since it depends on
other patches and they will be picked (or already be picked?) by you.
Thanks.
--yliu
^ permalink raw reply
* Re: [PATCH] eal: avoid unnecessary conflicts over rte_config file
From: Van Haaren, Harry @ 2016-10-13 16:07 UTC (permalink / raw)
To: John Ousterhout, Ananyev, Konstantin
Cc: thomas.monjalon@6wind.com, dev@dpdk.org
In-Reply-To: <CAGXJAmxYPtc2GigTVtvc2RkCs9DbaskPw0SY5vjN_HTBf0kMZw@mail.gmail.com>
Hi John,
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of John Ousterhout
> Subject: Re: [dpdk-dev] [PATCH] eal: avoid unnecessary conflicts over rte_config file
<snip>
> For example, it took me several hours
> to figure out why the problem was occurring and then to hunt down the
> --file-prefix solution. Is there some reason why it would be a bad idea to
> fix this in DPDK?
Right now, DPDK will by default always use a consistent .rte_config location, which allows other applications to monitor that. For example, Collectd is able to monitor a DPDK primary process by checking if the .rte_config file exists at its default location[1].
If we change the default behavior of DPDK, other projects can no longer rely on that file being created, and these monitoring projects must be updated in sync with DPDK to avoid breakage if versions mismatch.
Although I see your use-case, I think using the --file-prefix as Konstantin suggests is a better solution in this case.
Regards, -Harry
[1] https://github.com/collectd/collectd/blob/master/src/dpdkstat.c#L60
> On Thu, Oct 13, 2016 at 3:53 AM, Ananyev, Konstantin <
> konstantin.ananyev@intel.com> wrote:
>
> >
> > Hi John,
> >
> > > Before this patch, DPDK used the file ~/.rte_config as a lock to detect
> > > potential interference between multiple DPDK applications running on the
> > > same machine. However, if a single user ran DPDK applications
> > concurrently
> > > on several different machines, and if the user's home directory was
> > shared
> > > between the machines via NFS, DPDK would incorrectly detect conflicts
> > > for all but the first application and abort them. This patch fixes the
> > > problem by incorporating the machine name into the config file name
> > (e.g.,
> > > ~/.rte_hostname_config).
> > >
> > > Signed-off-by: John Ousterhout <ouster@cs.stanford.edu>
> > > ---
> > > doc/guides/prog_guide/multi_proc_support.rst | 11 +++++++----
> > > lib/librte_eal/common/eal_common_proc.c | 8 ++------
> > > lib/librte_eal/common/eal_filesystem.h | 15 +++++++++++++--
> > > 3 files changed, 22 insertions(+), 12 deletions(-)
> > >
> > > diff --git a/doc/guides/prog_guide/multi_proc_support.rst
> > b/doc/guides/prog_guide/multi_proc_support.rst
> > > index badd102..a54fa1c 100644
> > > --- a/doc/guides/prog_guide/multi_proc_support.rst
> > > +++ b/doc/guides/prog_guide/multi_proc_support.rst
> > > @@ -129,10 +129,13 @@ Support for this usage scenario is provided using
> > the ``--file-prefix`` paramete
> > >
> > > By default, the EAL creates hugepage files on each hugetlbfs filesystem
> > using the rtemap_X filename,
> > > where X is in the range 0 to the maximum number of hugepages -1.
> > > -Similarly, it creates shared configuration files, memory mapped in each
> > process, using the /var/run/.rte_config filename,
> > > -when run as root (or $HOME/.rte_config when run as a non-root user;
> > > -if filesystem and device permissions are set up to allow this).
> > > -The rte part of the filenames of each of the above is configurable
> > using the file-prefix parameter.
> > > +Similarly, it creates shared configuration files, memory mapped in each
> > process.
> > > +When run as root, the name of the configuration file will be
> > > +/var/run/.rte_*host*_config, where *host* is the name of the machine.
> > > +When run as a non-root user, the the name of the configuration file
> > will be
> > > +$HOME/.rte_*host*_config (if filesystem and device permissions are set
> > up to allow this).
> > > +If the ``--file-prefix`` parameter has been specified, its value will
> > be used
> > > +in place of "rte" in the file names.
> >
> > I am not sure that we need to handle all such cases inside EAL.
> > User can easily overcome that problem by just adding something like:
> > --file-prefix=`uname -n`
> > to his command-line.
> > Konstantin
> >
> > >
> > > In addition to specifying the file-prefix parameter,
> > > any DPDK applications that are to be run side-by-side must explicitly
> > limit their memory use.
> > > diff --git a/lib/librte_eal/common/eal_common_proc.c
> > b/lib/librte_eal/common/eal_common_proc.c
> > > index 12e0fca..517aa0c 100644
> > > --- a/lib/librte_eal/common/eal_common_proc.c
> > > +++ b/lib/librte_eal/common/eal_common_proc.c
> > > @@ -45,12 +45,8 @@ rte_eal_primary_proc_alive(const char
> > *config_file_path)
> > >
> > > if (config_file_path)
> > > config_fd = open(config_file_path, O_RDONLY);
> > > - else {
> > > - char default_path[PATH_MAX+1];
> > > - snprintf(default_path, PATH_MAX, RUNTIME_CONFIG_FMT,
> > > - default_config_dir, "rte");
> > > - config_fd = open(default_path, O_RDONLY);
> > > - }
> > > + else
> > > + config_fd = open(eal_runtime_config_path(), O_RDONLY);
> > > if (config_fd < 0)
> > > return 0;
> > >
> > > diff --git a/lib/librte_eal/common/eal_filesystem.h
> > b/lib/librte_eal/common/eal_filesystem.h
> > > index fdb4a70..4929aa3 100644
> > > --- a/lib/librte_eal/common/eal_filesystem.h
> > > +++ b/lib/librte_eal/common/eal_filesystem.h
> > > @@ -41,7 +41,7 @@
> > > #define EAL_FILESYSTEM_H
> > >
> > > /** Path of rte config file. */
> > > -#define RUNTIME_CONFIG_FMT "%s/.%s_config"
> > > +#define RUNTIME_CONFIG_FMT "%s/.%s_%s_config"
> > >
> > > #include <stdint.h>
> > > #include <limits.h>
> > > @@ -59,11 +59,22 @@ eal_runtime_config_path(void)
> > > static char buffer[PATH_MAX]; /* static so auto-zeroed */
> > > const char *directory = default_config_dir;
> > > const char *home_dir = getenv("HOME");
> > > + static char nameBuffer[1000];
> > > + int result;
> > >
> > > if (getuid() != 0 && home_dir != NULL)
> > > directory = home_dir;
> > > +
> > > + /*
> > > + * Include the name of the host in the config file path. Otherwise,
> > > + * if DPDK applications run on different hosts but share a home
> > > + * directory (e.g. via NFS), they will choose the same config
> > > + * file and conflict unnecessarily.
> > > + */
> > > + result = gethostname(nameBuffer, sizeof(nameBuffer)-1);
> > > snprintf(buffer, sizeof(buffer) - 1, RUNTIME_CONFIG_FMT, directory,
> > > - internal_config.hugefile_prefix);
> > > + internal_config.hugefile_prefix,
> > > + (result == 0) ? nameBuffer : "unknown-host");
> > > return buffer;
> > > }
> > >
> > > --
> > > 2.8.3
> >
> >
^ permalink raw reply
* [PATCH v8] drivers/net:new PMD using tun/tap host interface
From: Keith Wiles @ 2016-10-13 16:11 UTC (permalink / raw)
To: dev; +Cc: pmatilai, yuanhan.liu, ferruh.yigit
In-Reply-To: <1474423220-10207-1-git-send-email-keith.wiles@intel.com>
The rte_eth_tap.c PMD creates a device using TUN/TAP interfaces
on the local host. The PMD allows for DPDK and the host to
communicate using a raw device interface on the host and in
the DPDK application. The device created is a Tap device with
a L2 packet header.
v8 - Fix issue with tap_tx_queue_setup() not return zero on success.
v7 - Reword the comment in common_base and fix the data->name issue
v6 - fixed the checkpatch issues
v5 - merge in changes from list review see related emails
fixed many minor edits
v4 - merge with latest driver changes
v3 - fix includes by removing ifdef for other type besides Linux
Fix the copyright notice in the Makefile
v2 - merge all of the patches into one patch
Fix a typo on naming the tap device
Update the maintainers list
Signed-off-by: Keith Wiles <keith.wiles@intel.com>
---
MAINTAINERS | 5 +
config/common_base | 9 +
config/common_linuxapp | 1 +
doc/guides/nics/tap.rst | 138 ++++++
drivers/net/Makefile | 1 +
drivers/net/tap/Makefile | 57 +++
drivers/net/tap/rte_eth_tap.c | 756 ++++++++++++++++++++++++++++++++
drivers/net/tap/rte_pmd_tap_version.map | 4 +
mk/rte.app.mk | 1 +
9 files changed, 972 insertions(+)
create mode 100644 doc/guides/nics/tap.rst
create mode 100644 drivers/net/tap/Makefile
create mode 100644 drivers/net/tap/rte_eth_tap.c
create mode 100644 drivers/net/tap/rte_pmd_tap_version.map
diff --git a/MAINTAINERS b/MAINTAINERS
index cd8d167..f905709 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -394,6 +394,11 @@ F: doc/guides/nics/pcap_ring.rst
F: app/test/test_pmd_ring.c
F: app/test/test_pmd_ring_perf.c
+Tap PMD
+M: Keith Wiles <keith.wiles@intel.com>
+F: drivers/net/tap
+F: doc/guides/nics/tap.rst
+
Null Networking PMD
M: Tetsuya Mukawa <mtetsuyah@gmail.com>
F: drivers/net/null/
diff --git a/config/common_base b/config/common_base
index f5d2eff..47ef843 100644
--- a/config/common_base
+++ b/config/common_base
@@ -592,3 +592,12 @@ CONFIG_RTE_APP_TEST_RESOURCE_TAR=n
CONFIG_RTE_TEST_PMD=y
CONFIG_RTE_TEST_PMD_RECORD_CORE_CYCLES=n
CONFIG_RTE_TEST_PMD_RECORD_BURST_STATS=n
+
+#
+# Compile the TAP PMD
+#
+# The TAP PMD is currently only built for Linux and the
+# option is enabled by default in common_linuxapp file,
+# set to 'n' in the common_base file.
+#
+CONFIG_RTE_LIBRTE_PMD_TAP=n
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 2483dfa..782b503 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -44,3 +44,4 @@ CONFIG_RTE_LIBRTE_PMD_VHOST=y
CONFIG_RTE_LIBRTE_PMD_AF_PACKET=y
CONFIG_RTE_LIBRTE_POWER=y
CONFIG_RTE_VIRTIO_USER=y
+CONFIG_RTE_LIBRTE_PMD_TAP=y
diff --git a/doc/guides/nics/tap.rst b/doc/guides/nics/tap.rst
new file mode 100644
index 0000000..bffc649
--- /dev/null
+++ b/doc/guides/nics/tap.rst
@@ -0,0 +1,138 @@
+.. BSD LICENSE
+ Copyright(c) 2016 Intel Corporation. All rights reserved.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Tun/Tap Poll Mode Driver
+========================================
+
+The rte_eth_tap.c PMD creates a device using TUN/TAP interfaces on the local
+host. The PMD allows for DPDK and the host to communicate using a raw device
+interface on the host and in the DPDK application.
+
+The device created is a TAP device, which sends/receives packet in a raw format
+with a L2 header. The usage for a TAP PMD is for connectivity to the local host
+using a TAP interface. When the TAP PMD is initialized it will create a number
+of tap devices in the host accessed via 'ifconfig -a' or 'ip' command. The
+commands can be used to assign and query the virtual like device.
+
+These TAP interfaces can be used with wireshark or tcpdump or Pktgen-DPDK along
+with being able to be used as a network connection to the DPDK application. The
+method enable one or more interfaces is to use the --vdev=net_tap option on the
+DPDK application command line. Each --vdev=net_tap option give will create an
+interface named dtap0, dtap1, ... and so forth.
+
+.. code-block:: console
+
+ The interfaced name can be changed by adding the iface=foo0
+ e.g. --vdev=net_tap,iface=foo0 --vdev=net_tap,iface=foo1, ...
+
+.. code-block:: console
+
+ Also the speed of the interface can be changed from 10G to whatever number
+ needed, but the interface does not enforce that speed.
+ e.g. --vdev=net_tap,iface=foo0,speed=25000
+
+After the DPDK application is started you can send and receive packets on the
+interface using the standard rx_burst/tx_burst APIs in DPDK. From the host point
+of view you can use any host tool like tcpdump, wireshark, ping, Pktgen and
+others to communicate with the DPDK application. The DPDK application may not
+understand network protocols like IPv4/6, UDP or TCP unless the application has
+been written to understand these protocols.
+
+If you need the interface as a real network interface meaning running and has
+a valid IP address then you can do this with the following commands:
+
+.. code-block:: console
+
+ sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
+ sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
+
+Please change the IP addresses as you see fit.
+
+If routing is enabled on the host you can also communicate with the DPDK App
+over the internet via a standard socket layer application as long as you account
+for the protocol handing in the application.
+
+If you have a Network Stack in your DPDK application or something like it you
+can utilize that stack to handle the network protocols. Plus you would be able
+to address the interface using an IP address assigned to the internal interface.
+
+A very crude test you can do the following:
+
+Apply the patch below and make sure you have socat installed on your system.
+
+Build DPDK, then pull down Pktgen and build pktgen using the DPDK SDK/Target
+used to build the dpdk you pulled down.
+
+Run pktgen from the pktgen repo directory in an xterm:
+ Note: change the -b options to blacklist all of your physical ports. The
+ following command line is all one line.
+
+.. code-block:: console
+
+ sudo ./app/app/x86_64-native-linuxapp-gcc/app/pktgen -l 1-5 -n 4 \
+ --proc-type auto --log-level 8 --socket-mem 512,512 --file-prefix pg \
+ --vdev=net_tap --vdev=net_tap -b 05:00.0 -b 05:00.1 \
+ -b 04:00.0 -b 04:00.1 -b 04:00.2 -b 04:00.3 \
+ -b 81:00.0 -b 81:00.1 -b 81:00.2 -b 81:00.3 \
+ -b 82:00.0 -b 83:00.0 -- -T -P -m [2:3].0 -m [4:5].1 \
+ -f themes/black-yellow.theme
+
+I normally put the line above into a file called doit.sh, just to allow for a
+simple execution of the line above.
+
+You can leave the -f themes/black-yellow.theme off if the colors does not work
+for your system configuration.
+
+Verify with 'ifconfig -a' command in a different xterm window, should have a
+dtap0 and dtap1 interfaces created.
+
+Next set the links for the two interfaces to up via the commands below.
+
+.. code-block:: console
+
+ sudo ip link set dtap0 up; sudo ip addr add 192.168.0.250/24 dev dtap0
+ sudo ip link set dtap1 up; sudo ip addr add 192.168.1.250/24 dev dtap1
+
+Then use socat to create a loopback for the two interfaces.
+
+.. code-block:: console
+
+ sudo socat interface:dtap0 interface:dtap1
+
+Then on the Pktgen command line interface you can start sending packets using
+the commands 'start 0' and 'start 1' or you can start both at the same time
+with 'start all'. The command 'str' is an alias for 'start all' and 'stp' is
+an alias for 'stop all'.
+
+While running you should see the 64 byte counters increasing to verify the
+traffic is being looped back. You can use 'set all size XXX' to change the
+size of the packets after you stop the traffic. Use the pktgen 'help' command
+to see a list of all commands. You can also use the '-f' option to load commands
+at startup.
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index bc93230..e366a85 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -51,6 +51,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PMD_PCAP) += pcap
DIRS-$(CONFIG_RTE_LIBRTE_QEDE_PMD) += qede
DIRS-$(CONFIG_RTE_LIBRTE_PMD_RING) += ring
DIRS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += szedata2
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += tap
DIRS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += thunderx
DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += virtio
DIRS-$(CONFIG_RTE_LIBRTE_VMXNET3_PMD) += vmxnet3
diff --git a/drivers/net/tap/Makefile b/drivers/net/tap/Makefile
new file mode 100644
index 0000000..e18f30c
--- /dev/null
+++ b/drivers/net/tap/Makefile
@@ -0,0 +1,57 @@
+# BSD LICENSE
+#
+# Copyright(c) 2016 Intel Corporation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_tap.a
+
+EXPORT_MAP := rte_pmd_tap_version.map
+
+LIBABIVER := 1
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += rte_eth_tap.c
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_mempool
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_kvargs
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
new file mode 100644
index 0000000..7f303db
--- /dev/null
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -0,0 +1,756 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_malloc.h>
+#include <rte_vdev.h>
+#include <rte_kvargs.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <poll.h>
+#include <arpa/inet.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <linux/if_ether.h>
+#include <fcntl.h>
+
+/* Linux based path to the TUN device */
+#define TUN_TAP_DEV_PATH "/dev/net/tun"
+#define DEFAULT_TAP_NAME "dtap"
+
+#define ETH_TAP_IFACE_ARG "iface"
+#define ETH_TAP_SPEED_ARG "speed"
+
+#define RTE_PMD_TAP_MAX_QUEUES 32
+
+static const char *valid_arguments[] = {
+ ETH_TAP_IFACE_ARG,
+ ETH_TAP_SPEED_ARG,
+ NULL
+};
+
+static const char *drivername = "Tap PMD";
+static int tap_unit;
+
+static struct rte_eth_link pmd_link = {
+ .link_speed = ETH_SPEED_NUM_10G,
+ .link_duplex = ETH_LINK_FULL_DUPLEX,
+ .link_status = ETH_LINK_DOWN,
+ .link_autoneg = ETH_LINK_SPEED_AUTONEG
+};
+
+struct pkt_stats {
+ uint64_t opackets; /* Number of output packets */
+ uint64_t ipackets; /* Number of input packets */
+ uint64_t obytes; /* Number of bytes on output */
+ uint64_t ibytes; /* Number of bytes on input */
+ uint64_t errs; /* Number of error packets */
+};
+
+struct rx_queue {
+ struct rte_mempool *mp; /* Mempool for RX packets */
+ uint16_t in_port; /* Port ID */
+ int fd;
+
+ struct pkt_stats stats; /* Stats for this RX queue */
+};
+
+struct tx_queue {
+ int fd;
+ struct pkt_stats stats; /* Stats for this TX queue */
+};
+
+struct pmd_internals {
+ char name[RTE_ETH_NAME_MAX_LEN]; /* Internal Tap device name */
+ uint16_t nb_queues; /* Number of queues supported */
+ struct ether_addr eth_addr; /* Mac address of the device port */
+
+ int if_index; /* IF_INDEX for the port */
+ int fds[RTE_PMD_TAP_MAX_QUEUES]; /* List of all file descriptors */
+
+ struct rx_queue rxq[RTE_PMD_TAP_MAX_QUEUES]; /* List of RX queues */
+ struct tx_queue txq[RTE_PMD_TAP_MAX_QUEUES]; /* List of TX queues */
+};
+
+/* Tun/Tap allocation routine
+ *
+ * name is the number of the interface to use, unless NULL to take the host
+ * supplied name.
+ */
+static int
+tun_alloc(char *name)
+{
+ struct ifreq ifr;
+ unsigned int features;
+ int fd;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (name && name[0])
+ strncpy(ifr.ifr_name, name, IFNAMSIZ);
+
+ fd = open(TUN_TAP_DEV_PATH, O_RDWR);
+ if (fd < 0) {
+ RTE_LOG(ERR, PMD, "Unable to create TAP interface");
+ goto error;
+ }
+
+ /* Grab the TUN features to verify we can work */
+ if (ioctl(fd, TUNGETFEATURES, &features) < 0) {
+ RTE_LOG(ERR, PMD, "Unable to get TUN/TAP features\n");
+ goto error;
+ }
+ RTE_LOG(DEBUG, PMD, "TUN/TAP Features %08x\n", features);
+
+ if (!(features & IFF_MULTI_QUEUE) && (RTE_PMD_TAP_MAX_QUEUES > 1)) {
+ RTE_LOG(DEBUG, PMD, "TUN/TAP device only one queue\n");
+ goto error;
+ } else if ((features & IFF_ONE_QUEUE) &&
+ (RTE_PMD_TAP_MAX_QUEUES == 1)) {
+ ifr.ifr_flags |= IFF_ONE_QUEUE;
+ RTE_LOG(DEBUG, PMD, "Single queue only support\n");
+ } else {
+ ifr.ifr_flags |= IFF_MULTI_QUEUE;
+ RTE_LOG(DEBUG, PMD, "Multi-queue support for %d queues\n",
+ RTE_PMD_TAP_MAX_QUEUES);
+ }
+
+ /* Set the TUN/TAP configuration and get the name if needed */
+ if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) {
+ RTE_LOG(ERR, PMD, "Unable to set TUNSETIFF for %s\n",
+ ifr.ifr_name);
+ perror("TUNSETIFF");
+ goto error;
+ }
+
+ /* Always set the file descriptor to non-blocking */
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
+ RTE_LOG(ERR, PMD, "Unable to set to nonblocking\n");
+ perror("F_SETFL, NONBLOCK");
+ goto error;
+ }
+
+ /* If the name is different that new name as default */
+ if (name && strcmp(name, ifr.ifr_name))
+ snprintf(name, RTE_ETH_NAME_MAX_LEN - 1, "%s", ifr.ifr_name);
+
+ return fd;
+
+error:
+ if (fd > 0)
+ close(fd);
+ return -1;
+}
+
+/* Callback to handle the rx burst of packets to the correct interface and
+ * file descriptor(s) in a multi-queue setup.
+ */
+static uint16_t
+pmd_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+ int len;
+ struct rte_mbuf *mbuf;
+ struct rx_queue *rxq = queue;
+ uint16_t num_rx;
+ unsigned long num_rx_bytes = 0;
+
+ for (num_rx = 0; num_rx < nb_pkts; ) {
+ /* allocate the next mbuf */
+ mbuf = rte_pktmbuf_alloc(rxq->mp);
+ if (unlikely(!mbuf)) {
+ RTE_LOG(WARNING, PMD, "Unable to allocate mbuf\n");
+ break;
+ }
+
+ len = read(rxq->fd, rte_pktmbuf_mtod(mbuf, char *),
+ rte_pktmbuf_tailroom(mbuf));
+ if (len <= 0) {
+ rte_pktmbuf_free(mbuf);
+ break;
+ }
+
+ mbuf->data_len = len;
+ mbuf->pkt_len = len;
+ mbuf->port = rxq->in_port;
+
+ /* account for the receive frame */
+ bufs[num_rx++] = mbuf;
+ num_rx_bytes += mbuf->pkt_len;
+ }
+ rxq->stats.ipackets += num_rx;
+ rxq->stats.ibytes += num_rx_bytes;
+
+ return num_rx;
+}
+
+/* Callback to handle sending packets from the tap interface
+ */
+static uint16_t
+pmd_tx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+ struct rte_mbuf *mbuf;
+ struct tx_queue *txq = queue;
+ struct pollfd pfd;
+ uint16_t num_tx = 0;
+ unsigned long num_tx_bytes = 0;
+ int i, n;
+
+ if (unlikely(nb_pkts == 0))
+ return 0;
+
+ pfd.events = POLLOUT;
+ pfd.fd = txq->fd;
+ for (i = 0; i < nb_pkts; i++) {
+ n = poll(&pfd, 1, 0);
+
+ if (n <= 0)
+ break;
+
+ if (pfd.revents & POLLOUT) {
+ /* copy the tx frame data */
+ mbuf = bufs[num_tx];
+ n = write(pfd.fd, rte_pktmbuf_mtod(mbuf, void*),
+ rte_pktmbuf_pkt_len(mbuf));
+ if (n <= 0)
+ break;
+
+ num_tx++;
+ num_tx_bytes += mbuf->pkt_len;
+ rte_pktmbuf_free(mbuf);
+ }
+ }
+
+ txq->stats.opackets += num_tx;
+ txq->stats.errs += nb_pkts - num_tx;
+ txq->stats.obytes += num_tx_bytes;
+
+ return num_tx;
+}
+
+static int
+tap_dev_start(struct rte_eth_dev *dev)
+{
+ /* Force the Link up */
+ dev->data->dev_link.link_status = ETH_LINK_UP;
+
+ return 0;
+}
+
+/* This function gets called when the current port gets stopped.
+ */
+static void
+tap_dev_stop(struct rte_eth_dev *dev)
+{
+ int i;
+ struct pmd_internals *internals = dev->data->dev_private;
+
+ for (i = 0; i < internals->nb_queues; i++)
+ if (internals->fds[i] != -1)
+ close(internals->fds[i]);
+
+ dev->data->dev_link.link_status = ETH_LINK_DOWN;
+}
+
+static int
+tap_dev_configure(struct rte_eth_dev *dev __rte_unused)
+{
+ return 0;
+}
+
+static void
+tap_dev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
+{
+ struct pmd_internals *internals = dev->data->dev_private;
+
+ dev_info->driver_name = drivername;
+ dev_info->if_index = internals->if_index;
+ dev_info->max_mac_addrs = 1;
+ dev_info->max_rx_pktlen = (uint32_t)ETHER_MAX_VLAN_FRAME_LEN;
+ dev_info->max_rx_queues = internals->nb_queues;
+ dev_info->max_tx_queues = internals->nb_queues;
+ dev_info->min_rx_bufsize = 0;
+ dev_info->pci_dev = NULL;
+}
+
+static void
+tap_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *tap_stats)
+{
+ unsigned int i, imax;
+ unsigned long rx_total = 0, tx_total = 0, tx_err_total = 0;
+ unsigned long rx_bytes_total = 0, tx_bytes_total = 0;
+ const struct pmd_internals *pmd = dev->data->dev_private;
+
+ imax = (pmd->nb_queues < RTE_ETHDEV_QUEUE_STAT_CNTRS) ?
+ pmd->nb_queues : RTE_ETHDEV_QUEUE_STAT_CNTRS;
+
+ for (i = 0; i < imax; i++) {
+ tap_stats->q_ipackets[i] = pmd->rxq[i].stats.ipackets;
+ tap_stats->q_ibytes[i] = pmd->rxq[i].stats.ibytes;
+ rx_total += tap_stats->q_ipackets[i];
+ rx_bytes_total += tap_stats->q_ibytes[i];
+ }
+
+ for (i = 0; i < imax; i++) {
+ tap_stats->q_opackets[i] = pmd->txq[i].stats.opackets;
+ tap_stats->q_errors[i] = pmd->txq[i].stats.errs;
+ tap_stats->q_obytes[i] = pmd->txq[i].stats.obytes;
+ tx_total += tap_stats->q_opackets[i];
+ tx_err_total += tap_stats->q_errors[i];
+ tx_bytes_total += tap_stats->q_obytes[i];
+ }
+
+ tap_stats->ipackets = rx_total;
+ tap_stats->ibytes = rx_bytes_total;
+ tap_stats->opackets = tx_total;
+ tap_stats->oerrors = tx_err_total;
+ tap_stats->obytes = tx_bytes_total;
+}
+
+static void
+tap_stats_reset(struct rte_eth_dev *dev)
+{
+ int i;
+ struct pmd_internals *pmd = dev->data->dev_private;
+
+ for (i = 0; i < pmd->nb_queues; i++) {
+ pmd->rxq[i].stats.ipackets = 0;
+ pmd->rxq[i].stats.ibytes = 0;
+ }
+
+ for (i = 0; i < pmd->nb_queues; i++) {
+ pmd->txq[i].stats.opackets = 0;
+ pmd->txq[i].stats.errs = 0;
+ pmd->txq[i].stats.obytes = 0;
+ }
+}
+
+static void
+tap_dev_close(struct rte_eth_dev *dev __rte_unused)
+{
+}
+
+static void
+tap_rx_queue_release(void *queue)
+{
+ struct rx_queue *rxq = queue;
+
+ if (rxq && (rxq->fd > 0)) {
+ close(rxq->fd);
+ rxq->fd = -1;
+ }
+}
+
+static void
+tap_tx_queue_release(void *queue)
+{
+ struct tx_queue *txq = queue;
+
+ if (txq && (txq->fd > 0)) {
+ close(txq->fd);
+ txq->fd = -1;
+ }
+}
+
+static int
+tap_link_update(struct rte_eth_dev *dev __rte_unused,
+ int wait_to_complete __rte_unused)
+{
+ return 0;
+}
+
+static int
+tap_setup_queue(struct rte_eth_dev *dev,
+ struct pmd_internals *internals,
+ uint16_t qid)
+{
+ struct rx_queue *rx = &internals->rxq[qid];
+ struct tx_queue *tx = &internals->txq[qid];
+ int fd;
+
+ fd = rx->fd;
+ if (fd < 0) {
+ fd = tx->fd;
+ if (fd < 0) {
+ RTE_LOG(INFO, PMD, "Add queue to TAP %s for qid %d\n",
+ dev->data->name, qid);
+ fd = tun_alloc(dev->data->name);
+ if (fd < 0) {
+ RTE_LOG(ERR, PMD, "tun_alloc(%s) failed\n",
+ dev->data->name);
+ return -1;
+ }
+ }
+ }
+ dev->data->rx_queues[qid] = rx;
+ dev->data->tx_queues[qid] = tx;
+
+ rx->fd = fd;
+ tx->fd = fd;
+
+ return fd;
+}
+
+static int
+tap_rx_queue_setup(struct rte_eth_dev *dev,
+ uint16_t rx_queue_id,
+ uint16_t nb_rx_desc __rte_unused,
+ unsigned int socket_id __rte_unused,
+ const struct rte_eth_rxconf *rx_conf __rte_unused,
+ struct rte_mempool *mp)
+{
+ struct pmd_internals *internals = dev->data->dev_private;
+ uint16_t buf_size;
+ int fd;
+
+ if ((rx_queue_id >= internals->nb_queues) || !mp) {
+ RTE_LOG(ERR, PMD, "nb_queues %d mp %p\n",
+ internals->nb_queues, mp);
+ return -1;
+ }
+
+ internals->rxq[rx_queue_id].mp = mp;
+ internals->rxq[rx_queue_id].in_port = dev->data->port_id;
+
+ /* Now get the space available for data in the mbuf */
+ buf_size = (uint16_t)(rte_pktmbuf_data_room_size(mp) -
+ RTE_PKTMBUF_HEADROOM);
+
+ if (buf_size < ETH_FRAME_LEN) {
+ RTE_LOG(ERR, PMD,
+ "%s: %d bytes will not fit in mbuf (%d bytes)\n",
+ dev->data->name, ETH_FRAME_LEN, buf_size);
+ return -ENOMEM;
+ }
+
+ fd = tap_setup_queue(dev, internals, rx_queue_id);
+ if (fd == -1)
+ return -1;
+
+ internals->fds[rx_queue_id] = fd;
+ RTE_LOG(INFO, PMD, "RX TAP device name %s, qid %d on fd %d\n",
+ dev->data->name, rx_queue_id, internals->rxq[rx_queue_id].fd);
+
+ return 0;
+}
+
+static int
+tap_tx_queue_setup(struct rte_eth_dev *dev,
+ uint16_t tx_queue_id,
+ uint16_t nb_tx_desc __rte_unused,
+ unsigned int socket_id __rte_unused,
+ const struct rte_eth_txconf *tx_conf __rte_unused)
+{
+ struct pmd_internals *internals = dev->data->dev_private;
+ int ret;
+
+ if (tx_queue_id >= internals->nb_queues)
+ return -1;
+
+ ret = tap_setup_queue(dev, internals, tx_queue_id);
+ if (ret == -1)
+ return -1;
+
+ RTE_LOG(INFO, PMD, "TX TAP device name %s, qid %d on fd %d\n",
+ dev->data->name, tx_queue_id, internals->txq[tx_queue_id].fd);
+
+ return 0;
+}
+
+static const struct eth_dev_ops ops = {
+ .dev_start = tap_dev_start,
+ .dev_stop = tap_dev_stop,
+ .dev_close = tap_dev_close,
+ .dev_configure = tap_dev_configure,
+ .dev_infos_get = tap_dev_info,
+ .rx_queue_setup = tap_rx_queue_setup,
+ .tx_queue_setup = tap_tx_queue_setup,
+ .rx_queue_release = tap_rx_queue_release,
+ .tx_queue_release = tap_tx_queue_release,
+ .link_update = tap_link_update,
+ .stats_get = tap_stats_get,
+ .stats_reset = tap_stats_reset,
+};
+
+static int
+pmd_mac_address(int fd, struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+ struct ifreq ifr;
+
+ if ((fd <= 0) || !dev || !addr)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) {
+ RTE_LOG(ERR, PMD, "ioctl failed (SIOCGIFHWADDR) (%s)\n",
+ ifr.ifr_name);
+ return -1;
+ }
+
+ /* Set the host based MAC address to this special MAC format */
+ ifr.ifr_hwaddr.sa_data[0] = 'T';
+ ifr.ifr_hwaddr.sa_data[1] = 'a';
+ ifr.ifr_hwaddr.sa_data[2] = 'p';
+ ifr.ifr_hwaddr.sa_data[3] = '-';
+ ifr.ifr_hwaddr.sa_data[4] = dev->data->port_id;
+ ifr.ifr_hwaddr.sa_data[5] = dev->data->numa_node;
+ if (ioctl(fd, SIOCSIFHWADDR, &ifr) == -1) {
+ RTE_LOG(ERR, PMD, "%s: ioctl failed (SIOCSIFHWADDR) (%s)\n",
+ dev->data->name, ifr.ifr_name);
+ return -1;
+ }
+
+ /* Set the local application MAC address, needs to be different then
+ * the host based MAC address.
+ */
+ ifr.ifr_hwaddr.sa_data[0] = 'd';
+ ifr.ifr_hwaddr.sa_data[1] = 'n';
+ ifr.ifr_hwaddr.sa_data[2] = 'e';
+ ifr.ifr_hwaddr.sa_data[3] = 't';
+ ifr.ifr_hwaddr.sa_data[4] = dev->data->port_id;
+ ifr.ifr_hwaddr.sa_data[5] = dev->data->numa_node;
+ rte_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ return 0;
+}
+
+static int
+eth_dev_tap_create(const char *name, char *tap_name)
+{
+ int numa_node = rte_socket_id();
+ struct rte_eth_dev *dev = NULL;
+ struct pmd_internals *pmd = NULL;
+ struct rte_eth_dev_data *data = NULL;
+ int i, fd = -1;
+
+ RTE_LOG(INFO, PMD,
+ "%s: Create TAP Ethernet device with %d queues on numa %u\n",
+ name, RTE_PMD_TAP_MAX_QUEUES, rte_socket_id());
+
+ data = rte_zmalloc_socket(tap_name, sizeof(*data), 0, numa_node);
+ if (!data)
+ goto error_exit;
+
+ pmd = rte_zmalloc_socket(tap_name, sizeof(*pmd), 0, numa_node);
+ if (!pmd)
+ goto error_exit;
+
+ /* Use the name and not the tap_name */
+ dev = rte_eth_dev_allocate(name);
+ if (!dev)
+ goto error_exit;
+
+ snprintf(pmd->name, sizeof(pmd->name), "%s", tap_name);
+
+ pmd->nb_queues = RTE_PMD_TAP_MAX_QUEUES;
+
+ /* Setup some default values */
+ data->dev_private = pmd;
+ data->port_id = dev->data->port_id;
+ data->dev_flags = RTE_ETH_DEV_DETACHABLE;
+ data->kdrv = RTE_KDRV_NONE;
+ data->drv_name = drivername;
+ data->numa_node = numa_node;
+
+ data->dev_link = pmd_link;
+ data->mac_addrs = &pmd->eth_addr;
+ data->nb_rx_queues = pmd->nb_queues;
+ data->nb_tx_queues = pmd->nb_queues;
+ data->drv_name = drivername;
+
+ dev->data = data;
+ dev->dev_ops = &ops;
+ dev->driver = NULL;
+ dev->rx_pkt_burst = pmd_rx_burst;
+ dev->tx_pkt_burst = pmd_tx_burst;
+ snprintf(dev->data->name, sizeof(dev->data->name), "%s", name);
+
+ /* Create the first Tap device */
+ fd = tun_alloc(tap_name);
+ if (fd < 0)
+ goto error_exit;
+
+ /* Presetup the fds to -1 as being not working */
+ for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
+ pmd->fds[i] = -1;
+ pmd->rxq[i].fd = -1;
+ pmd->txq[i].fd = -1;
+ }
+
+ /* Take the TUN/TAP fd and place in the first location */
+ pmd->rxq[0].fd = fd;
+ pmd->txq[0].fd = fd;
+ pmd->fds[0] = fd;
+
+ if (pmd_mac_address(fd, dev, &pmd->eth_addr) < 0)
+ goto error_exit;
+
+ return 0;
+
+error_exit:
+ RTE_PMD_DEBUG_TRACE("Unable to initialize %s\n", name);
+
+ rte_free(data);
+ rte_free(pmd);
+
+ rte_eth_dev_release_port(dev);
+
+ return -EINVAL;
+}
+
+static int
+set_interface_name(const char *key __rte_unused,
+ const char *value,
+ void *extra_args)
+{
+ char *name = (char *)extra_args;
+
+ if (value)
+ snprintf(name, RTE_ETH_NAME_MAX_LEN - 1, "%s", value);
+ else
+ snprintf(name, RTE_ETH_NAME_MAX_LEN - 1, "%s%d",
+ DEFAULT_TAP_NAME, (tap_unit - 1));
+
+ return 0;
+}
+
+static int
+set_interface_speed(const char *key __rte_unused,
+ const char *value,
+ void *extra_args)
+{
+ *(int *)extra_args = (value) ? atoi(value) : ETH_SPEED_NUM_10G;
+
+ return 0;
+}
+
+/* Open a TAP interface device.
+ */
+static int
+rte_pmd_tap_probe(const char *name, const char *params)
+{
+ int ret;
+ struct rte_kvargs *kvlist = NULL;
+ int speed;
+ char tap_name[RTE_ETH_NAME_MAX_LEN];
+
+ speed = ETH_SPEED_NUM_10G;
+ snprintf(tap_name, sizeof(tap_name), "%s%d",
+ DEFAULT_TAP_NAME, tap_unit++);
+
+ RTE_LOG(INFO, PMD, "Initializing pmd_tap for %s as %s\n",
+ name, tap_name);
+
+ if (params && (params[0] != '\0')) {
+ RTE_LOG(INFO, PMD, "paramaters (%s)\n", params);
+
+ kvlist = rte_kvargs_parse(params, valid_arguments);
+ if (kvlist) {
+ if (rte_kvargs_count(kvlist, ETH_TAP_SPEED_ARG) == 1) {
+ ret = rte_kvargs_process(kvlist,
+ ETH_TAP_SPEED_ARG,
+ &set_interface_speed,
+ &speed);
+ if (ret == -1)
+ goto leave;
+ }
+
+ if (rte_kvargs_count(kvlist, ETH_TAP_IFACE_ARG) == 1) {
+ ret = rte_kvargs_process(kvlist,
+ ETH_TAP_IFACE_ARG,
+ &set_interface_name,
+ tap_name);
+ if (ret == -1)
+ goto leave;
+ }
+ }
+ }
+ pmd_link.link_speed = speed;
+
+ ret = eth_dev_tap_create(name, tap_name);
+
+leave:
+ if (ret == -1) {
+ RTE_LOG(INFO, PMD, "Failed to create pmd_tap for %s as %s\n",
+ name, tap_name);
+ tap_unit--; /* Restore the unit number */
+ }
+ rte_kvargs_free(kvlist);
+
+ return ret;
+}
+
+/* detach a TAP device.
+ */
+static int
+rte_pmd_tap_remove(const char *name)
+{
+ struct rte_eth_dev *eth_dev = NULL;
+ struct pmd_internals *internals;
+ int i;
+
+ RTE_LOG(INFO, PMD, "Closing TUN/TAP Ethernet device on numa %u\n",
+ rte_socket_id());
+
+ /* find the ethdev entry */
+ eth_dev = rte_eth_dev_allocated(name);
+ if (!eth_dev)
+ return 0;
+
+ internals = eth_dev->data->dev_private;
+ for (i = 0; i < internals->nb_queues; i++)
+ if (internals->fds[i] != -1)
+ close(internals->fds[i]);
+
+ rte_free(eth_dev->data->dev_private);
+ rte_free(eth_dev->data);
+
+ rte_eth_dev_release_port(eth_dev);
+
+ return 0;
+}
+
+static struct rte_vdev_driver pmd_tap_drv = {
+ .probe = rte_pmd_tap_probe,
+ .remove = rte_pmd_tap_remove,
+};
+
+DRIVER_REGISTER_VDEV(net_tap, pmd_tap_drv);
+DRIVER_REGISTER_PARAM_STRING(net_tap, "iface=<string>,speed=N");
diff --git a/drivers/net/tap/rte_pmd_tap_version.map b/drivers/net/tap/rte_pmd_tap_version.map
new file mode 100644
index 0000000..61463bf
--- /dev/null
+++ b/drivers/net/tap/rte_pmd_tap_version.map
@@ -0,0 +1,4 @@
+DPDK_16.11 {
+
+ local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index ac50a21..40d16f7 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -123,6 +123,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_PCAP) += -lrte_pmd_pcap -lpcap
_LDLIBS-$(CONFIG_RTE_LIBRTE_QEDE_PMD) += -lrte_pmd_qede -lz
_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_RING) += -lrte_pmd_ring
_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SZEDATA2) += -lrte_pmd_szedata2 -lsze2
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += -lrte_pmd_tap
_LDLIBS-$(CONFIG_RTE_LIBRTE_THUNDERX_NICVF_PMD) += -lrte_pmd_thunderx_nicvf -lm
_LDLIBS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += -lrte_pmd_virtio
ifeq ($(CONFIG_RTE_LIBRTE_VHOST),y)
--
2.8.0.GIT
^ permalink raw reply related
* Re: [PATCH 1/1] doc: clarify usage of testpmd mac fwd mode
From: Thomas Monjalon @ 2016-10-13 16:12 UTC (permalink / raw)
To: Kavanagh, Mark B; +Cc: dev, Mcnamara, John
In-Reply-To: <B27915DBBA3421428155699D51E4CFE202621CD9@IRSMSX103.ger.corp.intel.com>
> > Explain default testpmd behavior in mac fwd mode to remove
> > amiguity/confusion regarding user's ability to specify Ethernet addresses.
> >
> > Signed-off-by: Mark Kavanagh <mark.b.kavanagh@intel.com>
>
> Acked-by: John McNamara <john.mcnamara@intel.com>
Applied, thanks
^ permalink raw reply
* Re: [PATCH 1/1] testpmd_ug: update userguide with xstats commands
From: Thomas Monjalon @ 2016-10-13 16:14 UTC (permalink / raw)
To: Tahhan, Maryam; +Cc: dev, Mcnamara, John
In-Reply-To: <B27915DBBA3421428155699D51E4CFE2026298F7@IRSMSX103.ger.corp.intel.com>
> > Update the testpmd user guide with instructions for retrieving extended
> > NIC statistics.
> >
> > Signed-off-by: Maryam Tahhan <maryam.tahhan@intel.com>
>
> Acked-by: John McNamara <john.mcnamara@intel.com>
Applied, thanks
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox