* [dpdk-dev] [PATCH v4 1/9] librte_ether: protect add/remove of rxtx callbacks with spinlocks
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 0/9] add " Reshma Pattan
@ 2016-05-23 21:38 ` Reshma Pattan
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 2/9] librte_ether: add new api rte_eth_add_first_rx_callback Reshma Pattan
` (9 subsequent siblings)
10 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-05-23 21:38 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Added spinlocks around add/remove logic of rxtx callbacks to
avoid corruption of callback lists in multithreaded context.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
lib/librte_ether/rte_ethdev.c | 82 +++++++++++++++++++++----------------------
1 file changed, 40 insertions(+), 42 deletions(-)
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index a31018e..cf25d8a 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -77,6 +77,12 @@ static uint8_t nb_ports;
/* spinlock for eth device callbacks */
static rte_spinlock_t rte_eth_dev_cb_lock = RTE_SPINLOCK_INITIALIZER;
+/* spinlock for add/remove rx callbacks */
+static rte_spinlock_t rte_eth_rx_cb_lock = RTE_SPINLOCK_INITIALIZER;
+
+/* spinlock for add/remove tx callbacks */
+static rte_spinlock_t rte_eth_tx_cb_lock = RTE_SPINLOCK_INITIALIZER;
+
/* store statistics names and its offset in stats structure */
struct rte_eth_xstats_name_off {
char name[RTE_ETH_XSTATS_NAME_SIZE];
@@ -1639,7 +1645,6 @@ rte_eth_dev_set_rx_queue_stats_mapping(uint8_t port_id, uint16_t rx_queue_id,
STAT_QMAP_RX);
}
-
void
rte_eth_dev_info_get(uint8_t port_id, struct rte_eth_dev_info *dev_info)
{
@@ -2925,7 +2930,6 @@ rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
rte_errno = EINVAL;
return NULL;
}
-
struct rte_eth_rxtx_callback *cb = rte_zmalloc(NULL, sizeof(*cb), 0);
if (cb == NULL) {
@@ -2936,6 +2940,7 @@ rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
cb->fn.rx = fn;
cb->param = user_param;
+ rte_spinlock_lock(&rte_eth_rx_cb_lock);
/* Add the callbacks in fifo order. */
struct rte_eth_rxtx_callback *tail =
rte_eth_devices[port_id].post_rx_burst_cbs[queue_id];
@@ -2948,6 +2953,7 @@ rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
tail = tail->next;
tail->next = cb;
}
+ rte_spinlock_unlock(&rte_eth_rx_cb_lock);
return cb;
}
@@ -2977,6 +2983,7 @@ rte_eth_add_tx_callback(uint8_t port_id, uint16_t queue_id,
cb->fn.tx = fn;
cb->param = user_param;
+ rte_spinlock_lock(&rte_eth_tx_cb_lock);
/* Add the callbacks in fifo order. */
struct rte_eth_rxtx_callback *tail =
rte_eth_devices[port_id].pre_tx_burst_cbs[queue_id];
@@ -2989,6 +2996,7 @@ rte_eth_add_tx_callback(uint8_t port_id, uint16_t queue_id,
tail = tail->next;
tail->next = cb;
}
+ rte_spinlock_unlock(&rte_eth_tx_cb_lock);
return cb;
}
@@ -3007,29 +3015,24 @@ rte_eth_remove_rx_callback(uint8_t port_id, uint16_t queue_id,
}
struct rte_eth_dev *dev = &rte_eth_devices[port_id];
- struct rte_eth_rxtx_callback *cb = dev->post_rx_burst_cbs[queue_id];
- struct rte_eth_rxtx_callback *prev_cb;
-
- /* Reset head pointer and remove user cb if first in the list. */
- if (cb == user_cb) {
- dev->post_rx_burst_cbs[queue_id] = user_cb->next;
- return 0;
- }
-
- /* Remove the user cb from the callback list. */
- do {
- prev_cb = cb;
- cb = cb->next;
-
+ struct rte_eth_rxtx_callback *cb;
+ struct rte_eth_rxtx_callback **prev_cb;
+ int ret = -EINVAL;
+
+ rte_spinlock_lock(&rte_eth_rx_cb_lock);
+ prev_cb = &dev->post_rx_burst_cbs[queue_id];
+ for (; *prev_cb != NULL; prev_cb = &cb->next) {
+ cb = *prev_cb;
if (cb == user_cb) {
- prev_cb->next = user_cb->next;
- return 0;
+ /* Remove the user cb from the callback list. */
+ *prev_cb = cb->next;
+ ret = 0;
+ break;
}
+ }
+ rte_spinlock_unlock(&rte_eth_rx_cb_lock);
- } while (cb != NULL);
-
- /* Callback wasn't found. */
- return -EINVAL;
+ return ret;
}
int
@@ -3046,29 +3049,24 @@ rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
}
struct rte_eth_dev *dev = &rte_eth_devices[port_id];
- struct rte_eth_rxtx_callback *cb = dev->pre_tx_burst_cbs[queue_id];
- struct rte_eth_rxtx_callback *prev_cb;
-
- /* Reset head pointer and remove user cb if first in the list. */
- if (cb == user_cb) {
- dev->pre_tx_burst_cbs[queue_id] = user_cb->next;
- return 0;
- }
-
- /* Remove the user cb from the callback list. */
- do {
- prev_cb = cb;
- cb = cb->next;
-
+ int ret = -EINVAL;
+ struct rte_eth_rxtx_callback *cb;
+ struct rte_eth_rxtx_callback **prev_cb;
+
+ rte_spinlock_lock(&rte_eth_tx_cb_lock);
+ prev_cb = &dev->pre_tx_burst_cbs[queue_id];
+ for (; *prev_cb != NULL; prev_cb = &cb->next) {
+ cb = *prev_cb;
if (cb == user_cb) {
- prev_cb->next = user_cb->next;
- return 0;
+ /* Remove the user cb from the callback list. */
+ *prev_cb = cb->next;
+ ret = 0;
+ break;
}
+ }
+ rte_spinlock_unlock(&rte_eth_tx_cb_lock);
- } while (cb != NULL);
-
- /* Callback wasn't found. */
- return -EINVAL;
+ return ret;
}
int
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v4 2/9] librte_ether: add new api rte_eth_add_first_rx_callback
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 0/9] add " Reshma Pattan
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 1/9] librte_ether: protect add/remove of rxtx callbacks with spinlocks Reshma Pattan
@ 2016-05-23 21:38 ` Reshma Pattan
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 3/9] librte_ether: add new fields to rte_eth_dev_info struct Reshma Pattan
` (8 subsequent siblings)
10 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-05-23 21:38 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Added new public api rte_eth_add_first_rx_callback to add given
callback as head of list.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
lib/librte_ether/rte_ethdev.c | 35 ++++++++++++++++++++++++++++++++++
lib/librte_ether/rte_ethdev.h | 27 ++++++++++++++++++++++++++
lib/librte_ether/rte_ether_version.map | 6 ++++++
3 files changed, 68 insertions(+)
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index cf25d8a..6331759 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2959,6 +2959,41 @@ rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
}
void *
+rte_eth_add_first_rx_callback(uint8_t port_id, uint16_t queue_id,
+ rte_rx_callback_fn fn, void *user_param)
+{
+#ifndef RTE_ETHDEV_RXTX_CALLBACKS
+ rte_errno = ENOTSUP;
+ return NULL;
+#endif
+ /* check input parameters */
+ if (!rte_eth_dev_is_valid_port(port_id) || fn == NULL ||
+ queue_id >= rte_eth_devices[port_id].data->nb_rx_queues) {
+ rte_errno = EINVAL;
+ return NULL;
+ }
+
+ struct rte_eth_rxtx_callback *cb = rte_zmalloc(NULL, sizeof(*cb), 0);
+
+ if (cb == NULL) {
+ rte_errno = ENOMEM;
+ return NULL;
+ }
+
+ cb->fn.rx = fn;
+ cb->param = user_param;
+
+ rte_spinlock_lock(&rte_eth_rx_cb_lock);
+ /* Add the callbacks at fisrt position*/
+ cb->next = rte_eth_devices[port_id].post_rx_burst_cbs[queue_id];
+ rte_smp_wmb();
+ rte_eth_devices[port_id].post_rx_burst_cbs[queue_id] = cb;
+ rte_spinlock_unlock(&rte_eth_rx_cb_lock);
+
+ return cb;
+}
+
+void *
rte_eth_add_tx_callback(uint8_t port_id, uint16_t queue_id,
rte_tx_callback_fn fn, void *user_param)
{
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 2757510..92b07a9 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -3825,6 +3825,33 @@ int rte_eth_dev_get_dcb_info(uint8_t port_id,
void *rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
rte_rx_callback_fn fn, void *user_param);
+/*
+* Add a callback that must be called first on packet RX on a given port and queue.
+*
+* This API configures a first function to be called for each burst of
+* packets received on a given NIC port queue. The return value is a pointer
+* that can be used to later remove the callback using
+* rte_eth_remove_rx_callback().
+*
+* Multiple functions are called in the order that they are added.
+*
+* @param port_id
+* The port identifier of the Ethernet device.
+* @param queue_id
+* The queue on the Ethernet device on which the callback is to be added.
+* @param fn
+* The callback function
+* @param user_param
+* A generic pointer parameter which will be passed to each invocation of the
+* callback function on this port and queue.
+*
+* @return
+* NULL on error.
+* On success, a pointer value which can later be used to remove the callback.
+*/
+void *rte_eth_add_first_rx_callback(uint8_t port_id, uint16_t queue_id,
+ rte_rx_callback_fn fn, void *user_param);
+
/**
* Add a callback to be called on packet TX on a given port and queue.
*
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index 214ecc7..c990b04 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -132,3 +132,9 @@ DPDK_16.04 {
rte_eth_tx_buffer_set_err_callback;
} DPDK_2.2;
+
+DPDK_16.07 {
+ global:
+
+ rte_eth_add_first_rx_callback;
+} DPDK_16.04;
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v4 3/9] librte_ether: add new fields to rte_eth_dev_info struct
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 0/9] add " Reshma Pattan
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 1/9] librte_ether: protect add/remove of rxtx callbacks with spinlocks Reshma Pattan
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 2/9] librte_ether: add new api rte_eth_add_first_rx_callback Reshma Pattan
@ 2016-05-23 21:38 ` Reshma Pattan
2016-05-23 22:24 ` Stephen Hemminger
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 4/9] librte_ether: make rte_eth_dev_get_port_by_name api public Reshma Pattan
` (7 subsequent siblings)
10 siblings, 1 reply; 82+ messages in thread
From: Reshma Pattan @ 2016-05-23 21:38 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Add new fields to rte_eth_dev_info struct
New fields nb_rx_queues and nb_tx_queues are added to
rte_eth_dev_info structure.
Changes to API rte_eth_dev_info_get() are done to update
these new fields to rte_eth_dev_info object.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
lib/librte_ether/rte_ethdev.c | 2 ++
lib/librte_ether/rte_ethdev.h | 3 +++
lib/librte_ether/rte_ether_version.map | 1 +
3 files changed, 6 insertions(+)
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 6331759..3ee5b9f 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -1666,6 +1666,8 @@ rte_eth_dev_info_get(uint8_t port_id, struct rte_eth_dev_info *dev_info)
(*dev->dev_ops->dev_infos_get)(dev, dev_info);
dev_info->pci_dev = dev->pci_dev;
dev_info->driver_name = dev->data->drv_name;
+ dev_info->nb_rx_queues = dev->data->nb_rx_queues;
+ dev_info->nb_tx_queues = dev->data->nb_tx_queues;
}
int
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 92b07a9..106318f 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -882,6 +882,9 @@ struct rte_eth_dev_info {
struct rte_eth_desc_lim rx_desc_lim; /**< RX descriptors limits */
struct rte_eth_desc_lim tx_desc_lim; /**< TX descriptors limits */
uint32_t speed_capa; /**< Supported speeds bitmap (ETH_LINK_SPEED_). */
+ /** Configured number of rx/tx queues */
+ uint16_t nb_rx_queues; /**< Number of RX queues. */
+ uint16_t nb_tx_queues; /**< Number of TX queues. */
};
/**
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index c990b04..d06d648 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -137,4 +137,5 @@ DPDK_16.07 {
global:
rte_eth_add_first_rx_callback;
+ rte_eth_dev_info_get;
} DPDK_16.04;
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v4 3/9] librte_ether: add new fields to rte_eth_dev_info struct
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 3/9] librte_ether: add new fields to rte_eth_dev_info struct Reshma Pattan
@ 2016-05-23 22:24 ` Stephen Hemminger
2016-05-24 8:09 ` Pattan, Reshma
0 siblings, 1 reply; 82+ messages in thread
From: Stephen Hemminger @ 2016-05-23 22:24 UTC (permalink / raw)
To: Reshma Pattan; +Cc: dev
On Mon, 23 May 2016 22:38:26 +0100
Reshma Pattan <reshma.pattan@intel.com> wrote:
> Add new fields to rte_eth_dev_info struct
> New fields nb_rx_queues and nb_tx_queues are added to
> rte_eth_dev_info structure.
> Changes to API rte_eth_dev_info_get() are done to update
> these new fields to rte_eth_dev_info object.
>
> Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
This is an ABI break because rte_dev_info_get will clobber the
the stack of the caller if the caller thinks dev_info is old size.
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v4 3/9] librte_ether: add new fields to rte_eth_dev_info struct
2016-05-23 22:24 ` Stephen Hemminger
@ 2016-05-24 8:09 ` Pattan, Reshma
0 siblings, 0 replies; 82+ messages in thread
From: Pattan, Reshma @ 2016-05-24 8:09 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: dev
> -----Original Message-----
> From: Stephen Hemminger [mailto:stephen@networkplumber.org]
> Sent: Monday, May 23, 2016 11:25 PM
> To: Pattan, Reshma <reshma.pattan@intel.com>
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v4 3/9] librte_ether: add new fields to
> rte_eth_dev_info struct
>
> On Mon, 23 May 2016 22:38:26 +0100
> Reshma Pattan <reshma.pattan@intel.com> wrote:
>
> > Add new fields to rte_eth_dev_info struct New fields nb_rx_queues and
> > nb_tx_queues are added to rte_eth_dev_info structure.
> > Changes to API rte_eth_dev_info_get() are done to update these new
> > fields to rte_eth_dev_info object.
> >
> > Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
>
> This is an ABI break because rte_dev_info_get will clobber the the stack of the
> caller if the caller thinks dev_info is old size.
Yes and the ABI breakage was announced as RFC earlier, please check the below mails, now this is formal patch for the same.
http://dpdk.org/ml/archives/dev/2016-April/037458.html
http://dpdk.org/ml/archives/dev/2016-April/037459.html
http://dpdk.org/ml/archives/dev/2016-April/037460.html
Thanks,
Reshma
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v4 4/9] librte_ether: make rte_eth_dev_get_port_by_name api public
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 0/9] add " Reshma Pattan
` (2 preceding siblings ...)
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 3/9] librte_ether: add new fields to rte_eth_dev_info struct Reshma Pattan
@ 2016-05-23 21:38 ` Reshma Pattan
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 5/9] lib/librte_pdump: add new library for packet capturing support Reshma Pattan
` (6 subsequent siblings)
10 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-05-23 21:38 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Converted rte_eth_dev_get_port_by_name to public API.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
lib/librte_ether/rte_ethdev.c | 2 +-
lib/librte_ether/rte_ethdev.h | 15 +++++++++++++++
lib/librte_ether/rte_ether_version.map | 1 +
3 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 3ee5b9f..a50bb1e 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -427,7 +427,7 @@ rte_eth_dev_get_name_by_port(uint8_t port_id, char *name)
return 0;
}
-static int
+int
rte_eth_dev_get_port_by_name(const char *name, uint8_t *port_id)
{
int i;
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 106318f..b20f5cd 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -4283,6 +4283,21 @@ rte_eth_dev_l2_tunnel_offload_set(uint8_t port_id,
uint32_t mask,
uint8_t en);
+/**
+* Get the port id from pci adrress or device name
+* Ex: 0000:2:00.0 or vdev name eth_pcap0
+*
+* @param name
+* pci address or name of the device
+* @param port_id
+* pointer to port identifier of the device
+* @return
+* - (0) if successful.
+* - (-ENODEV) on failure.
+*/
+int
+rte_eth_dev_get_port_by_name(const char *name, uint8_t *port_id);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index d06d648..512f38f 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -137,5 +137,6 @@ DPDK_16.07 {
global:
rte_eth_add_first_rx_callback;
+ rte_eth_dev_get_port_by_name;
rte_eth_dev_info_get;
} DPDK_16.04;
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v4 5/9] lib/librte_pdump: add new library for packet capturing support
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 0/9] add " Reshma Pattan
` (3 preceding siblings ...)
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 4/9] librte_ether: make rte_eth_dev_get_port_by_name api public Reshma Pattan
@ 2016-05-23 21:38 ` Reshma Pattan
2016-05-27 13:39 ` Ananyev, Konstantin
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 6/9] app/pdump: add pdump tool for packet capturing Reshma Pattan
` (5 subsequent siblings)
10 siblings, 1 reply; 82+ messages in thread
From: Reshma Pattan @ 2016-05-23 21:38 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Added new library for packet capturing support.
Added public api rte_pdump_init, applications should call
this as part of their application setup to have packet
capturing framework ready.
Added public api rte_pdump_uninit to un initialize the packet
capturing framework.
Added public apis rte_pdump_enable and rte_pdump_disable to
enable and disable packet capturing on specific port and queue.
Added public apis rte_pdump_enable_by_deviceid and
rte_pdump_disable_by_deviceid to enable and disable packet
capturing on a specific device (pci address or name) and queue.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
MAINTAINERS | 4 +
config/common_base | 5 +
lib/Makefile | 1 +
lib/librte_pdump/Makefile | 55 +++
lib/librte_pdump/rte_pdump.c | 816 +++++++++++++++++++++++++++++++++
lib/librte_pdump/rte_pdump.h | 186 ++++++++
lib/librte_pdump/rte_pdump_version.map | 12 +
mk/rte.app.mk | 1 +
8 files changed, 1080 insertions(+)
create mode 100644 lib/librte_pdump/Makefile
create mode 100644 lib/librte_pdump/rte_pdump.c
create mode 100644 lib/librte_pdump/rte_pdump.h
create mode 100644 lib/librte_pdump/rte_pdump_version.map
diff --git a/MAINTAINERS b/MAINTAINERS
index 9dd0738..8656239 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -433,6 +433,10 @@ F: app/test/test_reorder*
F: examples/packet_ordering/
F: doc/guides/sample_app_ug/packet_ordering.rst
+Pdump
+M: Reshma Pattan <reshma.pattan@intel.com>
+F: lib/librte_pdump/
+
Hierarchical scheduler
M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
F: lib/librte_sched/
diff --git a/config/common_base b/config/common_base
index 3535c6e..259bf0a 100644
--- a/config/common_base
+++ b/config/common_base
@@ -484,6 +484,11 @@ CONFIG_RTE_LIBRTE_DISTRIBUTOR=y
CONFIG_RTE_LIBRTE_REORDER=y
#
+# Compile the pdump library
+#
+CONFIG_RTE_LIBRTE_PDUMP=y
+
+#
# Compile librte_port
#
CONFIG_RTE_LIBRTE_PORT=y
diff --git a/lib/Makefile b/lib/Makefile
index f254dba..ca7c02f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -57,6 +57,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
DIRS-$(CONFIG_RTE_LIBRTE_TABLE) += librte_table
DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += librte_pipeline
DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
+DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += librte_pdump
ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
diff --git a/lib/librte_pdump/Makefile b/lib/librte_pdump/Makefile
new file mode 100644
index 0000000..af81a28
--- /dev/null
+++ b/lib/librte_pdump/Makefile
@@ -0,0 +1,55 @@
+# 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_SDK)/mk/rte.vars.mk
+
+# library name
+LIB = librte_pdump.a
+
+CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
+CFLAGS += -D_GNU_SOURCE
+
+EXPORT_MAP := rte_pdump_version.map
+
+LIBABIVER := 1
+
+# all source are stored in SRCS-y
+SRCS-$(CONFIG_RTE_LIBRTE_PDUMP) := rte_pdump.c
+
+# install this header file
+SYMLINK-$(CONFIG_RTE_LIBRTE_PDUMP)-include := rte_pdump.h
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_ether
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pdump/rte_pdump.c b/lib/librte_pdump/rte_pdump.c
new file mode 100644
index 0000000..915cd37
--- /dev/null
+++ b/lib/librte_pdump/rte_pdump.c
@@ -0,0 +1,816 @@
+/*-
+ * 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 <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <stdbool.h>
+
+#include <rte_memcpy.h>
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_lcore.h>
+#include <rte_log.h>
+#include <rte_errno.h>
+#include <rte_pci.h>
+
+#include "rte_pdump.h"
+
+#define SOCKET_PATH_VAR_RUN "/var/run/pdump_sockets"
+#define SOCKET_PATH_HOME "HOME/pdump_sockets"
+#define SERVER_SOCKET "%s/pdump_server_socket"
+#define CLIENT_SOCKET "%s/pdump_client_socket_%d_%u"
+#define DEVICE_ID_SIZE 64
+/* Macros for printing using RTE_LOG */
+#define RTE_LOGTYPE_PDUMP RTE_LOGTYPE_USER1
+
+enum pdump_operation {
+ DISABLE = 1,
+ ENABLE = 2
+};
+
+enum pdump_socktype {
+ SERVER = 1,
+ CLIENT = 2
+};
+
+enum pdump_version {
+ V1 = 1
+};
+
+static pthread_t pdump_thread;
+static int pdump_socket_fd;
+
+struct pdump_request {
+ uint16_t ver;
+ uint16_t op;
+ uint32_t dir;
+ union pdump_data {
+ struct enable_v1 {
+ char device[DEVICE_ID_SIZE];
+ uint16_t queue;
+ struct rte_ring *ring;
+ struct rte_mempool *mp;
+ void *filter;
+ bool is_pci_or_name;
+ } en_v1;
+ struct disable_v1 {
+ char device[DEVICE_ID_SIZE];
+ uint16_t queue;
+ struct rte_ring *ring;
+ struct rte_mempool *mp;
+ void *filter;
+ bool is_pci_or_name;
+ } dis_v1;
+ } data;
+};
+
+struct pdump_response {
+ uint16_t ver;
+ uint16_t res_op;
+ int32_t err_value;
+};
+
+static struct pdump_rxtx_cbs {
+ struct rte_ring *ring;
+ struct rte_mempool *mp;
+ struct rte_eth_rxtx_callback *cb;
+ void *filter;
+} rx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT],
+tx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
+
+static inline int
+pdump_pktmbuf_copy_data(struct rte_mbuf *seg, const struct rte_mbuf *m)
+{
+ if (rte_pktmbuf_tailroom(seg) < m->data_len) {
+ RTE_LOG(ERR, PDUMP, "User mempool: insufficient data_len of mbuf\n");
+ return -EINVAL;
+ }
+
+ seg->port = m->port;
+ seg->vlan_tci = m->vlan_tci;
+ seg->hash = m->hash;
+ seg->tx_offload = m->tx_offload;
+ seg->ol_flags = m->ol_flags;
+ seg->packet_type = m->packet_type;
+ seg->vlan_tci_outer = m->vlan_tci_outer;
+ seg->data_len = m->data_len;
+ seg->pkt_len = seg->data_len;
+ rte_memcpy(rte_pktmbuf_mtod(seg, void *),
+ rte_pktmbuf_mtod(m, void *),
+ rte_pktmbuf_data_len(seg));
+
+ __rte_mbuf_sanity_check(seg, 1);
+
+ return 0;
+}
+
+static inline struct rte_mbuf *
+pdump_pktmbuf_copy(struct rte_mbuf *m, struct rte_mempool *mp)
+{
+ struct rte_mbuf *m_dup, *seg, **prev;
+ uint32_t pktlen;
+ uint8_t nseg;
+
+ m_dup = rte_pktmbuf_alloc(mp);
+ if (unlikely(m_dup == NULL))
+ return NULL;
+
+ seg = m_dup;
+ prev = &seg->next;
+ pktlen = m->pkt_len;
+ nseg = 0;
+
+ do {
+ nseg++;
+ if (pdump_pktmbuf_copy_data(seg, m) < 0) {
+ rte_pktmbuf_free(m_dup);
+ return NULL;
+ }
+ *prev = seg;
+ prev = &seg->next;
+ } while ((m = m->next) != NULL &&
+ (seg = rte_pktmbuf_alloc(mp)) != NULL);
+
+ *prev = NULL;
+ m_dup->nb_segs = nseg;
+ m_dup->pkt_len = pktlen;
+
+ /* Allocation of new indirect segment failed */
+ if (unlikely(seg == NULL)) {
+ rte_pktmbuf_free(m_dup);
+ return NULL;
+ }
+
+ __rte_mbuf_sanity_check(m_dup, 1);
+ return m_dup;
+}
+
+static inline void
+pdump_copy(struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
+{
+ unsigned i;
+ int ring_enq;
+ uint16_t d_pkts = 0;
+ struct rte_mbuf *dup_bufs[nb_pkts];
+ struct pdump_rxtx_cbs *cbs;
+ struct rte_ring *ring;
+ struct rte_mempool *mp;
+ struct rte_mbuf *p;
+
+ cbs = user_params;
+ ring = cbs->ring;
+ mp = cbs->mp;
+ for (i = 0; i < nb_pkts; i++) {
+ p = pdump_pktmbuf_copy(pkts[i], mp);
+ if (p)
+ dup_bufs[d_pkts++] = p;
+ }
+
+ ring_enq = rte_ring_enqueue_burst(ring, (void *)dup_bufs, d_pkts);
+ if (unlikely(ring_enq < d_pkts)) {
+ RTE_LOG(DEBUG, PDUMP, "only %d of packets enqueued to ring\n", ring_enq);
+ do {
+ rte_pktmbuf_free(dup_bufs[ring_enq]);
+ } while (++ring_enq < d_pkts);
+ }
+}
+
+static uint16_t
+pdump_rx(uint8_t port __rte_unused, uint16_t qidx __rte_unused,
+ struct rte_mbuf **pkts, uint16_t nb_pkts, uint16_t max_pkts __rte_unused,
+ void *user_params)
+{
+ pdump_copy(pkts, nb_pkts, user_params);
+ return nb_pkts;
+}
+
+static uint16_t
+pdump_tx(uint8_t port __rte_unused, uint16_t qidx __rte_unused,
+ struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
+{
+ pdump_copy(pkts, nb_pkts, user_params);
+ return nb_pkts;
+}
+
+static int
+pdump_get_dombdf(char *device_id, char *domBDF)
+{
+ int ret;
+ struct rte_pci_addr dev_addr = {0};
+
+ ret = eal_parse_pci_DomBDF(device_id, &dev_addr);
+ if (ret < 0)
+ return -1;
+
+ if (dev_addr.domain)
+ snprintf(domBDF, DEVICE_ID_SIZE, "%u:%u:%u.%u", dev_addr.domain,
+ dev_addr.bus, dev_addr.devid, dev_addr.function);
+ else
+ snprintf(domBDF, DEVICE_ID_SIZE, "%u:%u.%u", dev_addr.bus, dev_addr.devid,
+ dev_addr.function);
+
+ return 0;
+}
+
+static int
+pdump_regitser_callbacks(uint32_t dir, uint16_t end_q,
+ uint8_t port, uint16_t queue,
+ struct rte_ring *ring, struct rte_mempool *mp,
+ uint16_t operation)
+{
+
+ uint16_t qid;
+ struct pdump_rxtx_cbs *cbs = NULL;
+
+ qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
+ for (; qid < end_q; qid++) {
+ if ((dir & RTE_PDUMP_FLAG_RX) != 0)
+ cbs = &rx_cbs[port][qid];
+ if ((dir & RTE_PDUMP_FLAG_TX) != 0)
+ cbs = &tx_cbs[port][qid];
+ if (cbs && operation == ENABLE) {
+ if (cbs->cb) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to add callback for port=%d and "
+ "queue=%d, callback already exists\n",
+ port, qid);
+ return -EEXIST;
+ }
+ cbs->ring = ring;
+ cbs->mp = mp;
+ if ((dir & RTE_PDUMP_FLAG_RX) != 0) {
+ cbs->cb = rte_eth_add_first_rx_callback(port, qid,
+ pdump_rx, cbs);
+ if (cbs->cb == NULL) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to add rx callback, errno=%d\n",
+ rte_errno);
+ return rte_errno;
+ }
+ }
+ if ((dir & RTE_PDUMP_FLAG_TX) != 0) {
+ cbs->cb = rte_eth_add_tx_callback(port, qid, pdump_tx,
+ cbs);
+ if (cbs->cb == NULL) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to add tx callback, errno=%d\n",
+ rte_errno);
+ return rte_errno;
+ }
+ }
+ }
+ if (cbs && operation == DISABLE) {
+ int ret;
+
+ if (cbs->cb == NULL) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to delete non existing callback "
+ "for port=%d and queue=%d\n", port, qid);
+ return -EINVAL;
+ }
+ if ((dir & RTE_PDUMP_FLAG_RX) != 0) {
+ ret = rte_eth_remove_rx_callback(port, qid, cbs->cb);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to remove rx callback, errno=%d\n",
+ rte_errno);
+ return ret;
+ }
+ }
+ if ((dir & RTE_PDUMP_FLAG_TX) != 0) {
+ ret = rte_eth_remove_tx_callback(port, qid, cbs->cb);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to remove tx callback, errno=%d\n",
+ rte_errno);
+ return ret;
+ }
+ }
+ cbs->cb = NULL;
+ }
+ }
+
+ return 0;
+}
+
+static int
+set_pdump_rxtx_cbs(struct pdump_request *p)
+{
+ uint16_t nb_rx_q, nb_tx_q = 0, end_q, queue;
+ uint8_t port;
+ int ret = 0;
+ uint32_t dir;
+ uint16_t operation;
+ struct rte_ring *ring;
+ struct rte_mempool *mp;
+ char domBDF[DEVICE_ID_SIZE];
+
+ dir = p->dir;
+ operation = p->op;
+ if (operation == ENABLE) {
+ if (p->data.en_v1.is_pci_or_name == true) {
+ /* check if device is pci address or name */
+ if (pdump_get_dombdf(p->data.en_v1.device, domBDF) == 0)
+ ret = rte_eth_dev_get_port_by_name(domBDF, &port);
+ else
+ ret = rte_eth_dev_get_port_by_name(p->data.en_v1.device,
+ &port);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to get potid for device id=%s\n",
+ p->data.en_v1.device);
+ return -EINVAL;
+ }
+ } else /* if device is port id */
+ port = atoi(p->data.en_v1.device);
+ queue = p->data.en_v1.queue;
+ ring = p->data.en_v1.ring;
+ mp = p->data.en_v1.mp;
+ } else {
+ if (p->data.dis_v1.is_pci_or_name == true) {
+ /* check if device is pci address or name */
+ if (pdump_get_dombdf(p->data.dis_v1.device, domBDF) == 0)
+ ret = rte_eth_dev_get_port_by_name(domBDF, &port);
+ else
+ ret = rte_eth_dev_get_port_by_name(p->data.dis_v1.device,
+ &port);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to get potid for device id=%s\n",
+ p->data.dis_v1.device);
+ return -EINVAL;
+ }
+ } else /* if device is port id */
+ port = atoi(p->data.dis_v1.device);
+ queue = p->data.dis_v1.queue;
+ ring = p->data.dis_v1.ring;
+ mp = p->data.dis_v1.mp;
+ }
+
+ /* validation if packet capture is for all queues */
+ if (queue == RTE_PDUMP_ALL_QUEUES) {
+ struct rte_eth_dev_info dev_info;
+
+ rte_eth_dev_info_get(port, &dev_info);
+ nb_rx_q = dev_info.nb_rx_queues;
+ nb_tx_q = dev_info.nb_tx_queues;
+ if (nb_rx_q == 0 && dir == RTE_PDUMP_FLAG_RX) {
+ RTE_LOG(ERR, PDUMP, "number of rx queues cannot be 0\n");
+ return -EINVAL;
+ }
+ if (nb_tx_q == 0 && dir == RTE_PDUMP_FLAG_TX) {
+ RTE_LOG(ERR, PDUMP, "number of tx queues cannot be 0\n");
+ return -EINVAL;
+ }
+ if ((nb_tx_q == 0 || nb_rx_q == 0) && dir == RTE_PDUMP_FLAG_RXTX) {
+ RTE_LOG(ERR, PDUMP, "both tx&rx queues must be non zero\n");
+ return -EINVAL;
+ }
+ }
+
+ /* register RX callback for dir rx/rxtx */
+ if (dir == RTE_PDUMP_FLAG_RX || dir == RTE_PDUMP_FLAG_RXTX) {
+ end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_rx_q : queue + 1;
+ ret = pdump_regitser_callbacks(RTE_PDUMP_FLAG_RX, end_q, port, queue,
+ ring, mp, operation);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* register TX callback for dir tx/rxtx */
+ if (dir == RTE_PDUMP_FLAG_TX || dir == RTE_PDUMP_FLAG_RXTX) {
+ end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_tx_q : queue + 1;
+ ret = pdump_regitser_callbacks(RTE_PDUMP_FLAG_TX, end_q, port, queue,
+ ring, mp, operation);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ret;
+}
+
+/* get socket path (/var/run if root, $HOME otherwise) */
+static void
+pdump_get_socket_path(char *buffer, int bufsz, enum pdump_socktype type)
+{
+ const char *dir = SOCKET_PATH_VAR_RUN;
+ const char *home_dir = getenv(SOCKET_PATH_HOME);
+
+ if (getuid() != 0 && home_dir != NULL)
+ dir = home_dir;
+
+ mkdir(dir, 700);
+ if (type == SERVER)
+ snprintf(buffer, bufsz, SERVER_SOCKET, dir);
+ else
+ snprintf(buffer, bufsz, CLIENT_SOCKET, dir, getpid(),
+ rte_sys_gettid());
+}
+
+static int
+pdump_create_server_socket(void)
+{
+ int ret, socket_fd;
+ struct sockaddr_un addr;
+ socklen_t addr_len;
+
+ pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), SERVER);
+ addr.sun_family = AF_UNIX;
+
+ /* remove if file already exists */
+ unlink(addr.sun_path);
+
+ /* set up a server socket */
+ socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (socket_fd < 0) {
+ RTE_LOG(ERR, PDUMP, "Failed to create server socket: %s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ return -1;
+ }
+
+ addr_len = sizeof(struct sockaddr_un);
+ ret = bind(socket_fd, (struct sockaddr *) &addr, addr_len);
+ if (ret) {
+ RTE_LOG(ERR, PDUMP, "Failed to bind to server socket: %s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ close(socket_fd);
+ return -1;
+ }
+
+ /* save the socket in local configuration */
+ pdump_socket_fd = socket_fd;
+
+ return 0;
+}
+
+static __attribute__((noreturn)) void *
+pdump_thread_main(__rte_unused void *arg)
+{
+ struct sockaddr_un cli_addr;
+ socklen_t cli_len;
+ struct pdump_request cli_req;
+ struct pdump_response resp;
+ int n;
+ int ret = 0;
+
+ /* host thread, never break out */
+ for (;;) {
+ /* recv client requests */
+ cli_len = sizeof(cli_addr);
+ n = recvfrom(pdump_socket_fd, &cli_req, sizeof(struct pdump_request), 0,
+ (struct sockaddr *)&cli_addr, &cli_len);
+ if (n < 0) {
+ RTE_LOG(ERR, PDUMP, "failed to recv from client:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ continue;
+ }
+
+ ret = set_pdump_rxtx_cbs(&cli_req);
+
+ resp.ver = cli_req.ver;
+ resp.res_op = cli_req.op;
+ resp.err_value = ret;
+ n = sendto(pdump_socket_fd, &resp, sizeof(struct pdump_response),
+ 0, (struct sockaddr *)&cli_addr, cli_len);
+ if (n < 0) {
+ RTE_LOG(ERR, PDUMP, "failed to send to client:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ }
+ }
+}
+
+int
+rte_pdump_init(void)
+{
+ int ret = 0;
+ char thread_name[RTE_MAX_THREAD_NAME_LEN];
+
+ ret = pdump_create_server_socket();
+ if (ret != 0) {
+ RTE_LOG(ERR, PDUMP, "Failed to create server socket:%s:%d\n",
+ __func__, __LINE__);
+ return -1;
+ }
+
+ /* create the host thread to wait/handle pdump requests */
+ ret = pthread_create(&pdump_thread, NULL, pdump_thread_main, NULL);
+ if (ret != 0) {
+ RTE_LOG(ERR, PDUMP, "Failed to create the pdump thread:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ return -1;
+ }
+ /* Set thread_name for aid in debugging. */
+ snprintf(thread_name, RTE_MAX_THREAD_NAME_LEN, "pdump-thread");
+ ret = rte_thread_setname(pdump_thread, thread_name);
+ if (ret != 0) {
+ RTE_LOG(DEBUG, PDUMP,
+ "Failed to set thread name for pdump handling\n");
+ }
+
+ return 0;
+}
+
+int
+rte_pdump_uninit(void)
+{
+ int ret;
+
+ ret = pthread_cancel(pdump_thread);
+ if (ret != 0) {
+ RTE_LOG(ERR, PDUMP, "Failed to cancel the pdump thread:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ return -1;
+ }
+
+ ret = close(pdump_socket_fd);
+ if (ret != 0) {
+ RTE_LOG(ERR, PDUMP, "Failed to close server socket: %s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ return -1;
+ }
+
+ struct sockaddr_un addr;
+
+ pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), SERVER);
+ ret = unlink(addr.sun_path);
+ if (ret != 0) {
+ RTE_LOG(ERR, PDUMP, "Failed to remove server socket addr: %s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+pdump_create_client_socket(struct pdump_request *p)
+{
+ int ret, socket_fd;
+ int pid;
+ int n;
+ struct pdump_response server_resp;
+ struct sockaddr_un addr, serv_addr, from;
+ socklen_t addr_len, serv_len;
+
+ pid = getpid();
+
+ socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (socket_fd < 0) {
+ RTE_LOG(ERR, PDUMP, "client socket(): %s:pid(%d):tid(%u), %s:%d\n",
+ strerror(errno), pid, rte_sys_gettid(), __func__, __LINE__);
+ ret = errno;
+ return ret;
+ }
+
+ pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), CLIENT);
+ addr.sun_family = AF_UNIX;
+ addr_len = sizeof(struct sockaddr_un);
+
+ do {
+ ret = bind(socket_fd, (struct sockaddr *) &addr, addr_len);
+ if (ret) {
+ RTE_LOG(ERR, PDUMP, "client bind(): %s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ ret = errno;
+ break;
+ }
+
+ serv_len = sizeof(struct sockaddr_un);
+ memset(&serv_addr, 0, sizeof(serv_addr));
+ pdump_get_socket_path(serv_addr.sun_path, sizeof(serv_addr.sun_path),
+ SERVER);
+ serv_addr.sun_family = AF_UNIX;
+
+ n = sendto(socket_fd, p, sizeof(struct pdump_request), 0,
+ (struct sockaddr *)&serv_addr, serv_len);
+ if (n < 0) {
+ RTE_LOG(ERR, PDUMP, "failed to send to server:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ ret = errno;
+ break;
+ }
+
+ n = recvfrom(socket_fd, &server_resp, sizeof(struct pdump_response), 0,
+ (struct sockaddr *)&from, &serv_len);
+ if (n < 0) {
+ RTE_LOG(ERR, PDUMP, "failed to recv from server:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ ret = errno;
+ break;
+ }
+ ret = server_resp.err_value;
+ } while (0);
+
+ close(socket_fd);
+ unlink(addr.sun_path);
+ return ret;
+}
+
+static int
+pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp)
+{
+ if (ring == NULL || mp == NULL) {
+ RTE_LOG(ERR, PDUMP, "NULL ring or mempool are passed %s:%d\n",
+ __func__, __LINE__);
+ rte_errno = EINVAL;
+ return -1;
+ }
+ if (mp->flags & MEMPOOL_F_SP_PUT || mp->flags & MEMPOOL_F_SC_GET) {
+ RTE_LOG(ERR, PDUMP, "mempool with either SP or SC settings"
+ " is not valid for pdump, should have MP and MC settings\n");
+ rte_errno = EINVAL;
+ return -1;
+ }
+ if (ring->prod.sp_enqueue || ring->cons.sc_dequeue) {
+ RTE_LOG(ERR, PDUMP, "ring with either SP or SC settings"
+ " is not valid for pdump, should have MP and MC settings\n");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+pdump_validate_dir(uint32_t dir)
+{
+ if (dir != RTE_PDUMP_FLAG_RX && dir != RTE_PDUMP_FLAG_TX &&
+ dir != RTE_PDUMP_FLAG_RXTX) {
+ RTE_LOG(ERR, PDUMP, "invalid direction, should be either rx/tx/rxtx\n");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+pdump_validate_port(uint8_t port)
+{
+ if (port >= RTE_MAX_ETHPORTS) {
+ RTE_LOG(ERR, PDUMP, "Invalid port id %u, %s:%d\n", port,
+ __func__, __LINE__);
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+pdump_prepare_client_request(char *device, bool is_pci_or_name, uint16_t queue,
+ uint32_t dir,
+ uint16_t operation,
+ struct rte_ring *ring,
+ struct rte_mempool *mp,
+ void *filter)
+{
+ int ret;
+ struct pdump_request req = {.ver = 1,};
+
+ req.dir = dir;
+ req.op = operation;
+ if ((operation & ENABLE) != 0) {
+ strncpy(req.data.en_v1.device, device, strlen(device));
+ req.data.en_v1.is_pci_or_name = is_pci_or_name;
+ req.data.en_v1.queue = queue;
+ req.data.en_v1.ring = ring;
+ req.data.en_v1.mp = mp;
+ req.data.en_v1.filter = filter;
+ } else {
+ strncpy(req.data.dis_v1.device, device, strlen(device));
+ req.data.dis_v1.is_pci_or_name = is_pci_or_name;
+ req.data.dis_v1.queue = queue;
+ req.data.dis_v1.ring = NULL;
+ req.data.dis_v1.mp = NULL;
+ req.data.dis_v1.filter = NULL;
+ }
+
+ ret = pdump_create_client_socket(&req);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP, "client request for pdump enable/disable failed\n");
+ rte_errno = ret;
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+rte_pdump_enable(uint8_t port, uint16_t queue, uint32_t dir,
+ struct rte_ring *ring,
+ struct rte_mempool *mp,
+ void *filter)
+{
+
+ int ret = 0;
+ char device[DEVICE_ID_SIZE];
+
+ ret = pdump_validate_port(port);
+ if (ret < 0)
+ return ret;
+ ret = pdump_validate_ring_mp(ring, mp);
+ if (ret < 0)
+ return ret;
+ pdump_validate_dir(dir);
+ if (ret < 0)
+ return ret;
+
+ snprintf(device, sizeof(device), "%u", port);
+ ret = pdump_prepare_client_request(device, false, queue, dir,
+ ENABLE, ring, mp, filter);
+
+ return ret;
+}
+
+int
+rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
+ uint32_t dir,
+ struct rte_ring *ring,
+ struct rte_mempool *mp,
+ void *filter)
+{
+ int ret = 0;
+
+ ret = pdump_validate_ring_mp(ring, mp);
+ if (ret < 0)
+ return ret;
+ ret = pdump_validate_dir(dir);
+ if (ret < 0)
+ return ret;
+
+ ret = pdump_prepare_client_request(device_id, true, queue, dir,
+ ENABLE, ring, mp, filter);
+
+ return ret;
+}
+
+int
+rte_pdump_disable(uint8_t port, uint16_t queue, uint32_t dir)
+{
+ int ret = 0;
+ char device[DEVICE_ID_SIZE];
+
+ ret = pdump_validate_port(port);
+ if (ret < 0)
+ return ret;
+ ret = pdump_validate_dir(dir);
+ if (ret < 0)
+ return ret;
+
+ snprintf(device, sizeof(device), "%u", port);
+ ret = pdump_prepare_client_request(device, false, queue, dir,
+ DISABLE, NULL, NULL, NULL);
+
+ return ret;
+}
+
+int
+rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
+ uint32_t dir)
+{
+ int ret = 0;
+
+ ret = pdump_validate_dir(dir);
+ if (ret < 0)
+ return ret;
+
+ ret = pdump_prepare_client_request(device_id, true, queue, dir,
+ DISABLE, NULL, NULL, NULL);
+
+ return ret;
+}
diff --git a/lib/librte_pdump/rte_pdump.h b/lib/librte_pdump/rte_pdump.h
new file mode 100644
index 0000000..fcd02de
--- /dev/null
+++ b/lib/librte_pdump/rte_pdump.h
@@ -0,0 +1,186 @@
+/*-
+ * 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.
+ */
+
+#ifndef _RTE_PDUMP_H_
+#define _RTE_PDUMP_H_
+
+/**
+ * @file
+ * RTE pdump
+ *
+ * packet dump library to provide packet capturing support on dpdk.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RTE_PDUMP_ALL_QUEUES UINT16_MAX
+
+enum {
+ RTE_PDUMP_FLAG_RX = 1, /* receive direction */
+ RTE_PDUMP_FLAG_TX = 2, /* transmit direction */
+ /* both receive and transmit directions */
+ RTE_PDUMP_FLAG_RXTX = (RTE_PDUMP_FLAG_RX|RTE_PDUMP_FLAG_TX)
+};
+
+/**
+ * Initialize packet capturing handling
+ *
+ * Creates pthread and server socket for handling clients
+ * requests to enable/disable rxtx callbacks.
+ *
+ * @return
+ * 0 on success, -1 on error
+ */
+int
+rte_pdump_init(void);
+
+/**
+ * Un initialize packet capturing handling
+ *
+ * Cancels pthread, close server socket, removes server socket address.
+ *
+ * @return
+ * 0 on success, -1 on error
+ */
+int
+rte_pdump_uninit(void);
+
+/**
+ * Enables packet capturing on given port and queue.
+ *
+ * @param port
+ * port on which packet capturing should be enabled.
+ * @param queue
+ * queue of a given port on which packet capturing should be enabled.
+ * users should pass on value UINT16_MAX to enable packet capturing on all
+ * queues of a given port.
+ * @param dir
+ * dir specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
+ * on which packet capturing should be enabled for a given port and queue.
+ * @param ring
+ * ring on which captured packets will be enqueued for user.
+ * @param mp
+ * mempool on to which original packets will be mirrored or duplicated.
+ * @param filter
+ * place holder for packet filtering.
+ *
+ * @return
+ * 0 on success, -1 on error, rte_errno is set accordingly.
+ */
+
+int
+rte_pdump_enable(uint8_t port, uint16_t queue, uint32_t dir,
+ struct rte_ring *ring,
+ struct rte_mempool *mp,
+ void *filter);
+
+/**
+ * Disables packet capturing on given port and queue.
+ *
+ * @param port
+ * port on which packet capturing should be disabled.
+ * @param queue
+ * queue of a given port on which packet capturing should be disabled.
+ * users should pass on value UINT16_MAX to disable packet capturing on all
+ * queues of a given port.
+ * @param dir
+ * dir specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
+ * on which packet capturing should be enabled for a given port and queue.
+ *
+ * @return
+ * 0 on success, -1 on error, rte_errno is set accordingly.
+ */
+
+int
+rte_pdump_disable(uint8_t port, uint16_t queue, uint32_t dir);
+
+/**
+ * Enables packet capturing on given device id and queue.
+ * device_id can be name or pci address of device.
+ *
+ * @param device_id
+ * device id on which packet capturing should be enabled.
+ * @param queue
+ * queue of a given device id on which packet capturing should be enabled.
+ * users should pass on value UINT16_MAX to enable packet capturing on all
+ * queues of a given device id.
+ * @param dir
+ * dir specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
+ * on which packet capturing should be enabled for a given port and queue.
+ * @param ring
+ * ring on which captured packets will be enqueued for user.
+ * @param mp
+ * mempool on to which original packets will be mirrored or duplicated.
+ * @param filter
+ * place holder for packet filtering.
+ *
+ * @return
+ * 0 on success, -1 on error, rte_errno is set accordingly.
+ */
+
+int
+rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
+ uint32_t dir,
+ struct rte_ring *ring,
+ struct rte_mempool *mp,
+ void *filter);
+
+/**
+ * Disables packet capturing on given device_id and queue.
+ * device_id can be name or pci address of device.
+ *
+ * @param device_id
+ * pci address or name of the device on which packet capturing
+ * should be disabled.
+ * @param queue
+ * queue of a given device on which packet capturing should be disabled.
+ * users should pass on value UINT16_MAX to disable packet capturing on all
+ * queues of a given device id.
+ * @param dir
+ * dir specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
+ * on which packet capturing should be enabled for a given port and queue.
+ *
+ * @return
+ * 0 on success, -1 on error, rte_errno is set accordingly.
+ */
+int
+rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
+ uint32_t dir);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_PDUMP_H_ */
diff --git a/lib/librte_pdump/rte_pdump_version.map b/lib/librte_pdump/rte_pdump_version.map
new file mode 100644
index 0000000..3e744f3
--- /dev/null
+++ b/lib/librte_pdump/rte_pdump_version.map
@@ -0,0 +1,12 @@
+DPDK_16.07 {
+ global:
+
+ rte_pdump_disable;
+ rte_pdump_disable_by_deviceid;
+ rte_pdump_enable;
+ rte_pdump_enable_by_deviceid;
+ rte_pdump_init;
+ rte_pdump_uninit;
+
+ local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index b84b56d..f792f2a 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -61,6 +61,7 @@ _LDLIBS-y += --whole-archive
_LDLIBS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += -lrte_distributor
_LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER) += -lrte_reorder
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PDUMP) += -lrte_pdump
ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
_LDLIBS-$(CONFIG_RTE_LIBRTE_KNI) += -lrte_kni
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v4 5/9] lib/librte_pdump: add new library for packet capturing support
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 5/9] lib/librte_pdump: add new library for packet capturing support Reshma Pattan
@ 2016-05-27 13:39 ` Ananyev, Konstantin
2016-05-27 14:54 ` Pattan, Reshma
2016-05-31 15:00 ` Pattan, Reshma
0 siblings, 2 replies; 82+ messages in thread
From: Ananyev, Konstantin @ 2016-05-27 13:39 UTC (permalink / raw)
To: Pattan, Reshma, dev; +Cc: Pattan, Reshma
Hi Reshma,
>
> Added new library for packet capturing support.
>
> Added public api rte_pdump_init, applications should call
> this as part of their application setup to have packet
> capturing framework ready.
>
> Added public api rte_pdump_uninit to un initialize the packet
> capturing framework.
>
> Added public apis rte_pdump_enable and rte_pdump_disable to
> enable and disable packet capturing on specific port and queue.
>
> Added public apis rte_pdump_enable_by_deviceid and
> rte_pdump_disable_by_deviceid to enable and disable packet
> capturing on a specific device (pci address or name) and queue.
>
> Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
> ---
> MAINTAINERS | 4 +
> config/common_base | 5 +
> lib/Makefile | 1 +
> lib/librte_pdump/Makefile | 55 +++
> lib/librte_pdump/rte_pdump.c | 816 +++++++++++++++++++++++++++++++++
> lib/librte_pdump/rte_pdump.h | 186 ++++++++
> lib/librte_pdump/rte_pdump_version.map | 12 +
> mk/rte.app.mk | 1 +
> 8 files changed, 1080 insertions(+)
> create mode 100644 lib/librte_pdump/Makefile
> create mode 100644 lib/librte_pdump/rte_pdump.c
> create mode 100644 lib/librte_pdump/rte_pdump.h
> create mode 100644 lib/librte_pdump/rte_pdump_version.map
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 9dd0738..8656239 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -433,6 +433,10 @@ F: app/test/test_reorder*
> F: examples/packet_ordering/
> F: doc/guides/sample_app_ug/packet_ordering.rst
>
> +Pdump
> +M: Reshma Pattan <reshma.pattan@intel.com>
> +F: lib/librte_pdump/
> +
> Hierarchical scheduler
> M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
> F: lib/librte_sched/
> diff --git a/config/common_base b/config/common_base
> index 3535c6e..259bf0a 100644
> --- a/config/common_base
> +++ b/config/common_base
> @@ -484,6 +484,11 @@ CONFIG_RTE_LIBRTE_DISTRIBUTOR=y
> CONFIG_RTE_LIBRTE_REORDER=y
>
> #
> +# Compile the pdump library
> +#
> +CONFIG_RTE_LIBRTE_PDUMP=y
> +
> +#
> # Compile librte_port
> #
> CONFIG_RTE_LIBRTE_PORT=y
> diff --git a/lib/Makefile b/lib/Makefile
> index f254dba..ca7c02f 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -57,6 +57,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
> DIRS-$(CONFIG_RTE_LIBRTE_TABLE) += librte_table
> DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += librte_pipeline
> DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
> +DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += librte_pdump
>
> ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
> DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
> diff --git a/lib/librte_pdump/Makefile b/lib/librte_pdump/Makefile
> new file mode 100644
> index 0000000..af81a28
> --- /dev/null
> +++ b/lib/librte_pdump/Makefile
> @@ -0,0 +1,55 @@
> +# 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_SDK)/mk/rte.vars.mk
> +
> +# library name
> +LIB = librte_pdump.a
> +
> +CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
> +CFLAGS += -D_GNU_SOURCE
> +
> +EXPORT_MAP := rte_pdump_version.map
> +
> +LIBABIVER := 1
> +
> +# all source are stored in SRCS-y
> +SRCS-$(CONFIG_RTE_LIBRTE_PDUMP) := rte_pdump.c
> +
> +# install this header file
> +SYMLINK-$(CONFIG_RTE_LIBRTE_PDUMP)-include := rte_pdump.h
> +
> +# this lib depends upon:
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_mbuf
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_eal
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_ether
> +
> +include $(RTE_SDK)/mk/rte.lib.mk
> diff --git a/lib/librte_pdump/rte_pdump.c b/lib/librte_pdump/rte_pdump.c
> new file mode 100644
> index 0000000..915cd37
> --- /dev/null
> +++ b/lib/librte_pdump/rte_pdump.c
> @@ -0,0 +1,816 @@
> +/*-
> + * 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 <sys/socket.h>
> +#include <sys/un.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include <pthread.h>
> +#include <stdbool.h>
> +
> +#include <rte_memcpy.h>
> +#include <rte_mbuf.h>
> +#include <rte_ethdev.h>
> +#include <rte_lcore.h>
> +#include <rte_log.h>
> +#include <rte_errno.h>
> +#include <rte_pci.h>
> +
> +#include "rte_pdump.h"
> +
> +#define SOCKET_PATH_VAR_RUN "/var/run/pdump_sockets"
> +#define SOCKET_PATH_HOME "HOME/pdump_sockets"
> +#define SERVER_SOCKET "%s/pdump_server_socket"
> +#define CLIENT_SOCKET "%s/pdump_client_socket_%d_%u"
> +#define DEVICE_ID_SIZE 64
> +/* Macros for printing using RTE_LOG */
> +#define RTE_LOGTYPE_PDUMP RTE_LOGTYPE_USER1
> +
> +enum pdump_operation {
> + DISABLE = 1,
> + ENABLE = 2
> +};
> +
> +enum pdump_socktype {
> + SERVER = 1,
> + CLIENT = 2
> +};
> +
> +enum pdump_version {
> + V1 = 1
> +};
> +
> +static pthread_t pdump_thread;
> +static int pdump_socket_fd;
> +
> +struct pdump_request {
> + uint16_t ver;
> + uint16_t op;
> + uint32_t dir;
I understand why you named it 'dir' (as right now it could be only RX & TX),
but I think we better name it in a more generic way: flags or so.
There are 29 unused bits right now, and probably in future will use it
For something more than just traffic direction indication.
> + union pdump_data {
> + struct enable_v1 {
> + char device[DEVICE_ID_SIZE];
> + uint16_t queue;
> + struct rte_ring *ring;
> + struct rte_mempool *mp;
> + void *filter;
> + bool is_pci_or_name;
> + } en_v1;
> + struct disable_v1 {
> + char device[DEVICE_ID_SIZE];
> + uint16_t queue;
> + struct rte_ring *ring;
> + struct rte_mempool *mp;
> + void *filter;
> + bool is_pci_or_name;
> + } dis_v1;
> + } data;
> +};
> +
> +struct pdump_response {
> + uint16_t ver;
> + uint16_t res_op;
> + int32_t err_value;
> +};
> +
> +static struct pdump_rxtx_cbs {
> + struct rte_ring *ring;
> + struct rte_mempool *mp;
> + struct rte_eth_rxtx_callback *cb;
> + void *filter;
> +} rx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT],
> +tx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
> +
> +static inline int
> +pdump_pktmbuf_copy_data(struct rte_mbuf *seg, const struct rte_mbuf *m)
> +{
> + if (rte_pktmbuf_tailroom(seg) < m->data_len) {
> + RTE_LOG(ERR, PDUMP, "User mempool: insufficient data_len of mbuf\n");
> + return -EINVAL;
> + }
> +
> + seg->port = m->port;
> + seg->vlan_tci = m->vlan_tci;
> + seg->hash = m->hash;
> + seg->tx_offload = m->tx_offload;
> + seg->ol_flags = m->ol_flags;
> + seg->packet_type = m->packet_type;
> + seg->vlan_tci_outer = m->vlan_tci_outer;
> + seg->data_len = m->data_len;
> + seg->pkt_len = seg->data_len;
> + rte_memcpy(rte_pktmbuf_mtod(seg, void *),
> + rte_pktmbuf_mtod(m, void *),
> + rte_pktmbuf_data_len(seg));
> +
> + __rte_mbuf_sanity_check(seg, 1);
And I don't think you need that sanity_check() here at all, as you call it anyway
in pdump_pktmbuf_copy().
But if you still like to have it there, then _sanity_check(seg, 0) seems enough here.
> +
> + return 0;
> +}
> +
> +static inline struct rte_mbuf *
> +pdump_pktmbuf_copy(struct rte_mbuf *m, struct rte_mempool *mp)
> +{
> + struct rte_mbuf *m_dup, *seg, **prev;
> + uint32_t pktlen;
> + uint8_t nseg;
> +
> + m_dup = rte_pktmbuf_alloc(mp);
> + if (unlikely(m_dup == NULL))
> + return NULL;
> +
> + seg = m_dup;
> + prev = &seg->next;
> + pktlen = m->pkt_len;
> + nseg = 0;
> +
> + do {
> + nseg++;
> + if (pdump_pktmbuf_copy_data(seg, m) < 0) {
> + rte_pktmbuf_free(m_dup);
> + return NULL;
> + }
> + *prev = seg;
> + prev = &seg->next;
> + } while ((m = m->next) != NULL &&
> + (seg = rte_pktmbuf_alloc(mp)) != NULL);
> +
> + *prev = NULL;
> + m_dup->nb_segs = nseg;
> + m_dup->pkt_len = pktlen;
> +
> + /* Allocation of new indirect segment failed */
> + if (unlikely(seg == NULL)) {
> + rte_pktmbuf_free(m_dup);
> + return NULL;
> + }
> +
> + __rte_mbuf_sanity_check(m_dup, 1);
> + return m_dup;
> +}
> +
> +static inline void
> +pdump_copy(struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
> +{
> + unsigned i;
> + int ring_enq;
> + uint16_t d_pkts = 0;
> + struct rte_mbuf *dup_bufs[nb_pkts];
> + struct pdump_rxtx_cbs *cbs;
> + struct rte_ring *ring;
> + struct rte_mempool *mp;
> + struct rte_mbuf *p;
> +
> + cbs = user_params;
> + ring = cbs->ring;
> + mp = cbs->mp;
> + for (i = 0; i < nb_pkts; i++) {
> + p = pdump_pktmbuf_copy(pkts[i], mp);
> + if (p)
> + dup_bufs[d_pkts++] = p;
> + }
> +
> + ring_enq = rte_ring_enqueue_burst(ring, (void *)dup_bufs, d_pkts);
> + if (unlikely(ring_enq < d_pkts)) {
> + RTE_LOG(DEBUG, PDUMP, "only %d of packets enqueued to ring\n", ring_enq);
> + do {
> + rte_pktmbuf_free(dup_bufs[ring_enq]);
> + } while (++ring_enq < d_pkts);
> + }
> +}
> +
> +static uint16_t
> +pdump_rx(uint8_t port __rte_unused, uint16_t qidx __rte_unused,
> + struct rte_mbuf **pkts, uint16_t nb_pkts, uint16_t max_pkts __rte_unused,
> + void *user_params)
> +{
> + pdump_copy(pkts, nb_pkts, user_params);
> + return nb_pkts;
> +}
> +
> +static uint16_t
> +pdump_tx(uint8_t port __rte_unused, uint16_t qidx __rte_unused,
> + struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
> +{
> + pdump_copy(pkts, nb_pkts, user_params);
> + return nb_pkts;
> +}
> +
> +static int
> +pdump_get_dombdf(char *device_id, char *domBDF)
> +{
> + int ret;
> + struct rte_pci_addr dev_addr = {0};
> +
> + ret = eal_parse_pci_DomBDF(device_id, &dev_addr);
> + if (ret < 0)
> + return -1;
> +
> + if (dev_addr.domain)
> + snprintf(domBDF, DEVICE_ID_SIZE, "%u:%u:%u.%u", dev_addr.domain,
> + dev_addr.bus, dev_addr.devid, dev_addr.function);
> + else
> + snprintf(domBDF, DEVICE_ID_SIZE, "%u:%u.%u", dev_addr.bus, dev_addr.devid,
> + dev_addr.function);
Instead of implicitly assume that domBDF is at least DEVICE_ID_SIZE bytes long,
why just not pass its size as an extra parameter?
> +
> + return 0;
> +}
> +
> +static int
> +pdump_regitser_callbacks(uint32_t dir, uint16_t end_q,
> + uint8_t port, uint16_t queue,
> + struct rte_ring *ring, struct rte_mempool *mp,
> + uint16_t operation)
> +{
> +
> + uint16_t qid;
> + struct pdump_rxtx_cbs *cbs = NULL;
> +
> + qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
> + for (; qid < end_q; qid++) {
> + if ((dir & RTE_PDUMP_FLAG_RX) != 0)
> + cbs = &rx_cbs[port][qid];
> + if ((dir & RTE_PDUMP_FLAG_TX) != 0)
> + cbs = &tx_cbs[port][qid];
In case you have dir == (RTE_PDUMP_FLAG_RX | RTE_PDUMP_FLAG_TX)
you'll overwrite your rx_cbs pointer with tx_cbs pointer.
I suppose you need 2 local vars: cbs_rx and cbs_tx here.
Again probably worth to have 2 helper functions:
pdump_regitser_rx_callback() and pdump_regitser_tx_callback()
and call them from that one.
Or you'll never invoke that function with dir ==(RTE_PDUMP_FLAG_RX | RTE_PDUMP_FLAG_TX)?
If so, it porbably worth to put it into comments, though if it would be me, I still think it would
be good to split it in a way I mentioned above.
> + if (cbs && operation == ENABLE) {
> + if (cbs->cb) {
> + RTE_LOG(ERR, PDUMP,
> + "failed to add callback for port=%d and "
> + "queue=%d, callback already exists\n",
> + port, qid);
> + return -EEXIST;
> + }
> + cbs->ring = ring;
> + cbs->mp = mp;
> + if ((dir & RTE_PDUMP_FLAG_RX) != 0) {
> + cbs->cb = rte_eth_add_first_rx_callback(port, qid,
> + pdump_rx, cbs);
> + if (cbs->cb == NULL) {
> + RTE_LOG(ERR, PDUMP,
> + "failed to add rx callback, errno=%d\n",
> + rte_errno);
> + return rte_errno;
> + }
> + }
> + if ((dir & RTE_PDUMP_FLAG_TX) != 0) {
> + cbs->cb = rte_eth_add_tx_callback(port, qid, pdump_tx,
> + cbs);
> + if (cbs->cb == NULL) {
> + RTE_LOG(ERR, PDUMP,
> + "failed to add tx callback, errno=%d\n",
> + rte_errno);
> + return rte_errno;
> + }
> + }
> + }
> + if (cbs && operation == DISABLE) {
> + int ret;
> +
> + if (cbs->cb == NULL) {
> + RTE_LOG(ERR, PDUMP,
> + "failed to delete non existing callback "
> + "for port=%d and queue=%d\n", port, qid);
> + return -EINVAL;
> + }
> + if ((dir & RTE_PDUMP_FLAG_RX) != 0) {
> + ret = rte_eth_remove_rx_callback(port, qid, cbs->cb);
> + if (ret < 0) {
> + RTE_LOG(ERR, PDUMP,
> + "failed to remove rx callback, errno=%d\n",
> + rte_errno);
> + return ret;
> + }
> + }
> + if ((dir & RTE_PDUMP_FLAG_TX) != 0) {
> + ret = rte_eth_remove_tx_callback(port, qid, cbs->cb);
> + if (ret < 0) {
> + RTE_LOG(ERR, PDUMP,
> + "failed to remove tx callback, errno=%d\n",
> + rte_errno);
> + return ret;
> + }
> + }
> + cbs->cb = NULL;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int
> +set_pdump_rxtx_cbs(struct pdump_request *p)
> +{
> + uint16_t nb_rx_q, nb_tx_q = 0, end_q, queue;
> + uint8_t port;
> + int ret = 0;
> + uint32_t dir;
> + uint16_t operation;
> + struct rte_ring *ring;
> + struct rte_mempool *mp;
> + char domBDF[DEVICE_ID_SIZE];
> +
> + dir = p->dir;
> + operation = p->op;
> + if (operation == ENABLE) {
> + if (p->data.en_v1.is_pci_or_name == true) {
> + /* check if device is pci address or name */
> + if (pdump_get_dombdf(p->data.en_v1.device, domBDF) == 0)
> + ret = rte_eth_dev_get_port_by_name(domBDF, &port);
> + else
> + ret = rte_eth_dev_get_port_by_name(p->data.en_v1.device,
> + &port);
Why we can't force client to have device name in predefined format?
Then you woudn't need that name conversion here.
> + if (ret < 0) {
> + RTE_LOG(ERR, PDUMP,
> + "failed to get potid for device id=%s\n",
> + p->data.en_v1.device);
> + return -EINVAL;
> + }
> + } else /* if device is port id */
> + port = atoi(p->data.en_v1.device);
Hmm, again why not make server to accept requests only by device id?
Then it would be client responsibility to do port to device id, and you can
get rid of some duplicated code here.
> + queue = p->data.en_v1.queue;
> + ring = p->data.en_v1.ring;
> + mp = p->data.en_v1.mp;
> + } else {
> + if (p->data.dis_v1.is_pci_or_name == true) {
> + /* check if device is pci address or name */
> + if (pdump_get_dombdf(p->data.dis_v1.device, domBDF) == 0)
> + ret = rte_eth_dev_get_port_by_name(domBDF, &port);
> + else
> + ret = rte_eth_dev_get_port_by_name(p->data.dis_v1.device,
> + &port);
> + if (ret < 0) {
> + RTE_LOG(ERR, PDUMP,
> + "failed to get potid for device id=%s\n",
> + p->data.dis_v1.device);
> + return -EINVAL;
> + }
> + } else /* if device is port id */
> + port = atoi(p->data.dis_v1.device);
> + queue = p->data.dis_v1.queue;
> + ring = p->data.dis_v1.ring;
> + mp = p->data.dis_v1.mp;
> + }
> +
> + /* validation if packet capture is for all queues */
> + if (queue == RTE_PDUMP_ALL_QUEUES) {
> + struct rte_eth_dev_info dev_info;
> +
> + rte_eth_dev_info_get(port, &dev_info);
> + nb_rx_q = dev_info.nb_rx_queues;
> + nb_tx_q = dev_info.nb_tx_queues;
> + if (nb_rx_q == 0 && dir == RTE_PDUMP_FLAG_RX) {
> + RTE_LOG(ERR, PDUMP, "number of rx queues cannot be 0\n");
> + return -EINVAL;
> + }
> + if (nb_tx_q == 0 && dir == RTE_PDUMP_FLAG_TX) {
> + RTE_LOG(ERR, PDUMP, "number of tx queues cannot be 0\n");
> + return -EINVAL;
> + }
> + if ((nb_tx_q == 0 || nb_rx_q == 0) && dir == RTE_PDUMP_FLAG_RXTX) {
> + RTE_LOG(ERR, PDUMP, "both tx&rx queues must be non zero\n");
> + return -EINVAL;
> + }
> + }
> +
> + /* register RX callback for dir rx/rxtx */
> + if (dir == RTE_PDUMP_FLAG_RX || dir == RTE_PDUMP_FLAG_RXTX) {
just if (dir & RTE_PDUMP_FLAG_RX)
?
> + end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_rx_q : queue + 1;
> + ret = pdump_regitser_callbacks(RTE_PDUMP_FLAG_RX, end_q, port, queue,
> + ring, mp, operation);
> + if (ret < 0)
> + return ret;
> + }
> +
> + /* register TX callback for dir tx/rxtx */
> + if (dir == RTE_PDUMP_FLAG_TX || dir == RTE_PDUMP_FLAG_RXTX) {
> + end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_tx_q : queue + 1;
> + ret = pdump_regitser_callbacks(RTE_PDUMP_FLAG_TX, end_q, port, queue,
> + ring, mp, operation);
> + if (ret < 0)
> + return ret;
> + }
> +
> + return ret;
> +}
> +
> +/* get socket path (/var/run if root, $HOME otherwise) */
> +static void
> +pdump_get_socket_path(char *buffer, int bufsz, enum pdump_socktype type)
> +{
> + const char *dir = SOCKET_PATH_VAR_RUN;
> + const char *home_dir = getenv(SOCKET_PATH_HOME);
> +
> + if (getuid() != 0 && home_dir != NULL)
> + dir = home_dir;
> +
> + mkdir(dir, 700);
> + if (type == SERVER)
> + snprintf(buffer, bufsz, SERVER_SOCKET, dir);
> + else
> + snprintf(buffer, bufsz, CLIENT_SOCKET, dir, getpid(),
> + rte_sys_gettid());
Probably add internal_config.hugefile_prefix into the name too,
in case there is multiple primary DPDK procs running?
Konstantin
> +}
> +
> +static int
> +pdump_create_server_socket(void)
> +{
> + int ret, socket_fd;
> + struct sockaddr_un addr;
> + socklen_t addr_len;
> +
> + pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), SERVER);
> + addr.sun_family = AF_UNIX;
> +
> + /* remove if file already exists */
> + unlink(addr.sun_path);
> +
> + /* set up a server socket */
> + socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
> + if (socket_fd < 0) {
> + RTE_LOG(ERR, PDUMP, "Failed to create server socket: %s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + return -1;
> + }
> +
> + addr_len = sizeof(struct sockaddr_un);
> + ret = bind(socket_fd, (struct sockaddr *) &addr, addr_len);
> + if (ret) {
> + RTE_LOG(ERR, PDUMP, "Failed to bind to server socket: %s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + close(socket_fd);
> + return -1;
> + }
> +
> + /* save the socket in local configuration */
> + pdump_socket_fd = socket_fd;
> +
> + return 0;
> +}
> +
> +static __attribute__((noreturn)) void *
> +pdump_thread_main(__rte_unused void *arg)
> +{
> + struct sockaddr_un cli_addr;
> + socklen_t cli_len;
> + struct pdump_request cli_req;
> + struct pdump_response resp;
> + int n;
> + int ret = 0;
> +
> + /* host thread, never break out */
> + for (;;) {
> + /* recv client requests */
> + cli_len = sizeof(cli_addr);
> + n = recvfrom(pdump_socket_fd, &cli_req, sizeof(struct pdump_request), 0,
> + (struct sockaddr *)&cli_addr, &cli_len);
> + if (n < 0) {
> + RTE_LOG(ERR, PDUMP, "failed to recv from client:%s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + continue;
> + }
> +
> + ret = set_pdump_rxtx_cbs(&cli_req);
> +
> + resp.ver = cli_req.ver;
> + resp.res_op = cli_req.op;
> + resp.err_value = ret;
> + n = sendto(pdump_socket_fd, &resp, sizeof(struct pdump_response),
> + 0, (struct sockaddr *)&cli_addr, cli_len);
> + if (n < 0) {
> + RTE_LOG(ERR, PDUMP, "failed to send to client:%s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + }
> + }
> +}
> +
> +int
> +rte_pdump_init(void)
> +{
> + int ret = 0;
> + char thread_name[RTE_MAX_THREAD_NAME_LEN];
> +
> + ret = pdump_create_server_socket();
> + if (ret != 0) {
> + RTE_LOG(ERR, PDUMP, "Failed to create server socket:%s:%d\n",
> + __func__, __LINE__);
> + return -1;
> + }
> +
> + /* create the host thread to wait/handle pdump requests */
> + ret = pthread_create(&pdump_thread, NULL, pdump_thread_main, NULL);
> + if (ret != 0) {
> + RTE_LOG(ERR, PDUMP, "Failed to create the pdump thread:%s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + return -1;
> + }
> + /* Set thread_name for aid in debugging. */
> + snprintf(thread_name, RTE_MAX_THREAD_NAME_LEN, "pdump-thread");
> + ret = rte_thread_setname(pdump_thread, thread_name);
> + if (ret != 0) {
> + RTE_LOG(DEBUG, PDUMP,
> + "Failed to set thread name for pdump handling\n");
> + }
> +
> + return 0;
> +}
> +
> +int
> +rte_pdump_uninit(void)
> +{
> + int ret;
> +
> + ret = pthread_cancel(pdump_thread);
> + if (ret != 0) {
> + RTE_LOG(ERR, PDUMP, "Failed to cancel the pdump thread:%s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + return -1;
> + }
> +
> + ret = close(pdump_socket_fd);
> + if (ret != 0) {
> + RTE_LOG(ERR, PDUMP, "Failed to close server socket: %s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + return -1;
> + }
> +
> + struct sockaddr_un addr;
> +
> + pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), SERVER);
> + ret = unlink(addr.sun_path);
> + if (ret != 0) {
> + RTE_LOG(ERR, PDUMP, "Failed to remove server socket addr: %s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +pdump_create_client_socket(struct pdump_request *p)
> +{
> + int ret, socket_fd;
> + int pid;
> + int n;
> + struct pdump_response server_resp;
> + struct sockaddr_un addr, serv_addr, from;
> + socklen_t addr_len, serv_len;
> +
> + pid = getpid();
> +
> + socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
> + if (socket_fd < 0) {
> + RTE_LOG(ERR, PDUMP, "client socket(): %s:pid(%d):tid(%u), %s:%d\n",
> + strerror(errno), pid, rte_sys_gettid(), __func__, __LINE__);
> + ret = errno;
> + return ret;
> + }
> +
> + pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), CLIENT);
> + addr.sun_family = AF_UNIX;
> + addr_len = sizeof(struct sockaddr_un);
> +
> + do {
> + ret = bind(socket_fd, (struct sockaddr *) &addr, addr_len);
> + if (ret) {
> + RTE_LOG(ERR, PDUMP, "client bind(): %s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + ret = errno;
> + break;
> + }
> +
> + serv_len = sizeof(struct sockaddr_un);
> + memset(&serv_addr, 0, sizeof(serv_addr));
> + pdump_get_socket_path(serv_addr.sun_path, sizeof(serv_addr.sun_path),
> + SERVER);
> + serv_addr.sun_family = AF_UNIX;
> +
> + n = sendto(socket_fd, p, sizeof(struct pdump_request), 0,
> + (struct sockaddr *)&serv_addr, serv_len);
> + if (n < 0) {
> + RTE_LOG(ERR, PDUMP, "failed to send to server:%s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + ret = errno;
> + break;
> + }
> +
> + n = recvfrom(socket_fd, &server_resp, sizeof(struct pdump_response), 0,
> + (struct sockaddr *)&from, &serv_len);
> + if (n < 0) {
> + RTE_LOG(ERR, PDUMP, "failed to recv from server:%s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + ret = errno;
> + break;
> + }
> + ret = server_resp.err_value;
> + } while (0);
> +
> + close(socket_fd);
> + unlink(addr.sun_path);
> + return ret;
> +}
> +
> +static int
> +pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp)
> +{
> + if (ring == NULL || mp == NULL) {
> + RTE_LOG(ERR, PDUMP, "NULL ring or mempool are passed %s:%d\n",
> + __func__, __LINE__);
> + rte_errno = EINVAL;
> + return -1;
> + }
> + if (mp->flags & MEMPOOL_F_SP_PUT || mp->flags & MEMPOOL_F_SC_GET) {
> + RTE_LOG(ERR, PDUMP, "mempool with either SP or SC settings"
> + " is not valid for pdump, should have MP and MC settings\n");
> + rte_errno = EINVAL;
> + return -1;
> + }
> + if (ring->prod.sp_enqueue || ring->cons.sc_dequeue) {
> + RTE_LOG(ERR, PDUMP, "ring with either SP or SC settings"
> + " is not valid for pdump, should have MP and MC settings\n");
> + rte_errno = EINVAL;
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +pdump_validate_dir(uint32_t dir)
> +{
> + if (dir != RTE_PDUMP_FLAG_RX && dir != RTE_PDUMP_FLAG_TX &&
> + dir != RTE_PDUMP_FLAG_RXTX) {
> + RTE_LOG(ERR, PDUMP, "invalid direction, should be either rx/tx/rxtx\n");
> + rte_errno = EINVAL;
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +pdump_validate_port(uint8_t port)
> +{
> + if (port >= RTE_MAX_ETHPORTS) {
> + RTE_LOG(ERR, PDUMP, "Invalid port id %u, %s:%d\n", port,
> + __func__, __LINE__);
> + rte_errno = EINVAL;
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +pdump_prepare_client_request(char *device, bool is_pci_or_name, uint16_t queue,
> + uint32_t dir,
> + uint16_t operation,
> + struct rte_ring *ring,
> + struct rte_mempool *mp,
> + void *filter)
> +{
> + int ret;
> + struct pdump_request req = {.ver = 1,};
> +
> + req.dir = dir;
> + req.op = operation;
> + if ((operation & ENABLE) != 0) {
> + strncpy(req.data.en_v1.device, device, strlen(device));
> + req.data.en_v1.is_pci_or_name = is_pci_or_name;
> + req.data.en_v1.queue = queue;
> + req.data.en_v1.ring = ring;
> + req.data.en_v1.mp = mp;
> + req.data.en_v1.filter = filter;
> + } else {
> + strncpy(req.data.dis_v1.device, device, strlen(device));
> + req.data.dis_v1.is_pci_or_name = is_pci_or_name;
> + req.data.dis_v1.queue = queue;
> + req.data.dis_v1.ring = NULL;
> + req.data.dis_v1.mp = NULL;
> + req.data.dis_v1.filter = NULL;
> + }
> +
> + ret = pdump_create_client_socket(&req);
> + if (ret < 0) {
> + RTE_LOG(ERR, PDUMP, "client request for pdump enable/disable failed\n");
> + rte_errno = ret;
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +int
> +rte_pdump_enable(uint8_t port, uint16_t queue, uint32_t dir,
> + struct rte_ring *ring,
> + struct rte_mempool *mp,
> + void *filter)
> +{
> +
> + int ret = 0;
> + char device[DEVICE_ID_SIZE];
> +
> + ret = pdump_validate_port(port);
> + if (ret < 0)
> + return ret;
> + ret = pdump_validate_ring_mp(ring, mp);
> + if (ret < 0)
> + return ret;
> + pdump_validate_dir(dir);
> + if (ret < 0)
> + return ret;
> +
> + snprintf(device, sizeof(device), "%u", port);
> + ret = pdump_prepare_client_request(device, false, queue, dir,
> + ENABLE, ring, mp, filter);
> +
> + return ret;
> +}
> +
> +int
> +rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
> + uint32_t dir,
> + struct rte_ring *ring,
> + struct rte_mempool *mp,
> + void *filter)
> +{
> + int ret = 0;
> +
> + ret = pdump_validate_ring_mp(ring, mp);
> + if (ret < 0)
> + return ret;
> + ret = pdump_validate_dir(dir);
> + if (ret < 0)
> + return ret;
> +
> + ret = pdump_prepare_client_request(device_id, true, queue, dir,
> + ENABLE, ring, mp, filter);
> +
> + return ret;
> +}
> +
> +int
> +rte_pdump_disable(uint8_t port, uint16_t queue, uint32_t dir)
> +{
> + int ret = 0;
> + char device[DEVICE_ID_SIZE];
> +
> + ret = pdump_validate_port(port);
> + if (ret < 0)
> + return ret;
> + ret = pdump_validate_dir(dir);
> + if (ret < 0)
> + return ret;
> +
> + snprintf(device, sizeof(device), "%u", port);
> + ret = pdump_prepare_client_request(device, false, queue, dir,
> + DISABLE, NULL, NULL, NULL);
> +
> + return ret;
> +}
> +
> +int
> +rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
> + uint32_t dir)
> +{
> + int ret = 0;
> +
> + ret = pdump_validate_dir(dir);
> + if (ret < 0)
> + return ret;
> +
> + ret = pdump_prepare_client_request(device_id, true, queue, dir,
> + DISABLE, NULL, NULL, NULL);
> +
> + return ret;
> +}
> diff --git a/lib/librte_pdump/rte_pdump.h b/lib/librte_pdump/rte_pdump.h
> new file mode 100644
> index 0000000..fcd02de
> --- /dev/null
> +++ b/lib/librte_pdump/rte_pdump.h
> @@ -0,0 +1,186 @@
> +/*-
> + * 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.
> + */
> +
> +#ifndef _RTE_PDUMP_H_
> +#define _RTE_PDUMP_H_
> +
> +/**
> + * @file
> + * RTE pdump
> + *
> + * packet dump library to provide packet capturing support on dpdk.
> + */
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +#define RTE_PDUMP_ALL_QUEUES UINT16_MAX
> +
> +enum {
> + RTE_PDUMP_FLAG_RX = 1, /* receive direction */
> + RTE_PDUMP_FLAG_TX = 2, /* transmit direction */
> + /* both receive and transmit directions */
> + RTE_PDUMP_FLAG_RXTX = (RTE_PDUMP_FLAG_RX|RTE_PDUMP_FLAG_TX)
> +};
> +
> +/**
> + * Initialize packet capturing handling
> + *
> + * Creates pthread and server socket for handling clients
> + * requests to enable/disable rxtx callbacks.
> + *
> + * @return
> + * 0 on success, -1 on error
> + */
> +int
> +rte_pdump_init(void);
> +
> +/**
> + * Un initialize packet capturing handling
> + *
> + * Cancels pthread, close server socket, removes server socket address.
> + *
> + * @return
> + * 0 on success, -1 on error
> + */
> +int
> +rte_pdump_uninit(void);
> +
> +/**
> + * Enables packet capturing on given port and queue.
> + *
> + * @param port
> + * port on which packet capturing should be enabled.
> + * @param queue
> + * queue of a given port on which packet capturing should be enabled.
> + * users should pass on value UINT16_MAX to enable packet capturing on all
> + * queues of a given port.
> + * @param dir
> + * dir specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
> + * on which packet capturing should be enabled for a given port and queue.
> + * @param ring
> + * ring on which captured packets will be enqueued for user.
> + * @param mp
> + * mempool on to which original packets will be mirrored or duplicated.
> + * @param filter
> + * place holder for packet filtering.
> + *
> + * @return
> + * 0 on success, -1 on error, rte_errno is set accordingly.
> + */
> +
> +int
> +rte_pdump_enable(uint8_t port, uint16_t queue, uint32_t dir,
> + struct rte_ring *ring,
> + struct rte_mempool *mp,
> + void *filter);
> +
> +/**
> + * Disables packet capturing on given port and queue.
> + *
> + * @param port
> + * port on which packet capturing should be disabled.
> + * @param queue
> + * queue of a given port on which packet capturing should be disabled.
> + * users should pass on value UINT16_MAX to disable packet capturing on all
> + * queues of a given port.
> + * @param dir
> + * dir specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
> + * on which packet capturing should be enabled for a given port and queue.
> + *
> + * @return
> + * 0 on success, -1 on error, rte_errno is set accordingly.
> + */
> +
> +int
> +rte_pdump_disable(uint8_t port, uint16_t queue, uint32_t dir);
> +
> +/**
> + * Enables packet capturing on given device id and queue.
> + * device_id can be name or pci address of device.
> + *
> + * @param device_id
> + * device id on which packet capturing should be enabled.
> + * @param queue
> + * queue of a given device id on which packet capturing should be enabled.
> + * users should pass on value UINT16_MAX to enable packet capturing on all
> + * queues of a given device id.
> + * @param dir
> + * dir specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
> + * on which packet capturing should be enabled for a given port and queue.
> + * @param ring
> + * ring on which captured packets will be enqueued for user.
> + * @param mp
> + * mempool on to which original packets will be mirrored or duplicated.
> + * @param filter
> + * place holder for packet filtering.
> + *
> + * @return
> + * 0 on success, -1 on error, rte_errno is set accordingly.
> + */
> +
> +int
> +rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
> + uint32_t dir,
> + struct rte_ring *ring,
> + struct rte_mempool *mp,
> + void *filter);
> +
> +/**
> + * Disables packet capturing on given device_id and queue.
> + * device_id can be name or pci address of device.
> + *
> + * @param device_id
> + * pci address or name of the device on which packet capturing
> + * should be disabled.
> + * @param queue
> + * queue of a given device on which packet capturing should be disabled.
> + * users should pass on value UINT16_MAX to disable packet capturing on all
> + * queues of a given device id.
> + * @param dir
> + * dir specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
> + * on which packet capturing should be enabled for a given port and queue.
> + *
> + * @return
> + * 0 on success, -1 on error, rte_errno is set accordingly.
> + */
> +int
> +rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
> + uint32_t dir);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif /* _RTE_PDUMP_H_ */
> diff --git a/lib/librte_pdump/rte_pdump_version.map b/lib/librte_pdump/rte_pdump_version.map
> new file mode 100644
> index 0000000..3e744f3
> --- /dev/null
> +++ b/lib/librte_pdump/rte_pdump_version.map
> @@ -0,0 +1,12 @@
> +DPDK_16.07 {
> + global:
> +
> + rte_pdump_disable;
> + rte_pdump_disable_by_deviceid;
> + rte_pdump_enable;
> + rte_pdump_enable_by_deviceid;
> + rte_pdump_init;
> + rte_pdump_uninit;
> +
> + local: *;
> +};
> diff --git a/mk/rte.app.mk b/mk/rte.app.mk
> index b84b56d..f792f2a 100644
> --- a/mk/rte.app.mk
> +++ b/mk/rte.app.mk
> @@ -61,6 +61,7 @@ _LDLIBS-y += --whole-archive
>
> _LDLIBS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += -lrte_distributor
> _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER) += -lrte_reorder
> +_LDLIBS-$(CONFIG_RTE_LIBRTE_PDUMP) += -lrte_pdump
>
> ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
> _LDLIBS-$(CONFIG_RTE_LIBRTE_KNI) += -lrte_kni
> --
> 2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v4 5/9] lib/librte_pdump: add new library for packet capturing support
2016-05-27 13:39 ` Ananyev, Konstantin
@ 2016-05-27 14:54 ` Pattan, Reshma
2016-05-27 15:25 ` Ananyev, Konstantin
2016-05-31 15:00 ` Pattan, Reshma
1 sibling, 1 reply; 82+ messages in thread
From: Pattan, Reshma @ 2016-05-27 14:54 UTC (permalink / raw)
To: Ananyev, Konstantin, dev; +Cc: Pattan, Reshma
> -----Original Message-----
> From: Ananyev, Konstantin
> Sent: Friday, May 27, 2016 2:39 PM
> To: Pattan, Reshma <reshma.pattan@intel.com>; dev@dpdk.org
> Cc: Pattan, Reshma <reshma.pattan@intel.com>
> Subject: RE: [dpdk-dev] [PATCH v4 5/9] lib/librte_pdump: add new library for
> packet capturing support
>
> Hi Reshma,
> > +static int
> > +pdump_regitser_callbacks(uint32_t dir, uint16_t end_q,
> > + uint8_t port, uint16_t queue,
> > + struct rte_ring *ring, struct rte_mempool *mp,
> > + uint16_t operation)
> > +{
> > +
> > + uint16_t qid;
> > + struct pdump_rxtx_cbs *cbs = NULL;
> > +
> > + qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
> > + for (; qid < end_q; qid++) {
> > + if ((dir & RTE_PDUMP_FLAG_RX) != 0)
> > + cbs = &rx_cbs[port][qid];
> > + if ((dir & RTE_PDUMP_FLAG_TX) != 0)
> > + cbs = &tx_cbs[port][qid];
>
> In case you have dir == (RTE_PDUMP_FLAG_RX | RTE_PDUMP_FLAG_TX) you'll
> overwrite your rx_cbs pointer with tx_cbs pointer.
> I suppose you need 2 local vars: cbs_rx and cbs_tx here.
> Again probably worth to have 2 helper functions:
> pdump_regitser_rx_callback() and pdump_regitser_tx_callback() and call them
> from that one.
> Or you'll never invoke that function with dir ==(RTE_PDUMP_FLAG_RX |
> RTE_PDUMP_FLAG_TX)?
> If so, it porbably worth to put it into comments, though if it would be me, I still
> think it would be good to split it in a way I mentioned above.
>
Yes, I never invoke the function with dir ==(RTE_PDUMP_FLAG_RX | RTE_PDUMP_FLAG_TX).
> > +
> > + dir = p->dir;
> > + operation = p->op;
> > + if (operation == ENABLE) {
> > + if (p->data.en_v1.is_pci_or_name == true) {
> > + /* check if device is pci address or name */
> > + if (pdump_get_dombdf(p->data.en_v1.device, domBDF)
> == 0)
> > + ret = rte_eth_dev_get_port_by_name(domBDF,
> &port);
> > + else
> > + ret = rte_eth_dev_get_port_by_name(p-
> >data.en_v1.device,
> > +
> &port);
>
>
> Why we can't force client to have device name in predefined format?
> Then you woudn't need that name conversion here.
You mean I should do the conversion pdump_get_dombdf() in client and then pass that value to server?
>
> > + if (ret < 0) {
> > + RTE_LOG(ERR, PDUMP,
> > + "failed to get potid for device
> id=%s\n",
> > + p->data.en_v1.device);
> > + return -EINVAL;
> > + }
> > + } else /* if device is port id */
> > + port = atoi(p->data.en_v1.device);
>
> Hmm, again why not make server to accept requests only by device id?
> Then it would be client responsibility to do port to device id, and you can get rid
> of some duplicated code here.
If client is secondary process then the same port id on primary and secondary processes might be mapping to different devices right?
If so I cannot do port id to device name conversion in client.
Thanks,
Reshma
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v4 5/9] lib/librte_pdump: add new library for packet capturing support
2016-05-27 14:54 ` Pattan, Reshma
@ 2016-05-27 15:25 ` Ananyev, Konstantin
2016-05-31 14:55 ` Pattan, Reshma
0 siblings, 1 reply; 82+ messages in thread
From: Ananyev, Konstantin @ 2016-05-27 15:25 UTC (permalink / raw)
To: Pattan, Reshma, dev
> -----Original Message-----
> From: Pattan, Reshma
> Sent: Friday, May 27, 2016 3:55 PM
> To: Ananyev, Konstantin; dev@dpdk.org
> Cc: Pattan, Reshma
> Subject: RE: [dpdk-dev] [PATCH v4 5/9] lib/librte_pdump: add new library for packet capturing support
>
>
>
> > -----Original Message-----
> > From: Ananyev, Konstantin
> > Sent: Friday, May 27, 2016 2:39 PM
> > To: Pattan, Reshma <reshma.pattan@intel.com>; dev@dpdk.org
> > Cc: Pattan, Reshma <reshma.pattan@intel.com>
> > Subject: RE: [dpdk-dev] [PATCH v4 5/9] lib/librte_pdump: add new library for
> > packet capturing support
> >
> > Hi Reshma,
>
> > > +static int
> > > +pdump_regitser_callbacks(uint32_t dir, uint16_t end_q,
> > > + uint8_t port, uint16_t queue,
> > > + struct rte_ring *ring, struct rte_mempool *mp,
> > > + uint16_t operation)
> > > +{
> > > +
> > > + uint16_t qid;
> > > + struct pdump_rxtx_cbs *cbs = NULL;
> > > +
> > > + qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
> > > + for (; qid < end_q; qid++) {
> > > + if ((dir & RTE_PDUMP_FLAG_RX) != 0)
> > > + cbs = &rx_cbs[port][qid];
> > > + if ((dir & RTE_PDUMP_FLAG_TX) != 0)
> > > + cbs = &tx_cbs[port][qid];
> >
> > In case you have dir == (RTE_PDUMP_FLAG_RX | RTE_PDUMP_FLAG_TX) you'll
> > overwrite your rx_cbs pointer with tx_cbs pointer.
> > I suppose you need 2 local vars: cbs_rx and cbs_tx here.
> > Again probably worth to have 2 helper functions:
> > pdump_regitser_rx_callback() and pdump_regitser_tx_callback() and call them
> > from that one.
> > Or you'll never invoke that function with dir ==(RTE_PDUMP_FLAG_RX |
> > RTE_PDUMP_FLAG_TX)?
> > If so, it porbably worth to put it into comments, though if it would be me, I still
> > think it would be good to split it in a way I mentioned above.
> >
>
> Yes, I never invoke the function with dir ==(RTE_PDUMP_FLAG_RX | RTE_PDUMP_FLAG_TX).
Ok, then at least probably comment it somehow.
Though I still think 2 different variables (and might be functions) would be better.
>
> > > +
> > > + dir = p->dir;
> > > + operation = p->op;
> > > + if (operation == ENABLE) {
> > > + if (p->data.en_v1.is_pci_or_name == true) {
> > > + /* check if device is pci address or name */
> > > + if (pdump_get_dombdf(p->data.en_v1.device, domBDF)
> > == 0)
> > > + ret = rte_eth_dev_get_port_by_name(domBDF,
> > &port);
> > > + else
> > > + ret = rte_eth_dev_get_port_by_name(p-
> > >data.en_v1.device,
> > > +
> > &port);
> >
> >
> > Why we can't force client to have device name in predefined format?
> > Then you woudn't need that name conversion here.
>
> You mean I should do the conversion pdump_get_dombdf() in client and then pass that value to server?
Yes.
>
> >
> > > + if (ret < 0) {
> > > + RTE_LOG(ERR, PDUMP,
> > > + "failed to get potid for device
> > id=%s\n",
> > > + p->data.en_v1.device);
> > > + return -EINVAL;
> > > + }
> > > + } else /* if device is port id */
> > > + port = atoi(p->data.en_v1.device);
> >
> > Hmm, again why not make server to accept requests only by device id?
> > Then it would be client responsibility to do port to device id, and you can get rid
> > of some duplicated code here.
>
> If client is secondary process then the same port id on primary and secondary processes might be mapping to different devices right?
Yes.
> If so I cannot do port id to device name conversion in client.
Ok, but the client can do either port_enable/disable by client port id,
or (if that device is not mapped on the client) by device_id.
Konstantin
>
> Thanks,
> Reshma
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v4 5/9] lib/librte_pdump: add new library for packet capturing support
2016-05-27 15:25 ` Ananyev, Konstantin
@ 2016-05-31 14:55 ` Pattan, Reshma
0 siblings, 0 replies; 82+ messages in thread
From: Pattan, Reshma @ 2016-05-31 14:55 UTC (permalink / raw)
To: Ananyev, Konstantin, dev
> -----Original Message-----
> From: Ananyev, Konstantin
> Sent: Friday, May 27, 2016 4:26 PM
> To: Pattan, Reshma <reshma.pattan@intel.com>; dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH v4 5/9] lib/librte_pdump: add new library for
> packet capturing support
>
>
>
> > -----Original Message-----
> > From: Pattan, Reshma
> > Sent: Friday, May 27, 2016 3:55 PM
> > To: Ananyev, Konstantin; dev@dpdk.org
> > Cc: Pattan, Reshma
> > Subject: RE: [dpdk-dev] [PATCH v4 5/9] lib/librte_pdump: add new
> > library for packet capturing support
> >
> >
> >
> > > -----Original Message-----
> > > From: Ananyev, Konstantin
> > > Sent: Friday, May 27, 2016 2:39 PM
> > > To: Pattan, Reshma <reshma.pattan@intel.com>; dev@dpdk.org
> > > Cc: Pattan, Reshma <reshma.pattan@intel.com>
> > > Subject: RE: [dpdk-dev] [PATCH v4 5/9] lib/librte_pdump: add new
> > > library for packet capturing support
> > >
> > > Hi Reshma,
> >
> > > > +static int
> > > > +pdump_regitser_callbacks(uint32_t dir, uint16_t end_q,
> > > > + uint8_t port, uint16_t queue,
> > > > + struct rte_ring *ring, struct rte_mempool *mp,
> > > > + uint16_t operation)
> > > > +{
> > > > +
> > > > + uint16_t qid;
> > > > + struct pdump_rxtx_cbs *cbs = NULL;
> > > > +
> > > > + qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
> > > > + for (; qid < end_q; qid++) {
> > > > + if ((dir & RTE_PDUMP_FLAG_RX) != 0)
> > > > + cbs = &rx_cbs[port][qid];
> > > > + if ((dir & RTE_PDUMP_FLAG_TX) != 0)
> > > > + cbs = &tx_cbs[port][qid];
> > >
> > > In case you have dir == (RTE_PDUMP_FLAG_RX | RTE_PDUMP_FLAG_TX)
> > > you'll overwrite your rx_cbs pointer with tx_cbs pointer.
> > > I suppose you need 2 local vars: cbs_rx and cbs_tx here.
> > > Again probably worth to have 2 helper functions:
> > > pdump_regitser_rx_callback() and pdump_regitser_tx_callback() and
> > > call them from that one.
> > > Or you'll never invoke that function with dir ==(RTE_PDUMP_FLAG_RX |
> > > RTE_PDUMP_FLAG_TX)?
> > > If so, it porbably worth to put it into comments, though if it would
> > > be me, I still think it would be good to split it in a way I mentioned above.
> > >
> >
> > Yes, I never invoke the function with dir ==(RTE_PDUMP_FLAG_RX |
> RTE_PDUMP_FLAG_TX).
>
> Ok, then at least probably comment it somehow.
> Though I still think 2 different variables (and might be functions) would be
> better.
>
> >
Ok, I will add a comment.
Thanks,
Reshma
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v4 5/9] lib/librte_pdump: add new library for packet capturing support
2016-05-27 13:39 ` Ananyev, Konstantin
2016-05-27 14:54 ` Pattan, Reshma
@ 2016-05-31 15:00 ` Pattan, Reshma
1 sibling, 0 replies; 82+ messages in thread
From: Pattan, Reshma @ 2016-05-31 15:00 UTC (permalink / raw)
To: Ananyev, Konstantin, dev
> -----Original Message-----
> From: Ananyev, Konstantin
> Sent: Friday, May 27, 2016 2:39 PM
> To: Pattan, Reshma <reshma.pattan@intel.com>; dev@dpdk.org
> Cc: Pattan, Reshma <reshma.pattan@intel.com>
> Subject: RE: [dpdk-dev] [PATCH v4 5/9] lib/librte_pdump: add new library for
> packet capturing support
>
> > +/* get socket path (/var/run if root, $HOME otherwise) */ static void
> > +pdump_get_socket_path(char *buffer, int bufsz, enum pdump_socktype
> > +type) {
> > + const char *dir = SOCKET_PATH_VAR_RUN;
> > + const char *home_dir = getenv(SOCKET_PATH_HOME);
> > +
> > + if (getuid() != 0 && home_dir != NULL)
> > + dir = home_dir;
> > +
> > + mkdir(dir, 700);
> > + if (type == SERVER)
> > + snprintf(buffer, bufsz, SERVER_SOCKET, dir);
> > + else
> > + snprintf(buffer, bufsz, CLIENT_SOCKET, dir, getpid(),
> > + rte_sys_gettid());
>
>
> Probably add internal_config.hugefile_prefix into the name too, in case there is
> multiple primary DPDK procs running?
>
Since there is no public api in rte_eal to get internal_config.hugefile_prefix info, this cannot be affixed to the server name.
> Konstantin
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v4 6/9] app/pdump: add pdump tool for packet capturing
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 0/9] add " Reshma Pattan
` (4 preceding siblings ...)
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 5/9] lib/librte_pdump: add new library for packet capturing support Reshma Pattan
@ 2016-05-23 21:38 ` Reshma Pattan
2016-05-27 15:21 ` Ananyev, Konstantin
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 7/9] app/test-pmd: add pdump initialization uninitialization Reshma Pattan
` (4 subsequent siblings)
10 siblings, 1 reply; 82+ messages in thread
From: Reshma Pattan @ 2016-05-23 21:38 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
New tool added for packet capturing on dpdk.
This tool supports command line options.
This tool runs as secondary process by default.
Command line supports various parameters to capture
the packets.
User should pass on a)port and queue (or) b)pci address
and queue (or) c)device name and queue to capture
the packets.
Users also need to pass on either pcap file name or
any linux iface, on to which packets captured from dpdk
ports will be sent on for the users to view using tcpdump.
Users have option to capture packets either a) in RX
direction, b)(or) in TX direction c)(or) from both the
directions.
User can pass on ring_size and mempool parameters using
command line, but these are optional parameters.
These are used to create ring and mempool objects for packet
mirroring from primary application to tool. If user doesn't
provide any values, default values will be used internally
for the creation of the ring and mempool.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
MAINTAINERS | 1 +
app/Makefile | 1 +
app/pdump/Makefile | 45 +++
app/pdump/main.c | 888 +++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 935 insertions(+)
create mode 100644 app/pdump/Makefile
create mode 100644 app/pdump/main.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 8656239..ae706b9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -436,6 +436,7 @@ F: doc/guides/sample_app_ug/packet_ordering.rst
Pdump
M: Reshma Pattan <reshma.pattan@intel.com>
F: lib/librte_pdump/
+F: app/pdump/
Hierarchical scheduler
M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
diff --git a/app/Makefile b/app/Makefile
index 1151e09..c593efa 100644
--- a/app/Makefile
+++ b/app/Makefile
@@ -37,5 +37,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += test-pipeline
DIRS-$(CONFIG_RTE_TEST_PMD) += test-pmd
DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_test
DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += proc_info
+DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += pdump
include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/app/pdump/Makefile b/app/pdump/Makefile
new file mode 100644
index 0000000..96bb4af
--- /dev/null
+++ b/app/pdump/Makefile
@@ -0,0 +1,45 @@
+# 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_SDK)/mk/rte.vars.mk
+
+APP = dpdk_pdump
+
+CFLAGS += $(WERROR_FLAGS)
+
+# all source are stored in SRCS-y
+
+SRCS-y := main.c
+
+# this application needs libraries first
+DEPDIRS-y += lib
+
+include $(RTE_SDK)/mk/rte.app.mk
diff --git a/app/pdump/main.c b/app/pdump/main.c
new file mode 100644
index 0000000..f507f3b
--- /dev/null
+++ b/app/pdump/main.c
@@ -0,0 +1,888 @@
+/*
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <net/if.h>
+
+#include <rte_eal.h>
+#include <rte_common.h>
+#include <rte_debug.h>
+#include <rte_ethdev.h>
+#include <rte_memory.h>
+#include <rte_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_errno.h>
+#include <rte_dev.h>
+#include <rte_kvargs.h>
+#include <rte_mempool.h>
+#include <rte_ring.h>
+#include <rte_pdump.h>
+
+#define PDUMP_PORT_ARG "port"
+#define PDUMP_PCI_ARG "device_id"
+#define PDUMP_QUEUE_ARG "queue"
+#define PDUMP_DIR_ARG "dir"
+#define PDUMP_RX_DEV_ARG "rx-dev"
+#define PDUMP_TX_DEV_ARG "tx-dev"
+#define PDUMP_RING_SIZE_ARG "ring-size"
+#define PDUMP_MSIZE_ARG "mbuf-size"
+#define PDUMP_NUM_MBUFS_ARG "total-num-mbufs"
+
+#define VDEV_PCAP "eth_pcap_%s_%d,tx_pcap=%s"
+#define VDEV_IFACE "eth_pcap_%s_%d,tx_iface=%s"
+#define TX_STREAM_SIZE 64
+
+#define MP_NAME "pdump_pool_%d"
+
+#define RX_RING "rx_ring_%d"
+#define TX_RING "tx_ring_%d"
+
+#define RX_STR "rx"
+#define TX_STR "tx"
+
+/* Maximum long option length for option parsing. */
+#define APP_ARG_TCPDUMP_MAX_TUPLES 54
+#define MBUF_POOL_CACHE_SIZE 250
+#define TX_DESC_PER_QUEUE 512
+#define RX_DESC_PER_QUEUE 128
+#define MBUFS_PER_POOL 65535
+#define MAX_LONG_OPT_SZ 64
+#define RING_SIZE 16384
+#define SIZE 256
+#define BURST_SIZE 32
+#define NUM_VDEVS 2
+
+enum pdump_en_dis {
+ DISABLE = 1,
+ ENABLE = 2
+};
+
+enum pcap_stream {
+ IFACE = 1,
+ PCAP = 2
+};
+
+enum pdump_by {
+ PORT_ID = 1,
+ DEVICE_ID = 2
+};
+
+const char *valid_pdump_arguments[] = {
+ PDUMP_PORT_ARG,
+ PDUMP_PCI_ARG,
+ PDUMP_QUEUE_ARG,
+ PDUMP_DIR_ARG,
+ PDUMP_RX_DEV_ARG,
+ PDUMP_TX_DEV_ARG,
+ PDUMP_RING_SIZE_ARG,
+ PDUMP_MSIZE_ARG,
+ PDUMP_NUM_MBUFS_ARG,
+ NULL
+};
+
+struct pdump_stats {
+ uint64_t dequeue_pkts;
+ uint64_t tx_pkts;
+ uint64_t freed_pkts;
+};
+
+struct pdump_tuples {
+ /* cli params */
+ uint8_t port;
+ char *device_id;
+ uint16_t queue;
+ char rx_dev[TX_STREAM_SIZE];
+ char tx_dev[TX_STREAM_SIZE];
+ uint32_t ring_size;
+ uint16_t mbuf_data_size;
+ uint32_t total_num_mbufs;
+
+ /* params for library API call */
+ uint32_t dir;
+ struct rte_mempool *mp;
+ struct rte_ring *rx_ring;
+ struct rte_ring *tx_ring;
+
+ /* params for packet dumping */
+ enum pdump_by dump_by_type;
+ int rx_vdev_id;
+ int tx_vdev_id;
+ enum pcap_stream rx_vdev_stream_type;
+ enum pcap_stream tx_vdev_stream_type;
+ bool single_pdump_dev;
+
+ /* stats */
+ struct pdump_stats stats;
+} __rte_cache_aligned;
+static struct pdump_tuples pdump_t[APP_ARG_TCPDUMP_MAX_TUPLES];
+
+int num_tuples;
+static struct rte_eth_conf port_conf_default;
+volatile uint8_t quit_signal;
+
+/**< display usage */
+static void
+pdump_usage(const char *prgname)
+{
+ printf("%s [EAL options] -- --pdump "
+ "'(port=<port id> | device_id=<pci id or vdev name>),"
+ "(queue=<queue_id>),"
+ "(rx-dev=<iface or pcap file> |"
+ " tx-dev=<iface or pcap file>,"
+ "[ring-size=<ring size>default:16384],"
+ "[mbuf-size=<mbuf data size>default:2176],"
+ "[total-num-mbufs=<number of mbufs>default:65535]"
+ "'\n",
+ prgname);
+}
+
+static int
+parse_port(const char *key __rte_unused, const char *value, void *extra_args)
+{
+ int n;
+ struct pdump_tuples *pt = extra_args;
+
+ n = atoi(value);
+ if (n >= RTE_MAX_ETHPORTS) {
+ printf("port %d >= RTE_MAX_ETHPORTS(%d)\n", n, RTE_MAX_ETHPORTS);
+ return -1;
+ }
+ pt->port = (uint8_t) n;
+ pt->dump_by_type = PORT_ID;
+
+ return 0;
+}
+
+static int
+parse_device_id(const char *key __rte_unused, const char *value, void *extra_args)
+{
+ struct pdump_tuples *pt = extra_args;
+
+ pt->device_id = strdup(value);
+ pt->dump_by_type = DEVICE_ID;
+
+ return 0;
+}
+
+static int
+parse_queue(const char *key __rte_unused, const char *value, void *extra_args)
+{
+ int n;
+ struct pdump_tuples *pt = extra_args;
+
+ if (!strcmp(value, "*"))
+ pt->queue = RTE_PDUMP_ALL_QUEUES;
+ else {
+ n = atoi(value);
+ if (n >= 0)
+ pt->queue = (uint16_t) n;
+ else {
+ printf("queue id %d invalid - must be >= 0\n", n);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int
+parse_rxtxdev(const char *key, const char *value, void *extra_args)
+{
+
+ struct pdump_tuples *pt = extra_args;
+
+ if (!strcmp(key, PDUMP_RX_DEV_ARG)) {
+ strncpy(pt->rx_dev, value, strlen(value));
+ /* identify the tx stream type for pcap vdev */
+ if (if_nametoindex(pt->rx_dev))
+ pt->rx_vdev_stream_type = IFACE;
+ } else if (!strcmp(key, PDUMP_TX_DEV_ARG)) {
+ strncpy(pt->tx_dev, value, strlen(value));
+ /* identify the tx stream type for pcap vdev */
+ if (if_nametoindex(pt->tx_dev))
+ pt->tx_vdev_stream_type = IFACE;
+ } else {
+ printf("dev type %s invalid must be rx|tx|rxtx\n", value);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+parse_ring_size(const char *key __rte_unused, const char *value, void *extra_args)
+{
+ int n;
+ struct pdump_tuples *pt = extra_args;
+
+ n = atoi(value);
+ if (n >= 0)
+ pt->ring_size = (uint32_t) n;
+ else {
+ printf("ring_size %d invalid - must be >= 0\n", n);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+parse_mbuf_data_size(const char *key __rte_unused, const char *value, void *extra_args)
+{
+ int n;
+ struct pdump_tuples *pt = extra_args;
+
+ n = atoi(value);
+ if (n > 0 && n <= 0xFFFF)
+ pt->mbuf_data_size = (uint16_t) n;
+ else {
+ printf("mbuf_data_size %d invalid - must be > 0 and < 65536\n", n);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+parse_num_mbufs(const char *key __rte_unused, const char *value, void *extra_args)
+{
+ int n;
+ struct pdump_tuples *pt = extra_args;
+
+ n = atoi(value);
+ if (n > 1024)
+ pt->total_num_mbufs = (uint16_t) n;
+ else {
+ printf("total-num-mbufs %d invalid - must be > 1024\n", n);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+parse_pdump(const char *optarg)
+{
+ struct rte_kvargs *kvlist;
+ int ret = 0, cnt1, cnt2;
+ struct pdump_tuples *pt;
+
+ pt = &pdump_t[num_tuples];
+
+ /* initial check for invalid arguments */
+ kvlist = rte_kvargs_parse(optarg, valid_pdump_arguments);
+ if (kvlist == NULL) {
+ printf("invalid arguments passed in --pdump parameter\n");
+ return -1;
+ }
+
+ /* port/device_id parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_PORT_ARG);
+ cnt2 = rte_kvargs_count(kvlist, PDUMP_PCI_ARG);
+ if (!((cnt1 == 1 && cnt2 == 0) || (cnt1 == 0 && cnt2 == 1))) {
+ printf("--pdump parameter must have either port id or device_id "
+ "( i.e.pci or dev name) address argument\n");
+ ret = -1;
+ goto free_kvlist;
+ } else if (cnt1 == 1)
+ ret = rte_kvargs_process(kvlist, PDUMP_PORT_ARG,
+ &parse_port, pt);
+ else if (cnt2 == 1)
+ ret = rte_kvargs_process(kvlist, PDUMP_PCI_ARG,
+ &parse_device_id, pt);
+ if (ret < 0)
+ goto free_kvlist;
+
+ /* queue parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_QUEUE_ARG);
+ if (cnt1 != 1) {
+ printf("--pdump parameter must have queue argument\n");
+ ret = -1;
+ goto free_kvlist;
+ }
+ ret = rte_kvargs_process(kvlist, PDUMP_QUEUE_ARG, &parse_queue, pt);
+ if (ret < 0)
+ goto free_kvlist;
+
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_RX_DEV_ARG);
+ cnt2 = rte_kvargs_count(kvlist, PDUMP_TX_DEV_ARG);
+ if (cnt1 == 0 && cnt2 == 0) {
+ printf("--pdump must have either rx/tx device for packet capturing\n");
+ ret = -1;
+ goto free_kvlist;
+ } else if (cnt1 == 1 && cnt2 == 1) {
+ ret = rte_kvargs_process(kvlist, PDUMP_RX_DEV_ARG, &parse_rxtxdev, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ ret = rte_kvargs_process(kvlist, PDUMP_TX_DEV_ARG, &parse_rxtxdev, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ /* if captured packets has to send to the same vdev */
+ if (!strcmp(pt->rx_dev, pt->tx_dev))
+ pt->single_pdump_dev = true;
+ pt->dir = RTE_PDUMP_FLAG_RXTX;
+ } else if (cnt1 == 1) {
+ ret = rte_kvargs_process(kvlist, PDUMP_RX_DEV_ARG, &parse_rxtxdev, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ pt->dir = RTE_PDUMP_FLAG_RX;
+ } else if (cnt2 == 1) {
+ ret = rte_kvargs_process(kvlist, PDUMP_TX_DEV_ARG, &parse_rxtxdev, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ pt->dir = RTE_PDUMP_FLAG_TX;
+ }
+
+ /* optional */
+ /* ring_size parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_RING_SIZE_ARG);
+ if (cnt1 == 1) {
+ ret = rte_kvargs_process(kvlist, PDUMP_RING_SIZE_ARG,
+ &parse_ring_size, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ } else
+ pt->ring_size = RING_SIZE;
+
+ /* mbuf_data_size parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_MSIZE_ARG);
+ if (cnt1 == 1) {
+ ret = rte_kvargs_process(kvlist, PDUMP_MSIZE_ARG,
+ &parse_mbuf_data_size, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ } else
+ pt->mbuf_data_size = RTE_MBUF_DEFAULT_BUF_SIZE;
+
+ /* total_num_mbufs parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_NUM_MBUFS_ARG);
+ if (cnt1 == 1) {
+ ret = rte_kvargs_process(kvlist, PDUMP_NUM_MBUFS_ARG,
+ &parse_num_mbufs, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ } else
+ pt->total_num_mbufs = MBUFS_PER_POOL;
+
+ num_tuples++;
+ return 0;
+
+free_kvlist:
+ rte_kvargs_free(kvlist);
+ return ret;
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+launch_args_parse(int argc, char **argv)
+{
+ int opt, ret;
+ int option_index;
+ char *prgname = argv[0];
+ static struct option long_option[] = {
+ {"pdump", 1, 0, 0},
+ {NULL, 0, 0, 0}
+ };
+
+ if (argc == 1)
+ pdump_usage(prgname);
+
+ /* Parse command line */
+ while ((opt = getopt_long(argc, argv, " ",
+ long_option, &option_index)) != EOF) {
+ switch (opt) {
+ case 0:
+ if (!strncmp(long_option[option_index].name, "pdump",
+ MAX_LONG_OPT_SZ)) {
+ ret = parse_pdump(optarg);
+ if (ret) {
+ printf("invalid pdump\n");
+ pdump_usage(prgname);
+ return -1;
+ }
+ }
+ break;
+ default:
+ pdump_usage(prgname);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static void
+print_pdump_stats(void)
+{
+ int i;
+ struct pdump_tuples *pt;
+
+ for (i = 0; i < num_tuples; i++) {
+ printf("##### PDUMP DEBUG STATS #####\n");
+ pt = &pdump_t[i];
+ printf(" -packets dequeued: %"PRIu64"\n",
+ pt->stats.dequeue_pkts);
+ printf(" -packets transmitted to vdev: %"PRIu64"\n",
+ pt->stats.tx_pkts);
+ printf(" -packets freed: %"PRIu64"\n",
+ pt->stats.freed_pkts);
+ }
+}
+
+static inline void
+disable_pdump(struct pdump_tuples *pt)
+{
+ if (pt->dump_by_type == DEVICE_ID)
+ rte_pdump_disable_by_deviceid(pt->device_id, pt->queue, pt->dir);
+ else if (pt->dump_by_type == PORT_ID)
+ rte_pdump_disable(pt->port, pt->queue, pt->dir);
+}
+
+static void
+free_ring_data(struct rte_ring *ring, uint8_t vdev_id, struct pdump_stats *stats)
+{
+ while (rte_ring_count(ring)) {
+ /* write input packets of port to vdev for pdump */
+ struct rte_mbuf *rxtx_bufs[BURST_SIZE];
+
+ /* first dequeue packets from ring of primary process */
+ const uint16_t nb_in_deq = rte_ring_dequeue_burst(ring,
+ (void *)rxtx_bufs, BURST_SIZE);
+ stats->dequeue_pkts += nb_in_deq;
+
+ if (nb_in_deq) {
+ /* then sent on vdev */
+ uint16_t nb_in_txd = rte_eth_tx_burst(
+ vdev_id,
+ 0, rxtx_bufs, nb_in_deq);
+ stats->tx_pkts += nb_in_txd;
+
+ if (unlikely(nb_in_txd < nb_in_deq)) {
+ do {
+ rte_pktmbuf_free(rxtx_bufs[nb_in_txd]);
+ stats->freed_pkts++;
+ } while (++nb_in_txd < nb_in_deq);
+ }
+ }
+ }
+}
+
+static void
+cleanup_pdump_resources(void)
+{
+ int i;
+ struct pdump_tuples *pt;
+
+ /* disable pdump and free the pdump_tuple resources */
+ for (i = 0; i < num_tuples; i++) {
+ pt = &pdump_t[i];
+
+ /* remove callbacks */
+ disable_pdump(pt);
+
+ /*
+ * transmit rest enqueued packets of the rings to vdev,
+ * in order to release mbufs to the mepool
+ **/
+ if (pt->single_pdump_dev && pt->dir == RTE_PDUMP_FLAG_RXTX)
+ free_ring_data(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
+ else if (pt->dir == RTE_PDUMP_FLAG_RXTX) {
+ free_ring_data(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
+ free_ring_data(pt->tx_ring, pt->tx_vdev_id, &pt->stats);
+ } else if (pt->dir == RTE_PDUMP_FLAG_RX)
+ free_ring_data(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
+ else if (pt->dir == RTE_PDUMP_FLAG_TX)
+ free_ring_data(pt->tx_ring, pt->tx_vdev_id, &pt->stats);
+
+ if (pt->device_id)
+ free(pt->device_id);
+
+ /* free the rings */
+ if (pt->rx_ring)
+ rte_ring_free(pt->rx_ring);
+ if (pt->tx_ring)
+ rte_ring_free(pt->tx_ring);
+ }
+}
+
+static void
+signal_handler(int sig_num)
+{
+ if (sig_num == SIGINT) {
+ printf("\n\nSignal %d received, preparing to exit...\n",
+ sig_num);
+ quit_signal = 1;
+ }
+}
+
+static inline int
+configure_vdev(uint8_t port_id)
+{
+ struct ether_addr addr;
+ const uint16_t rxRings = 0, txRings = 1;
+ const uint8_t nb_ports = rte_eth_dev_count();
+ int ret;
+ uint16_t q;
+
+ if (port_id > nb_ports)
+ return -1;
+
+ ret = rte_eth_dev_configure(port_id, rxRings, txRings, &port_conf_default);
+ if (ret != 0)
+ rte_exit(EXIT_FAILURE, "dev config failed\n");
+
+ for (q = 0; q < txRings; q++) {
+ ret = rte_eth_tx_queue_setup(port_id, q, TX_DESC_PER_QUEUE,
+ rte_eth_dev_socket_id(port_id), NULL);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "queue setup failed\n");
+ }
+
+ ret = rte_eth_dev_start(port_id);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "dev start failed\n");
+
+ rte_eth_macaddr_get(port_id, &addr);
+ printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
+ " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
+ (unsigned)port_id,
+ addr.addr_bytes[0], addr.addr_bytes[1],
+ addr.addr_bytes[2], addr.addr_bytes[3],
+ addr.addr_bytes[4], addr.addr_bytes[5]);
+
+ rte_eth_promiscuous_enable(port_id);
+
+ return 0;
+}
+
+static void
+create_mp_ring_vdev(void)
+{
+ int i;
+ uint8_t portid;
+ struct pdump_tuples *pt = NULL;
+ struct rte_mempool *mbuf_pool = NULL;
+ char vdev_args[SIZE];
+ char ring_name[SIZE];
+ char mempool_name[SIZE];
+
+ for (i = 0; i < num_tuples; i++) {
+ pt = &pdump_t[i];
+ snprintf(mempool_name, SIZE, MP_NAME, i);
+ mbuf_pool = rte_mempool_lookup(mempool_name);
+ if (mbuf_pool == NULL) {
+ /* create mempool */
+ mbuf_pool = rte_pktmbuf_pool_create(mempool_name,
+ pt->total_num_mbufs,
+ MBUF_POOL_CACHE_SIZE, 0, pt->mbuf_data_size,
+ rte_socket_id());
+ if (mbuf_pool == NULL)
+ rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno));
+ }
+ pt->mp = mbuf_pool;
+
+ if (pt->dir == RTE_PDUMP_FLAG_RXTX && pt->single_pdump_dev) {
+ /* if captured packets has to send to the same vdev */
+ snprintf(ring_name, SIZE, RX_RING, i);
+ pt->rx_ring = rte_ring_create(ring_name, pt->ring_size,
+ rte_socket_id(), 0);
+ if (pt->rx_ring == NULL)
+ rte_exit(EXIT_FAILURE, "%s:%s:%d\n",
+ rte_strerror(rte_errno), __func__, __LINE__);
+
+ /* create vdevs */
+ (pt->rx_vdev_stream_type == IFACE) ?
+ snprintf(vdev_args, SIZE, VDEV_IFACE, RX_STR, i, pt->rx_dev) :
+ snprintf(vdev_args, SIZE, VDEV_PCAP, RX_STR, i, pt->rx_dev);
+ if (rte_eth_dev_attach(vdev_args, &portid) < 0)
+ rte_exit(EXIT_FAILURE, "vdev creation failed:%s:%d\n",
+ __func__, __LINE__);
+ pt->rx_vdev_id = portid;
+
+ /* configure vdev */
+ configure_vdev(pt->rx_vdev_id);
+
+ } else if (pt->dir == RTE_PDUMP_FLAG_RXTX) {
+ /* if captured packets has to send to the same vdev */
+ /* create rx_ring */
+ snprintf(ring_name, SIZE, RX_RING, i);
+ pt->rx_ring = rte_ring_create(ring_name, pt->ring_size,
+ rte_socket_id(), 0);
+ if (pt->rx_ring == NULL)
+ rte_exit(EXIT_FAILURE, "%s:%s:%d\n",
+ rte_strerror(rte_errno),
+ __func__, __LINE__);
+
+ /* create tx_ring */
+ snprintf(ring_name, SIZE, TX_RING, i);
+ pt->tx_ring = rte_ring_create(ring_name, pt->ring_size,
+ rte_socket_id(), 0);
+ if (pt->tx_ring == NULL)
+ rte_exit(EXIT_FAILURE, "%s:%s:%d\n",
+ rte_strerror(rte_errno),
+ __func__, __LINE__);
+
+ /* create vdevs */
+ (pt->rx_vdev_stream_type == IFACE) ?
+ snprintf(vdev_args, SIZE, VDEV_IFACE, RX_STR, i, pt->rx_dev) :
+ snprintf(vdev_args, SIZE, VDEV_PCAP, RX_STR, i, pt->rx_dev);
+ if (rte_eth_dev_attach(vdev_args, &portid) < 0)
+ rte_exit(EXIT_FAILURE, "vdev creation failed:%s:%d\n",
+ __func__, __LINE__);
+ pt->rx_vdev_id = portid;
+
+ /* configure vdev */
+ configure_vdev(pt->rx_vdev_id);
+
+ (pt->tx_vdev_stream_type == IFACE) ?
+ snprintf(vdev_args, SIZE, VDEV_IFACE, TX_STR, i, pt->tx_dev) :
+ snprintf(vdev_args, SIZE, VDEV_PCAP, TX_STR, i, pt->tx_dev);
+ if (rte_eth_dev_attach(vdev_args, &portid) < 0)
+ rte_exit(EXIT_FAILURE, "vdev creation failed:%s:%d\n",
+ __func__, __LINE__);
+ pt->tx_vdev_id = portid;
+
+ /* configure vdev */
+ configure_vdev(pt->tx_vdev_id);
+
+ } else if (pt->dir == RTE_PDUMP_FLAG_RX) {
+
+ /* create rx_ring */
+ snprintf(ring_name, SIZE, RX_RING, i);
+ pt->rx_ring = rte_ring_create(ring_name, pt->ring_size,
+ rte_socket_id(), 0);
+ if (pt->rx_ring == NULL)
+ rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno));
+
+ (pt->rx_vdev_stream_type == IFACE) ?
+ snprintf(vdev_args, SIZE, VDEV_IFACE, RX_STR, i, pt->rx_dev) :
+ snprintf(vdev_args, SIZE, VDEV_PCAP, RX_STR, i, pt->rx_dev);
+ if (rte_eth_dev_attach(vdev_args, &portid) < 0)
+ rte_exit(EXIT_FAILURE, "vdev creation failed:%s:%d\n",
+ __func__, __LINE__);
+ pt->rx_vdev_id = portid;
+ /* configure vdev */
+ configure_vdev(pt->rx_vdev_id);
+
+ } else if (pt->dir == RTE_PDUMP_FLAG_TX) {
+
+ /* create tx_ring */
+ snprintf(ring_name, SIZE, TX_RING, i);
+ pt->tx_ring = rte_ring_create(ring_name, pt->ring_size,
+ rte_socket_id(), 0);
+ if (pt->tx_ring == NULL)
+ rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno));
+
+ (pt->tx_vdev_stream_type == IFACE) ?
+ snprintf(vdev_args, SIZE, VDEV_IFACE, TX_STR, i, pt->tx_dev) :
+ snprintf(vdev_args, SIZE, VDEV_PCAP, TX_STR, i, pt->tx_dev);
+ if (rte_eth_dev_attach(vdev_args, &portid) < 0)
+ rte_exit(EXIT_FAILURE, "vdev creation failed\n");
+ pt->tx_vdev_id = portid;
+
+ /* configure vdev */
+ configure_vdev(pt->tx_vdev_id);
+
+ }
+ }
+}
+
+static void
+enable_pdump(void)
+{
+ int i;
+ struct pdump_tuples *pt;
+ int ret = 0, ret1 = 0;
+
+ for (i = 0; i < num_tuples; i++) {
+ pt = &pdump_t[i];
+ if (pt->single_pdump_dev && pt->dir == RTE_PDUMP_FLAG_RXTX) {
+ if (pt->dump_by_type == DEVICE_ID)
+ ret = rte_pdump_enable_by_deviceid(pt->device_id,
+ pt->queue, pt->dir,
+ pt->rx_ring,
+ pt->mp, NULL);
+ else if (pt->dump_by_type == PORT_ID)
+ ret = rte_pdump_enable(pt->port, pt->queue, pt->dir,
+ pt->rx_ring, pt->mp, NULL);
+ } else if (pt->dir == RTE_PDUMP_FLAG_RXTX) {
+ if (pt->dump_by_type == DEVICE_ID) {
+ ret = rte_pdump_enable_by_deviceid(pt->device_id,
+ pt->queue,
+ RTE_PDUMP_FLAG_RX,
+ pt->rx_ring,
+ pt->mp, NULL);
+ ret = rte_pdump_enable_by_deviceid(pt->device_id,
+ pt->queue,
+ RTE_PDUMP_FLAG_TX,
+ pt->tx_ring,
+ pt->mp, NULL);
+ } else if (pt->dump_by_type == PORT_ID) {
+ ret = rte_pdump_enable(pt->port, pt->queue,
+ RTE_PDUMP_FLAG_RX,
+ pt->rx_ring, pt->mp, NULL);
+ ret1 = rte_pdump_enable(pt->port, pt->queue,
+ RTE_PDUMP_FLAG_TX,
+ pt->tx_ring, pt->mp, NULL);
+ }
+ } else if (pt->dir == RTE_PDUMP_FLAG_RX) {
+ if (pt->dump_by_type == DEVICE_ID)
+ ret = rte_pdump_enable_by_deviceid(pt->device_id,
+ pt->queue,
+ pt->dir, pt->rx_ring,
+ pt->mp, NULL);
+ else if (pt->dump_by_type == PORT_ID)
+ ret = rte_pdump_enable(pt->port, pt->queue, pt->dir,
+ pt->rx_ring, pt->mp, NULL);
+ } else if (pt->dir == RTE_PDUMP_FLAG_TX) {
+ if (pt->dump_by_type == DEVICE_ID)
+ ret = rte_pdump_enable_by_deviceid(pt->device_id,
+ pt->queue,
+ pt->dir,
+ pt->tx_ring, pt->mp, NULL);
+ else if (pt->dump_by_type == PORT_ID)
+ ret = rte_pdump_enable(pt->port, pt->queue, pt->dir,
+ pt->tx_ring, pt->mp, NULL);
+ }
+ if (ret < 0 || ret1 < 0) {
+ cleanup_pdump_resources();
+ rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno));
+ }
+ }
+}
+
+static inline void
+pdump_rxtx(struct rte_ring *ring, uint8_t vdev_id, struct pdump_stats *stats)
+{
+ /* write input packets of port to vdev for pdump */
+ struct rte_mbuf *rxtx_bufs[BURST_SIZE];
+
+ /* first dequeue packets from ring of primary process */
+ const uint16_t nb_in_deq = rte_ring_dequeue_burst(ring,
+ (void *)rxtx_bufs, BURST_SIZE);
+ stats->dequeue_pkts += nb_in_deq;
+
+ if (nb_in_deq) {
+ /* then sent on vdev */
+ uint16_t nb_in_txd = rte_eth_tx_burst(
+ vdev_id,
+ 0, rxtx_bufs, nb_in_deq);
+ stats->tx_pkts += nb_in_txd;
+
+ if (unlikely(nb_in_txd < nb_in_deq)) {
+ do {
+ rte_pktmbuf_free(rxtx_bufs[nb_in_txd]);
+ stats->freed_pkts++;
+ } while (++nb_in_txd < nb_in_deq);
+ }
+ }
+}
+
+static inline void
+dump_packets(void)
+{
+ int i;
+ struct pdump_tuples *pt;
+
+ while (!quit_signal) {
+ for (i = 0; i < num_tuples; i++) {
+ pt = &pdump_t[i];
+ if (pt->single_pdump_dev && pt->dir == RTE_PDUMP_FLAG_RXTX)
+ pdump_rxtx(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
+ else if (pt->dir == RTE_PDUMP_FLAG_RXTX) {
+ pdump_rxtx(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
+ pdump_rxtx(pt->tx_ring, pt->tx_vdev_id, &pt->stats);
+ } else if (pt->dir == RTE_PDUMP_FLAG_RX)
+ pdump_rxtx(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
+ else if (pt->dir == RTE_PDUMP_FLAG_TX)
+ pdump_rxtx(pt->tx_ring, pt->tx_vdev_id, &pt->stats);
+ }
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ int diag;
+ int ret;
+ int i;
+
+ char c_flag[] = "-c1";
+ char n_flag[] = "-n4";
+ char mp_flag[] = "--proc-type=secondary";
+ char *argp[argc + 3];
+
+ /* catch ctrl-c so we can print on exit */
+ signal(SIGINT, signal_handler);
+
+ argp[0] = argv[0];
+ argp[1] = c_flag;
+ argp[2] = n_flag;
+ argp[3] = mp_flag;
+
+ for (i = 1; i < argc; i++)
+ argp[i + 3] = argv[i];
+
+ argc += 3;
+
+ diag = rte_eal_init(argc, argp);
+ if (diag < 0)
+ rte_panic("Cannot init EAL\n");
+
+ argc -= diag;
+ argv += (diag - 3);
+
+ /* parse app arguments */
+ if (argc > 1) {
+ ret = launch_args_parse(argc, argv);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Invalid argument\n");
+ }
+
+ /* create mempool, ring and vdevs info */
+ create_mp_ring_vdev();
+ enable_pdump();
+ dump_packets();
+
+ cleanup_pdump_resources();
+ /* dump debug stats */
+ print_pdump_stats();
+
+ return 0;
+}
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v4 6/9] app/pdump: add pdump tool for packet capturing
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 6/9] app/pdump: add pdump tool for packet capturing Reshma Pattan
@ 2016-05-27 15:21 ` Ananyev, Konstantin
2016-05-31 14:50 ` Pattan, Reshma
0 siblings, 1 reply; 82+ messages in thread
From: Ananyev, Konstantin @ 2016-05-27 15:21 UTC (permalink / raw)
To: Pattan, Reshma, dev; +Cc: Pattan, Reshma
>
> New tool added for packet capturing on dpdk.
> This tool supports command line options.
> This tool runs as secondary process by default.
>
> Command line supports various parameters to capture
> the packets.
>
> User should pass on a)port and queue (or) b)pci address
> and queue (or) c)device name and queue to capture
> the packets.
>
> Users also need to pass on either pcap file name or
> any linux iface, on to which packets captured from dpdk
> ports will be sent on for the users to view using tcpdump.
>
> Users have option to capture packets either a) in RX
> direction, b)(or) in TX direction c)(or) from both the
> directions.
>
> User can pass on ring_size and mempool parameters using
> command line, but these are optional parameters.
> These are used to create ring and mempool objects for packet
> mirroring from primary application to tool. If user doesn't
> provide any values, default values will be used internally
> for the creation of the ring and mempool.
>
> Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
> ---
> MAINTAINERS | 1 +
> app/Makefile | 1 +
> app/pdump/Makefile | 45 +++
> app/pdump/main.c | 888 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 935 insertions(+)
> create mode 100644 app/pdump/Makefile
> create mode 100644 app/pdump/main.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 8656239..ae706b9 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -436,6 +436,7 @@ F: doc/guides/sample_app_ug/packet_ordering.rst
> Pdump
> M: Reshma Pattan <reshma.pattan@intel.com>
> F: lib/librte_pdump/
> +F: app/pdump/
>
> Hierarchical scheduler
> M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
> diff --git a/app/Makefile b/app/Makefile
> index 1151e09..c593efa 100644
> --- a/app/Makefile
> +++ b/app/Makefile
> @@ -37,5 +37,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += test-pipeline
> DIRS-$(CONFIG_RTE_TEST_PMD) += test-pmd
> DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_test
> DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += proc_info
> +DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += pdump
>
> include $(RTE_SDK)/mk/rte.subdir.mk
> diff --git a/app/pdump/Makefile b/app/pdump/Makefile
> new file mode 100644
> index 0000000..96bb4af
> --- /dev/null
> +++ b/app/pdump/Makefile
> @@ -0,0 +1,45 @@
> +# 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_SDK)/mk/rte.vars.mk
> +
> +APP = dpdk_pdump
> +
> +CFLAGS += $(WERROR_FLAGS)
> +
> +# all source are stored in SRCS-y
> +
> +SRCS-y := main.c
> +
> +# this application needs libraries first
> +DEPDIRS-y += lib
> +
> +include $(RTE_SDK)/mk/rte.app.mk
> diff --git a/app/pdump/main.c b/app/pdump/main.c
> new file mode 100644
> index 0000000..f507f3b
> --- /dev/null
> +++ b/app/pdump/main.c
> @@ -0,0 +1,888 @@
> +/*
> + * 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 <stdio.h>
> +#include <string.h>
> +#include <stdint.h>
> +#include <inttypes.h>
> +#include <stdlib.h>
> +#include <getopt.h>
> +#include <signal.h>
> +#include <stdbool.h>
> +#include <net/if.h>
> +
> +#include <rte_eal.h>
> +#include <rte_common.h>
> +#include <rte_debug.h>
> +#include <rte_ethdev.h>
> +#include <rte_memory.h>
> +#include <rte_lcore.h>
> +#include <rte_branch_prediction.h>
> +#include <rte_errno.h>
> +#include <rte_dev.h>
> +#include <rte_kvargs.h>
> +#include <rte_mempool.h>
> +#include <rte_ring.h>
> +#include <rte_pdump.h>
> +
> +#define PDUMP_PORT_ARG "port"
> +#define PDUMP_PCI_ARG "device_id"
> +#define PDUMP_QUEUE_ARG "queue"
> +#define PDUMP_DIR_ARG "dir"
> +#define PDUMP_RX_DEV_ARG "rx-dev"
> +#define PDUMP_TX_DEV_ARG "tx-dev"
> +#define PDUMP_RING_SIZE_ARG "ring-size"
> +#define PDUMP_MSIZE_ARG "mbuf-size"
> +#define PDUMP_NUM_MBUFS_ARG "total-num-mbufs"
> +
> +#define VDEV_PCAP "eth_pcap_%s_%d,tx_pcap=%s"
> +#define VDEV_IFACE "eth_pcap_%s_%d,tx_iface=%s"
> +#define TX_STREAM_SIZE 64
> +
> +#define MP_NAME "pdump_pool_%d"
> +
> +#define RX_RING "rx_ring_%d"
> +#define TX_RING "tx_ring_%d"
> +
> +#define RX_STR "rx"
> +#define TX_STR "tx"
> +
> +/* Maximum long option length for option parsing. */
> +#define APP_ARG_TCPDUMP_MAX_TUPLES 54
> +#define MBUF_POOL_CACHE_SIZE 250
> +#define TX_DESC_PER_QUEUE 512
> +#define RX_DESC_PER_QUEUE 128
> +#define MBUFS_PER_POOL 65535
> +#define MAX_LONG_OPT_SZ 64
> +#define RING_SIZE 16384
> +#define SIZE 256
> +#define BURST_SIZE 32
> +#define NUM_VDEVS 2
> +
> +enum pdump_en_dis {
> + DISABLE = 1,
> + ENABLE = 2
> +};
> +
> +enum pcap_stream {
> + IFACE = 1,
> + PCAP = 2
> +};
> +
> +enum pdump_by {
> + PORT_ID = 1,
> + DEVICE_ID = 2
> +};
> +
> +const char *valid_pdump_arguments[] = {
> + PDUMP_PORT_ARG,
> + PDUMP_PCI_ARG,
> + PDUMP_QUEUE_ARG,
> + PDUMP_DIR_ARG,
> + PDUMP_RX_DEV_ARG,
> + PDUMP_TX_DEV_ARG,
> + PDUMP_RING_SIZE_ARG,
> + PDUMP_MSIZE_ARG,
> + PDUMP_NUM_MBUFS_ARG,
> + NULL
> +};
> +
> +struct pdump_stats {
> + uint64_t dequeue_pkts;
> + uint64_t tx_pkts;
> + uint64_t freed_pkts;
> +};
> +
> +struct pdump_tuples {
> + /* cli params */
> + uint8_t port;
> + char *device_id;
> + uint16_t queue;
> + char rx_dev[TX_STREAM_SIZE];
> + char tx_dev[TX_STREAM_SIZE];
> + uint32_t ring_size;
> + uint16_t mbuf_data_size;
> + uint32_t total_num_mbufs;
> +
> + /* params for library API call */
> + uint32_t dir;
> + struct rte_mempool *mp;
> + struct rte_ring *rx_ring;
> + struct rte_ring *tx_ring;
> +
> + /* params for packet dumping */
> + enum pdump_by dump_by_type;
> + int rx_vdev_id;
> + int tx_vdev_id;
> + enum pcap_stream rx_vdev_stream_type;
> + enum pcap_stream tx_vdev_stream_type;
> + bool single_pdump_dev;
> +
> + /* stats */
> + struct pdump_stats stats;
> +} __rte_cache_aligned;
> +static struct pdump_tuples pdump_t[APP_ARG_TCPDUMP_MAX_TUPLES];
> +
> +int num_tuples;
> +static struct rte_eth_conf port_conf_default;
> +volatile uint8_t quit_signal;
> +
> +/**< display usage */
> +static void
> +pdump_usage(const char *prgname)
> +{
> + printf("%s [EAL options] -- --pdump "
> + "'(port=<port id> | device_id=<pci id or vdev name>),"
> + "(queue=<queue_id>),"
> + "(rx-dev=<iface or pcap file> |"
> + " tx-dev=<iface or pcap file>,"
> + "[ring-size=<ring size>default:16384],"
> + "[mbuf-size=<mbuf data size>default:2176],"
> + "[total-num-mbufs=<number of mbufs>default:65535]"
> + "'\n",
> + prgname);
> +}
> +
> +static int
> +parse_port(const char *key __rte_unused, const char *value, void *extra_args)
> +{
> + int n;
> + struct pdump_tuples *pt = extra_args;
> +
> + n = atoi(value);
Here and in other places - better to use strtoul() - it provides error checking and
accepts input in different notations.
> + if (n >= RTE_MAX_ETHPORTS) {
> + printf("port %d >= RTE_MAX_ETHPORTS(%d)\n", n, RTE_MAX_ETHPORTS);
> + return -1;
> + }
> + pt->port = (uint8_t) n;
> + pt->dump_by_type = PORT_ID;
> +
> + return 0;
> +}
> +
> +static int
> +parse_device_id(const char *key __rte_unused, const char *value, void *extra_args)
> +{
> + struct pdump_tuples *pt = extra_args;
> +
> + pt->device_id = strdup(value);
> + pt->dump_by_type = DEVICE_ID;
> +
> + return 0;
> +}
> +
> +static int
> +parse_queue(const char *key __rte_unused, const char *value, void *extra_args)
> +{
> + int n;
> + struct pdump_tuples *pt = extra_args;
> +
> + if (!strcmp(value, "*"))
> + pt->queue = RTE_PDUMP_ALL_QUEUES;
> + else {
> + n = atoi(value);
> + if (n >= 0)
> + pt->queue = (uint16_t) n;
> + else {
> + printf("queue id %d invalid - must be >= 0\n", n);
> + return -1;
> + }
> + }
> + return 0;
> +}
> +
> +static int
> +parse_rxtxdev(const char *key, const char *value, void *extra_args)
> +{
> +
> + struct pdump_tuples *pt = extra_args;
> +
> + if (!strcmp(key, PDUMP_RX_DEV_ARG)) {
> + strncpy(pt->rx_dev, value, strlen(value));
> + /* identify the tx stream type for pcap vdev */
> + if (if_nametoindex(pt->rx_dev))
> + pt->rx_vdev_stream_type = IFACE;
> + } else if (!strcmp(key, PDUMP_TX_DEV_ARG)) {
> + strncpy(pt->tx_dev, value, strlen(value));
> + /* identify the tx stream type for pcap vdev */
> + if (if_nametoindex(pt->tx_dev))
> + pt->tx_vdev_stream_type = IFACE;
> + } else {
> + printf("dev type %s invalid must be rx|tx|rxtx\n", value);
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +parse_ring_size(const char *key __rte_unused, const char *value, void *extra_args)
> +{
> + int n;
> + struct pdump_tuples *pt = extra_args;
> +
> + n = atoi(value);
> + if (n >= 0)
> + pt->ring_size = (uint32_t) n;
> + else {
> + printf("ring_size %d invalid - must be >= 0\n", n);
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +parse_mbuf_data_size(const char *key __rte_unused, const char *value, void *extra_args)
> +{
> + int n;
> + struct pdump_tuples *pt = extra_args;
> +
> + n = atoi(value);
> + if (n > 0 && n <= 0xFFFF)
> + pt->mbuf_data_size = (uint16_t) n;
> + else {
> + printf("mbuf_data_size %d invalid - must be > 0 and < 65536\n", n);
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +parse_num_mbufs(const char *key __rte_unused, const char *value, void *extra_args)
> +{
> + int n;
> + struct pdump_tuples *pt = extra_args;
> +
> + n = atoi(value);
> + if (n > 1024)
> + pt->total_num_mbufs = (uint16_t) n;
> + else {
> + printf("total-num-mbufs %d invalid - must be > 1024\n", n);
> + return -1;
> + }
> +
> + return 0;
> +}
You have several parse functions - doing almost the same thing:
convert string to integer value and then check that this valu is within specific range.
Why not to introduce one function that would accept as extra_args pointer to
the struct {uint64_t v; uint64_t min; uint64_t max; }
So inside that function you can check that: v >= min && v < max or so.
Then you can use that function all over the places.
Another possibility just have parse function that only does conversion
without any boundary checking, and make boundary check later in parse_pdump().
In both cases you can re-use same parse function.
> +
> +static int
> +parse_pdump(const char *optarg)
> +{
> + struct rte_kvargs *kvlist;
> + int ret = 0, cnt1, cnt2;
> + struct pdump_tuples *pt;
> +
> + pt = &pdump_t[num_tuples];
> +
> + /* initial check for invalid arguments */
> + kvlist = rte_kvargs_parse(optarg, valid_pdump_arguments);
> + if (kvlist == NULL) {
> + printf("invalid arguments passed in --pdump parameter\n");
> + return -1;
> + }
> +
> + /* port/device_id parsing and validation */
> + cnt1 = rte_kvargs_count(kvlist, PDUMP_PORT_ARG);
> + cnt2 = rte_kvargs_count(kvlist, PDUMP_PCI_ARG);
> + if (!((cnt1 == 1 && cnt2 == 0) || (cnt1 == 0 && cnt2 == 1))) {
> + printf("--pdump parameter must have either port id or device_id "
> + "( i.e.pci or dev name) address argument\n");
Here and in other places: for usability it might be usefull to print optarg in error message,
so for user it would be easier to understand which of --pdump parameters is wrong:
printf("--pdump=\"%s\": parameter must have either port id or device_id...\n",
optarg, ...);
> + ret = -1;
> + goto free_kvlist;
> + } else if (cnt1 == 1)
> + ret = rte_kvargs_process(kvlist, PDUMP_PORT_ARG,
> + &parse_port, pt);
> + else if (cnt2 == 1)
> + ret = rte_kvargs_process(kvlist, PDUMP_PCI_ARG,
> + &parse_device_id, pt);
> + if (ret < 0)
> + goto free_kvlist;
> +
> + /* queue parsing and validation */
> + cnt1 = rte_kvargs_count(kvlist, PDUMP_QUEUE_ARG);
> + if (cnt1 != 1) {
> + printf("--pdump parameter must have queue argument\n");
> + ret = -1;
> + goto free_kvlist;
> + }
> + ret = rte_kvargs_process(kvlist, PDUMP_QUEUE_ARG, &parse_queue, pt);
> + if (ret < 0)
> + goto free_kvlist;
> +
> + cnt1 = rte_kvargs_count(kvlist, PDUMP_RX_DEV_ARG);
> + cnt2 = rte_kvargs_count(kvlist, PDUMP_TX_DEV_ARG);
> + if (cnt1 == 0 && cnt2 == 0) {
> + printf("--pdump must have either rx/tx device for packet capturing\n");
> + ret = -1;
> + goto free_kvlist;
> + } else if (cnt1 == 1 && cnt2 == 1) {
> + ret = rte_kvargs_process(kvlist, PDUMP_RX_DEV_ARG, &parse_rxtxdev, pt);
> + if (ret < 0)
> + goto free_kvlist;
> + ret = rte_kvargs_process(kvlist, PDUMP_TX_DEV_ARG, &parse_rxtxdev, pt);
> + if (ret < 0)
> + goto free_kvlist;
> + /* if captured packets has to send to the same vdev */
> + if (!strcmp(pt->rx_dev, pt->tx_dev))
> + pt->single_pdump_dev = true;
> + pt->dir = RTE_PDUMP_FLAG_RXTX;
> + } else if (cnt1 == 1) {
> + ret = rte_kvargs_process(kvlist, PDUMP_RX_DEV_ARG, &parse_rxtxdev, pt);
> + if (ret < 0)
> + goto free_kvlist;
> + pt->dir = RTE_PDUMP_FLAG_RX;
> + } else if (cnt2 == 1) {
> + ret = rte_kvargs_process(kvlist, PDUMP_TX_DEV_ARG, &parse_rxtxdev, pt);
> + if (ret < 0)
> + goto free_kvlist;
> + pt->dir = RTE_PDUMP_FLAG_TX;
> + }
> +
> + /* optional */
> + /* ring_size parsing and validation */
> + cnt1 = rte_kvargs_count(kvlist, PDUMP_RING_SIZE_ARG);
> + if (cnt1 == 1) {
> + ret = rte_kvargs_process(kvlist, PDUMP_RING_SIZE_ARG,
> + &parse_ring_size, pt);
> + if (ret < 0)
> + goto free_kvlist;
> + } else
> + pt->ring_size = RING_SIZE;
> +
> + /* mbuf_data_size parsing and validation */
> + cnt1 = rte_kvargs_count(kvlist, PDUMP_MSIZE_ARG);
> + if (cnt1 == 1) {
> + ret = rte_kvargs_process(kvlist, PDUMP_MSIZE_ARG,
> + &parse_mbuf_data_size, pt);
> + if (ret < 0)
> + goto free_kvlist;
> + } else
> + pt->mbuf_data_size = RTE_MBUF_DEFAULT_BUF_SIZE;
> +
> + /* total_num_mbufs parsing and validation */
> + cnt1 = rte_kvargs_count(kvlist, PDUMP_NUM_MBUFS_ARG);
> + if (cnt1 == 1) {
> + ret = rte_kvargs_process(kvlist, PDUMP_NUM_MBUFS_ARG,
> + &parse_num_mbufs, pt);
> + if (ret < 0)
> + goto free_kvlist;
> + } else
> + pt->total_num_mbufs = MBUFS_PER_POOL;
> +
Shouldn't you call rte_kvargs_free(kvlist) in case of successful
completion also?
> + num_tuples++;
> + return 0;
> +
> +free_kvlist:
> + rte_kvargs_free(kvlist);
> + return ret;
> +}
> +
> +/* Parse the argument given in the command line of the application */
> +static int
> +launch_args_parse(int argc, char **argv)
> +{
> + int opt, ret;
> + int option_index;
> + char *prgname = argv[0];
> + static struct option long_option[] = {
> + {"pdump", 1, 0, 0},
> + {NULL, 0, 0, 0}
> + };
> +
> + if (argc == 1)
> + pdump_usage(prgname);
> +
> + /* Parse command line */
> + while ((opt = getopt_long(argc, argv, " ",
> + long_option, &option_index)) != EOF) {
> + switch (opt) {
> + case 0:
> + if (!strncmp(long_option[option_index].name, "pdump",
> + MAX_LONG_OPT_SZ)) {
> + ret = parse_pdump(optarg);
> + if (ret) {
> + printf("invalid pdump\n");
> + pdump_usage(prgname);
> + return -1;
> + }
> + }
> + break;
> + default:
> + pdump_usage(prgname);
> + return -1;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static void
> +print_pdump_stats(void)
> +{
> + int i;
> + struct pdump_tuples *pt;
> +
> + for (i = 0; i < num_tuples; i++) {
> + printf("##### PDUMP DEBUG STATS #####\n");
> + pt = &pdump_t[i];
> + printf(" -packets dequeued: %"PRIu64"\n",
> + pt->stats.dequeue_pkts);
> + printf(" -packets transmitted to vdev: %"PRIu64"\n",
> + pt->stats.tx_pkts);
> + printf(" -packets freed: %"PRIu64"\n",
> + pt->stats.freed_pkts);
> + }
> +}
> +
> +static inline void
> +disable_pdump(struct pdump_tuples *pt)
> +{
> + if (pt->dump_by_type == DEVICE_ID)
> + rte_pdump_disable_by_deviceid(pt->device_id, pt->queue, pt->dir);
> + else if (pt->dump_by_type == PORT_ID)
> + rte_pdump_disable(pt->port, pt->queue, pt->dir);
> +}
> +
> +static void
> +free_ring_data(struct rte_ring *ring, uint8_t vdev_id, struct pdump_stats *stats)
> +{
> + while (rte_ring_count(ring)) {
> + /* write input packets of port to vdev for pdump */
> + struct rte_mbuf *rxtx_bufs[BURST_SIZE];
> +
> + /* first dequeue packets from ring of primary process */
> + const uint16_t nb_in_deq = rte_ring_dequeue_burst(ring,
> + (void *)rxtx_bufs, BURST_SIZE);
> + stats->dequeue_pkts += nb_in_deq;
> +
> + if (nb_in_deq) {
> + /* then sent on vdev */
> + uint16_t nb_in_txd = rte_eth_tx_burst(
> + vdev_id,
> + 0, rxtx_bufs, nb_in_deq);
> + stats->tx_pkts += nb_in_txd;
> +
> + if (unlikely(nb_in_txd < nb_in_deq)) {
> + do {
> + rte_pktmbuf_free(rxtx_bufs[nb_in_txd]);
> + stats->freed_pkts++;
> + } while (++nb_in_txd < nb_in_deq);
> + }
> + }
> + }
> +}
> +
> +static void
> +cleanup_pdump_resources(void)
> +{
> + int i;
> + struct pdump_tuples *pt;
> +
> + /* disable pdump and free the pdump_tuple resources */
> + for (i = 0; i < num_tuples; i++) {
> + pt = &pdump_t[i];
> +
> + /* remove callbacks */
> + disable_pdump(pt);
> +
> + /*
> + * transmit rest enqueued packets of the rings to vdev,
> + * in order to release mbufs to the mepool
> + **/
> + if (pt->single_pdump_dev && pt->dir == RTE_PDUMP_FLAG_RXTX)
> + free_ring_data(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
> + else if (pt->dir == RTE_PDUMP_FLAG_RXTX) {
> + free_ring_data(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
> + free_ring_data(pt->tx_ring, pt->tx_vdev_id, &pt->stats);
> + } else if (pt->dir == RTE_PDUMP_FLAG_RX)
> + free_ring_data(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
> + else if (pt->dir == RTE_PDUMP_FLAG_TX)
> + free_ring_data(pt->tx_ring, pt->tx_vdev_id, &pt->stats);
> +
That code above seems almost identical to what dump_packets() is doing,
and free_ring_data() itself seems identical to pdump_rxtx().
Could it be merged somehow to avoid duplicated code?
> + if (pt->device_id)
> + free(pt->device_id);
> +
> + /* free the rings */
> + if (pt->rx_ring)
> + rte_ring_free(pt->rx_ring);
> + if (pt->tx_ring)
> + rte_ring_free(pt->tx_ring);
> + }
> +}
> +
> +static void
> +signal_handler(int sig_num)
> +{
> + if (sig_num == SIGINT) {
> + printf("\n\nSignal %d received, preparing to exit...\n",
> + sig_num);
> + quit_signal = 1;
> + }
> +}
> +
> +static inline int
> +configure_vdev(uint8_t port_id)
> +{
> + struct ether_addr addr;
> + const uint16_t rxRings = 0, txRings = 1;
> + const uint8_t nb_ports = rte_eth_dev_count();
> + int ret;
> + uint16_t q;
> +
> + if (port_id > nb_ports)
> + return -1;
> +
> + ret = rte_eth_dev_configure(port_id, rxRings, txRings, &port_conf_default);
> + if (ret != 0)
> + rte_exit(EXIT_FAILURE, "dev config failed\n");
> +
> + for (q = 0; q < txRings; q++) {
> + ret = rte_eth_tx_queue_setup(port_id, q, TX_DESC_PER_QUEUE,
> + rte_eth_dev_socket_id(port_id), NULL);
> + if (ret < 0)
> + rte_exit(EXIT_FAILURE, "queue setup failed\n");
> + }
> +
> + ret = rte_eth_dev_start(port_id);
> + if (ret < 0)
> + rte_exit(EXIT_FAILURE, "dev start failed\n");
> +
> + rte_eth_macaddr_get(port_id, &addr);
> + printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
> + " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
> + (unsigned)port_id,
> + addr.addr_bytes[0], addr.addr_bytes[1],
> + addr.addr_bytes[2], addr.addr_bytes[3],
> + addr.addr_bytes[4], addr.addr_bytes[5]);
> +
> + rte_eth_promiscuous_enable(port_id);
> +
> + return 0;
> +}
> +
> +static void
> +create_mp_ring_vdev(void)
> +{
> + int i;
> + uint8_t portid;
> + struct pdump_tuples *pt = NULL;
> + struct rte_mempool *mbuf_pool = NULL;
> + char vdev_args[SIZE];
> + char ring_name[SIZE];
> + char mempool_name[SIZE];
> +
> + for (i = 0; i < num_tuples; i++) {
> + pt = &pdump_t[i];
> + snprintf(mempool_name, SIZE, MP_NAME, i);
> + mbuf_pool = rte_mempool_lookup(mempool_name);
> + if (mbuf_pool == NULL) {
> + /* create mempool */
> + mbuf_pool = rte_pktmbuf_pool_create(mempool_name,
> + pt->total_num_mbufs,
> + MBUF_POOL_CACHE_SIZE, 0, pt->mbuf_data_size,
> + rte_socket_id());
> + if (mbuf_pool == NULL)
> + rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno));
> + }
> + pt->mp = mbuf_pool;
> +
> + if (pt->dir == RTE_PDUMP_FLAG_RXTX && pt->single_pdump_dev) {
> + /* if captured packets has to send to the same vdev */
> + snprintf(ring_name, SIZE, RX_RING, i);
> + pt->rx_ring = rte_ring_create(ring_name, pt->ring_size,
> + rte_socket_id(), 0);
> + if (pt->rx_ring == NULL)
> + rte_exit(EXIT_FAILURE, "%s:%s:%d\n",
> + rte_strerror(rte_errno), __func__, __LINE__);
> +
> + /* create vdevs */
> + (pt->rx_vdev_stream_type == IFACE) ?
> + snprintf(vdev_args, SIZE, VDEV_IFACE, RX_STR, i, pt->rx_dev) :
> + snprintf(vdev_args, SIZE, VDEV_PCAP, RX_STR, i, pt->rx_dev);
> + if (rte_eth_dev_attach(vdev_args, &portid) < 0)
> + rte_exit(EXIT_FAILURE, "vdev creation failed:%s:%d\n",
> + __func__, __LINE__);
> + pt->rx_vdev_id = portid;
> +
> + /* configure vdev */
> + configure_vdev(pt->rx_vdev_id);
> +
> + } else if (pt->dir == RTE_PDUMP_FLAG_RXTX) {
> + /* if captured packets has to send to the same vdev */
> + /* create rx_ring */
> + snprintf(ring_name, SIZE, RX_RING, i);
> + pt->rx_ring = rte_ring_create(ring_name, pt->ring_size,
> + rte_socket_id(), 0);
> + if (pt->rx_ring == NULL)
> + rte_exit(EXIT_FAILURE, "%s:%s:%d\n",
> + rte_strerror(rte_errno),
> + __func__, __LINE__);
> +
> + /* create tx_ring */
> + snprintf(ring_name, SIZE, TX_RING, i);
> + pt->tx_ring = rte_ring_create(ring_name, pt->ring_size,
> + rte_socket_id(), 0);
> + if (pt->tx_ring == NULL)
> + rte_exit(EXIT_FAILURE, "%s:%s:%d\n",
> + rte_strerror(rte_errno),
> + __func__, __LINE__);
> +
> + /* create vdevs */
> + (pt->rx_vdev_stream_type == IFACE) ?
> + snprintf(vdev_args, SIZE, VDEV_IFACE, RX_STR, i, pt->rx_dev) :
> + snprintf(vdev_args, SIZE, VDEV_PCAP, RX_STR, i, pt->rx_dev);
> + if (rte_eth_dev_attach(vdev_args, &portid) < 0)
> + rte_exit(EXIT_FAILURE, "vdev creation failed:%s:%d\n",
> + __func__, __LINE__);
> + pt->rx_vdev_id = portid;
> +
> + /* configure vdev */
> + configure_vdev(pt->rx_vdev_id);
> +
> + (pt->tx_vdev_stream_type == IFACE) ?
> + snprintf(vdev_args, SIZE, VDEV_IFACE, TX_STR, i, pt->tx_dev) :
> + snprintf(vdev_args, SIZE, VDEV_PCAP, TX_STR, i, pt->tx_dev);
> + if (rte_eth_dev_attach(vdev_args, &portid) < 0)
> + rte_exit(EXIT_FAILURE, "vdev creation failed:%s:%d\n",
> + __func__, __LINE__);
> + pt->tx_vdev_id = portid;
> +
> + /* configure vdev */
> + configure_vdev(pt->tx_vdev_id);
> +
> + } else if (pt->dir == RTE_PDUMP_FLAG_RX) {
> +
> + /* create rx_ring */
> + snprintf(ring_name, SIZE, RX_RING, i);
> + pt->rx_ring = rte_ring_create(ring_name, pt->ring_size,
> + rte_socket_id(), 0);
> + if (pt->rx_ring == NULL)
> + rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno));
> +
> + (pt->rx_vdev_stream_type == IFACE) ?
> + snprintf(vdev_args, SIZE, VDEV_IFACE, RX_STR, i, pt->rx_dev) :
> + snprintf(vdev_args, SIZE, VDEV_PCAP, RX_STR, i, pt->rx_dev);
> + if (rte_eth_dev_attach(vdev_args, &portid) < 0)
> + rte_exit(EXIT_FAILURE, "vdev creation failed:%s:%d\n",
> + __func__, __LINE__);
> + pt->rx_vdev_id = portid;
> + /* configure vdev */
> + configure_vdev(pt->rx_vdev_id);
> +
> + } else if (pt->dir == RTE_PDUMP_FLAG_TX) {
> +
> + /* create tx_ring */
> + snprintf(ring_name, SIZE, TX_RING, i);
> + pt->tx_ring = rte_ring_create(ring_name, pt->ring_size,
> + rte_socket_id(), 0);
> + if (pt->tx_ring == NULL)
> + rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno));
> +
> + (pt->tx_vdev_stream_type == IFACE) ?
> + snprintf(vdev_args, SIZE, VDEV_IFACE, TX_STR, i, pt->tx_dev) :
> + snprintf(vdev_args, SIZE, VDEV_PCAP, TX_STR, i, pt->tx_dev);
> + if (rte_eth_dev_attach(vdev_args, &portid) < 0)
> + rte_exit(EXIT_FAILURE, "vdev creation failed\n");
> + pt->tx_vdev_id = portid;
> +
> + /* configure vdev */
> + configure_vdev(pt->tx_vdev_id);
> +
> + }
> + }
> +}
> +
> +static void
> +enable_pdump(void)
> +{
> + int i;
> + struct pdump_tuples *pt;
> + int ret = 0, ret1 = 0;
> +
> + for (i = 0; i < num_tuples; i++) {
> + pt = &pdump_t[i];
> + if (pt->single_pdump_dev && pt->dir == RTE_PDUMP_FLAG_RXTX) {
> + if (pt->dump_by_type == DEVICE_ID)
> + ret = rte_pdump_enable_by_deviceid(pt->device_id,
> + pt->queue, pt->dir,
> + pt->rx_ring,
> + pt->mp, NULL);
> + else if (pt->dump_by_type == PORT_ID)
> + ret = rte_pdump_enable(pt->port, pt->queue, pt->dir,
> + pt->rx_ring, pt->mp, NULL);
> + } else if (pt->dir == RTE_PDUMP_FLAG_RXTX) {
> + if (pt->dump_by_type == DEVICE_ID) {
> + ret = rte_pdump_enable_by_deviceid(pt->device_id,
> + pt->queue,
> + RTE_PDUMP_FLAG_RX,
> + pt->rx_ring,
> + pt->mp, NULL);
> + ret = rte_pdump_enable_by_deviceid(pt->device_id,
> + pt->queue,
> + RTE_PDUMP_FLAG_TX,
> + pt->tx_ring,
> + pt->mp, NULL);
> + } else if (pt->dump_by_type == PORT_ID) {
> + ret = rte_pdump_enable(pt->port, pt->queue,
> + RTE_PDUMP_FLAG_RX,
> + pt->rx_ring, pt->mp, NULL);
> + ret1 = rte_pdump_enable(pt->port, pt->queue,
> + RTE_PDUMP_FLAG_TX,
> + pt->tx_ring, pt->mp, NULL);
> + }
> + } else if (pt->dir == RTE_PDUMP_FLAG_RX) {
> + if (pt->dump_by_type == DEVICE_ID)
> + ret = rte_pdump_enable_by_deviceid(pt->device_id,
> + pt->queue,
> + pt->dir, pt->rx_ring,
> + pt->mp, NULL);
> + else if (pt->dump_by_type == PORT_ID)
> + ret = rte_pdump_enable(pt->port, pt->queue, pt->dir,
> + pt->rx_ring, pt->mp, NULL);
> + } else if (pt->dir == RTE_PDUMP_FLAG_TX) {
> + if (pt->dump_by_type == DEVICE_ID)
> + ret = rte_pdump_enable_by_deviceid(pt->device_id,
> + pt->queue,
> + pt->dir,
> + pt->tx_ring, pt->mp, NULL);
> + else if (pt->dump_by_type == PORT_ID)
> + ret = rte_pdump_enable(pt->port, pt->queue, pt->dir,
> + pt->tx_ring, pt->mp, NULL);
> + }
> + if (ret < 0 || ret1 < 0) {
> + cleanup_pdump_resources();
> + rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno));
> + }
> + }
> +}
> +
> +static inline void
> +pdump_rxtx(struct rte_ring *ring, uint8_t vdev_id, struct pdump_stats *stats)
> +{
> + /* write input packets of port to vdev for pdump */
> + struct rte_mbuf *rxtx_bufs[BURST_SIZE];
> +
> + /* first dequeue packets from ring of primary process */
> + const uint16_t nb_in_deq = rte_ring_dequeue_burst(ring,
> + (void *)rxtx_bufs, BURST_SIZE);
> + stats->dequeue_pkts += nb_in_deq;
> +
> + if (nb_in_deq) {
> + /* then sent on vdev */
> + uint16_t nb_in_txd = rte_eth_tx_burst(
> + vdev_id,
> + 0, rxtx_bufs, nb_in_deq);
> + stats->tx_pkts += nb_in_txd;
> +
> + if (unlikely(nb_in_txd < nb_in_deq)) {
> + do {
> + rte_pktmbuf_free(rxtx_bufs[nb_in_txd]);
> + stats->freed_pkts++;
> + } while (++nb_in_txd < nb_in_deq);
> + }
> + }
> +}
> +
> +static inline void
> +dump_packets(void)
> +{
> + int i;
> + struct pdump_tuples *pt;
> +
> + while (!quit_signal) {
> + for (i = 0; i < num_tuples; i++) {
> + pt = &pdump_t[i];
> + if (pt->single_pdump_dev && pt->dir == RTE_PDUMP_FLAG_RXTX)
Not sure why do you need all this complicated logig with single_pdump_dev?
If the user wants both RX and TX go to the same pcap-vdev, you still can
create 2 different rings (or probably store one ring ptr for both rx_ring and tx_ring), and then just:
for (i = 0; i < num_tuples; i++) {
pt = &pdump_t[i];
if (pt->dir & RTE_PDUMP_FLAG_RXTX)
pdump_rxtx(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
if (pt->dir & RTE_PDUMP_FLAG_TX)
pdump_rxtx(pt->tx_ring, pt->tx_vdev_id, &pt->stats);
}
No?
Konstantin
> + pdump_rxtx(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
> + else if (pt->dir == RTE_PDUMP_FLAG_RXTX) {
> + pdump_rxtx(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
> + pdump_rxtx(pt->tx_ring, pt->tx_vdev_id, &pt->stats);
> + } else if (pt->dir == RTE_PDUMP_FLAG_RX)
> + pdump_rxtx(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
> + else if (pt->dir == RTE_PDUMP_FLAG_TX)
> + pdump_rxtx(pt->tx_ring, pt->tx_vdev_id, &pt->stats);
> + }
> + }
> +}
> +
> +int
> +main(int argc, char **argv)
> +{
> + int diag;
> + int ret;
> + int i;
> +
> + char c_flag[] = "-c1";
> + char n_flag[] = "-n4";
> + char mp_flag[] = "--proc-type=secondary";
> + char *argp[argc + 3];
> +
> + /* catch ctrl-c so we can print on exit */
> + signal(SIGINT, signal_handler);
> +
> + argp[0] = argv[0];
> + argp[1] = c_flag;
> + argp[2] = n_flag;
> + argp[3] = mp_flag;
> +
> + for (i = 1; i < argc; i++)
> + argp[i + 3] = argv[i];
> +
> + argc += 3;
> +
> + diag = rte_eal_init(argc, argp);
> + if (diag < 0)
> + rte_panic("Cannot init EAL\n");
> +
> + argc -= diag;
> + argv += (diag - 3);
> +
> + /* parse app arguments */
> + if (argc > 1) {
> + ret = launch_args_parse(argc, argv);
> + if (ret < 0)
> + rte_exit(EXIT_FAILURE, "Invalid argument\n");
> + }
> +
> + /* create mempool, ring and vdevs info */
> + create_mp_ring_vdev();
> + enable_pdump();
> + dump_packets();
> +
> + cleanup_pdump_resources();
> + /* dump debug stats */
> + print_pdump_stats();
> +
> + return 0;
> +}
> --
> 2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v4 6/9] app/pdump: add pdump tool for packet capturing
2016-05-27 15:21 ` Ananyev, Konstantin
@ 2016-05-31 14:50 ` Pattan, Reshma
2016-05-31 17:21 ` Ananyev, Konstantin
0 siblings, 1 reply; 82+ messages in thread
From: Pattan, Reshma @ 2016-05-31 14:50 UTC (permalink / raw)
To: Ananyev, Konstantin, dev
> -----Original Message-----
> From: Ananyev, Konstantin
> Sent: Friday, May 27, 2016 4:22 PM
> To: Pattan, Reshma <reshma.pattan@intel.com>; dev@dpdk.org
> Cc: Pattan, Reshma <reshma.pattan@intel.com>
> Subject: RE: [dpdk-dev] [PATCH v4 6/9] app/pdump: add pdump tool for packet
> capturing
>
>
> > +static int
> > +parse_num_mbufs(const char *key __rte_unused, const char *value, void
> > +*extra_args) {
> > + int n;
> > + struct pdump_tuples *pt = extra_args;
> > +
> > + n = atoi(value);
> > + if (n > 1024)
> > + pt->total_num_mbufs = (uint16_t) n;
> > + else {
> > + printf("total-num-mbufs %d invalid - must be > 1024\n", n);
> > + return -1;
> > + }
> > +
> > + return 0;
> > +}
>
>
> You have several parse functions - doing almost the same thing:
> convert string to integer value and then check that this valu is within specific
> range.
> Why not to introduce one function that would accept as extra_args pointer to
> the struct {uint64_t v; uint64_t min; uint64_t max; } So inside that function you
> can check that: v >= min && v < max or so.
> Then you can use that function all over the places.
> Another possibility just have parse function that only does conversion without
> any boundary checking, and make boundary check later in parse_pdump().
> In both cases you can re-use same parse function.
>
Yes, I do have 4 functions but in all I am not checking min and max values and log message also differs in each
function. So I would like to retain this as it is now.
Thanks,
Reshma
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v4 6/9] app/pdump: add pdump tool for packet capturing
2016-05-31 14:50 ` Pattan, Reshma
@ 2016-05-31 17:21 ` Ananyev, Konstantin
2016-06-02 12:31 ` Pattan, Reshma
0 siblings, 1 reply; 82+ messages in thread
From: Ananyev, Konstantin @ 2016-05-31 17:21 UTC (permalink / raw)
To: Pattan, Reshma, dev
> -----Original Message-----
> From: Pattan, Reshma
> Sent: Tuesday, May 31, 2016 3:50 PM
> To: Ananyev, Konstantin; dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH v4 6/9] app/pdump: add pdump tool for packet capturing
>
>
>
> > -----Original Message-----
> > From: Ananyev, Konstantin
> > Sent: Friday, May 27, 2016 4:22 PM
> > To: Pattan, Reshma <reshma.pattan@intel.com>; dev@dpdk.org
> > Cc: Pattan, Reshma <reshma.pattan@intel.com>
> > Subject: RE: [dpdk-dev] [PATCH v4 6/9] app/pdump: add pdump tool for packet
> > capturing
> >
> >
> > > +static int
> > > +parse_num_mbufs(const char *key __rte_unused, const char *value, void
> > > +*extra_args) {
> > > + int n;
> > > + struct pdump_tuples *pt = extra_args;
> > > +
> > > + n = atoi(value);
> > > + if (n > 1024)
> > > + pt->total_num_mbufs = (uint16_t) n;
> > > + else {
> > > + printf("total-num-mbufs %d invalid - must be > 1024\n", n);
> > > + return -1;
> > > + }
> > > +
> > > + return 0;
> > > +}
> >
> >
> > You have several parse functions - doing almost the same thing:
> > convert string to integer value and then check that this valu is within specific
> > range.
> > Why not to introduce one function that would accept as extra_args pointer to
> > the struct {uint64_t v; uint64_t min; uint64_t max; } So inside that function you
> > can check that: v >= min && v < max or so.
> > Then you can use that function all over the places.
> > Another possibility just have parse function that only does conversion without
> > any boundary checking, and make boundary check later in parse_pdump().
> > In both cases you can re-use same parse function.
> >
>
> Yes, I do have 4 functions but in all I am not checking min and max values and log message also differs in each
> function. So I would like to retain this as it is now.
What for?
>
> Thanks,
> Reshma
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v4 6/9] app/pdump: add pdump tool for packet capturing
2016-05-31 17:21 ` Ananyev, Konstantin
@ 2016-06-02 12:31 ` Pattan, Reshma
2016-06-02 14:22 ` Ananyev, Konstantin
0 siblings, 1 reply; 82+ messages in thread
From: Pattan, Reshma @ 2016-06-02 12:31 UTC (permalink / raw)
To: Ananyev, Konstantin, dev
> -----Original Message-----
> From: Ananyev, Konstantin
> Sent: Tuesday, May 31, 2016 6:21 PM
> To: Pattan, Reshma <reshma.pattan@intel.com>; dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH v4 6/9] app/pdump: add pdump tool for packet
> capturing
>
>
>
> > -----Original Message-----
> > From: Pattan, Reshma
> > Sent: Tuesday, May 31, 2016 3:50 PM
> > To: Ananyev, Konstantin; dev@dpdk.org
> > Subject: RE: [dpdk-dev] [PATCH v4 6/9] app/pdump: add pdump tool for
> > packet capturing
> >
> >
> >
> > > -----Original Message-----
> > > From: Ananyev, Konstantin
> > > Sent: Friday, May 27, 2016 4:22 PM
> > > To: Pattan, Reshma <reshma.pattan@intel.com>; dev@dpdk.org
> > > Cc: Pattan, Reshma <reshma.pattan@intel.com>
> > > Subject: RE: [dpdk-dev] [PATCH v4 6/9] app/pdump: add pdump tool for
> > > packet capturing
> > >
> > >
> > > > +static int
> > > > +parse_num_mbufs(const char *key __rte_unused, const char *value,
> > > > +void
> > > > +*extra_args) {
> > > > + int n;
> > > > + struct pdump_tuples *pt = extra_args;
> > > > +
> > > > + n = atoi(value);
> > > > + if (n > 1024)
> > > > + pt->total_num_mbufs = (uint16_t) n;
> > > > + else {
> > > > + printf("total-num-mbufs %d invalid - must be > 1024\n", n);
> > > > + return -1;
> > > > + }
> > > > +
> > > > + return 0;
> > > > +}
> > >
> > >
> > > You have several parse functions - doing almost the same thing:
> > > convert string to integer value and then check that this valu is
> > > within specific range.
> > > Why not to introduce one function that would accept as extra_args
> > > pointer to the struct {uint64_t v; uint64_t min; uint64_t max; } So
> > > inside that function you can check that: v >= min && v < max or so.
> > > Then you can use that function all over the places.
> > > Another possibility just have parse function that only does
> > > conversion without any boundary checking, and make boundary check later
> in parse_pdump().
> > > In both cases you can re-use same parse function.
> > >
> >
> > Yes, I do have 4 functions but in all I am not checking min and max
> > values and log message also differs in each function. So I would like to retain
> this as it is now.
>
> What for?
>
OK, I will make changes to have parse function only for conversion and boundary checks will be done
In parse_pdump(). This looks ok to me.
I agree with rest of the comments and will take care of the same in next revision of patch set.
> >
> > Thanks,
> > Reshma
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v4 6/9] app/pdump: add pdump tool for packet capturing
2016-06-02 12:31 ` Pattan, Reshma
@ 2016-06-02 14:22 ` Ananyev, Konstantin
0 siblings, 0 replies; 82+ messages in thread
From: Ananyev, Konstantin @ 2016-06-02 14:22 UTC (permalink / raw)
To: Pattan, Reshma, dev
> -----Original Message-----
> From: Pattan, Reshma
> Sent: Thursday, June 02, 2016 1:32 PM
> To: Ananyev, Konstantin; dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH v4 6/9] app/pdump: add pdump tool for packet capturing
>
>
>
> > -----Original Message-----
> > From: Ananyev, Konstantin
> > Sent: Tuesday, May 31, 2016 6:21 PM
> > To: Pattan, Reshma <reshma.pattan@intel.com>; dev@dpdk.org
> > Subject: RE: [dpdk-dev] [PATCH v4 6/9] app/pdump: add pdump tool for packet
> > capturing
> >
> >
> >
> > > -----Original Message-----
> > > From: Pattan, Reshma
> > > Sent: Tuesday, May 31, 2016 3:50 PM
> > > To: Ananyev, Konstantin; dev@dpdk.org
> > > Subject: RE: [dpdk-dev] [PATCH v4 6/9] app/pdump: add pdump tool for
> > > packet capturing
> > >
> > >
> > >
> > > > -----Original Message-----
> > > > From: Ananyev, Konstantin
> > > > Sent: Friday, May 27, 2016 4:22 PM
> > > > To: Pattan, Reshma <reshma.pattan@intel.com>; dev@dpdk.org
> > > > Cc: Pattan, Reshma <reshma.pattan@intel.com>
> > > > Subject: RE: [dpdk-dev] [PATCH v4 6/9] app/pdump: add pdump tool for
> > > > packet capturing
> > > >
> > > >
> > > > > +static int
> > > > > +parse_num_mbufs(const char *key __rte_unused, const char *value,
> > > > > +void
> > > > > +*extra_args) {
> > > > > + int n;
> > > > > + struct pdump_tuples *pt = extra_args;
> > > > > +
> > > > > + n = atoi(value);
> > > > > + if (n > 1024)
> > > > > + pt->total_num_mbufs = (uint16_t) n;
> > > > > + else {
> > > > > + printf("total-num-mbufs %d invalid - must be > 1024\n", n);
> > > > > + return -1;
> > > > > + }
> > > > > +
> > > > > + return 0;
> > > > > +}
> > > >
> > > >
> > > > You have several parse functions - doing almost the same thing:
> > > > convert string to integer value and then check that this valu is
> > > > within specific range.
> > > > Why not to introduce one function that would accept as extra_args
> > > > pointer to the struct {uint64_t v; uint64_t min; uint64_t max; } So
> > > > inside that function you can check that: v >= min && v < max or so.
> > > > Then you can use that function all over the places.
> > > > Another possibility just have parse function that only does
> > > > conversion without any boundary checking, and make boundary check later
> > in parse_pdump().
> > > > In both cases you can re-use same parse function.
> > > >
> > >
> > > Yes, I do have 4 functions but in all I am not checking min and max
> > > values and log message also differs in each function. So I would like to retain
> > this as it is now.
> >
> > What for?
> >
>
> OK, I will make changes to have parse function only for conversion and boundary checks will be done
> In parse_pdump(). This looks ok to me.
>
> I agree with rest of the comments and will take care of the same in next revision of patch set.
Ok, thanks.
Konstantin
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v4 7/9] app/test-pmd: add pdump initialization uninitialization
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 0/9] add " Reshma Pattan
` (5 preceding siblings ...)
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 6/9] app/pdump: add pdump tool for packet capturing Reshma Pattan
@ 2016-05-23 21:38 ` Reshma Pattan
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 8/9] doc: update doc for packet capture framework Reshma Pattan
` (3 subsequent siblings)
10 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-05-23 21:38 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Call rte_pdump_init and rte_pdump_uninit for packet
capturing initialization and uninitialization.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
app/test-pmd/testpmd.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 9d11830..645bf50 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -75,6 +75,7 @@
#ifdef RTE_LIBRTE_PMD_XENVIRT
#include <rte_eth_xenvirt.h>
#endif
+#include <rte_pdump.h>
#include "testpmd.h"
@@ -2023,6 +2024,8 @@ signal_handler(int signum)
if (signum == SIGINT || signum == SIGTERM) {
printf("\nSignal %d received, preparing to exit...\n",
signum);
+ /* uninitialize packet capture framework */
+ rte_pdump_uninit();
force_quit();
/* exit with the expected status */
signal(signum, SIG_DFL);
@@ -2043,6 +2046,9 @@ main(int argc, char** argv)
if (diag < 0)
rte_panic("Cannot init EAL\n");
+ /* initialize packet capture framework */
+ rte_pdump_init();
+
nb_ports = (portid_t) rte_eth_dev_count();
if (nb_ports == 0)
RTE_LOG(WARNING, EAL, "No probed ethernet devices\n");
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v4 8/9] doc: update doc for packet capture framework
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 0/9] add " Reshma Pattan
` (6 preceding siblings ...)
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 7/9] app/test-pmd: add pdump initialization uninitialization Reshma Pattan
@ 2016-05-23 21:38 ` Reshma Pattan
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 9/9] doc: announce ABI change for rte_eth_dev_info structure Reshma Pattan
` (2 subsequent siblings)
10 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-05-23 21:38 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Added programmers guide for librte_pdump.
Added sample application guide for app/pdump application.
Updated release note for packet capture framework changes.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
MAINTAINERS | 3 +
doc/guides/prog_guide/index.rst | 1 +
doc/guides/prog_guide/pdump_library.rst | 106 +++++++++++++++++++++++++++++
doc/guides/rel_notes/release_16_07.rst | 11 +++
doc/guides/sample_app_ug/index.rst | 1 +
doc/guides/sample_app_ug/pdump.rst | 115 ++++++++++++++++++++++++++++++++
6 files changed, 237 insertions(+)
create mode 100644 doc/guides/prog_guide/pdump_library.rst
create mode 100644 doc/guides/sample_app_ug/pdump.rst
diff --git a/MAINTAINERS b/MAINTAINERS
index ae706b9..8b00f41 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -437,6 +437,9 @@ Pdump
M: Reshma Pattan <reshma.pattan@intel.com>
F: lib/librte_pdump/
F: app/pdump/
+F: doc/guides/prog_guide/pdump_library.rst
+F: doc/guides/sample_app_ug/pdump.rst
+
Hierarchical scheduler
M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
index b862d0c..4caf969 100644
--- a/doc/guides/prog_guide/index.rst
+++ b/doc/guides/prog_guide/index.rst
@@ -71,6 +71,7 @@ Programmer's Guide
writing_efficient_code
profile_app
glossary
+ pdump_library
**Figures**
diff --git a/doc/guides/prog_guide/pdump_library.rst b/doc/guides/prog_guide/pdump_library.rst
new file mode 100644
index 0000000..8d9ef29
--- /dev/null
+++ b/doc/guides/prog_guide/pdump_library.rst
@@ -0,0 +1,106 @@
+.. 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.
+
+.. _Pdump_Library:
+
+pdump Library
+=============
+
+The ``pdump`` library provides the framework for the packet capturing on DPDK.
+Library provides the below APIs to initialize the packet capture framework, to enable
+or disable the packet capture and to un initialize the packet capture framework.
+
+``rte_pdump_init()``:
+This API initializes the packet capture framework.
+
+``rte_pdump_enable()``:
+This API enables the packet capture on a given port and the queue.
+Note: filter option in the API is the place holder for the future enhancements.
+
+``rte_pdump_enable_by_deviceid()``:
+This API enables the packet capture on a given device id(``vdev name or pci address``) and the queue.
+Note: filter option in the API is the place holder for the future enhancements.
+
+``rte_pdump_disable()``:
+This API disables the packet capture on a given port and the queue.
+
+``rte_pdump_disable_by_deviceid()``:
+This API disables the packet capture on a given device id(``vdev name or pci address``) and the queue.
+
+``rte_pdump_uninit()``:
+This API un initializes the packet capture framework.
+
+
+Operation
+---------
+
+The ``pdump`` library works on the server and the client based model. The sever is responsible for enabling or
+disabling the packet capture and the clients are responsible to request enable or disable the packet capture.
+
+The packet capture framework, as part of it's initialization, creates the pthread and creates the server socket in
+the pthread. The application who calls the framework initialization first, will have the server socket created and
+the further calls to the framework initialization by same application or other applications is not allowed i.e. only
+one server socket is allowed on the system. So the other applications, can only request for enabling or disabling of
+the packet capture and the client socket is created to send the request to the server. The server socket will be
+listening to the client requests for enabling or disabling the packet capture.
+
+
+Implementation Details
+----------------------
+
+The library API ``rte_pdump_init()``, initializes the packet capture framework by creating the pthread and the server
+socket.The server socket in the pthread context will be listening to the client requests to enable or disable the
+packet capture. Who ever calls this API first will have the server socket created, the subsequent calls to this APIs
+will not create any further server socket. i.e. only one server socket is allowed.
+
+These library APIs ``rte_pdump_enable()/rte_pdump_enable_by_deviceid()`` enables the packet capture, on each call to
+these APIs, library creates the separate client socket, creates the pdump enable request and send the request to the
+server. Server who is listening on the socket will take the request, enable the packet capture by registering the
+Ethernet rx/tx callbacks for the given port or device_id and queue combinations. Then server will mirror the packets
+to the new mempool and enqueue them to the ring that clients has passed in to these APIs, server also sends the response
+back to the client about the status of the request that was processed. After the response is received from the server,
+client socket is closed.
+
+The library APIs ``rte_pdump_disable()/rte_pdump_disable_by_deviceid()`` disables the packet capture, on each call to
+these APIs, library creates the separate client socket, creates the pdump disable request and send the request to the
+server. Server who is listening on the socket will take the request, disable the packet capture by removing the
+Ethernet rx/tx callbacks for the given port or device_id and queue combinations. Server sends the response back to the
+client about the status of the request that was processed. After the response is received from the server, client
+socket is closed.
+
+The library API ``rte_pdump_uninit()``, un initializes the packet capture framework by closing the pthread and the
+server socket.
+
+
+Use Case: Packet Capturing
+--------------------------
+
+DPDK ``app/pdump`` tool is developed based on this library to capture the packets in DPDK.
+Users can use this library to develop their own packet capturing application.
diff --git a/doc/guides/rel_notes/release_16_07.rst b/doc/guides/rel_notes/release_16_07.rst
index 30e78d4..e3cd64a 100644
--- a/doc/guides/rel_notes/release_16_07.rst
+++ b/doc/guides/rel_notes/release_16_07.rst
@@ -47,6 +47,10 @@ New Features
* Dropped specific Xen Dom0 code.
* Dropped specific anonymous mempool code in testpmd.
+* **Added packet capture framework.**
+
+ * The new library ``librte_pdump`` is added to provide packet capture APIs.
+ * The new ``app/pdump`` tool is added to capture packets on DPDK.
Resolved Issues
---------------
@@ -116,6 +120,11 @@ API Changes
ibadcrc, ibadlen, imcasts, fdirmatch, fdirmiss,
tx_pause_xon, rx_pause_xon, tx_pause_xoff, rx_pause_xoff.
+* Function ``rte_eth_dev_get_port_by_name`` changed to public API.
+
+* Function ``rte_eth_dev_info_get`` updated to return new fields ``nb_rx_queues`` and ``nb_tx_queues``
+ in ``rte_eth_dev_info`` object.
+
ABI Changes
-----------
@@ -127,6 +136,8 @@ ABI Changes
* The ``rte_port_source_params`` structure has new fields to support PCAP file.
It was already in release 16.04 with ``RTE_NEXT_ABI`` flag.
+* The ``rte_eth_dev_info`` structure has new fields ``nb_rx_queues`` and ``nb_tx_queues``
+ to support number of queues configured by software.
Shared Library Versions
-----------------------
diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst
index 930f68c..96bb317 100644
--- a/doc/guides/sample_app_ug/index.rst
+++ b/doc/guides/sample_app_ug/index.rst
@@ -76,6 +76,7 @@ Sample Applications User Guide
ptpclient
performance_thread
ipsec_secgw
+ pdump
**Figures**
diff --git a/doc/guides/sample_app_ug/pdump.rst b/doc/guides/sample_app_ug/pdump.rst
new file mode 100644
index 0000000..89b14ec
--- /dev/null
+++ b/doc/guides/sample_app_ug/pdump.rst
@@ -0,0 +1,115 @@
+
+.. 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.
+
+
+dpdk_pdump Application
+======================
+
+The ``dpdk_pdump`` application is a Data Plane Development Kit (DPDK) application that runs as a DPDK secondary process and
+is capable of enabling packet capture on dpdk ports.
+
+
+Running the Application
+-----------------------
+
+The application has a ``--pdump`` command line option with various sub arguments:
+
+.. code-block:: console
+
+ ./build/app/dpdk_pdump --
+ --pdump '(port=<port id> | device_id=<pci id or vdev name>),
+ (queue=<queue_id>),
+ (rx-dev=<iface or pcap file> |
+ tx-dev=<iface or pcap file>),
+ [ring-size=<ring size>],
+ [mbuf-size=<mbuf data size>],
+ [total-num-mbufs=<number of mbufs>]'
+
+Note:
+
+* Parameters inside the parentheses represents mandatory parameters.
+
+* Parameters inside the square brackets represents optional parameters.
+
+Multiple instances of ``--pdump`` can be passed to capture packets on different port and queue combinations.
+
+
+Parameters
+~~~~~~~~~~
+
+``port``:
+Port id of the eth device on which packets should be captured.
+
+``device_id``:
+PCI address (or) name of the eth device on which packets should be captured.
+
+``queue``:
+Queue id of the eth device on which packets should be captured. The user can pass a queue value of ``*`` to enable
+packet capture on all queues of the eth device.
+
+``rx-dev``:
+Can be either a pcap file name or any Linux iface.
+
+``tx-dev``:
+Can be either a pcap file name or any Linux iface.
+
+ .. Note::
+
+ * To receive ingress packets only, ``rx-dev`` should be passed.
+
+ * To receive egress packets only, ``tx-dev`` should be passed.
+
+ * To receive ingress and egress packets separately ``rx-dev`` and ``tx-dev``
+ should both be passed with the different file names or the Linux iface names.
+
+ * To receive ingress and egress packets separately ``rx-dev`` and ``tx-dev``
+ should both be passed with the same file names or the the Linux iface names.
+
+``ring-size``:
+Size of the ring. This value is used internally for ring creation. The ring will be used to enqueue the packets from
+the primary application to the secondary. This is an optional parameter with default size 16384.
+
+``mbuf-size``:
+Size of the mbuf data. This is used internally for mempool creation. Ideally this value must be same as
+the primary application's mempool's mbuf data size which is used for packet RX. This is an optional parameter with
+default size 2176.
+
+``total-num-mbufs``:
+Total number mbufs in mempool. This is used internally for mempool creation. This is an optional parameter with default
+value 65535.
+
+
+Example
+-------
+
+.. code-block:: console
+
+ $ sudo ./build/app/dpdk_pdump -- --pdump 'port=0,queue=*,rx-dev=/tmp/rx.pcap'
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v4 9/9] doc: announce ABI change for rte_eth_dev_info structure
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 0/9] add " Reshma Pattan
` (7 preceding siblings ...)
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 8/9] doc: update doc for packet capture framework Reshma Pattan
@ 2016-05-23 21:38 ` Reshma Pattan
2016-05-26 8:15 ` [dpdk-dev] [PATCH v4 0/9] add packet capture framework Thomas Monjalon
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 " Reshma Pattan
10 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-05-23 21:38 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
New fields nb_rx_queues and nb_tx_queues will be added to
rte_eth_dev_info structure.
Changes to API rte_eth_dev_info_get() will be done to update
these new fields to rte_eth_dev_info object.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
doc/guides/rel_notes/deprecation.rst | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index ad05eba..04316fb 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -57,3 +57,9 @@ Deprecation Notices
a handle, like the way kernel exposes an fd to user for locating a
specific file, and to keep all major structures internally, so that
we are likely to be free from ABI violations in future.
+
+* A librte_ether public structure ``rte_eth_dev_info`` will be changed in 16.07.
+ The proposed change will add new parameters ``nb_rx_queues``, ``nb_tx_queues``
+ to the structure. These are the number of queues configured by software.
+ Modification to definition of ``rte_eth_dev_info_get()`` will be done
+ to update new parameters to ``rte_eth_dev_info`` object.
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v4 0/9] add packet capture framework
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 0/9] add " Reshma Pattan
` (8 preceding siblings ...)
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 9/9] doc: announce ABI change for rte_eth_dev_info structure Reshma Pattan
@ 2016-05-26 8:15 ` Thomas Monjalon
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 " Reshma Pattan
10 siblings, 0 replies; 82+ messages in thread
From: Thomas Monjalon @ 2016-05-26 8:15 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
HELP is needed to review this patchset, please,
especially patches 5 and 6.
Thanks
2016-05-23 22:38, Reshma Pattan:
> This patchset include below changes
>
> 1)Changes to librte_ether.
> 2)New library librte_pdump added for packet capture framework.
> 3)New app/pdump tool added for packet capturing.
> 4)Test pmd changes done to initialize packet capture framework.
> 5)Documentation update.
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v5 0/9] add packet capture framework
2016-05-23 21:38 ` [dpdk-dev] [PATCH v4 0/9] add " Reshma Pattan
` (9 preceding siblings ...)
2016-05-26 8:15 ` [dpdk-dev] [PATCH v4 0/9] add packet capture framework Thomas Monjalon
@ 2016-06-08 13:38 ` Reshma Pattan
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 1/9] librte_ether: protect add/remove of rxtx callbacks with spinlocks Reshma Pattan
` (9 more replies)
10 siblings, 10 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-08 13:38 UTC (permalink / raw)
To: dev
This patch set include below changes
1)Changes to librte_ether.
2)A new library librte_pdump added for packet capture framework.
3)A new app/pdump tool added for packet capturing.
4)Test pmd changes done to initialize packet capture framework.
5)Documentation update.
1)librte_pdump
==============
To support packet capturing on dpdk Ethernet devices, a new library librte_pdump
is added.Users can develop their own packet capturing application using new library APIs.
Operation:
----------
Pdump library provides APIs to support packet capturing on dpdk Ethernet devices.
Library provides APIs to initialize the packet capture framework, enable/disable
the packet capture and uninitialize the packet capture framework.
Pdump library works on client/server based model.
Sever is responsible for enabling/disabling the packet captures.
Clients are responsible for requesting enable/disable of the
packet captures.
As part of packet capture framework initialization, pthread and
the server socket is created. Only one server socket is allowed on the system.
As part of enabling/disabling the packet capture, client sockets are created
and multiple client sockets are allowed.
Who ever calls initialization first they will succeed with the initialization,
next subsequent calls of initialization are not allowed. So next users can only
request enabling/disabling the packet capture.
Applications using below APIs need to pass port/device_id, queue, mempool and
ring parameters. Library uses user provided ring and mempool to mirror the rx/tx
packets of the port for users. Users need to dequeue the rings and write the packets
to vdev(pcap/tuntap) to view the packets using any standard tools.
Note:
Mempool and Ring should be mc/mp supportable.
Mempool mbuf size should be big enough to handle the rx/tx packets of a port.
APIs:
-----
rte_pdump_init()
rte_pdump_enable()
rte_pdump_enable_by_deviceid()
rte_pdump_disable()
rte_pdump_disable_by_deviceid()
rte_pdump_uninit()
2)app/pdump tool
================
Tool app/pdump is designed based on librte_pdump for packet capturing in DPDK.
This tool by default runs as secondary process, and provides the support for
the command line options for packet capture.
./build/app/dpdk_pdump --
--pdump '(port=<port id> | device_id=<pci id or vdev name>),
(queue=<queue id>),
(rx-dev=<iface or pcap file> |
tx-dev=<iface or pcap file>),
[ring-size=<ring size>],
[mbuf-size=<mbuf data size>],
[total-num-mbufs=<number of mbufs>]'
Parameters inside the parenthesis represents the mandatory parameters.
Parameters inside the square brackets represents optional parameters.
User has to pass on packet capture parameters under --pdump parameters, multiples of
--pdump can be passed to capture packets on different port and queue combinations
Operation:
----------
*Tool parse the user command line arguments,
creates the mempool, ring and the PCAP PMD vdev with 'tx_stream' as either
of the device passed in rx-dev|tx-dev parameters.
*Then calls the APIs of librte_pdump i.e. rte_pdump_enable()/rte_pdump_enable_by_deviceid()
to enable packet capturing on a specific port/device_id and queue by passing on
port|device_id, queue, mempool and ring info.
*Tool runs in while loop to dequeue the packets from the ring and write them to pcap device.
*Tool can be stopped using SIGINT, upon which tool calls
rte_pdump_disable()/rte_pdump_disable_by_deviceid() and free the allocated resources.
Note:
CONFIG_RTE_LIBRTE_PMD_PCAP flag should be set to yes to compile and run the pdump tool.
3)Test-pmd changes
==================
Changes are done to test-pmd application to initialize/uninitialize the packet capture framework.
So app/pdump tool can be run to see packets of dpdk ports that are used by test-pmd.
Similarly any application which needs packet capture should call initialize/uninitialize APIs of
librte_pdump and use pdump tool to start the capture.
4)Packet capture flow between pdump tool and librte_pdump
=========================================================
* Pdump tool (Secondary process) requests packet capture
for specific port|device_id and queue combinations.
*Library in secondary process context creates client socket and communicates
the port|device_id, queue, ring and mempool to server.
*Library initializes server in primary process 'test-pmd' context and server serves
the client request to enable Ethernet rxtx call-backs for a given port|device_id and queue.
*Copy the rx/tx packets to passed mempool and enqueue the packets to ring for secondary process.
*Pdump tool will dequeue the packets from ring and writes them to PCAPMD vdev,
so ultimately packets will be seen on the device that is passed in rx-dev|tx-dev.
*Once the pdump tool is terminated with SIGINT it will disable the packet capturing.
*Library receives the disable packet capture request, communicate the info to server,
server will remove the Ethernet rxtx call-backs.
*Packet capture can be seen using tcpdump command
"tcpdump -ni <iface>" (or) "tcpdump –nr <pcapfile>"
5)Example command line
======================
./build/app/dpdk_pdump -- --pdump 'device_id=0000:02:0.0,queue=*,tx-dev=/tmp/dt-file.pcap,rx-dev=/tmp/dr-file.pcap,ring-size=8192,mbuf-size=2176,total-num-mbufs=32768' --pdump 'device_id=0000:01:00.0,queue=*,rx-dev=/tmp/d-file.pcap,tx-dev=/tmp/d-file.pcap,ring-size=16384,mbuf-size=2176,total-num-mbufs=32768'
v5:
addressed code review comments for below patches
http://dpdk.org/dev/patchwork/patch/12955/
http://dpdk.org/dev/patchwork/patch/12951/
v4:
added missing deprecation notice for ABI changes of rte_eth_dev_info structure.
made doc changes as per doc guidelines.
replaced rte_eal_vdev_init with rte_eth_dev_attach in pdump tool.
removed rxtx-dev parameter from pdump tool command line.
v3:
app/pdump: Moved cleanup code from signal handler to main.
divided librte_ether changes into multiple patches.
example command changed in app/pdump application guide
v2:
fix compilation issues for 4.8.3
fix unnecessary #includes
Reshma Pattan (9):
librte_ether: protect add/remove of rxtx callbacks with spinlocks
librte_ether: add new api rte_eth_add_first_rx_callback
librte_ether: add new fields to rte_eth_dev_info struct
librte_ether: make rte_eth_dev_get_port_by_name
rte_eth_dev_get_name_by_port public
lib/librte_pdump: add new library for packet capturing support
app/pdump: add pdump tool for packet capturing
app/test-pmd: add pdump initialization uninitialization
doc: update doc for packet capture framework
doc: announce ABI change for rte_eth_dev_info structure
MAINTAINERS | 8 +
app/Makefile | 1 +
app/pdump/Makefile | 45 ++
app/pdump/main.c | 814 +++++++++++++++++++++++++++++++
app/test-pmd/testpmd.c | 6 +
config/common_base | 5 +
doc/guides/prog_guide/index.rst | 1 +
doc/guides/prog_guide/pdump_library.rst | 107 ++++
doc/guides/rel_notes/deprecation.rst | 6 +
doc/guides/rel_notes/release_16_07.rst | 13 +
doc/guides/sample_app_ug/index.rst | 1 +
doc/guides/sample_app_ug/pdump.rst | 122 +++++
lib/Makefile | 1 +
lib/librte_ether/rte_ethdev.c | 123 +++--
lib/librte_ether/rte_ethdev.h | 59 +++
lib/librte_ether/rte_ether_version.map | 9 +
lib/librte_pdump/Makefile | 55 +++
lib/librte_pdump/rte_pdump.c | 841 ++++++++++++++++++++++++++++++++
lib/librte_pdump/rte_pdump.h | 186 +++++++
lib/librte_pdump/rte_pdump_version.map | 12 +
mk/rte.app.mk | 1 +
21 files changed, 2372 insertions(+), 44 deletions(-)
create mode 100644 app/pdump/Makefile
create mode 100644 app/pdump/main.c
create mode 100644 doc/guides/prog_guide/pdump_library.rst
create mode 100644 doc/guides/sample_app_ug/pdump.rst
create mode 100644 lib/librte_pdump/Makefile
create mode 100644 lib/librte_pdump/rte_pdump.c
create mode 100644 lib/librte_pdump/rte_pdump.h
create mode 100644 lib/librte_pdump/rte_pdump_version.map
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v5 1/9] librte_ether: protect add/remove of rxtx callbacks with spinlocks
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 " Reshma Pattan
@ 2016-06-08 13:38 ` Reshma Pattan
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 2/9] librte_ether: add new api rte_eth_add_first_rx_callback Reshma Pattan
` (8 subsequent siblings)
9 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-08 13:38 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Added spinlocks around add/remove logic of rxtx callbacks to
avoid corruption of callback lists in multithreaded context.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
lib/librte_ether/rte_ethdev.c | 82 +++++++++++++++++++++----------------------
1 file changed, 40 insertions(+), 42 deletions(-)
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index e148028..ce70d58 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -77,6 +77,12 @@ static uint8_t nb_ports;
/* spinlock for eth device callbacks */
static rte_spinlock_t rte_eth_dev_cb_lock = RTE_SPINLOCK_INITIALIZER;
+/* spinlock for add/remove rx callbacks */
+static rte_spinlock_t rte_eth_rx_cb_lock = RTE_SPINLOCK_INITIALIZER;
+
+/* spinlock for add/remove tx callbacks */
+static rte_spinlock_t rte_eth_tx_cb_lock = RTE_SPINLOCK_INITIALIZER;
+
/* store statistics names and its offset in stats structure */
struct rte_eth_xstats_name_off {
char name[RTE_ETH_XSTATS_NAME_SIZE];
@@ -1634,7 +1640,6 @@ rte_eth_dev_set_rx_queue_stats_mapping(uint8_t port_id, uint16_t rx_queue_id,
STAT_QMAP_RX);
}
-
void
rte_eth_dev_info_get(uint8_t port_id, struct rte_eth_dev_info *dev_info)
{
@@ -2905,7 +2910,6 @@ rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
rte_errno = EINVAL;
return NULL;
}
-
struct rte_eth_rxtx_callback *cb = rte_zmalloc(NULL, sizeof(*cb), 0);
if (cb == NULL) {
@@ -2916,6 +2920,7 @@ rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
cb->fn.rx = fn;
cb->param = user_param;
+ rte_spinlock_lock(&rte_eth_rx_cb_lock);
/* Add the callbacks in fifo order. */
struct rte_eth_rxtx_callback *tail =
rte_eth_devices[port_id].post_rx_burst_cbs[queue_id];
@@ -2928,6 +2933,7 @@ rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
tail = tail->next;
tail->next = cb;
}
+ rte_spinlock_unlock(&rte_eth_rx_cb_lock);
return cb;
}
@@ -2957,6 +2963,7 @@ rte_eth_add_tx_callback(uint8_t port_id, uint16_t queue_id,
cb->fn.tx = fn;
cb->param = user_param;
+ rte_spinlock_lock(&rte_eth_tx_cb_lock);
/* Add the callbacks in fifo order. */
struct rte_eth_rxtx_callback *tail =
rte_eth_devices[port_id].pre_tx_burst_cbs[queue_id];
@@ -2969,6 +2976,7 @@ rte_eth_add_tx_callback(uint8_t port_id, uint16_t queue_id,
tail = tail->next;
tail->next = cb;
}
+ rte_spinlock_unlock(&rte_eth_tx_cb_lock);
return cb;
}
@@ -2987,29 +2995,24 @@ rte_eth_remove_rx_callback(uint8_t port_id, uint16_t queue_id,
return -EINVAL;
struct rte_eth_dev *dev = &rte_eth_devices[port_id];
- struct rte_eth_rxtx_callback *cb = dev->post_rx_burst_cbs[queue_id];
- struct rte_eth_rxtx_callback *prev_cb;
-
- /* Reset head pointer and remove user cb if first in the list. */
- if (cb == user_cb) {
- dev->post_rx_burst_cbs[queue_id] = user_cb->next;
- return 0;
- }
-
- /* Remove the user cb from the callback list. */
- do {
- prev_cb = cb;
- cb = cb->next;
-
+ struct rte_eth_rxtx_callback *cb;
+ struct rte_eth_rxtx_callback **prev_cb;
+ int ret = -EINVAL;
+
+ rte_spinlock_lock(&rte_eth_rx_cb_lock);
+ prev_cb = &dev->post_rx_burst_cbs[queue_id];
+ for (; *prev_cb != NULL; prev_cb = &cb->next) {
+ cb = *prev_cb;
if (cb == user_cb) {
- prev_cb->next = user_cb->next;
- return 0;
+ /* Remove the user cb from the callback list. */
+ *prev_cb = cb->next;
+ ret = 0;
+ break;
}
+ }
+ rte_spinlock_unlock(&rte_eth_rx_cb_lock);
- } while (cb != NULL);
-
- /* Callback wasn't found. */
- return -EINVAL;
+ return ret;
}
int
@@ -3026,29 +3029,24 @@ rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
return -EINVAL;
struct rte_eth_dev *dev = &rte_eth_devices[port_id];
- struct rte_eth_rxtx_callback *cb = dev->pre_tx_burst_cbs[queue_id];
- struct rte_eth_rxtx_callback *prev_cb;
-
- /* Reset head pointer and remove user cb if first in the list. */
- if (cb == user_cb) {
- dev->pre_tx_burst_cbs[queue_id] = user_cb->next;
- return 0;
- }
-
- /* Remove the user cb from the callback list. */
- do {
- prev_cb = cb;
- cb = cb->next;
-
+ int ret = -EINVAL;
+ struct rte_eth_rxtx_callback *cb;
+ struct rte_eth_rxtx_callback **prev_cb;
+
+ rte_spinlock_lock(&rte_eth_tx_cb_lock);
+ prev_cb = &dev->pre_tx_burst_cbs[queue_id];
+ for (; *prev_cb != NULL; prev_cb = &cb->next) {
+ cb = *prev_cb;
if (cb == user_cb) {
- prev_cb->next = user_cb->next;
- return 0;
+ /* Remove the user cb from the callback list. */
+ *prev_cb = cb->next;
+ ret = 0;
+ break;
}
+ }
+ rte_spinlock_unlock(&rte_eth_tx_cb_lock);
- } while (cb != NULL);
-
- /* Callback wasn't found. */
- return -EINVAL;
+ return ret;
}
int
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v5 2/9] librte_ether: add new api rte_eth_add_first_rx_callback
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 " Reshma Pattan
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 1/9] librte_ether: protect add/remove of rxtx callbacks with spinlocks Reshma Pattan
@ 2016-06-08 13:38 ` Reshma Pattan
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 3/9] librte_ether: add new fields to rte_eth_dev_info struct Reshma Pattan
` (7 subsequent siblings)
9 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-08 13:38 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Added new public api rte_eth_add_first_rx_callback to add given
callback as head of list.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
lib/librte_ether/rte_ethdev.c | 35 ++++++++++++++++++++++++++++++++++
lib/librte_ether/rte_ethdev.h | 27 ++++++++++++++++++++++++++
lib/librte_ether/rte_ether_version.map | 6 ++++++
3 files changed, 68 insertions(+)
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index ce70d58..f13c70a 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2939,6 +2939,41 @@ rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
}
void *
+rte_eth_add_first_rx_callback(uint8_t port_id, uint16_t queue_id,
+ rte_rx_callback_fn fn, void *user_param)
+{
+#ifndef RTE_ETHDEV_RXTX_CALLBACKS
+ rte_errno = ENOTSUP;
+ return NULL;
+#endif
+ /* check input parameters */
+ if (!rte_eth_dev_is_valid_port(port_id) || fn == NULL ||
+ queue_id >= rte_eth_devices[port_id].data->nb_rx_queues) {
+ rte_errno = EINVAL;
+ return NULL;
+ }
+
+ struct rte_eth_rxtx_callback *cb = rte_zmalloc(NULL, sizeof(*cb), 0);
+
+ if (cb == NULL) {
+ rte_errno = ENOMEM;
+ return NULL;
+ }
+
+ cb->fn.rx = fn;
+ cb->param = user_param;
+
+ rte_spinlock_lock(&rte_eth_rx_cb_lock);
+ /* Add the callbacks at fisrt position*/
+ cb->next = rte_eth_devices[port_id].post_rx_burst_cbs[queue_id];
+ rte_smp_wmb();
+ rte_eth_devices[port_id].post_rx_burst_cbs[queue_id] = cb;
+ rte_spinlock_unlock(&rte_eth_rx_cb_lock);
+
+ return cb;
+}
+
+void *
rte_eth_add_tx_callback(uint8_t port_id, uint16_t queue_id,
rte_tx_callback_fn fn, void *user_param)
{
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 2757510..92b07a9 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -3825,6 +3825,33 @@ int rte_eth_dev_get_dcb_info(uint8_t port_id,
void *rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
rte_rx_callback_fn fn, void *user_param);
+/*
+* Add a callback that must be called first on packet RX on a given port and queue.
+*
+* This API configures a first function to be called for each burst of
+* packets received on a given NIC port queue. The return value is a pointer
+* that can be used to later remove the callback using
+* rte_eth_remove_rx_callback().
+*
+* Multiple functions are called in the order that they are added.
+*
+* @param port_id
+* The port identifier of the Ethernet device.
+* @param queue_id
+* The queue on the Ethernet device on which the callback is to be added.
+* @param fn
+* The callback function
+* @param user_param
+* A generic pointer parameter which will be passed to each invocation of the
+* callback function on this port and queue.
+*
+* @return
+* NULL on error.
+* On success, a pointer value which can later be used to remove the callback.
+*/
+void *rte_eth_add_first_rx_callback(uint8_t port_id, uint16_t queue_id,
+ rte_rx_callback_fn fn, void *user_param);
+
/**
* Add a callback to be called on packet TX on a given port and queue.
*
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index 214ecc7..c990b04 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -132,3 +132,9 @@ DPDK_16.04 {
rte_eth_tx_buffer_set_err_callback;
} DPDK_2.2;
+
+DPDK_16.07 {
+ global:
+
+ rte_eth_add_first_rx_callback;
+} DPDK_16.04;
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v5 3/9] librte_ether: add new fields to rte_eth_dev_info struct
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 " Reshma Pattan
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 1/9] librte_ether: protect add/remove of rxtx callbacks with spinlocks Reshma Pattan
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 2/9] librte_ether: add new api rte_eth_add_first_rx_callback Reshma Pattan
@ 2016-06-08 13:38 ` Reshma Pattan
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 4/9] librte_ether: make rte_eth_dev_get_port_by_name rte_eth_dev_get_name_by_port public Reshma Pattan
` (6 subsequent siblings)
9 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-08 13:38 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
New fields nb_rx_queues and nb_tx_queues are added to
rte_eth_dev_info structure.
Changes to API rte_eth_dev_info_get() are done to update
these new fields to rte_eth_dev_info object.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
lib/librte_ether/rte_ethdev.c | 2 ++
lib/librte_ether/rte_ethdev.h | 3 +++
lib/librte_ether/rte_ether_version.map | 1 +
3 files changed, 6 insertions(+)
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index f13c70a..4d732e8 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -1661,6 +1661,8 @@ rte_eth_dev_info_get(uint8_t port_id, struct rte_eth_dev_info *dev_info)
(*dev->dev_ops->dev_infos_get)(dev, dev_info);
dev_info->pci_dev = dev->pci_dev;
dev_info->driver_name = dev->data->drv_name;
+ dev_info->nb_rx_queues = dev->data->nb_rx_queues;
+ dev_info->nb_tx_queues = dev->data->nb_tx_queues;
}
int
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 92b07a9..106318f 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -882,6 +882,9 @@ struct rte_eth_dev_info {
struct rte_eth_desc_lim rx_desc_lim; /**< RX descriptors limits */
struct rte_eth_desc_lim tx_desc_lim; /**< TX descriptors limits */
uint32_t speed_capa; /**< Supported speeds bitmap (ETH_LINK_SPEED_). */
+ /** Configured number of rx/tx queues */
+ uint16_t nb_rx_queues; /**< Number of RX queues. */
+ uint16_t nb_tx_queues; /**< Number of TX queues. */
};
/**
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index c990b04..d06d648 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -137,4 +137,5 @@ DPDK_16.07 {
global:
rte_eth_add_first_rx_callback;
+ rte_eth_dev_info_get;
} DPDK_16.04;
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v5 4/9] librte_ether: make rte_eth_dev_get_port_by_name rte_eth_dev_get_name_by_port public
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 " Reshma Pattan
` (2 preceding siblings ...)
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 3/9] librte_ether: add new fields to rte_eth_dev_info struct Reshma Pattan
@ 2016-06-08 13:38 ` Reshma Pattan
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 5/9] lib/librte_pdump: add new library for packet capturing support Reshma Pattan
` (5 subsequent siblings)
9 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-08 13:38 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Converted rte_eth_dev_get_port_by_name to a public API.
Converted rte_eth_dev_get_name_by_port to a public API.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
lib/librte_ether/rte_ethdev.c | 4 ++--
lib/librte_ether/rte_ethdev.h | 29 +++++++++++++++++++++++++++++
lib/librte_ether/rte_ether_version.map | 2 ++
3 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 4d732e8..d8aac99 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -406,7 +406,7 @@ rte_eth_dev_get_addr_by_port(uint8_t port_id, struct rte_pci_addr *addr)
return 0;
}
-static int
+int
rte_eth_dev_get_name_by_port(uint8_t port_id, char *name)
{
char *tmp;
@@ -425,7 +425,7 @@ rte_eth_dev_get_name_by_port(uint8_t port_id, char *name)
return 0;
}
-static int
+int
rte_eth_dev_get_port_by_name(const char *name, uint8_t *port_id)
{
int i;
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 106318f..6f5a61a 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -4283,6 +4283,35 @@ rte_eth_dev_l2_tunnel_offload_set(uint8_t port_id,
uint32_t mask,
uint8_t en);
+/**
+* Get the port id from pci adrress or device name
+* Ex: 0000:2:00.0 or vdev name eth_pcap0
+*
+* @param name
+* pci address or name of the device
+* @param port_id
+* pointer to port identifier of the device
+* @return
+* - (0) if successful.
+* - (-ENODEV or -EINVAL) on failure.
+*/
+int
+rte_eth_dev_get_port_by_name(const char *name, uint8_t *port_id);
+
+/**
+* Get the device name from port id
+*
+* @param port_id
+* pointer to port identifier of the device
+* @param name
+* pci address or name of the device
+* @return
+* - (0) if successful.
+* - (-EINVAL) on failure.
+*/
+int
+rte_eth_dev_get_name_by_port(uint8_t port_id, char *name);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index d06d648..73e730d 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -137,5 +137,7 @@ DPDK_16.07 {
global:
rte_eth_add_first_rx_callback;
+ rte_eth_dev_get_name_by_port;
+ rte_eth_dev_get_port_by_name;
rte_eth_dev_info_get;
} DPDK_16.04;
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v5 5/9] lib/librte_pdump: add new library for packet capturing support
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 " Reshma Pattan
` (3 preceding siblings ...)
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 4/9] librte_ether: make rte_eth_dev_get_port_by_name rte_eth_dev_get_name_by_port public Reshma Pattan
@ 2016-06-08 13:38 ` Reshma Pattan
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 6/9] app/pdump: add pdump tool for packet capturing Reshma Pattan
` (4 subsequent siblings)
9 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-08 13:38 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Added new library for packet capturing support.
Added public api rte_pdump_init, applications should call
this as part of their application setup to have packet
capturing framework ready.
Added public api rte_pdump_uninit to uninitialize the packet
capturing framework.
Added public apis rte_pdump_enable and rte_pdump_disable to
enable and disable packet capturing on specific port and queue.
Added public apis rte_pdump_enable_by_deviceid and
rte_pdump_disable_by_deviceid to enable and disable packet
capturing on a specific device (pci address or name) and queue.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
MAINTAINERS | 4 +
config/common_base | 5 +
lib/Makefile | 1 +
lib/librte_pdump/Makefile | 55 +++
lib/librte_pdump/rte_pdump.c | 841 +++++++++++++++++++++++++++++++++
lib/librte_pdump/rte_pdump.h | 186 ++++++++
lib/librte_pdump/rte_pdump_version.map | 12 +
mk/rte.app.mk | 1 +
8 files changed, 1105 insertions(+)
create mode 100644 lib/librte_pdump/Makefile
create mode 100644 lib/librte_pdump/rte_pdump.c
create mode 100644 lib/librte_pdump/rte_pdump.h
create mode 100644 lib/librte_pdump/rte_pdump_version.map
diff --git a/MAINTAINERS b/MAINTAINERS
index 3e8558f..cc3ffdb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -432,6 +432,10 @@ F: app/test/test_reorder*
F: examples/packet_ordering/
F: doc/guides/sample_app_ug/packet_ordering.rst
+Pdump
+M: Reshma Pattan <reshma.pattan@intel.com>
+F: lib/librte_pdump/
+
Hierarchical scheduler
M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
F: lib/librte_sched/
diff --git a/config/common_base b/config/common_base
index 47c26f6..a2d5d72 100644
--- a/config/common_base
+++ b/config/common_base
@@ -484,6 +484,11 @@ CONFIG_RTE_LIBRTE_DISTRIBUTOR=y
CONFIG_RTE_LIBRTE_REORDER=y
#
+# Compile the pdump library
+#
+CONFIG_RTE_LIBRTE_PDUMP=y
+
+#
# Compile librte_port
#
CONFIG_RTE_LIBRTE_PORT=y
diff --git a/lib/Makefile b/lib/Makefile
index f254dba..ca7c02f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -57,6 +57,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
DIRS-$(CONFIG_RTE_LIBRTE_TABLE) += librte_table
DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += librte_pipeline
DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
+DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += librte_pdump
ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
diff --git a/lib/librte_pdump/Makefile b/lib/librte_pdump/Makefile
new file mode 100644
index 0000000..af81a28
--- /dev/null
+++ b/lib/librte_pdump/Makefile
@@ -0,0 +1,55 @@
+# 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_SDK)/mk/rte.vars.mk
+
+# library name
+LIB = librte_pdump.a
+
+CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
+CFLAGS += -D_GNU_SOURCE
+
+EXPORT_MAP := rte_pdump_version.map
+
+LIBABIVER := 1
+
+# all source are stored in SRCS-y
+SRCS-$(CONFIG_RTE_LIBRTE_PDUMP) := rte_pdump.c
+
+# install this header file
+SYMLINK-$(CONFIG_RTE_LIBRTE_PDUMP)-include := rte_pdump.h
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_ether
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pdump/rte_pdump.c b/lib/librte_pdump/rte_pdump.c
new file mode 100644
index 0000000..4aff34a
--- /dev/null
+++ b/lib/librte_pdump/rte_pdump.c
@@ -0,0 +1,841 @@
+/*-
+ * 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 <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <stdbool.h>
+
+#include <rte_memcpy.h>
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_lcore.h>
+#include <rte_log.h>
+#include <rte_errno.h>
+#include <rte_pci.h>
+
+#include "rte_pdump.h"
+
+#define SOCKET_PATH_VAR_RUN "/var/run/pdump_sockets"
+#define SOCKET_PATH_HOME "HOME/pdump_sockets"
+#define SERVER_SOCKET "%s/pdump_server_socket"
+#define CLIENT_SOCKET "%s/pdump_client_socket_%d_%u"
+#define DEVICE_ID_SIZE 64
+/* Macros for printing using RTE_LOG */
+#define RTE_LOGTYPE_PDUMP RTE_LOGTYPE_USER1
+
+enum pdump_operation {
+ DISABLE = 1,
+ ENABLE = 2
+};
+
+enum pdump_socktype {
+ SERVER = 1,
+ CLIENT = 2
+};
+
+enum pdump_version {
+ V1 = 1
+};
+
+static pthread_t pdump_thread;
+static int pdump_socket_fd;
+
+struct pdump_request {
+ uint16_t ver;
+ uint16_t op;
+ uint32_t flags;
+ union pdump_data {
+ struct enable_v1 {
+ char device[DEVICE_ID_SIZE];
+ uint16_t queue;
+ struct rte_ring *ring;
+ struct rte_mempool *mp;
+ void *filter;
+ } en_v1;
+ struct disable_v1 {
+ char device[DEVICE_ID_SIZE];
+ uint16_t queue;
+ struct rte_ring *ring;
+ struct rte_mempool *mp;
+ void *filter;
+ } dis_v1;
+ } data;
+};
+
+struct pdump_response {
+ uint16_t ver;
+ uint16_t res_op;
+ int32_t err_value;
+};
+
+static struct pdump_rxtx_cbs {
+ struct rte_ring *ring;
+ struct rte_mempool *mp;
+ struct rte_eth_rxtx_callback *cb;
+ void *filter;
+} rx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT],
+tx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
+
+static inline int
+pdump_pktmbuf_copy_data(struct rte_mbuf *seg, const struct rte_mbuf *m)
+{
+ if (rte_pktmbuf_tailroom(seg) < m->data_len) {
+ RTE_LOG(ERR, PDUMP, "User mempool: insufficient data_len of mbuf\n");
+ return -EINVAL;
+ }
+
+ seg->port = m->port;
+ seg->vlan_tci = m->vlan_tci;
+ seg->hash = m->hash;
+ seg->tx_offload = m->tx_offload;
+ seg->ol_flags = m->ol_flags;
+ seg->packet_type = m->packet_type;
+ seg->vlan_tci_outer = m->vlan_tci_outer;
+ seg->data_len = m->data_len;
+ seg->pkt_len = seg->data_len;
+ rte_memcpy(rte_pktmbuf_mtod(seg, void *),
+ rte_pktmbuf_mtod(m, void *),
+ rte_pktmbuf_data_len(seg));
+
+ return 0;
+}
+
+static inline struct rte_mbuf *
+pdump_pktmbuf_copy(struct rte_mbuf *m, struct rte_mempool *mp)
+{
+ struct rte_mbuf *m_dup, *seg, **prev;
+ uint32_t pktlen;
+ uint8_t nseg;
+
+ m_dup = rte_pktmbuf_alloc(mp);
+ if (unlikely(m_dup == NULL))
+ return NULL;
+
+ seg = m_dup;
+ prev = &seg->next;
+ pktlen = m->pkt_len;
+ nseg = 0;
+
+ do {
+ nseg++;
+ if (pdump_pktmbuf_copy_data(seg, m) < 0) {
+ rte_pktmbuf_free(m_dup);
+ return NULL;
+ }
+ *prev = seg;
+ prev = &seg->next;
+ } while ((m = m->next) != NULL &&
+ (seg = rte_pktmbuf_alloc(mp)) != NULL);
+
+ *prev = NULL;
+ m_dup->nb_segs = nseg;
+ m_dup->pkt_len = pktlen;
+
+ /* Allocation of new indirect segment failed */
+ if (unlikely(seg == NULL)) {
+ rte_pktmbuf_free(m_dup);
+ return NULL;
+ }
+
+ __rte_mbuf_sanity_check(m_dup, 1);
+ return m_dup;
+}
+
+static inline void
+pdump_copy(struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
+{
+ unsigned i;
+ int ring_enq;
+ uint16_t d_pkts = 0;
+ struct rte_mbuf *dup_bufs[nb_pkts];
+ struct pdump_rxtx_cbs *cbs;
+ struct rte_ring *ring;
+ struct rte_mempool *mp;
+ struct rte_mbuf *p;
+
+ cbs = user_params;
+ ring = cbs->ring;
+ mp = cbs->mp;
+ for (i = 0; i < nb_pkts; i++) {
+ p = pdump_pktmbuf_copy(pkts[i], mp);
+ if (p)
+ dup_bufs[d_pkts++] = p;
+ }
+
+ ring_enq = rte_ring_enqueue_burst(ring, (void *)dup_bufs, d_pkts);
+ if (unlikely(ring_enq < d_pkts)) {
+ RTE_LOG(DEBUG, PDUMP, "only %d of packets enqueued to ring\n", ring_enq);
+ do {
+ rte_pktmbuf_free(dup_bufs[ring_enq]);
+ } while (++ring_enq < d_pkts);
+ }
+}
+
+static uint16_t
+pdump_rx(uint8_t port __rte_unused, uint16_t qidx __rte_unused,
+ struct rte_mbuf **pkts, uint16_t nb_pkts, uint16_t max_pkts __rte_unused,
+ void *user_params)
+{
+ pdump_copy(pkts, nb_pkts, user_params);
+ return nb_pkts;
+}
+
+static uint16_t
+pdump_tx(uint8_t port __rte_unused, uint16_t qidx __rte_unused,
+ struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
+{
+ pdump_copy(pkts, nb_pkts, user_params);
+ return nb_pkts;
+}
+
+static int
+pdump_get_dombdf(char *device_id, char *domBDF, size_t len)
+{
+ int ret;
+ struct rte_pci_addr dev_addr = {0};
+
+ /* identify if device_id is pci address or name */
+ ret = eal_parse_pci_DomBDF(device_id, &dev_addr);
+ if (ret < 0)
+ return -1;
+
+ if (dev_addr.domain)
+ ret = snprintf(domBDF, len, "%u:%u:%u.%u", dev_addr.domain,
+ dev_addr.bus, dev_addr.devid, dev_addr.function);
+ else
+ ret = snprintf(domBDF, len, "%u:%u.%u", dev_addr.bus, dev_addr.devid,
+ dev_addr.function);
+
+ return ret;
+}
+
+static int
+pdump_regitser_rx_callbacks(uint16_t end_q, uint8_t port, uint16_t queue,
+ struct rte_ring *ring, struct rte_mempool *mp,
+ uint16_t operation)
+{
+ uint16_t qid;
+ struct pdump_rxtx_cbs *cbs = NULL;
+
+ qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
+ for (; qid < end_q; qid++) {
+ cbs = &rx_cbs[port][qid];
+ if (cbs && operation == ENABLE) {
+ if (cbs->cb) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to add rx callback for port=%d and "
+ "queue=%d, callback already exists\n",
+ port, qid);
+ return -EEXIST;
+ }
+ cbs->ring = ring;
+ cbs->mp = mp;
+ cbs->cb = rte_eth_add_first_rx_callback(port, qid,
+ pdump_rx, cbs);
+ if (cbs->cb == NULL) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to add rx callback, errno=%d\n",
+ rte_errno);
+ return rte_errno;
+ }
+ }
+ if (cbs && operation == DISABLE) {
+ int ret;
+
+ if (cbs->cb == NULL) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to delete non existing rx callback "
+ "for port=%d and queue=%d\n", port, qid);
+ return -EINVAL;
+ }
+ ret = rte_eth_remove_rx_callback(port, qid, cbs->cb);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to remove rx callback, errno=%d\n",
+ rte_errno);
+ return ret;
+ }
+ cbs->cb = NULL;
+ }
+ }
+
+ return 0;
+}
+
+static int
+pdump_regitser_tx_callbacks(uint16_t end_q, uint8_t port, uint16_t queue,
+ struct rte_ring *ring, struct rte_mempool *mp,
+ uint16_t operation)
+{
+
+ uint16_t qid;
+ struct pdump_rxtx_cbs *cbs = NULL;
+
+ qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
+ for (; qid < end_q; qid++) {
+ cbs = &tx_cbs[port][qid];
+ if (cbs && operation == ENABLE) {
+ if (cbs->cb) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to add tx callback for port=%d and "
+ "queue=%d, callback already exists\n",
+ port, qid);
+ return -EEXIST;
+ }
+ cbs->ring = ring;
+ cbs->mp = mp;
+ cbs->cb = rte_eth_add_tx_callback(port, qid, pdump_tx,
+ cbs);
+ if (cbs->cb == NULL) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to add tx callback, errno=%d\n",
+ rte_errno);
+ return rte_errno;
+ }
+ }
+ if (cbs && operation == DISABLE) {
+ int ret;
+
+ if (cbs->cb == NULL) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to delete non existing tx callback "
+ "for port=%d and queue=%d\n", port, qid);
+ return -EINVAL;
+ }
+ ret = rte_eth_remove_tx_callback(port, qid, cbs->cb);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to remove tx callback, errno=%d\n",
+ rte_errno);
+ return ret;
+ }
+ cbs->cb = NULL;
+ }
+ }
+
+ return 0;
+}
+
+static int
+set_pdump_rxtx_cbs(struct pdump_request *p)
+{
+ uint16_t nb_rx_q, nb_tx_q = 0, end_q, queue;
+ uint8_t port;
+ int ret = 0;
+ uint32_t flags;
+ uint16_t operation;
+ struct rte_ring *ring;
+ struct rte_mempool *mp;
+
+ flags = p->flags;
+ operation = p->op;
+ if (operation == ENABLE) {
+ ret = rte_eth_dev_get_port_by_name(p->data.en_v1.device,
+ &port);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to get potid for device id=%s\n",
+ p->data.en_v1.device);
+ return -EINVAL;
+ }
+ queue = p->data.en_v1.queue;
+ ring = p->data.en_v1.ring;
+ mp = p->data.en_v1.mp;
+ } else {
+ ret = rte_eth_dev_get_port_by_name(p->data.dis_v1.device,
+ &port);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to get potid for device id=%s\n",
+ p->data.dis_v1.device);
+ return -EINVAL;
+ }
+ queue = p->data.dis_v1.queue;
+ ring = p->data.dis_v1.ring;
+ mp = p->data.dis_v1.mp;
+ }
+
+ /* validation if packet capture is for all queues */
+ if (queue == RTE_PDUMP_ALL_QUEUES) {
+ struct rte_eth_dev_info dev_info;
+
+ rte_eth_dev_info_get(port, &dev_info);
+ nb_rx_q = dev_info.nb_rx_queues;
+ nb_tx_q = dev_info.nb_tx_queues;
+ if (nb_rx_q == 0 && flags & RTE_PDUMP_FLAG_RX) {
+ RTE_LOG(ERR, PDUMP, "number of rx queues cannot be 0\n");
+ return -EINVAL;
+ }
+ if (nb_tx_q == 0 && flags & RTE_PDUMP_FLAG_TX) {
+ RTE_LOG(ERR, PDUMP, "number of tx queues cannot be 0\n");
+ return -EINVAL;
+ }
+ if ((nb_tx_q == 0 || nb_rx_q == 0) && flags == RTE_PDUMP_FLAG_RXTX) {
+ RTE_LOG(ERR, PDUMP, "both tx&rx queues must be non zero\n");
+ return -EINVAL;
+ }
+ }
+
+ /* register RX callback */
+ if (flags & RTE_PDUMP_FLAG_RX) {
+ end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_rx_q : queue + 1;
+ ret = pdump_regitser_rx_callbacks(end_q, port, queue, ring, mp,
+ operation);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* register TX callback */
+ if (flags & RTE_PDUMP_FLAG_TX) {
+ end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_tx_q : queue + 1;
+ ret = pdump_regitser_tx_callbacks(end_q, port, queue, ring, mp,
+ operation);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ret;
+}
+
+/* get socket path (/var/run if root, $HOME otherwise) */
+static void
+pdump_get_socket_path(char *buffer, int bufsz, enum pdump_socktype type)
+{
+ const char *dir = SOCKET_PATH_VAR_RUN;
+ const char *home_dir = getenv(SOCKET_PATH_HOME);
+
+ if (getuid() != 0 && home_dir != NULL)
+ dir = home_dir;
+
+ mkdir(dir, 700);
+ if (type == SERVER)
+ snprintf(buffer, bufsz, SERVER_SOCKET, dir);
+ else
+ snprintf(buffer, bufsz, CLIENT_SOCKET, dir, getpid(),
+ rte_sys_gettid());
+}
+
+static int
+pdump_create_server_socket(void)
+{
+ int ret, socket_fd;
+ struct sockaddr_un addr;
+ socklen_t addr_len;
+
+ pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), SERVER);
+ addr.sun_family = AF_UNIX;
+
+ /* remove if file already exists */
+ unlink(addr.sun_path);
+
+ /* set up a server socket */
+ socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (socket_fd < 0) {
+ RTE_LOG(ERR, PDUMP, "Failed to create server socket: %s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ return -1;
+ }
+
+ addr_len = sizeof(struct sockaddr_un);
+ ret = bind(socket_fd, (struct sockaddr *) &addr, addr_len);
+ if (ret) {
+ RTE_LOG(ERR, PDUMP, "Failed to bind to server socket: %s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ close(socket_fd);
+ return -1;
+ }
+
+ /* save the socket in local configuration */
+ pdump_socket_fd = socket_fd;
+
+ return 0;
+}
+
+static __attribute__((noreturn)) void *
+pdump_thread_main(__rte_unused void *arg)
+{
+ struct sockaddr_un cli_addr;
+ socklen_t cli_len;
+ struct pdump_request cli_req;
+ struct pdump_response resp;
+ int n;
+ int ret = 0;
+
+ /* host thread, never break out */
+ for (;;) {
+ /* recv client requests */
+ cli_len = sizeof(cli_addr);
+ n = recvfrom(pdump_socket_fd, &cli_req, sizeof(struct pdump_request), 0,
+ (struct sockaddr *)&cli_addr, &cli_len);
+ if (n < 0) {
+ RTE_LOG(ERR, PDUMP, "failed to recv from client:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ continue;
+ }
+
+ ret = set_pdump_rxtx_cbs(&cli_req);
+
+ resp.ver = cli_req.ver;
+ resp.res_op = cli_req.op;
+ resp.err_value = ret;
+ n = sendto(pdump_socket_fd, &resp, sizeof(struct pdump_response),
+ 0, (struct sockaddr *)&cli_addr, cli_len);
+ if (n < 0) {
+ RTE_LOG(ERR, PDUMP, "failed to send to client:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ }
+ }
+}
+
+int
+rte_pdump_init(void)
+{
+ int ret = 0;
+ char thread_name[RTE_MAX_THREAD_NAME_LEN];
+
+ ret = pdump_create_server_socket();
+ if (ret != 0) {
+ RTE_LOG(ERR, PDUMP, "Failed to create server socket:%s:%d\n",
+ __func__, __LINE__);
+ return -1;
+ }
+
+ /* create the host thread to wait/handle pdump requests */
+ ret = pthread_create(&pdump_thread, NULL, pdump_thread_main, NULL);
+ if (ret != 0) {
+ RTE_LOG(ERR, PDUMP, "Failed to create the pdump thread:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ return -1;
+ }
+ /* Set thread_name for aid in debugging. */
+ snprintf(thread_name, RTE_MAX_THREAD_NAME_LEN, "pdump-thread");
+ ret = rte_thread_setname(pdump_thread, thread_name);
+ if (ret != 0) {
+ RTE_LOG(DEBUG, PDUMP,
+ "Failed to set thread name for pdump handling\n");
+ }
+
+ return 0;
+}
+
+int
+rte_pdump_uninit(void)
+{
+ int ret;
+
+ ret = pthread_cancel(pdump_thread);
+ if (ret != 0) {
+ RTE_LOG(ERR, PDUMP, "Failed to cancel the pdump thread:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ return -1;
+ }
+
+ ret = close(pdump_socket_fd);
+ if (ret != 0) {
+ RTE_LOG(ERR, PDUMP, "Failed to close server socket: %s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ return -1;
+ }
+
+ struct sockaddr_un addr;
+
+ pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), SERVER);
+ ret = unlink(addr.sun_path);
+ if (ret != 0) {
+ RTE_LOG(ERR, PDUMP, "Failed to remove server socket addr: %s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+pdump_create_client_socket(struct pdump_request *p)
+{
+ int ret, socket_fd;
+ int pid;
+ int n;
+ struct pdump_response server_resp;
+ struct sockaddr_un addr, serv_addr, from;
+ socklen_t addr_len, serv_len;
+
+ pid = getpid();
+
+ socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (socket_fd < 0) {
+ RTE_LOG(ERR, PDUMP, "client socket(): %s:pid(%d):tid(%u), %s:%d\n",
+ strerror(errno), pid, rte_sys_gettid(), __func__, __LINE__);
+ ret = errno;
+ return ret;
+ }
+
+ pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), CLIENT);
+ addr.sun_family = AF_UNIX;
+ addr_len = sizeof(struct sockaddr_un);
+
+ do {
+ ret = bind(socket_fd, (struct sockaddr *) &addr, addr_len);
+ if (ret) {
+ RTE_LOG(ERR, PDUMP, "client bind(): %s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ ret = errno;
+ break;
+ }
+
+ serv_len = sizeof(struct sockaddr_un);
+ memset(&serv_addr, 0, sizeof(serv_addr));
+ pdump_get_socket_path(serv_addr.sun_path, sizeof(serv_addr.sun_path),
+ SERVER);
+ serv_addr.sun_family = AF_UNIX;
+
+ n = sendto(socket_fd, p, sizeof(struct pdump_request), 0,
+ (struct sockaddr *)&serv_addr, serv_len);
+ if (n < 0) {
+ RTE_LOG(ERR, PDUMP, "failed to send to server:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ ret = errno;
+ break;
+ }
+
+ n = recvfrom(socket_fd, &server_resp, sizeof(struct pdump_response), 0,
+ (struct sockaddr *)&from, &serv_len);
+ if (n < 0) {
+ RTE_LOG(ERR, PDUMP, "failed to recv from server:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ ret = errno;
+ break;
+ }
+ ret = server_resp.err_value;
+ } while (0);
+
+ close(socket_fd);
+ unlink(addr.sun_path);
+ return ret;
+}
+
+static int
+pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp)
+{
+ if (ring == NULL || mp == NULL) {
+ RTE_LOG(ERR, PDUMP, "NULL ring or mempool are passed %s:%d\n",
+ __func__, __LINE__);
+ rte_errno = EINVAL;
+ return -1;
+ }
+ if (mp->flags & MEMPOOL_F_SP_PUT || mp->flags & MEMPOOL_F_SC_GET) {
+ RTE_LOG(ERR, PDUMP, "mempool with either SP or SC settings"
+ " is not valid for pdump, should have MP and MC settings\n");
+ rte_errno = EINVAL;
+ return -1;
+ }
+ if (ring->prod.sp_enqueue || ring->cons.sc_dequeue) {
+ RTE_LOG(ERR, PDUMP, "ring with either SP or SC settings"
+ " is not valid for pdump, should have MP and MC settings\n");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+pdump_validate_flags(uint32_t flags)
+{
+ if (flags != RTE_PDUMP_FLAG_RX && flags != RTE_PDUMP_FLAG_TX &&
+ flags != RTE_PDUMP_FLAG_RXTX) {
+ RTE_LOG(ERR, PDUMP, "invalid flags, should be either rx/tx/rxtx\n");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+pdump_validate_port(uint8_t port, char *name)
+{
+ int ret = 0;
+
+ if (port >= RTE_MAX_ETHPORTS) {
+ RTE_LOG(ERR, PDUMP, "Invalid port id %u, %s:%d\n", port,
+ __func__, __LINE__);
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ ret = rte_eth_dev_get_name_by_port(port, name);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "port id to name mapping failed for port id=%u, %s:%d\n",
+ port, __func__, __LINE__);
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+pdump_prepare_client_request(char *device, uint16_t queue,
+ uint32_t flags,
+ uint16_t operation,
+ struct rte_ring *ring,
+ struct rte_mempool *mp,
+ void *filter)
+{
+ int ret;
+ struct pdump_request req = {.ver = 1,};
+
+ req.flags = flags;
+ req.op = operation;
+ if ((operation & ENABLE) != 0) {
+ strncpy(req.data.en_v1.device, device, strlen(device));
+ req.data.en_v1.queue = queue;
+ req.data.en_v1.ring = ring;
+ req.data.en_v1.mp = mp;
+ req.data.en_v1.filter = filter;
+ } else {
+ strncpy(req.data.dis_v1.device, device, strlen(device));
+ req.data.dis_v1.queue = queue;
+ req.data.dis_v1.ring = NULL;
+ req.data.dis_v1.mp = NULL;
+ req.data.dis_v1.filter = NULL;
+ }
+
+ ret = pdump_create_client_socket(&req);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP, "client request for pdump enable/disable failed\n");
+ rte_errno = ret;
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+rte_pdump_enable(uint8_t port, uint16_t queue, uint32_t flags,
+ struct rte_ring *ring,
+ struct rte_mempool *mp,
+ void *filter)
+{
+
+ int ret = 0;
+ char name[DEVICE_ID_SIZE];
+
+ ret = pdump_validate_port(port, name);
+ if (ret < 0)
+ return ret;
+ ret = pdump_validate_ring_mp(ring, mp);
+ if (ret < 0)
+ return ret;
+ ret = pdump_validate_flags(flags);
+ if (ret < 0)
+ return ret;
+
+ ret = pdump_prepare_client_request(name, queue, flags,
+ ENABLE, ring, mp, filter);
+
+ return ret;
+}
+
+int
+rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
+ uint32_t flags,
+ struct rte_ring *ring,
+ struct rte_mempool *mp,
+ void *filter)
+{
+ int ret = 0;
+ char domBDF[DEVICE_ID_SIZE];
+
+ ret = pdump_validate_ring_mp(ring, mp);
+ if (ret < 0)
+ return ret;
+ ret = pdump_validate_flags(flags);
+ if (ret < 0)
+ return ret;
+
+ if (pdump_get_dombdf(device_id, domBDF, sizeof(domBDF)) > 0)
+ ret = pdump_prepare_client_request(domBDF, queue, flags,
+ ENABLE, ring, mp, filter);
+ else
+ ret = pdump_prepare_client_request(device_id, queue, flags,
+ ENABLE, ring, mp, filter);
+
+ return ret;
+}
+
+int
+rte_pdump_disable(uint8_t port, uint16_t queue, uint32_t flags)
+{
+ int ret = 0;
+ char name[DEVICE_ID_SIZE];
+
+ ret = pdump_validate_port(port, name);
+ if (ret < 0)
+ return ret;
+ ret = pdump_validate_flags(flags);
+ if (ret < 0)
+ return ret;
+
+ ret = pdump_prepare_client_request(name, queue, flags,
+ DISABLE, NULL, NULL, NULL);
+
+ return ret;
+}
+
+int
+rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
+ uint32_t flags)
+{
+ int ret = 0;
+ char domBDF[DEVICE_ID_SIZE];
+
+ ret = pdump_validate_flags(flags);
+ if (ret < 0)
+ return ret;
+
+ if (pdump_get_dombdf(device_id, domBDF, sizeof(domBDF)) > 0)
+ ret = pdump_prepare_client_request(domBDF, queue, flags,
+ DISABLE, NULL, NULL, NULL);
+ else
+ ret = pdump_prepare_client_request(device_id, queue, flags,
+ DISABLE, NULL, NULL, NULL);
+
+ return ret;
+}
diff --git a/lib/librte_pdump/rte_pdump.h b/lib/librte_pdump/rte_pdump.h
new file mode 100644
index 0000000..ca9333a
--- /dev/null
+++ b/lib/librte_pdump/rte_pdump.h
@@ -0,0 +1,186 @@
+/*-
+ * 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.
+ */
+
+#ifndef _RTE_PDUMP_H_
+#define _RTE_PDUMP_H_
+
+/**
+ * @file
+ * RTE pdump
+ *
+ * packet dump library to provide packet capturing support on dpdk.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RTE_PDUMP_ALL_QUEUES UINT16_MAX
+
+enum {
+ RTE_PDUMP_FLAG_RX = 1, /* receive direction */
+ RTE_PDUMP_FLAG_TX = 2, /* transmit direction */
+ /* both receive and transmit directions */
+ RTE_PDUMP_FLAG_RXTX = (RTE_PDUMP_FLAG_RX|RTE_PDUMP_FLAG_TX)
+};
+
+/**
+ * Initialize packet capturing handling
+ *
+ * Creates pthread and server socket for handling clients
+ * requests to enable/disable rxtx callbacks.
+ *
+ * @return
+ * 0 on success, -1 on error
+ */
+int
+rte_pdump_init(void);
+
+/**
+ * Un initialize packet capturing handling
+ *
+ * Cancels pthread, close server socket, removes server socket address.
+ *
+ * @return
+ * 0 on success, -1 on error
+ */
+int
+rte_pdump_uninit(void);
+
+/**
+ * Enables packet capturing on given port and queue.
+ *
+ * @param port
+ * port on which packet capturing should be enabled.
+ * @param queue
+ * queue of a given port on which packet capturing should be enabled.
+ * users should pass on value UINT16_MAX to enable packet capturing on all
+ * queues of a given port.
+ * @param flags
+ * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
+ * on which packet capturing should be enabled for a given port and queue.
+ * @param ring
+ * ring on which captured packets will be enqueued for user.
+ * @param mp
+ * mempool on to which original packets will be mirrored or duplicated.
+ * @param filter
+ * place holder for packet filtering.
+ *
+ * @return
+ * 0 on success, -1 on error, rte_errno is set accordingly.
+ */
+
+int
+rte_pdump_enable(uint8_t port, uint16_t queue, uint32_t flags,
+ struct rte_ring *ring,
+ struct rte_mempool *mp,
+ void *filter);
+
+/**
+ * Disables packet capturing on given port and queue.
+ *
+ * @param port
+ * port on which packet capturing should be disabled.
+ * @param queue
+ * queue of a given port on which packet capturing should be disabled.
+ * users should pass on value UINT16_MAX to disable packet capturing on all
+ * queues of a given port.
+ * @param flags
+ * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
+ * on which packet capturing should be enabled for a given port and queue.
+ *
+ * @return
+ * 0 on success, -1 on error, rte_errno is set accordingly.
+ */
+
+int
+rte_pdump_disable(uint8_t port, uint16_t queue, uint32_t flags);
+
+/**
+ * Enables packet capturing on given device id and queue.
+ * device_id can be name or pci address of device.
+ *
+ * @param device_id
+ * device id on which packet capturing should be enabled.
+ * @param queue
+ * queue of a given device id on which packet capturing should be enabled.
+ * users should pass on value UINT16_MAX to enable packet capturing on all
+ * queues of a given device id.
+ * @param flags
+ * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
+ * on which packet capturing should be enabled for a given port and queue.
+ * @param ring
+ * ring on which captured packets will be enqueued for user.
+ * @param mp
+ * mempool on to which original packets will be mirrored or duplicated.
+ * @param filter
+ * place holder for packet filtering.
+ *
+ * @return
+ * 0 on success, -1 on error, rte_errno is set accordingly.
+ */
+
+int
+rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
+ uint32_t flags,
+ struct rte_ring *ring,
+ struct rte_mempool *mp,
+ void *filter);
+
+/**
+ * Disables packet capturing on given device_id and queue.
+ * device_id can be name or pci address of device.
+ *
+ * @param device_id
+ * pci address or name of the device on which packet capturing
+ * should be disabled.
+ * @param queue
+ * queue of a given device on which packet capturing should be disabled.
+ * users should pass on value UINT16_MAX to disable packet capturing on all
+ * queues of a given device id.
+ * @param flags
+ * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
+ * on which packet capturing should be enabled for a given port and queue.
+ *
+ * @return
+ * 0 on success, -1 on error, rte_errno is set accordingly.
+ */
+int
+rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
+ uint32_t flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_PDUMP_H_ */
diff --git a/lib/librte_pdump/rte_pdump_version.map b/lib/librte_pdump/rte_pdump_version.map
new file mode 100644
index 0000000..3e744f3
--- /dev/null
+++ b/lib/librte_pdump/rte_pdump_version.map
@@ -0,0 +1,12 @@
+DPDK_16.07 {
+ global:
+
+ rte_pdump_disable;
+ rte_pdump_disable_by_deviceid;
+ rte_pdump_enable;
+ rte_pdump_enable_by_deviceid;
+ rte_pdump_init;
+ rte_pdump_uninit;
+
+ local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index b84b56d..f792f2a 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -61,6 +61,7 @@ _LDLIBS-y += --whole-archive
_LDLIBS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += -lrte_distributor
_LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER) += -lrte_reorder
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PDUMP) += -lrte_pdump
ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
_LDLIBS-$(CONFIG_RTE_LIBRTE_KNI) += -lrte_kni
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v5 6/9] app/pdump: add pdump tool for packet capturing
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 " Reshma Pattan
` (4 preceding siblings ...)
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 5/9] lib/librte_pdump: add new library for packet capturing support Reshma Pattan
@ 2016-06-08 13:38 ` Reshma Pattan
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 7/9] app/test-pmd: add pdump initialization uninitialization Reshma Pattan
` (3 subsequent siblings)
9 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-08 13:38 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
New tool added for packet capturing on dpdk.
This tool supports command line options.
This tool runs as secondary process by default.
Command line supports various parameters to capture
the packets.
User should pass on a)port and queue (or) b)pci address
and queue (or) c)device name and queue to capture
the packets.
Users also need to pass on either pcap file name or
any linux iface, on to which packets captured from dpdk
ports will be sent on for the users to view using tcpdump.
Users have option to capture packets either a) in RX
direction, b)(or) in TX direction c)(or) from both the
directions.
User can pass on ring_size and mempool parameters using
command line, but these are optional parameters.
These are used to create ring and mempool objects for packet
mirroring from primary application to tool. If user doesn't
provide any values, default values will be used internally
for the creation of the ring and mempool.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
MAINTAINERS | 1 +
app/Makefile | 1 +
app/pdump/Makefile | 45 +++
app/pdump/main.c | 814 +++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 861 insertions(+)
create mode 100644 app/pdump/Makefile
create mode 100644 app/pdump/main.c
diff --git a/MAINTAINERS b/MAINTAINERS
index cc3ffdb..a48c8de 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -435,6 +435,7 @@ F: doc/guides/sample_app_ug/packet_ordering.rst
Pdump
M: Reshma Pattan <reshma.pattan@intel.com>
F: lib/librte_pdump/
+F: app/pdump/
Hierarchical scheduler
M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
diff --git a/app/Makefile b/app/Makefile
index 1151e09..c593efa 100644
--- a/app/Makefile
+++ b/app/Makefile
@@ -37,5 +37,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += test-pipeline
DIRS-$(CONFIG_RTE_TEST_PMD) += test-pmd
DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_test
DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += proc_info
+DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += pdump
include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/app/pdump/Makefile b/app/pdump/Makefile
new file mode 100644
index 0000000..96bb4af
--- /dev/null
+++ b/app/pdump/Makefile
@@ -0,0 +1,45 @@
+# 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_SDK)/mk/rte.vars.mk
+
+APP = dpdk_pdump
+
+CFLAGS += $(WERROR_FLAGS)
+
+# all source are stored in SRCS-y
+
+SRCS-y := main.c
+
+# this application needs libraries first
+DEPDIRS-y += lib
+
+include $(RTE_SDK)/mk/rte.app.mk
diff --git a/app/pdump/main.c b/app/pdump/main.c
new file mode 100644
index 0000000..a4a5ca2
--- /dev/null
+++ b/app/pdump/main.c
@@ -0,0 +1,814 @@
+/*
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <net/if.h>
+
+#include <rte_eal.h>
+#include <rte_common.h>
+#include <rte_debug.h>
+#include <rte_ethdev.h>
+#include <rte_memory.h>
+#include <rte_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_errno.h>
+#include <rte_dev.h>
+#include <rte_kvargs.h>
+#include <rte_mempool.h>
+#include <rte_ring.h>
+#include <rte_pdump.h>
+
+#define PDUMP_PORT_ARG "port"
+#define PDUMP_PCI_ARG "device_id"
+#define PDUMP_QUEUE_ARG "queue"
+#define PDUMP_DIR_ARG "dir"
+#define PDUMP_RX_DEV_ARG "rx-dev"
+#define PDUMP_TX_DEV_ARG "tx-dev"
+#define PDUMP_RING_SIZE_ARG "ring-size"
+#define PDUMP_MSIZE_ARG "mbuf-size"
+#define PDUMP_NUM_MBUFS_ARG "total-num-mbufs"
+
+#define VDEV_PCAP "eth_pcap_%s_%d,tx_pcap=%s"
+#define VDEV_IFACE "eth_pcap_%s_%d,tx_iface=%s"
+#define TX_STREAM_SIZE 64
+
+#define MP_NAME "pdump_pool_%d"
+
+#define RX_RING "rx_ring_%d"
+#define TX_RING "tx_ring_%d"
+
+#define RX_STR "rx"
+#define TX_STR "tx"
+
+/* Maximum long option length for option parsing. */
+#define APP_ARG_TCPDUMP_MAX_TUPLES 54
+#define MBUF_POOL_CACHE_SIZE 250
+#define TX_DESC_PER_QUEUE 512
+#define RX_DESC_PER_QUEUE 128
+#define MBUFS_PER_POOL 65535
+#define MAX_LONG_OPT_SZ 64
+#define RING_SIZE 16384
+#define SIZE 256
+#define BURST_SIZE 32
+#define NUM_VDEVS 2
+
+#define RTE_RING_SZ_MASK (unsigned)(0x0fffffff) /**< Ring size mask */
+/* true if x is a power of 2 */
+#define POWEROF2(x) ((((x)-1) & (x)) == 0)
+
+enum pdump_en_dis {
+ DISABLE = 1,
+ ENABLE = 2
+};
+
+enum pcap_stream {
+ IFACE = 1,
+ PCAP = 2
+};
+
+enum pdump_by {
+ PORT_ID = 1,
+ DEVICE_ID = 2
+};
+
+const char *valid_pdump_arguments[] = {
+ PDUMP_PORT_ARG,
+ PDUMP_PCI_ARG,
+ PDUMP_QUEUE_ARG,
+ PDUMP_DIR_ARG,
+ PDUMP_RX_DEV_ARG,
+ PDUMP_TX_DEV_ARG,
+ PDUMP_RING_SIZE_ARG,
+ PDUMP_MSIZE_ARG,
+ PDUMP_NUM_MBUFS_ARG,
+ NULL
+};
+
+struct pdump_stats {
+ uint64_t dequeue_pkts;
+ uint64_t tx_pkts;
+ uint64_t freed_pkts;
+};
+
+struct pdump_tuples {
+ /* cli params */
+ uint8_t port;
+ char *device_id;
+ uint16_t queue;
+ char rx_dev[TX_STREAM_SIZE];
+ char tx_dev[TX_STREAM_SIZE];
+ uint32_t ring_size;
+ uint16_t mbuf_data_size;
+ uint32_t total_num_mbufs;
+
+ /* params for library API call */
+ uint32_t dir;
+ struct rte_mempool *mp;
+ struct rte_ring *rx_ring;
+ struct rte_ring *tx_ring;
+
+ /* params for packet dumping */
+ enum pdump_by dump_by_type;
+ int rx_vdev_id;
+ int tx_vdev_id;
+ enum pcap_stream rx_vdev_stream_type;
+ enum pcap_stream tx_vdev_stream_type;
+ bool single_pdump_dev;
+
+ /* stats */
+ struct pdump_stats stats;
+} __rte_cache_aligned;
+static struct pdump_tuples pdump_t[APP_ARG_TCPDUMP_MAX_TUPLES];
+
+struct parse_val {
+ uint64_t min;
+ uint64_t max;
+ uint64_t val;
+};
+
+int num_tuples;
+static struct rte_eth_conf port_conf_default;
+volatile uint8_t quit_signal;
+
+/**< display usage */
+static void
+pdump_usage(const char *prgname)
+{
+ printf("usage: %s [EAL options] -- --pdump "
+ "'(port=<port id> | device_id=<pci id or vdev name>),"
+ "(queue=<queue_id>),"
+ "(rx-dev=<iface or pcap file> |"
+ " tx-dev=<iface or pcap file>,"
+ "[ring-size=<ring size>default:16384],"
+ "[mbuf-size=<mbuf data size>default:2176],"
+ "[total-num-mbufs=<number of mbufs>default:65535]"
+ "'\n",
+ prgname);
+}
+
+static int
+parse_device_id(const char *key __rte_unused, const char *value, void *extra_args)
+{
+ struct pdump_tuples *pt = extra_args;
+
+ pt->device_id = strdup(value);
+ pt->dump_by_type = DEVICE_ID;
+
+ return 0;
+}
+
+static int
+parse_queue(const char *key __rte_unused, const char *value, void *extra_args)
+{
+ unsigned long n;
+ struct pdump_tuples *pt = extra_args;
+
+ if (!strcmp(value, "*"))
+ pt->queue = RTE_PDUMP_ALL_QUEUES;
+ else {
+ n = strtoul(value, NULL, 10);
+ pt->queue = (uint16_t) n;
+ }
+ return 0;
+}
+
+static int
+parse_rxtxdev(const char *key, const char *value, void *extra_args)
+{
+
+ struct pdump_tuples *pt = extra_args;
+
+ if (!strcmp(key, PDUMP_RX_DEV_ARG)) {
+ strncpy(pt->rx_dev, value, strlen(value));
+ /* identify the tx stream type for pcap vdev */
+ if (if_nametoindex(pt->rx_dev))
+ pt->rx_vdev_stream_type = IFACE;
+ } else if (!strcmp(key, PDUMP_TX_DEV_ARG)) {
+ strncpy(pt->tx_dev, value, strlen(value));
+ /* identify the tx stream type for pcap vdev */
+ if (if_nametoindex(pt->tx_dev))
+ pt->tx_vdev_stream_type = IFACE;
+ } else {
+ printf("invalid dev type %s, must be rx or tx\n", value);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+parse_uint_value(const char *key, const char *value, void *extra_args)
+{
+ struct parse_val *v;
+ unsigned long t;
+ char *end;
+ int ret = 0;
+
+ errno = 0;
+ v = extra_args;
+ t = strtoul(value, &end, 10);
+
+ if (errno != 0 || end[0] != 0 || t < v->min || t > v->max) {
+ printf("invalid value:\"%s\" for key:\"%s\", "
+ "value must be >= %"PRIu64" and <= %"PRIu64"\n",
+ value, key, v->min, v->max);
+ ret = -EINVAL;
+ }
+ if (!strcmp(key, PDUMP_RING_SIZE_ARG) && !POWEROF2(t)) {
+ printf("invalid value:\"%s\" for key:\"%s\", value must be power of 2\n",
+ value, key);
+ ret = -EINVAL;
+ }
+
+ if (ret != 0)
+ return ret;
+
+ v->val = t;
+ return 0;
+}
+
+static int
+parse_pdump(const char *optarg)
+{
+ struct rte_kvargs *kvlist;
+ int ret = 0, cnt1, cnt2;
+ struct pdump_tuples *pt;
+ struct parse_val v = {0};
+
+ pt = &pdump_t[num_tuples];
+
+ /* initial check for invalid arguments */
+ kvlist = rte_kvargs_parse(optarg, valid_pdump_arguments);
+ if (kvlist == NULL) {
+ printf("--pdump=\"%s\": invalid argument passed\n", optarg);
+ return -1;
+ }
+
+ /* port/device_id parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_PORT_ARG);
+ cnt2 = rte_kvargs_count(kvlist, PDUMP_PCI_ARG);
+ if (!((cnt1 == 1 && cnt2 == 0) || (cnt1 == 0 && cnt2 == 1))) {
+ printf("--pdump=\"%s\": must have either port or device_id argument\n",
+ optarg);
+ ret = -1;
+ goto free_kvlist;
+ } else if (cnt1 == 1) {
+ v.min = 0;
+ v.max = RTE_MAX_ETHPORTS-1;
+ ret = rte_kvargs_process(kvlist, PDUMP_PORT_ARG,
+ &parse_uint_value, &v);
+ if (ret < 0)
+ goto free_kvlist;
+ pt->port = (uint8_t) v.val;
+ pt->dump_by_type = PORT_ID;
+ } else if (cnt2 == 1) {
+ ret = rte_kvargs_process(kvlist, PDUMP_PCI_ARG,
+ &parse_device_id, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ }
+
+ /* queue parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_QUEUE_ARG);
+ if (cnt1 != 1) {
+ printf("--pdump=\"%s\": must have queue argument\n", optarg);
+ ret = -1;
+ goto free_kvlist;
+ }
+ ret = rte_kvargs_process(kvlist, PDUMP_QUEUE_ARG, &parse_queue, pt);
+ if (ret < 0)
+ goto free_kvlist;
+
+ /* rx-dev and tx-dev parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_RX_DEV_ARG);
+ cnt2 = rte_kvargs_count(kvlist, PDUMP_TX_DEV_ARG);
+ if (cnt1 == 0 && cnt2 == 0) {
+ printf("--pdump=\"%s\": must have either rx-dev or tx-dev argument\n",
+ optarg);
+ ret = -1;
+ goto free_kvlist;
+ } else if (cnt1 == 1 && cnt2 == 1) {
+ ret = rte_kvargs_process(kvlist, PDUMP_RX_DEV_ARG, &parse_rxtxdev, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ ret = rte_kvargs_process(kvlist, PDUMP_TX_DEV_ARG, &parse_rxtxdev, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ /* if captured packets has to send to the same vdev */
+ if (!strcmp(pt->rx_dev, pt->tx_dev))
+ pt->single_pdump_dev = true;
+ pt->dir = RTE_PDUMP_FLAG_RXTX;
+ } else if (cnt1 == 1) {
+ ret = rte_kvargs_process(kvlist, PDUMP_RX_DEV_ARG, &parse_rxtxdev, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ pt->dir = RTE_PDUMP_FLAG_RX;
+ } else if (cnt2 == 1) {
+ ret = rte_kvargs_process(kvlist, PDUMP_TX_DEV_ARG, &parse_rxtxdev, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ pt->dir = RTE_PDUMP_FLAG_TX;
+ }
+
+ /* optional */
+ /* ring_size parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_RING_SIZE_ARG);
+ if (cnt1 == 1) {
+ v.min = 2;
+ v.max = RTE_RING_SZ_MASK-1;
+ ret = rte_kvargs_process(kvlist, PDUMP_RING_SIZE_ARG,
+ &parse_uint_value, &v);
+ if (ret < 0)
+ goto free_kvlist;
+ pt->ring_size = (uint16_t) v.val;
+ } else
+ pt->ring_size = RING_SIZE;
+
+ /* mbuf_data_size parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_MSIZE_ARG);
+ if (cnt1 == 1) {
+ v.min = 1;
+ v.max = UINT16_MAX;
+ ret = rte_kvargs_process(kvlist, PDUMP_MSIZE_ARG,
+ &parse_uint_value, &v);
+ if (ret < 0)
+ goto free_kvlist;
+ pt->mbuf_data_size = (uint16_t) v.val;
+ } else
+ pt->mbuf_data_size = RTE_MBUF_DEFAULT_BUF_SIZE;
+
+ /* total_num_mbufs parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_NUM_MBUFS_ARG);
+ if (cnt1 == 1) {
+ v.min = 1025;
+ v.max = UINT16_MAX;
+ ret = rte_kvargs_process(kvlist, PDUMP_NUM_MBUFS_ARG,
+ &parse_uint_value, &v);
+ if (ret < 0)
+ goto free_kvlist;
+ pt->total_num_mbufs = (uint16_t) v.val;
+ } else
+ pt->total_num_mbufs = MBUFS_PER_POOL;
+
+ num_tuples++;
+
+free_kvlist:
+ rte_kvargs_free(kvlist);
+ return ret;
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+launch_args_parse(int argc, char **argv, char *prgname)
+{
+ int opt, ret;
+ int option_index;
+ static struct option long_option[] = {
+ {"pdump", 1, 0, 0},
+ {NULL, 0, 0, 0}
+ };
+
+ if (argc == 1)
+ pdump_usage(prgname);
+
+ /* Parse command line */
+ while ((opt = getopt_long(argc, argv, " ",
+ long_option, &option_index)) != EOF) {
+ switch (opt) {
+ case 0:
+ if (!strncmp(long_option[option_index].name, "pdump",
+ MAX_LONG_OPT_SZ)) {
+ ret = parse_pdump(optarg);
+ if (ret) {
+ pdump_usage(prgname);
+ return -1;
+ }
+ }
+ break;
+ default:
+ pdump_usage(prgname);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static void
+print_pdump_stats(void)
+{
+ int i;
+ struct pdump_tuples *pt;
+
+ for (i = 0; i < num_tuples; i++) {
+ printf("##### PDUMP DEBUG STATS #####\n");
+ pt = &pdump_t[i];
+ printf(" -packets dequeued: %"PRIu64"\n",
+ pt->stats.dequeue_pkts);
+ printf(" -packets transmitted to vdev: %"PRIu64"\n",
+ pt->stats.tx_pkts);
+ printf(" -packets freed: %"PRIu64"\n",
+ pt->stats.freed_pkts);
+ }
+}
+
+static inline void
+disable_pdump(struct pdump_tuples *pt)
+{
+ if (pt->dump_by_type == DEVICE_ID)
+ rte_pdump_disable_by_deviceid(pt->device_id, pt->queue, pt->dir);
+ else if (pt->dump_by_type == PORT_ID)
+ rte_pdump_disable(pt->port, pt->queue, pt->dir);
+}
+
+static inline void
+pdump_rxtx(struct rte_ring *ring, uint8_t vdev_id, struct pdump_stats *stats)
+{
+ /* write input packets of port to vdev for pdump */
+ struct rte_mbuf *rxtx_bufs[BURST_SIZE];
+
+ /* first dequeue packets from ring of primary process */
+ const uint16_t nb_in_deq = rte_ring_dequeue_burst(ring,
+ (void *)rxtx_bufs, BURST_SIZE);
+ stats->dequeue_pkts += nb_in_deq;
+
+ if (nb_in_deq) {
+ /* then sent on vdev */
+ uint16_t nb_in_txd = rte_eth_tx_burst(
+ vdev_id,
+ 0, rxtx_bufs, nb_in_deq);
+ stats->tx_pkts += nb_in_txd;
+
+ if (unlikely(nb_in_txd < nb_in_deq)) {
+ do {
+ rte_pktmbuf_free(rxtx_bufs[nb_in_txd]);
+ stats->freed_pkts++;
+ } while (++nb_in_txd < nb_in_deq);
+ }
+ }
+}
+
+static void
+free_ring_data(struct rte_ring *ring, uint8_t vdev_id, struct pdump_stats *stats)
+{
+ while (rte_ring_count(ring))
+ pdump_rxtx(ring, vdev_id, stats);
+}
+
+static void
+cleanup_pdump_resources(void)
+{
+ int i;
+ struct pdump_tuples *pt;
+
+ /* disable pdump and free the pdump_tuple resources */
+ for (i = 0; i < num_tuples; i++) {
+ pt = &pdump_t[i];
+
+ /* remove callbacks */
+ disable_pdump(pt);
+
+ /*
+ * transmit rest of the enqueued packets of the rings on to the vdev,
+ * in order to release mbufs to the mepool.
+ **/
+ if (pt->dir & RTE_PDUMP_FLAG_RX)
+ free_ring_data(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
+ if (pt->dir & RTE_PDUMP_FLAG_TX)
+ free_ring_data(pt->tx_ring, pt->tx_vdev_id, &pt->stats);
+
+ if (pt->device_id)
+ free(pt->device_id);
+
+ /* free the rings */
+ if (pt->rx_ring)
+ rte_ring_free(pt->rx_ring);
+ if (pt->tx_ring)
+ rte_ring_free(pt->tx_ring);
+ }
+}
+
+static void
+signal_handler(int sig_num)
+{
+ if (sig_num == SIGINT) {
+ printf("\n\nSignal %d received, preparing to exit...\n",
+ sig_num);
+ quit_signal = 1;
+ }
+}
+
+static inline int
+configure_vdev(uint8_t port_id)
+{
+ struct ether_addr addr;
+ const uint16_t rxRings = 0, txRings = 1;
+ const uint8_t nb_ports = rte_eth_dev_count();
+ int ret;
+ uint16_t q;
+
+ if (port_id > nb_ports)
+ return -1;
+
+ ret = rte_eth_dev_configure(port_id, rxRings, txRings, &port_conf_default);
+ if (ret != 0)
+ rte_exit(EXIT_FAILURE, "dev config failed\n");
+
+ for (q = 0; q < txRings; q++) {
+ ret = rte_eth_tx_queue_setup(port_id, q, TX_DESC_PER_QUEUE,
+ rte_eth_dev_socket_id(port_id), NULL);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "queue setup failed\n");
+ }
+
+ ret = rte_eth_dev_start(port_id);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "dev start failed\n");
+
+ rte_eth_macaddr_get(port_id, &addr);
+ printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
+ " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
+ (unsigned)port_id,
+ addr.addr_bytes[0], addr.addr_bytes[1],
+ addr.addr_bytes[2], addr.addr_bytes[3],
+ addr.addr_bytes[4], addr.addr_bytes[5]);
+
+ rte_eth_promiscuous_enable(port_id);
+
+ return 0;
+}
+
+static void
+create_mp_ring_vdev(void)
+{
+ int i;
+ uint8_t portid;
+ struct pdump_tuples *pt = NULL;
+ struct rte_mempool *mbuf_pool = NULL;
+ char vdev_args[SIZE];
+ char ring_name[SIZE];
+ char mempool_name[SIZE];
+
+ for (i = 0; i < num_tuples; i++) {
+ pt = &pdump_t[i];
+ snprintf(mempool_name, SIZE, MP_NAME, i);
+ mbuf_pool = rte_mempool_lookup(mempool_name);
+ if (mbuf_pool == NULL) {
+ /* create mempool */
+ mbuf_pool = rte_pktmbuf_pool_create(mempool_name,
+ pt->total_num_mbufs,
+ MBUF_POOL_CACHE_SIZE, 0, pt->mbuf_data_size,
+ rte_socket_id());
+ if (mbuf_pool == NULL)
+ rte_exit(EXIT_FAILURE, "Mempool creation failed: %s\n",
+ rte_strerror(rte_errno));
+ }
+ pt->mp = mbuf_pool;
+
+ if (pt->dir == RTE_PDUMP_FLAG_RXTX) {
+ /* if captured packets has to send to the same vdev */
+ /* create rx_ring */
+ snprintf(ring_name, SIZE, RX_RING, i);
+ pt->rx_ring = rte_ring_create(ring_name, pt->ring_size,
+ rte_socket_id(), 0);
+ if (pt->rx_ring == NULL)
+ rte_exit(EXIT_FAILURE, "%s:%s:%d\n",
+ rte_strerror(rte_errno),
+ __func__, __LINE__);
+
+ /* create tx_ring */
+ snprintf(ring_name, SIZE, TX_RING, i);
+ pt->tx_ring = rte_ring_create(ring_name, pt->ring_size,
+ rte_socket_id(), 0);
+ if (pt->tx_ring == NULL)
+ rte_exit(EXIT_FAILURE, "%s:%s:%d\n",
+ rte_strerror(rte_errno),
+ __func__, __LINE__);
+
+ /* create vdevs */
+ (pt->rx_vdev_stream_type == IFACE) ? snprintf(vdev_args, SIZE,
+ VDEV_IFACE, RX_STR, i, pt->rx_dev) : snprintf(vdev_args, SIZE,
+ VDEV_PCAP, RX_STR, i, pt->rx_dev);
+ if (rte_eth_dev_attach(vdev_args, &portid) < 0)
+ rte_exit(EXIT_FAILURE, "vdev creation failed:%s:%d\n",
+ __func__, __LINE__);
+ pt->rx_vdev_id = portid;
+
+ /* configure vdev */
+ configure_vdev(pt->rx_vdev_id);
+
+ if (pt->single_pdump_dev)
+ pt->tx_vdev_id = portid;
+ else {
+ (pt->tx_vdev_stream_type == IFACE) ?
+ snprintf(vdev_args, SIZE, VDEV_IFACE, TX_STR, i,
+ pt->tx_dev) :
+ snprintf(vdev_args, SIZE, VDEV_PCAP, TX_STR, i,
+ pt->tx_dev);
+ if (rte_eth_dev_attach(vdev_args, &portid) < 0)
+ rte_exit(EXIT_FAILURE, "vdev creation failed:"
+ "%s:%d\n", __func__, __LINE__);
+ pt->tx_vdev_id = portid;
+
+ /* configure vdev */
+ configure_vdev(pt->tx_vdev_id);
+ }
+ } else if (pt->dir == RTE_PDUMP_FLAG_RX) {
+
+ /* create rx_ring */
+ snprintf(ring_name, SIZE, RX_RING, i);
+ pt->rx_ring = rte_ring_create(ring_name, pt->ring_size,
+ rte_socket_id(), 0);
+ if (pt->rx_ring == NULL)
+ rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno));
+
+ (pt->rx_vdev_stream_type == IFACE) ?
+ snprintf(vdev_args, SIZE, VDEV_IFACE, RX_STR, i, pt->rx_dev) :
+ snprintf(vdev_args, SIZE, VDEV_PCAP, RX_STR, i, pt->rx_dev);
+ if (rte_eth_dev_attach(vdev_args, &portid) < 0)
+ rte_exit(EXIT_FAILURE, "vdev creation failed:%s:%d\n",
+ __func__, __LINE__);
+ pt->rx_vdev_id = portid;
+ /* configure vdev */
+ configure_vdev(pt->rx_vdev_id);
+ } else if (pt->dir == RTE_PDUMP_FLAG_TX) {
+
+ /* create tx_ring */
+ snprintf(ring_name, SIZE, TX_RING, i);
+ pt->tx_ring = rte_ring_create(ring_name, pt->ring_size,
+ rte_socket_id(), 0);
+ if (pt->tx_ring == NULL)
+ rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno));
+
+ (pt->tx_vdev_stream_type == IFACE) ?
+ snprintf(vdev_args, SIZE, VDEV_IFACE, TX_STR, i, pt->tx_dev) :
+ snprintf(vdev_args, SIZE, VDEV_PCAP, TX_STR, i, pt->tx_dev);
+ if (rte_eth_dev_attach(vdev_args, &portid) < 0)
+ rte_exit(EXIT_FAILURE, "vdev creation failed\n");
+ pt->tx_vdev_id = portid;
+
+ /* configure vdev */
+ configure_vdev(pt->tx_vdev_id);
+ }
+ }
+}
+
+static void
+enable_pdump(void)
+{
+ int i;
+ struct pdump_tuples *pt;
+ int ret = 0, ret1 = 0;
+
+ for (i = 0; i < num_tuples; i++) {
+ pt = &pdump_t[i];
+ if (pt->dir == RTE_PDUMP_FLAG_RXTX) {
+ if (pt->dump_by_type == DEVICE_ID) {
+ ret = rte_pdump_enable_by_deviceid(pt->device_id,
+ pt->queue,
+ RTE_PDUMP_FLAG_RX,
+ pt->rx_ring,
+ pt->mp, NULL);
+ ret = rte_pdump_enable_by_deviceid(pt->device_id,
+ pt->queue,
+ RTE_PDUMP_FLAG_TX,
+ pt->tx_ring,
+ pt->mp, NULL);
+ } else if (pt->dump_by_type == PORT_ID) {
+ ret = rte_pdump_enable(pt->port, pt->queue,
+ RTE_PDUMP_FLAG_RX,
+ pt->rx_ring, pt->mp, NULL);
+ ret1 = rte_pdump_enable(pt->port, pt->queue,
+ RTE_PDUMP_FLAG_TX,
+ pt->tx_ring, pt->mp, NULL);
+ }
+ } else if (pt->dir == RTE_PDUMP_FLAG_RX) {
+ if (pt->dump_by_type == DEVICE_ID)
+ ret = rte_pdump_enable_by_deviceid(pt->device_id,
+ pt->queue,
+ pt->dir, pt->rx_ring,
+ pt->mp, NULL);
+ else if (pt->dump_by_type == PORT_ID)
+ ret = rte_pdump_enable(pt->port, pt->queue, pt->dir,
+ pt->rx_ring, pt->mp, NULL);
+ } else if (pt->dir == RTE_PDUMP_FLAG_TX) {
+ if (pt->dump_by_type == DEVICE_ID)
+ ret = rte_pdump_enable_by_deviceid(pt->device_id,
+ pt->queue,
+ pt->dir,
+ pt->tx_ring, pt->mp, NULL);
+ else if (pt->dump_by_type == PORT_ID)
+ ret = rte_pdump_enable(pt->port, pt->queue, pt->dir,
+ pt->tx_ring, pt->mp, NULL);
+ }
+ if (ret < 0 || ret1 < 0) {
+ cleanup_pdump_resources();
+ rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno));
+ }
+ }
+}
+
+static inline void
+dump_packets(void)
+{
+ int i;
+ struct pdump_tuples *pt;
+
+ while (!quit_signal) {
+ for (i = 0; i < num_tuples; i++) {
+ pt = &pdump_t[i];
+ if (pt->dir & RTE_PDUMP_FLAG_RX)
+ pdump_rxtx(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
+ if (pt->dir & RTE_PDUMP_FLAG_TX)
+ pdump_rxtx(pt->tx_ring, pt->tx_vdev_id, &pt->stats);
+ }
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ int diag;
+ int ret;
+ int i;
+
+ char c_flag[] = "-c1";
+ char n_flag[] = "-n4";
+ char mp_flag[] = "--proc-type=secondary";
+ char *argp[argc + 3];
+
+ /* catch ctrl-c so we can print on exit */
+ signal(SIGINT, signal_handler);
+
+ argp[0] = argv[0];
+ argp[1] = c_flag;
+ argp[2] = n_flag;
+ argp[3] = mp_flag;
+
+ for (i = 1; i < argc; i++)
+ argp[i + 3] = argv[i];
+
+ argc += 3;
+
+ diag = rte_eal_init(argc, argp);
+ if (diag < 0)
+ rte_panic("Cannot init EAL\n");
+
+ argc -= diag;
+ argv += (diag - 3);
+
+ /* parse app arguments */
+ if (argc > 1) {
+ ret = launch_args_parse(argc, argv, argp[0]);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Invalid argument\n");
+ }
+
+ /* create mempool, ring and vdevs info */
+ create_mp_ring_vdev();
+ enable_pdump();
+ dump_packets();
+
+ cleanup_pdump_resources();
+ /* dump debug stats */
+ print_pdump_stats();
+
+ return 0;
+}
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v5 7/9] app/test-pmd: add pdump initialization uninitialization
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 " Reshma Pattan
` (5 preceding siblings ...)
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 6/9] app/pdump: add pdump tool for packet capturing Reshma Pattan
@ 2016-06-08 13:38 ` Reshma Pattan
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 8/9] doc: update doc for packet capture framework Reshma Pattan
` (2 subsequent siblings)
9 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-08 13:38 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Call rte_pdump_init and rte_pdump_uninit for packet
capturing initialization and uninitialization.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
app/test-pmd/testpmd.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 9d11830..645bf50 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -75,6 +75,7 @@
#ifdef RTE_LIBRTE_PMD_XENVIRT
#include <rte_eth_xenvirt.h>
#endif
+#include <rte_pdump.h>
#include "testpmd.h"
@@ -2023,6 +2024,8 @@ signal_handler(int signum)
if (signum == SIGINT || signum == SIGTERM) {
printf("\nSignal %d received, preparing to exit...\n",
signum);
+ /* uninitialize packet capture framework */
+ rte_pdump_uninit();
force_quit();
/* exit with the expected status */
signal(signum, SIG_DFL);
@@ -2043,6 +2046,9 @@ main(int argc, char** argv)
if (diag < 0)
rte_panic("Cannot init EAL\n");
+ /* initialize packet capture framework */
+ rte_pdump_init();
+
nb_ports = (portid_t) rte_eth_dev_count();
if (nb_ports == 0)
RTE_LOG(WARNING, EAL, "No probed ethernet devices\n");
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v5 8/9] doc: update doc for packet capture framework
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 " Reshma Pattan
` (6 preceding siblings ...)
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 7/9] app/test-pmd: add pdump initialization uninitialization Reshma Pattan
@ 2016-06-08 13:38 ` Reshma Pattan
2016-06-08 16:02 ` Mcnamara, John
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 9/9] doc: announce ABI change for rte_eth_dev_info structure Reshma Pattan
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 0/8] add packet capture framework Reshma Pattan
9 siblings, 1 reply; 82+ messages in thread
From: Reshma Pattan @ 2016-06-08 13:38 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Added programmers guide for librte_pdump.
Added sample application guide for app/pdump application.
Updated release note for packet capture framework changes.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
MAINTAINERS | 3 +
doc/guides/prog_guide/index.rst | 1 +
doc/guides/prog_guide/pdump_library.rst | 107 ++++++++++++++++++++++++++++
doc/guides/rel_notes/release_16_07.rst | 13 ++++
doc/guides/sample_app_ug/index.rst | 1 +
doc/guides/sample_app_ug/pdump.rst | 122 ++++++++++++++++++++++++++++++++
6 files changed, 247 insertions(+)
create mode 100644 doc/guides/prog_guide/pdump_library.rst
create mode 100644 doc/guides/sample_app_ug/pdump.rst
diff --git a/MAINTAINERS b/MAINTAINERS
index a48c8de..ce7c941 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -436,6 +436,9 @@ Pdump
M: Reshma Pattan <reshma.pattan@intel.com>
F: lib/librte_pdump/
F: app/pdump/
+F: doc/guides/prog_guide/pdump_library.rst
+F: doc/guides/sample_app_ug/pdump.rst
+
Hierarchical scheduler
M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
index b862d0c..4caf969 100644
--- a/doc/guides/prog_guide/index.rst
+++ b/doc/guides/prog_guide/index.rst
@@ -71,6 +71,7 @@ Programmer's Guide
writing_efficient_code
profile_app
glossary
+ pdump_library
**Figures**
diff --git a/doc/guides/prog_guide/pdump_library.rst b/doc/guides/prog_guide/pdump_library.rst
new file mode 100644
index 0000000..1809234
--- /dev/null
+++ b/doc/guides/prog_guide/pdump_library.rst
@@ -0,0 +1,107 @@
+.. 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.
+
+.. _pdump_library:
+
+The librte_pdump Library
+========================
+
+The ``librte_pdump`` library provides a framework for packet capturing in DPDK.
+The library provides the following APIs to initialize the packet capture framework, to enable
+or disable the packet capture, and to uninitialize it:
+
+* ``rte_pdump_init()``:
+ This API initializes the packet capture framework.
+
+* ``rte_pdump_enable()``:
+ This API enables the packet capture on a given port and queue.
+ Note: The filter option in the API is a place holder for future enhancements.
+
+* ``rte_pdump_enable_by_deviceid()``:
+ This API enables the packet capture on a given device id (``vdev name or pci address``) and queue.
+ Note: The filter option in the API is a place holder for future enhancements.
+
+* ``rte_pdump_disable()``:
+ This API disables the packet capture on a given port and queue.
+
+* ``rte_pdump_disable_by_deviceid()``:
+ This API disables the packet capture on a given device id (``vdev name or pci address``) and queue.
+
+* ``rte_pdump_uninit()``:
+ This API uninitializes the packet capture framework.
+
+
+Operation
+---------
+
+The ``librte_pdump`` library works on a client/server model. The server is responsible for enabling or
+disabling the packet capture and the clients are responsible for requesting the enabling or disabling of
+the packet capture.
+
+The packet capture framework, as part of its initialization, creates the pthread and the server socket in
+the pthread. The application that calls the framework initialization first will have the server socket created.
+Further calls to the framework initialization by the same application or other applications is not allowed i.e., only
+one server socket is allowed on the system. So the other applications can only request enabling or disabling of
+the packet capture at which point the client socket is created for them to send the request to the server.
+The server socket will listen for client requests for enabling or disabling the packet capture.
+
+
+Implementation Details
+----------------------
+
+The library API ``rte_pdump_init()``, initializes the packet capture framework by creating the pthread and the server
+socket. The server socket in the pthread context will be listening to the client requests to enable or disable the
+packet capture. Whoever calls this API first will have the server socket created, the subsequent calls to this APIs
+will not create any further server socket. i.e. only one server socket is allowed.
+
+The library APIs ``rte_pdump_enable()`` and ``rte_pdump_enable_by_deviceid()`` enables the packet capture.
+On each call to these APIs, the library creates a separate client socket, creates the "pdump enable" request and sends
+the request to the server. The server that is listening on the socket will take the request and enable the packet capture
+by registering the Ethernet RX and TX callbacks for the given port or device_id and queue combinations.
+Then the server will mirror the packets to the new mempool and enqueue them to the rte_ring that clients have passed
+to these APIs. The server also sends the response back to the client about the status of the request that was processed.
+After the response is received from the server, the client socket is closed.
+
+The library APIs ``rte_pdump_disable()`` and ``rte_pdump_disable_by_deviceid()`` disables the packet capture.
+On each call to these APIs, the library creates a separate client socket, creates the "pdump disable" request and sends
+the request to the server. The server that is listening on the socket will take the request and disable the packet
+capture by removing the Ethernet RX and TX callbacks for the given port or device_id and queue combinations. The server
+also sends the response back to the client about the status of the request that was processed. After the response is
+received from the server, the client socket is closed.
+
+The library API ``rte_pdump_uninit()``, uninitializes the packet capture framework by closing the pthread and the
+server socket.
+
+
+Use Case: Packet Capturing
+--------------------------
+
+The DPDK ``app/pdump`` tool is developed based on this library to capture packets in DPDK.
+Users can use this as an example to develop their own packet capturing application.
diff --git a/doc/guides/rel_notes/release_16_07.rst b/doc/guides/rel_notes/release_16_07.rst
index 307e7c4..438b705 100644
--- a/doc/guides/rel_notes/release_16_07.rst
+++ b/doc/guides/rel_notes/release_16_07.rst
@@ -57,6 +57,11 @@ New Features
Enabled support for the AES CTR algorithm for Intel QuickAssist devices.
Provided support for algorithm-chaining operations.
+* **Added packet capture framework.**
+
+ * A new library ``librte_pdump`` is added to provide packet capture APIs.
+ * A new ``app/pdump`` tool is added to capture packets in DPDK.
+
Resolved Issues
---------------
@@ -126,6 +131,11 @@ API Changes
ibadcrc, ibadlen, imcasts, fdirmatch, fdirmiss,
tx_pause_xon, rx_pause_xon, tx_pause_xoff, rx_pause_xoff.
+* Function ``rte_eth_dev_get_port_by_name`` changed to a public API.
+
+* Function ``rte_eth_dev_info_get`` updated to return new fields ``nb_rx_queues`` and ``nb_tx_queues``
+ in the ``rte_eth_dev_info`` object.
+
ABI Changes
-----------
@@ -137,6 +147,9 @@ ABI Changes
* The ``rte_port_source_params`` structure has new fields to support PCAP file.
It was already in release 16.04 with ``RTE_NEXT_ABI`` flag.
+* The ``rte_eth_dev_info`` structure has new fields ``nb_rx_queues`` and ``nb_tx_queues``
+ to support number of queues configured by software.
+
Shared Library Versions
-----------------------
diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst
index 930f68c..96bb317 100644
--- a/doc/guides/sample_app_ug/index.rst
+++ b/doc/guides/sample_app_ug/index.rst
@@ -76,6 +76,7 @@ Sample Applications User Guide
ptpclient
performance_thread
ipsec_secgw
+ pdump
**Figures**
diff --git a/doc/guides/sample_app_ug/pdump.rst b/doc/guides/sample_app_ug/pdump.rst
new file mode 100644
index 0000000..96c8709
--- /dev/null
+++ b/doc/guides/sample_app_ug/pdump.rst
@@ -0,0 +1,122 @@
+
+.. 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.
+
+
+dpdk_pdump Application
+======================
+
+The ``dpdk_pdump`` application is a Data Plane Development Kit (DPDK) application that runs as a DPDK secondary process and
+is capable of enabling packet capture on dpdk ports.
+
+
+Running the Application
+-----------------------
+
+The application has a ``--pdump`` command line option with various sub arguments:
+
+.. code-block:: console
+
+ ./build/app/dpdk_pdump --
+ --pdump '(port=<port id> | device_id=<pci id or vdev name>),
+ (queue=<queue_id>),
+ (rx-dev=<iface or pcap file> |
+ tx-dev=<iface or pcap file>),
+ [ring-size=<ring size>],
+ [mbuf-size=<mbuf data size>],
+ [total-num-mbufs=<number of mbufs>]'
+
+Note:
+
+* Parameters inside the parentheses represents mandatory parameters.
+
+* Parameters inside the square brackets represents optional parameters.
+
+Multiple instances of ``--pdump`` can be passed to capture packets on different port and queue combinations.
+
+
+Parameters
+~~~~~~~~~~
+
+``port``:
+Port id of the eth device on which packets should be captured.
+
+``device_id``:
+PCI address (or) name of the eth device on which packets should be captured.
+
+ .. Note::
+
+ * As of now the ``dpdk_pdump`` tool cannot capture the packets of virtual devices
+ in the primary process due to a bug in the ethdev library. Due to this bug, in a multi process context,
+ when the primary and secondary have different ports set, then the secondary process
+ (here the ``dpdk_pdump`` tool) overwrites the ``rte_eth_devices[]`` entries of the primary process.
+
+``queue``:
+Queue id of the eth device on which packets should be captured. The user can pass a queue value of ``*`` to enable
+packet capture on all queues of the eth device.
+
+``rx-dev``:
+Can be either a pcap file name or any Linux iface.
+
+``tx-dev``:
+Can be either a pcap file name or any Linux iface.
+
+ .. Note::
+
+ * To receive ingress packets only, ``rx-dev`` should be passed.
+
+ * To receive egress packets only, ``tx-dev`` should be passed.
+
+ * To receive ingress and egress packets separately ``rx-dev`` and ``tx-dev``
+ should both be passed with the different file names or the Linux iface names.
+
+ * To receive ingress and egress packets separately ``rx-dev`` and ``tx-dev``
+ should both be passed with the same file names or the the Linux iface names.
+
+``ring-size``:
+Size of the ring. This value is used internally for ring creation. The ring will be used to enqueue the packets from
+the primary application to the secondary. This is an optional parameter with default size 16384.
+
+``mbuf-size``:
+Size of the mbuf data. This is used internally for mempool creation. Ideally this value must be same as
+the primary application's mempool's mbuf data size which is used for packet RX. This is an optional parameter with
+default size 2176.
+
+``total-num-mbufs``:
+Total number mbufs in mempool. This is used internally for mempool creation. This is an optional parameter with default
+value 65535.
+
+
+Example
+-------
+
+.. code-block:: console
+
+ $ sudo ./build/app/dpdk_pdump -- --pdump 'port=0,queue=*,rx-dev=/tmp/rx.pcap'
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v5 8/9] doc: update doc for packet capture framework
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 8/9] doc: update doc for packet capture framework Reshma Pattan
@ 2016-06-08 16:02 ` Mcnamara, John
0 siblings, 0 replies; 82+ messages in thread
From: Mcnamara, John @ 2016-06-08 16:02 UTC (permalink / raw)
To: Pattan, Reshma, dev; +Cc: Pattan, Reshma
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Reshma Pattan
> Sent: Wednesday, June 8, 2016 2:38 PM
> To: dev@dpdk.org
> Cc: Pattan, Reshma <reshma.pattan@intel.com>
> Subject: [dpdk-dev] [PATCH v5 8/9] doc: update doc for packet capture
> framework
>
> Added programmers guide for librte_pdump.
> Added sample application guide for app/pdump application.
> Updated release note for packet capture framework changes.
>
> Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
Acked-by: John McNamara <john.mcnamara@intel.com>
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v5 9/9] doc: announce ABI change for rte_eth_dev_info structure
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 " Reshma Pattan
` (7 preceding siblings ...)
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 8/9] doc: update doc for packet capture framework Reshma Pattan
@ 2016-06-08 13:38 ` Reshma Pattan
2016-06-08 16:15 ` Mcnamara, John
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 0/8] add packet capture framework Reshma Pattan
9 siblings, 1 reply; 82+ messages in thread
From: Reshma Pattan @ 2016-06-08 13:38 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
New fields nb_rx_queues and nb_tx_queues will be added to
rte_eth_dev_info structure.
Changes to API rte_eth_dev_info_get() will be done to update
these new fields to rte_eth_dev_info object.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
doc/guides/rel_notes/deprecation.rst | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index ad05eba..04316fb 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -57,3 +57,9 @@ Deprecation Notices
a handle, like the way kernel exposes an fd to user for locating a
specific file, and to keep all major structures internally, so that
we are likely to be free from ABI violations in future.
+
+* A librte_ether public structure ``rte_eth_dev_info`` will be changed in 16.07.
+ The proposed change will add new parameters ``nb_rx_queues``, ``nb_tx_queues``
+ to the structure. These are the number of queues configured by software.
+ Modification to definition of ``rte_eth_dev_info_get()`` will be done
+ to update new parameters to ``rte_eth_dev_info`` object.
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v5 9/9] doc: announce ABI change for rte_eth_dev_info structure
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 9/9] doc: announce ABI change for rte_eth_dev_info structure Reshma Pattan
@ 2016-06-08 16:15 ` Mcnamara, John
0 siblings, 0 replies; 82+ messages in thread
From: Mcnamara, John @ 2016-06-08 16:15 UTC (permalink / raw)
To: Pattan, Reshma, dev; +Cc: Pattan, Reshma
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Reshma Pattan
> Sent: Wednesday, June 8, 2016 2:38 PM
> To: dev@dpdk.org
> Cc: Pattan, Reshma <reshma.pattan@intel.com>
> Subject: [dpdk-dev] [PATCH v5 9/9] doc: announce ABI change for
> rte_eth_dev_info structure
>
> New fields nb_rx_queues and nb_tx_queues will be added to rte_eth_dev_info
> structure.
> Changes to API rte_eth_dev_info_get() will be done to update these new
> fields to rte_eth_dev_info object.
>
> Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
> ---
> doc/guides/rel_notes/deprecation.rst | 6 ++++++
> 1 file changed, 6 insertions(+)
>
Hi,
This isn't required in this patchset since the deprecation has already occurred in this release.
John
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v6 0/8] add packet capture framework
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 " Reshma Pattan
` (8 preceding siblings ...)
2016-06-08 13:38 ` [dpdk-dev] [PATCH v5 9/9] doc: announce ABI change for rte_eth_dev_info structure Reshma Pattan
@ 2016-06-09 8:50 ` Reshma Pattan
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 1/8] librte_ether: protect add/remove of rxtx callbacks with spinlocks Reshma Pattan
` (8 more replies)
9 siblings, 9 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-09 8:50 UTC (permalink / raw)
To: dev
This patch set include below changes
1)Changes to librte_ether.
2)A new library librte_pdump added for packet capture framework.
3)A new app/pdump tool added for packet capturing.
4)Test pmd changes done to initialize packet capture framework.
5)Documentation update.
1)librte_pdump
==============
To support packet capturing on dpdk Ethernet devices, a new library librte_pdump
is added.Users can develop their own packet capturing application using new library APIs.
Operation:
----------
Pdump library provides APIs to support packet capturing on dpdk Ethernet devices.
Library provides APIs to initialize the packet capture framework, enable/disable
the packet capture and uninitialize the packet capture framework.
Pdump library works on client/server based model.
Sever is responsible for enabling/disabling the packet captures.
Clients are responsible for requesting enable/disable of the
packet captures.
As part of packet capture framework initialization, pthread and
the server socket is created. Only one server socket is allowed on the system.
As part of enabling/disabling the packet capture, client sockets are created
and multiple client sockets are allowed.
Who ever calls initialization first they will succeed with the initialization,
next subsequent calls of initialization are not allowed. So next users can only
request enabling/disabling the packet capture.
Applications using below APIs need to pass port/device_id, queue, mempool and
ring parameters. Library uses user provided ring and mempool to mirror the rx/tx
packets of the port for users. Users need to dequeue the rings and write the packets
to vdev(pcap/tuntap) to view the packets using any standard tools.
Note:
Mempool and Ring should be mc/mp supportable.
Mempool mbuf size should be big enough to handle the rx/tx packets of a port.
APIs:
-----
rte_pdump_init()
rte_pdump_enable()
rte_pdump_enable_by_deviceid()
rte_pdump_disable()
rte_pdump_disable_by_deviceid()
rte_pdump_uninit()
2)app/pdump tool
================
Tool app/pdump is designed based on librte_pdump for packet capturing in DPDK.
This tool by default runs as secondary process, and provides the support for
the command line options for packet capture.
./build/app/dpdk_pdump --
--pdump '(port=<port id> | device_id=<pci id or vdev name>),
(queue=<queue id>),
(rx-dev=<iface or pcap file> |
tx-dev=<iface or pcap file>),
[ring-size=<ring size>],
[mbuf-size=<mbuf data size>],
[total-num-mbufs=<number of mbufs>]'
Parameters inside the parenthesis represents the mandatory parameters.
Parameters inside the square brackets represents optional parameters.
User has to pass on packet capture parameters under --pdump parameters, multiples of
--pdump can be passed to capture packets on different port and queue combinations
Operation:
----------
*Tool parse the user command line arguments,
creates the mempool, ring and the PCAP PMD vdev with 'tx_stream' as either
of the device passed in rx-dev|tx-dev parameters.
*Then calls the APIs of librte_pdump i.e. rte_pdump_enable()/rte_pdump_enable_by_deviceid()
to enable packet capturing on a specific port/device_id and queue by passing on
port|device_id, queue, mempool and ring info.
*Tool runs in while loop to dequeue the packets from the ring and write them to pcap device.
*Tool can be stopped using SIGINT, upon which tool calls
rte_pdump_disable()/rte_pdump_disable_by_deviceid() and free the allocated resources.
Note:
CONFIG_RTE_LIBRTE_PMD_PCAP flag should be set to yes to compile and run the pdump tool.
3)Test-pmd changes
==================
Changes are done to test-pmd application to initialize/uninitialize the packet capture framework.
So app/pdump tool can be run to see packets of dpdk ports that are used by test-pmd.
Similarly any application which needs packet capture should call initialize/uninitialize APIs of
librte_pdump and use pdump tool to start the capture.
4)Packet capture flow between pdump tool and librte_pdump
=========================================================
* Pdump tool (Secondary process) requests packet capture
for specific port|device_id and queue combinations.
*Library in secondary process context creates client socket and communicates
the port|device_id, queue, ring and mempool to server.
*Library initializes server in primary process 'test-pmd' context and server serves
the client request to enable Ethernet rxtx call-backs for a given port|device_id and queue.
*Copy the rx/tx packets to passed mempool and enqueue the packets to ring for secondary process.
*Pdump tool will dequeue the packets from ring and writes them to PCAPMD vdev,
so ultimately packets will be seen on the device that is passed in rx-dev|tx-dev.
*Once the pdump tool is terminated with SIGINT it will disable the packet capturing.
*Library receives the disable packet capture request, communicate the info to server,
server will remove the Ethernet rxtx call-backs.
*Packet capture can be seen using tcpdump command
"tcpdump -ni <iface>" (or) "tcpdump –nr <pcapfile>"
5)Example command line
======================
./build/app/dpdk_pdump -- --pdump 'device_id=0000:02:0.0,queue=*,tx-dev=/tmp/dt-file.pcap,rx-dev=/tmp/dr-file.pcap,ring-size=8192,mbuf-size=2176,total-num-mbufs=32768' --pdump 'device_id=0000:01:00.0,queue=*,rx-dev=/tmp/d-file.pcap,tx-dev=/tmp/d-file.pcap,ring-size=16384,mbuf-size=2176,total-num-mbufs=32768'
v6:
removed below deprecation notice patch from patch set.
http://dpdk.org/dev/patchwork/patch/13372/
v5:
addressed code review comments for below patches
http://dpdk.org/dev/patchwork/patch/12955/
http://dpdk.org/dev/patchwork/patch/12951/
v4:
added missing deprecation notice for ABI changes of rte_eth_dev_info structure.
made doc changes as per doc guidelines.
replaced rte_eal_vdev_init with rte_eth_dev_attach in pdump tool.
removed rxtx-dev parameter from pdump tool command line.
v3:
app/pdump: Moved cleanup code from signal handler to main.
divided librte_ether changes into multiple patches.
example command changed in app/pdump application guide
v2:
fix compilation issues for 4.8.3
fix unnecessary #includes
Reshma Pattan (8):
librte_ether: protect add/remove of rxtx callbacks with spinlocks
librte_ether: add new api rte_eth_add_first_rx_callback
librte_ether: add new fields to rte_eth_dev_info struct
librte_ether: make rte_eth_dev_get_port_by_name
rte_eth_dev_get_name_by_port public
lib/librte_pdump: add new library for packet capturing support
app/pdump: add pdump tool for packet capturing
app/test-pmd: add pdump initialization uninitialization
doc: update doc for packet capture framework
MAINTAINERS | 8 +
app/Makefile | 1 +
app/pdump/Makefile | 45 ++
app/pdump/main.c | 814 +++++++++++++++++++++++++++++++
app/test-pmd/testpmd.c | 6 +
config/common_base | 5 +
doc/guides/prog_guide/index.rst | 1 +
doc/guides/prog_guide/pdump_library.rst | 107 ++++
doc/guides/rel_notes/release_16_07.rst | 13 +
doc/guides/sample_app_ug/index.rst | 1 +
doc/guides/sample_app_ug/pdump.rst | 122 +++++
lib/Makefile | 1 +
lib/librte_ether/rte_ethdev.c | 123 +++--
lib/librte_ether/rte_ethdev.h | 59 +++
lib/librte_ether/rte_ether_version.map | 9 +
lib/librte_pdump/Makefile | 55 +++
lib/librte_pdump/rte_pdump.c | 841 ++++++++++++++++++++++++++++++++
lib/librte_pdump/rte_pdump.h | 186 +++++++
lib/librte_pdump/rte_pdump_version.map | 12 +
mk/rte.app.mk | 1 +
20 files changed, 2366 insertions(+), 44 deletions(-)
create mode 100644 app/pdump/Makefile
create mode 100644 app/pdump/main.c
create mode 100644 doc/guides/prog_guide/pdump_library.rst
create mode 100644 doc/guides/sample_app_ug/pdump.rst
create mode 100644 lib/librte_pdump/Makefile
create mode 100644 lib/librte_pdump/rte_pdump.c
create mode 100644 lib/librte_pdump/rte_pdump.h
create mode 100644 lib/librte_pdump/rte_pdump_version.map
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v6 1/8] librte_ether: protect add/remove of rxtx callbacks with spinlocks
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 0/8] add packet capture framework Reshma Pattan
@ 2016-06-09 8:50 ` Reshma Pattan
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 2/8] librte_ether: add new api rte_eth_add_first_rx_callback Reshma Pattan
` (7 subsequent siblings)
8 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-09 8:50 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Added spinlocks around add/remove logic of rxtx callbacks to
avoid corruption of callback lists in multithreaded context.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
lib/librte_ether/rte_ethdev.c | 82 +++++++++++++++++++++----------------------
1 file changed, 40 insertions(+), 42 deletions(-)
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index e148028..ce70d58 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -77,6 +77,12 @@ static uint8_t nb_ports;
/* spinlock for eth device callbacks */
static rte_spinlock_t rte_eth_dev_cb_lock = RTE_SPINLOCK_INITIALIZER;
+/* spinlock for add/remove rx callbacks */
+static rte_spinlock_t rte_eth_rx_cb_lock = RTE_SPINLOCK_INITIALIZER;
+
+/* spinlock for add/remove tx callbacks */
+static rte_spinlock_t rte_eth_tx_cb_lock = RTE_SPINLOCK_INITIALIZER;
+
/* store statistics names and its offset in stats structure */
struct rte_eth_xstats_name_off {
char name[RTE_ETH_XSTATS_NAME_SIZE];
@@ -1634,7 +1640,6 @@ rte_eth_dev_set_rx_queue_stats_mapping(uint8_t port_id, uint16_t rx_queue_id,
STAT_QMAP_RX);
}
-
void
rte_eth_dev_info_get(uint8_t port_id, struct rte_eth_dev_info *dev_info)
{
@@ -2905,7 +2910,6 @@ rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
rte_errno = EINVAL;
return NULL;
}
-
struct rte_eth_rxtx_callback *cb = rte_zmalloc(NULL, sizeof(*cb), 0);
if (cb == NULL) {
@@ -2916,6 +2920,7 @@ rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
cb->fn.rx = fn;
cb->param = user_param;
+ rte_spinlock_lock(&rte_eth_rx_cb_lock);
/* Add the callbacks in fifo order. */
struct rte_eth_rxtx_callback *tail =
rte_eth_devices[port_id].post_rx_burst_cbs[queue_id];
@@ -2928,6 +2933,7 @@ rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
tail = tail->next;
tail->next = cb;
}
+ rte_spinlock_unlock(&rte_eth_rx_cb_lock);
return cb;
}
@@ -2957,6 +2963,7 @@ rte_eth_add_tx_callback(uint8_t port_id, uint16_t queue_id,
cb->fn.tx = fn;
cb->param = user_param;
+ rte_spinlock_lock(&rte_eth_tx_cb_lock);
/* Add the callbacks in fifo order. */
struct rte_eth_rxtx_callback *tail =
rte_eth_devices[port_id].pre_tx_burst_cbs[queue_id];
@@ -2969,6 +2976,7 @@ rte_eth_add_tx_callback(uint8_t port_id, uint16_t queue_id,
tail = tail->next;
tail->next = cb;
}
+ rte_spinlock_unlock(&rte_eth_tx_cb_lock);
return cb;
}
@@ -2987,29 +2995,24 @@ rte_eth_remove_rx_callback(uint8_t port_id, uint16_t queue_id,
return -EINVAL;
struct rte_eth_dev *dev = &rte_eth_devices[port_id];
- struct rte_eth_rxtx_callback *cb = dev->post_rx_burst_cbs[queue_id];
- struct rte_eth_rxtx_callback *prev_cb;
-
- /* Reset head pointer and remove user cb if first in the list. */
- if (cb == user_cb) {
- dev->post_rx_burst_cbs[queue_id] = user_cb->next;
- return 0;
- }
-
- /* Remove the user cb from the callback list. */
- do {
- prev_cb = cb;
- cb = cb->next;
-
+ struct rte_eth_rxtx_callback *cb;
+ struct rte_eth_rxtx_callback **prev_cb;
+ int ret = -EINVAL;
+
+ rte_spinlock_lock(&rte_eth_rx_cb_lock);
+ prev_cb = &dev->post_rx_burst_cbs[queue_id];
+ for (; *prev_cb != NULL; prev_cb = &cb->next) {
+ cb = *prev_cb;
if (cb == user_cb) {
- prev_cb->next = user_cb->next;
- return 0;
+ /* Remove the user cb from the callback list. */
+ *prev_cb = cb->next;
+ ret = 0;
+ break;
}
+ }
+ rte_spinlock_unlock(&rte_eth_rx_cb_lock);
- } while (cb != NULL);
-
- /* Callback wasn't found. */
- return -EINVAL;
+ return ret;
}
int
@@ -3026,29 +3029,24 @@ rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
return -EINVAL;
struct rte_eth_dev *dev = &rte_eth_devices[port_id];
- struct rte_eth_rxtx_callback *cb = dev->pre_tx_burst_cbs[queue_id];
- struct rte_eth_rxtx_callback *prev_cb;
-
- /* Reset head pointer and remove user cb if first in the list. */
- if (cb == user_cb) {
- dev->pre_tx_burst_cbs[queue_id] = user_cb->next;
- return 0;
- }
-
- /* Remove the user cb from the callback list. */
- do {
- prev_cb = cb;
- cb = cb->next;
-
+ int ret = -EINVAL;
+ struct rte_eth_rxtx_callback *cb;
+ struct rte_eth_rxtx_callback **prev_cb;
+
+ rte_spinlock_lock(&rte_eth_tx_cb_lock);
+ prev_cb = &dev->pre_tx_burst_cbs[queue_id];
+ for (; *prev_cb != NULL; prev_cb = &cb->next) {
+ cb = *prev_cb;
if (cb == user_cb) {
- prev_cb->next = user_cb->next;
- return 0;
+ /* Remove the user cb from the callback list. */
+ *prev_cb = cb->next;
+ ret = 0;
+ break;
}
+ }
+ rte_spinlock_unlock(&rte_eth_tx_cb_lock);
- } while (cb != NULL);
-
- /* Callback wasn't found. */
- return -EINVAL;
+ return ret;
}
int
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v6 2/8] librte_ether: add new api rte_eth_add_first_rx_callback
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 0/8] add packet capture framework Reshma Pattan
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 1/8] librte_ether: protect add/remove of rxtx callbacks with spinlocks Reshma Pattan
@ 2016-06-09 8:50 ` Reshma Pattan
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 3/8] librte_ether: add new fields to rte_eth_dev_info struct Reshma Pattan
` (6 subsequent siblings)
8 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-09 8:50 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Added new public api rte_eth_add_first_rx_callback to add given
callback as head of list.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
lib/librte_ether/rte_ethdev.c | 35 ++++++++++++++++++++++++++++++++++
lib/librte_ether/rte_ethdev.h | 27 ++++++++++++++++++++++++++
lib/librte_ether/rte_ether_version.map | 6 ++++++
3 files changed, 68 insertions(+)
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index ce70d58..f13c70a 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2939,6 +2939,41 @@ rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
}
void *
+rte_eth_add_first_rx_callback(uint8_t port_id, uint16_t queue_id,
+ rte_rx_callback_fn fn, void *user_param)
+{
+#ifndef RTE_ETHDEV_RXTX_CALLBACKS
+ rte_errno = ENOTSUP;
+ return NULL;
+#endif
+ /* check input parameters */
+ if (!rte_eth_dev_is_valid_port(port_id) || fn == NULL ||
+ queue_id >= rte_eth_devices[port_id].data->nb_rx_queues) {
+ rte_errno = EINVAL;
+ return NULL;
+ }
+
+ struct rte_eth_rxtx_callback *cb = rte_zmalloc(NULL, sizeof(*cb), 0);
+
+ if (cb == NULL) {
+ rte_errno = ENOMEM;
+ return NULL;
+ }
+
+ cb->fn.rx = fn;
+ cb->param = user_param;
+
+ rte_spinlock_lock(&rte_eth_rx_cb_lock);
+ /* Add the callbacks at fisrt position*/
+ cb->next = rte_eth_devices[port_id].post_rx_burst_cbs[queue_id];
+ rte_smp_wmb();
+ rte_eth_devices[port_id].post_rx_burst_cbs[queue_id] = cb;
+ rte_spinlock_unlock(&rte_eth_rx_cb_lock);
+
+ return cb;
+}
+
+void *
rte_eth_add_tx_callback(uint8_t port_id, uint16_t queue_id,
rte_tx_callback_fn fn, void *user_param)
{
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 2757510..92b07a9 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -3825,6 +3825,33 @@ int rte_eth_dev_get_dcb_info(uint8_t port_id,
void *rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
rte_rx_callback_fn fn, void *user_param);
+/*
+* Add a callback that must be called first on packet RX on a given port and queue.
+*
+* This API configures a first function to be called for each burst of
+* packets received on a given NIC port queue. The return value is a pointer
+* that can be used to later remove the callback using
+* rte_eth_remove_rx_callback().
+*
+* Multiple functions are called in the order that they are added.
+*
+* @param port_id
+* The port identifier of the Ethernet device.
+* @param queue_id
+* The queue on the Ethernet device on which the callback is to be added.
+* @param fn
+* The callback function
+* @param user_param
+* A generic pointer parameter which will be passed to each invocation of the
+* callback function on this port and queue.
+*
+* @return
+* NULL on error.
+* On success, a pointer value which can later be used to remove the callback.
+*/
+void *rte_eth_add_first_rx_callback(uint8_t port_id, uint16_t queue_id,
+ rte_rx_callback_fn fn, void *user_param);
+
/**
* Add a callback to be called on packet TX on a given port and queue.
*
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index 214ecc7..c990b04 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -132,3 +132,9 @@ DPDK_16.04 {
rte_eth_tx_buffer_set_err_callback;
} DPDK_2.2;
+
+DPDK_16.07 {
+ global:
+
+ rte_eth_add_first_rx_callback;
+} DPDK_16.04;
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v6 3/8] librte_ether: add new fields to rte_eth_dev_info struct
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 0/8] add packet capture framework Reshma Pattan
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 1/8] librte_ether: protect add/remove of rxtx callbacks with spinlocks Reshma Pattan
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 2/8] librte_ether: add new api rte_eth_add_first_rx_callback Reshma Pattan
@ 2016-06-09 8:50 ` Reshma Pattan
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 4/8] librte_ether: make rte_eth_dev_get_port_by_name rte_eth_dev_get_name_by_port public Reshma Pattan
` (5 subsequent siblings)
8 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-09 8:50 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
New fields nb_rx_queues and nb_tx_queues are added to
rte_eth_dev_info structure.
Changes to API rte_eth_dev_info_get() are done to update
these new fields to rte_eth_dev_info object.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
lib/librte_ether/rte_ethdev.c | 2 ++
lib/librte_ether/rte_ethdev.h | 3 +++
lib/librte_ether/rte_ether_version.map | 1 +
3 files changed, 6 insertions(+)
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index f13c70a..4d732e8 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -1661,6 +1661,8 @@ rte_eth_dev_info_get(uint8_t port_id, struct rte_eth_dev_info *dev_info)
(*dev->dev_ops->dev_infos_get)(dev, dev_info);
dev_info->pci_dev = dev->pci_dev;
dev_info->driver_name = dev->data->drv_name;
+ dev_info->nb_rx_queues = dev->data->nb_rx_queues;
+ dev_info->nb_tx_queues = dev->data->nb_tx_queues;
}
int
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 92b07a9..106318f 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -882,6 +882,9 @@ struct rte_eth_dev_info {
struct rte_eth_desc_lim rx_desc_lim; /**< RX descriptors limits */
struct rte_eth_desc_lim tx_desc_lim; /**< TX descriptors limits */
uint32_t speed_capa; /**< Supported speeds bitmap (ETH_LINK_SPEED_). */
+ /** Configured number of rx/tx queues */
+ uint16_t nb_rx_queues; /**< Number of RX queues. */
+ uint16_t nb_tx_queues; /**< Number of TX queues. */
};
/**
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index c990b04..d06d648 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -137,4 +137,5 @@ DPDK_16.07 {
global:
rte_eth_add_first_rx_callback;
+ rte_eth_dev_info_get;
} DPDK_16.04;
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v6 4/8] librte_ether: make rte_eth_dev_get_port_by_name rte_eth_dev_get_name_by_port public
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 0/8] add packet capture framework Reshma Pattan
` (2 preceding siblings ...)
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 3/8] librte_ether: add new fields to rte_eth_dev_info struct Reshma Pattan
@ 2016-06-09 8:50 ` Reshma Pattan
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 5/8] lib/librte_pdump: add new library for packet capturing support Reshma Pattan
` (4 subsequent siblings)
8 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-09 8:50 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Converted rte_eth_dev_get_port_by_name to a public API.
Converted rte_eth_dev_get_name_by_port to a public API.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
lib/librte_ether/rte_ethdev.c | 4 ++--
lib/librte_ether/rte_ethdev.h | 29 +++++++++++++++++++++++++++++
lib/librte_ether/rte_ether_version.map | 2 ++
3 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 4d732e8..d8aac99 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -406,7 +406,7 @@ rte_eth_dev_get_addr_by_port(uint8_t port_id, struct rte_pci_addr *addr)
return 0;
}
-static int
+int
rte_eth_dev_get_name_by_port(uint8_t port_id, char *name)
{
char *tmp;
@@ -425,7 +425,7 @@ rte_eth_dev_get_name_by_port(uint8_t port_id, char *name)
return 0;
}
-static int
+int
rte_eth_dev_get_port_by_name(const char *name, uint8_t *port_id)
{
int i;
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 106318f..6f5a61a 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -4283,6 +4283,35 @@ rte_eth_dev_l2_tunnel_offload_set(uint8_t port_id,
uint32_t mask,
uint8_t en);
+/**
+* Get the port id from pci adrress or device name
+* Ex: 0000:2:00.0 or vdev name eth_pcap0
+*
+* @param name
+* pci address or name of the device
+* @param port_id
+* pointer to port identifier of the device
+* @return
+* - (0) if successful.
+* - (-ENODEV or -EINVAL) on failure.
+*/
+int
+rte_eth_dev_get_port_by_name(const char *name, uint8_t *port_id);
+
+/**
+* Get the device name from port id
+*
+* @param port_id
+* pointer to port identifier of the device
+* @param name
+* pci address or name of the device
+* @return
+* - (0) if successful.
+* - (-EINVAL) on failure.
+*/
+int
+rte_eth_dev_get_name_by_port(uint8_t port_id, char *name);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index d06d648..73e730d 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -137,5 +137,7 @@ DPDK_16.07 {
global:
rte_eth_add_first_rx_callback;
+ rte_eth_dev_get_name_by_port;
+ rte_eth_dev_get_port_by_name;
rte_eth_dev_info_get;
} DPDK_16.04;
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v6 5/8] lib/librte_pdump: add new library for packet capturing support
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 0/8] add packet capture framework Reshma Pattan
` (3 preceding siblings ...)
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 4/8] librte_ether: make rte_eth_dev_get_port_by_name rte_eth_dev_get_name_by_port public Reshma Pattan
@ 2016-06-09 8:50 ` Reshma Pattan
2016-06-09 15:59 ` Aaron Conole
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 6/8] app/pdump: add pdump tool for packet capturing Reshma Pattan
` (3 subsequent siblings)
8 siblings, 1 reply; 82+ messages in thread
From: Reshma Pattan @ 2016-06-09 8:50 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Added new library for packet capturing support.
Added public api rte_pdump_init, applications should call
this as part of their application setup to have packet
capturing framework ready.
Added public api rte_pdump_uninit to uninitialize the packet
capturing framework.
Added public apis rte_pdump_enable and rte_pdump_disable to
enable and disable packet capturing on specific port and queue.
Added public apis rte_pdump_enable_by_deviceid and
rte_pdump_disable_by_deviceid to enable and disable packet
capturing on a specific device (pci address or name) and queue.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
MAINTAINERS | 4 +
config/common_base | 5 +
lib/Makefile | 1 +
lib/librte_pdump/Makefile | 55 +++
lib/librte_pdump/rte_pdump.c | 841 +++++++++++++++++++++++++++++++++
lib/librte_pdump/rte_pdump.h | 186 ++++++++
lib/librte_pdump/rte_pdump_version.map | 12 +
mk/rte.app.mk | 1 +
8 files changed, 1105 insertions(+)
create mode 100644 lib/librte_pdump/Makefile
create mode 100644 lib/librte_pdump/rte_pdump.c
create mode 100644 lib/librte_pdump/rte_pdump.h
create mode 100644 lib/librte_pdump/rte_pdump_version.map
diff --git a/MAINTAINERS b/MAINTAINERS
index 3e8558f..cc3ffdb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -432,6 +432,10 @@ F: app/test/test_reorder*
F: examples/packet_ordering/
F: doc/guides/sample_app_ug/packet_ordering.rst
+Pdump
+M: Reshma Pattan <reshma.pattan@intel.com>
+F: lib/librte_pdump/
+
Hierarchical scheduler
M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
F: lib/librte_sched/
diff --git a/config/common_base b/config/common_base
index 47c26f6..a2d5d72 100644
--- a/config/common_base
+++ b/config/common_base
@@ -484,6 +484,11 @@ CONFIG_RTE_LIBRTE_DISTRIBUTOR=y
CONFIG_RTE_LIBRTE_REORDER=y
#
+# Compile the pdump library
+#
+CONFIG_RTE_LIBRTE_PDUMP=y
+
+#
# Compile librte_port
#
CONFIG_RTE_LIBRTE_PORT=y
diff --git a/lib/Makefile b/lib/Makefile
index f254dba..ca7c02f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -57,6 +57,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
DIRS-$(CONFIG_RTE_LIBRTE_TABLE) += librte_table
DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += librte_pipeline
DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
+DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += librte_pdump
ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
diff --git a/lib/librte_pdump/Makefile b/lib/librte_pdump/Makefile
new file mode 100644
index 0000000..af81a28
--- /dev/null
+++ b/lib/librte_pdump/Makefile
@@ -0,0 +1,55 @@
+# 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_SDK)/mk/rte.vars.mk
+
+# library name
+LIB = librte_pdump.a
+
+CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
+CFLAGS += -D_GNU_SOURCE
+
+EXPORT_MAP := rte_pdump_version.map
+
+LIBABIVER := 1
+
+# all source are stored in SRCS-y
+SRCS-$(CONFIG_RTE_LIBRTE_PDUMP) := rte_pdump.c
+
+# install this header file
+SYMLINK-$(CONFIG_RTE_LIBRTE_PDUMP)-include := rte_pdump.h
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_ether
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pdump/rte_pdump.c b/lib/librte_pdump/rte_pdump.c
new file mode 100644
index 0000000..4aff34a
--- /dev/null
+++ b/lib/librte_pdump/rte_pdump.c
@@ -0,0 +1,841 @@
+/*-
+ * 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 <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <stdbool.h>
+
+#include <rte_memcpy.h>
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_lcore.h>
+#include <rte_log.h>
+#include <rte_errno.h>
+#include <rte_pci.h>
+
+#include "rte_pdump.h"
+
+#define SOCKET_PATH_VAR_RUN "/var/run/pdump_sockets"
+#define SOCKET_PATH_HOME "HOME/pdump_sockets"
+#define SERVER_SOCKET "%s/pdump_server_socket"
+#define CLIENT_SOCKET "%s/pdump_client_socket_%d_%u"
+#define DEVICE_ID_SIZE 64
+/* Macros for printing using RTE_LOG */
+#define RTE_LOGTYPE_PDUMP RTE_LOGTYPE_USER1
+
+enum pdump_operation {
+ DISABLE = 1,
+ ENABLE = 2
+};
+
+enum pdump_socktype {
+ SERVER = 1,
+ CLIENT = 2
+};
+
+enum pdump_version {
+ V1 = 1
+};
+
+static pthread_t pdump_thread;
+static int pdump_socket_fd;
+
+struct pdump_request {
+ uint16_t ver;
+ uint16_t op;
+ uint32_t flags;
+ union pdump_data {
+ struct enable_v1 {
+ char device[DEVICE_ID_SIZE];
+ uint16_t queue;
+ struct rte_ring *ring;
+ struct rte_mempool *mp;
+ void *filter;
+ } en_v1;
+ struct disable_v1 {
+ char device[DEVICE_ID_SIZE];
+ uint16_t queue;
+ struct rte_ring *ring;
+ struct rte_mempool *mp;
+ void *filter;
+ } dis_v1;
+ } data;
+};
+
+struct pdump_response {
+ uint16_t ver;
+ uint16_t res_op;
+ int32_t err_value;
+};
+
+static struct pdump_rxtx_cbs {
+ struct rte_ring *ring;
+ struct rte_mempool *mp;
+ struct rte_eth_rxtx_callback *cb;
+ void *filter;
+} rx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT],
+tx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
+
+static inline int
+pdump_pktmbuf_copy_data(struct rte_mbuf *seg, const struct rte_mbuf *m)
+{
+ if (rte_pktmbuf_tailroom(seg) < m->data_len) {
+ RTE_LOG(ERR, PDUMP, "User mempool: insufficient data_len of mbuf\n");
+ return -EINVAL;
+ }
+
+ seg->port = m->port;
+ seg->vlan_tci = m->vlan_tci;
+ seg->hash = m->hash;
+ seg->tx_offload = m->tx_offload;
+ seg->ol_flags = m->ol_flags;
+ seg->packet_type = m->packet_type;
+ seg->vlan_tci_outer = m->vlan_tci_outer;
+ seg->data_len = m->data_len;
+ seg->pkt_len = seg->data_len;
+ rte_memcpy(rte_pktmbuf_mtod(seg, void *),
+ rte_pktmbuf_mtod(m, void *),
+ rte_pktmbuf_data_len(seg));
+
+ return 0;
+}
+
+static inline struct rte_mbuf *
+pdump_pktmbuf_copy(struct rte_mbuf *m, struct rte_mempool *mp)
+{
+ struct rte_mbuf *m_dup, *seg, **prev;
+ uint32_t pktlen;
+ uint8_t nseg;
+
+ m_dup = rte_pktmbuf_alloc(mp);
+ if (unlikely(m_dup == NULL))
+ return NULL;
+
+ seg = m_dup;
+ prev = &seg->next;
+ pktlen = m->pkt_len;
+ nseg = 0;
+
+ do {
+ nseg++;
+ if (pdump_pktmbuf_copy_data(seg, m) < 0) {
+ rte_pktmbuf_free(m_dup);
+ return NULL;
+ }
+ *prev = seg;
+ prev = &seg->next;
+ } while ((m = m->next) != NULL &&
+ (seg = rte_pktmbuf_alloc(mp)) != NULL);
+
+ *prev = NULL;
+ m_dup->nb_segs = nseg;
+ m_dup->pkt_len = pktlen;
+
+ /* Allocation of new indirect segment failed */
+ if (unlikely(seg == NULL)) {
+ rte_pktmbuf_free(m_dup);
+ return NULL;
+ }
+
+ __rte_mbuf_sanity_check(m_dup, 1);
+ return m_dup;
+}
+
+static inline void
+pdump_copy(struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
+{
+ unsigned i;
+ int ring_enq;
+ uint16_t d_pkts = 0;
+ struct rte_mbuf *dup_bufs[nb_pkts];
+ struct pdump_rxtx_cbs *cbs;
+ struct rte_ring *ring;
+ struct rte_mempool *mp;
+ struct rte_mbuf *p;
+
+ cbs = user_params;
+ ring = cbs->ring;
+ mp = cbs->mp;
+ for (i = 0; i < nb_pkts; i++) {
+ p = pdump_pktmbuf_copy(pkts[i], mp);
+ if (p)
+ dup_bufs[d_pkts++] = p;
+ }
+
+ ring_enq = rte_ring_enqueue_burst(ring, (void *)dup_bufs, d_pkts);
+ if (unlikely(ring_enq < d_pkts)) {
+ RTE_LOG(DEBUG, PDUMP, "only %d of packets enqueued to ring\n", ring_enq);
+ do {
+ rte_pktmbuf_free(dup_bufs[ring_enq]);
+ } while (++ring_enq < d_pkts);
+ }
+}
+
+static uint16_t
+pdump_rx(uint8_t port __rte_unused, uint16_t qidx __rte_unused,
+ struct rte_mbuf **pkts, uint16_t nb_pkts, uint16_t max_pkts __rte_unused,
+ void *user_params)
+{
+ pdump_copy(pkts, nb_pkts, user_params);
+ return nb_pkts;
+}
+
+static uint16_t
+pdump_tx(uint8_t port __rte_unused, uint16_t qidx __rte_unused,
+ struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
+{
+ pdump_copy(pkts, nb_pkts, user_params);
+ return nb_pkts;
+}
+
+static int
+pdump_get_dombdf(char *device_id, char *domBDF, size_t len)
+{
+ int ret;
+ struct rte_pci_addr dev_addr = {0};
+
+ /* identify if device_id is pci address or name */
+ ret = eal_parse_pci_DomBDF(device_id, &dev_addr);
+ if (ret < 0)
+ return -1;
+
+ if (dev_addr.domain)
+ ret = snprintf(domBDF, len, "%u:%u:%u.%u", dev_addr.domain,
+ dev_addr.bus, dev_addr.devid, dev_addr.function);
+ else
+ ret = snprintf(domBDF, len, "%u:%u.%u", dev_addr.bus, dev_addr.devid,
+ dev_addr.function);
+
+ return ret;
+}
+
+static int
+pdump_regitser_rx_callbacks(uint16_t end_q, uint8_t port, uint16_t queue,
+ struct rte_ring *ring, struct rte_mempool *mp,
+ uint16_t operation)
+{
+ uint16_t qid;
+ struct pdump_rxtx_cbs *cbs = NULL;
+
+ qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
+ for (; qid < end_q; qid++) {
+ cbs = &rx_cbs[port][qid];
+ if (cbs && operation == ENABLE) {
+ if (cbs->cb) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to add rx callback for port=%d and "
+ "queue=%d, callback already exists\n",
+ port, qid);
+ return -EEXIST;
+ }
+ cbs->ring = ring;
+ cbs->mp = mp;
+ cbs->cb = rte_eth_add_first_rx_callback(port, qid,
+ pdump_rx, cbs);
+ if (cbs->cb == NULL) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to add rx callback, errno=%d\n",
+ rte_errno);
+ return rte_errno;
+ }
+ }
+ if (cbs && operation == DISABLE) {
+ int ret;
+
+ if (cbs->cb == NULL) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to delete non existing rx callback "
+ "for port=%d and queue=%d\n", port, qid);
+ return -EINVAL;
+ }
+ ret = rte_eth_remove_rx_callback(port, qid, cbs->cb);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to remove rx callback, errno=%d\n",
+ rte_errno);
+ return ret;
+ }
+ cbs->cb = NULL;
+ }
+ }
+
+ return 0;
+}
+
+static int
+pdump_regitser_tx_callbacks(uint16_t end_q, uint8_t port, uint16_t queue,
+ struct rte_ring *ring, struct rte_mempool *mp,
+ uint16_t operation)
+{
+
+ uint16_t qid;
+ struct pdump_rxtx_cbs *cbs = NULL;
+
+ qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
+ for (; qid < end_q; qid++) {
+ cbs = &tx_cbs[port][qid];
+ if (cbs && operation == ENABLE) {
+ if (cbs->cb) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to add tx callback for port=%d and "
+ "queue=%d, callback already exists\n",
+ port, qid);
+ return -EEXIST;
+ }
+ cbs->ring = ring;
+ cbs->mp = mp;
+ cbs->cb = rte_eth_add_tx_callback(port, qid, pdump_tx,
+ cbs);
+ if (cbs->cb == NULL) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to add tx callback, errno=%d\n",
+ rte_errno);
+ return rte_errno;
+ }
+ }
+ if (cbs && operation == DISABLE) {
+ int ret;
+
+ if (cbs->cb == NULL) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to delete non existing tx callback "
+ "for port=%d and queue=%d\n", port, qid);
+ return -EINVAL;
+ }
+ ret = rte_eth_remove_tx_callback(port, qid, cbs->cb);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to remove tx callback, errno=%d\n",
+ rte_errno);
+ return ret;
+ }
+ cbs->cb = NULL;
+ }
+ }
+
+ return 0;
+}
+
+static int
+set_pdump_rxtx_cbs(struct pdump_request *p)
+{
+ uint16_t nb_rx_q, nb_tx_q = 0, end_q, queue;
+ uint8_t port;
+ int ret = 0;
+ uint32_t flags;
+ uint16_t operation;
+ struct rte_ring *ring;
+ struct rte_mempool *mp;
+
+ flags = p->flags;
+ operation = p->op;
+ if (operation == ENABLE) {
+ ret = rte_eth_dev_get_port_by_name(p->data.en_v1.device,
+ &port);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to get potid for device id=%s\n",
+ p->data.en_v1.device);
+ return -EINVAL;
+ }
+ queue = p->data.en_v1.queue;
+ ring = p->data.en_v1.ring;
+ mp = p->data.en_v1.mp;
+ } else {
+ ret = rte_eth_dev_get_port_by_name(p->data.dis_v1.device,
+ &port);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to get potid for device id=%s\n",
+ p->data.dis_v1.device);
+ return -EINVAL;
+ }
+ queue = p->data.dis_v1.queue;
+ ring = p->data.dis_v1.ring;
+ mp = p->data.dis_v1.mp;
+ }
+
+ /* validation if packet capture is for all queues */
+ if (queue == RTE_PDUMP_ALL_QUEUES) {
+ struct rte_eth_dev_info dev_info;
+
+ rte_eth_dev_info_get(port, &dev_info);
+ nb_rx_q = dev_info.nb_rx_queues;
+ nb_tx_q = dev_info.nb_tx_queues;
+ if (nb_rx_q == 0 && flags & RTE_PDUMP_FLAG_RX) {
+ RTE_LOG(ERR, PDUMP, "number of rx queues cannot be 0\n");
+ return -EINVAL;
+ }
+ if (nb_tx_q == 0 && flags & RTE_PDUMP_FLAG_TX) {
+ RTE_LOG(ERR, PDUMP, "number of tx queues cannot be 0\n");
+ return -EINVAL;
+ }
+ if ((nb_tx_q == 0 || nb_rx_q == 0) && flags == RTE_PDUMP_FLAG_RXTX) {
+ RTE_LOG(ERR, PDUMP, "both tx&rx queues must be non zero\n");
+ return -EINVAL;
+ }
+ }
+
+ /* register RX callback */
+ if (flags & RTE_PDUMP_FLAG_RX) {
+ end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_rx_q : queue + 1;
+ ret = pdump_regitser_rx_callbacks(end_q, port, queue, ring, mp,
+ operation);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* register TX callback */
+ if (flags & RTE_PDUMP_FLAG_TX) {
+ end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_tx_q : queue + 1;
+ ret = pdump_regitser_tx_callbacks(end_q, port, queue, ring, mp,
+ operation);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ret;
+}
+
+/* get socket path (/var/run if root, $HOME otherwise) */
+static void
+pdump_get_socket_path(char *buffer, int bufsz, enum pdump_socktype type)
+{
+ const char *dir = SOCKET_PATH_VAR_RUN;
+ const char *home_dir = getenv(SOCKET_PATH_HOME);
+
+ if (getuid() != 0 && home_dir != NULL)
+ dir = home_dir;
+
+ mkdir(dir, 700);
+ if (type == SERVER)
+ snprintf(buffer, bufsz, SERVER_SOCKET, dir);
+ else
+ snprintf(buffer, bufsz, CLIENT_SOCKET, dir, getpid(),
+ rte_sys_gettid());
+}
+
+static int
+pdump_create_server_socket(void)
+{
+ int ret, socket_fd;
+ struct sockaddr_un addr;
+ socklen_t addr_len;
+
+ pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), SERVER);
+ addr.sun_family = AF_UNIX;
+
+ /* remove if file already exists */
+ unlink(addr.sun_path);
+
+ /* set up a server socket */
+ socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (socket_fd < 0) {
+ RTE_LOG(ERR, PDUMP, "Failed to create server socket: %s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ return -1;
+ }
+
+ addr_len = sizeof(struct sockaddr_un);
+ ret = bind(socket_fd, (struct sockaddr *) &addr, addr_len);
+ if (ret) {
+ RTE_LOG(ERR, PDUMP, "Failed to bind to server socket: %s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ close(socket_fd);
+ return -1;
+ }
+
+ /* save the socket in local configuration */
+ pdump_socket_fd = socket_fd;
+
+ return 0;
+}
+
+static __attribute__((noreturn)) void *
+pdump_thread_main(__rte_unused void *arg)
+{
+ struct sockaddr_un cli_addr;
+ socklen_t cli_len;
+ struct pdump_request cli_req;
+ struct pdump_response resp;
+ int n;
+ int ret = 0;
+
+ /* host thread, never break out */
+ for (;;) {
+ /* recv client requests */
+ cli_len = sizeof(cli_addr);
+ n = recvfrom(pdump_socket_fd, &cli_req, sizeof(struct pdump_request), 0,
+ (struct sockaddr *)&cli_addr, &cli_len);
+ if (n < 0) {
+ RTE_LOG(ERR, PDUMP, "failed to recv from client:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ continue;
+ }
+
+ ret = set_pdump_rxtx_cbs(&cli_req);
+
+ resp.ver = cli_req.ver;
+ resp.res_op = cli_req.op;
+ resp.err_value = ret;
+ n = sendto(pdump_socket_fd, &resp, sizeof(struct pdump_response),
+ 0, (struct sockaddr *)&cli_addr, cli_len);
+ if (n < 0) {
+ RTE_LOG(ERR, PDUMP, "failed to send to client:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ }
+ }
+}
+
+int
+rte_pdump_init(void)
+{
+ int ret = 0;
+ char thread_name[RTE_MAX_THREAD_NAME_LEN];
+
+ ret = pdump_create_server_socket();
+ if (ret != 0) {
+ RTE_LOG(ERR, PDUMP, "Failed to create server socket:%s:%d\n",
+ __func__, __LINE__);
+ return -1;
+ }
+
+ /* create the host thread to wait/handle pdump requests */
+ ret = pthread_create(&pdump_thread, NULL, pdump_thread_main, NULL);
+ if (ret != 0) {
+ RTE_LOG(ERR, PDUMP, "Failed to create the pdump thread:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ return -1;
+ }
+ /* Set thread_name for aid in debugging. */
+ snprintf(thread_name, RTE_MAX_THREAD_NAME_LEN, "pdump-thread");
+ ret = rte_thread_setname(pdump_thread, thread_name);
+ if (ret != 0) {
+ RTE_LOG(DEBUG, PDUMP,
+ "Failed to set thread name for pdump handling\n");
+ }
+
+ return 0;
+}
+
+int
+rte_pdump_uninit(void)
+{
+ int ret;
+
+ ret = pthread_cancel(pdump_thread);
+ if (ret != 0) {
+ RTE_LOG(ERR, PDUMP, "Failed to cancel the pdump thread:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ return -1;
+ }
+
+ ret = close(pdump_socket_fd);
+ if (ret != 0) {
+ RTE_LOG(ERR, PDUMP, "Failed to close server socket: %s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ return -1;
+ }
+
+ struct sockaddr_un addr;
+
+ pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), SERVER);
+ ret = unlink(addr.sun_path);
+ if (ret != 0) {
+ RTE_LOG(ERR, PDUMP, "Failed to remove server socket addr: %s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+pdump_create_client_socket(struct pdump_request *p)
+{
+ int ret, socket_fd;
+ int pid;
+ int n;
+ struct pdump_response server_resp;
+ struct sockaddr_un addr, serv_addr, from;
+ socklen_t addr_len, serv_len;
+
+ pid = getpid();
+
+ socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (socket_fd < 0) {
+ RTE_LOG(ERR, PDUMP, "client socket(): %s:pid(%d):tid(%u), %s:%d\n",
+ strerror(errno), pid, rte_sys_gettid(), __func__, __LINE__);
+ ret = errno;
+ return ret;
+ }
+
+ pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), CLIENT);
+ addr.sun_family = AF_UNIX;
+ addr_len = sizeof(struct sockaddr_un);
+
+ do {
+ ret = bind(socket_fd, (struct sockaddr *) &addr, addr_len);
+ if (ret) {
+ RTE_LOG(ERR, PDUMP, "client bind(): %s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ ret = errno;
+ break;
+ }
+
+ serv_len = sizeof(struct sockaddr_un);
+ memset(&serv_addr, 0, sizeof(serv_addr));
+ pdump_get_socket_path(serv_addr.sun_path, sizeof(serv_addr.sun_path),
+ SERVER);
+ serv_addr.sun_family = AF_UNIX;
+
+ n = sendto(socket_fd, p, sizeof(struct pdump_request), 0,
+ (struct sockaddr *)&serv_addr, serv_len);
+ if (n < 0) {
+ RTE_LOG(ERR, PDUMP, "failed to send to server:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ ret = errno;
+ break;
+ }
+
+ n = recvfrom(socket_fd, &server_resp, sizeof(struct pdump_response), 0,
+ (struct sockaddr *)&from, &serv_len);
+ if (n < 0) {
+ RTE_LOG(ERR, PDUMP, "failed to recv from server:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ ret = errno;
+ break;
+ }
+ ret = server_resp.err_value;
+ } while (0);
+
+ close(socket_fd);
+ unlink(addr.sun_path);
+ return ret;
+}
+
+static int
+pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp)
+{
+ if (ring == NULL || mp == NULL) {
+ RTE_LOG(ERR, PDUMP, "NULL ring or mempool are passed %s:%d\n",
+ __func__, __LINE__);
+ rte_errno = EINVAL;
+ return -1;
+ }
+ if (mp->flags & MEMPOOL_F_SP_PUT || mp->flags & MEMPOOL_F_SC_GET) {
+ RTE_LOG(ERR, PDUMP, "mempool with either SP or SC settings"
+ " is not valid for pdump, should have MP and MC settings\n");
+ rte_errno = EINVAL;
+ return -1;
+ }
+ if (ring->prod.sp_enqueue || ring->cons.sc_dequeue) {
+ RTE_LOG(ERR, PDUMP, "ring with either SP or SC settings"
+ " is not valid for pdump, should have MP and MC settings\n");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+pdump_validate_flags(uint32_t flags)
+{
+ if (flags != RTE_PDUMP_FLAG_RX && flags != RTE_PDUMP_FLAG_TX &&
+ flags != RTE_PDUMP_FLAG_RXTX) {
+ RTE_LOG(ERR, PDUMP, "invalid flags, should be either rx/tx/rxtx\n");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+pdump_validate_port(uint8_t port, char *name)
+{
+ int ret = 0;
+
+ if (port >= RTE_MAX_ETHPORTS) {
+ RTE_LOG(ERR, PDUMP, "Invalid port id %u, %s:%d\n", port,
+ __func__, __LINE__);
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ ret = rte_eth_dev_get_name_by_port(port, name);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "port id to name mapping failed for port id=%u, %s:%d\n",
+ port, __func__, __LINE__);
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+pdump_prepare_client_request(char *device, uint16_t queue,
+ uint32_t flags,
+ uint16_t operation,
+ struct rte_ring *ring,
+ struct rte_mempool *mp,
+ void *filter)
+{
+ int ret;
+ struct pdump_request req = {.ver = 1,};
+
+ req.flags = flags;
+ req.op = operation;
+ if ((operation & ENABLE) != 0) {
+ strncpy(req.data.en_v1.device, device, strlen(device));
+ req.data.en_v1.queue = queue;
+ req.data.en_v1.ring = ring;
+ req.data.en_v1.mp = mp;
+ req.data.en_v1.filter = filter;
+ } else {
+ strncpy(req.data.dis_v1.device, device, strlen(device));
+ req.data.dis_v1.queue = queue;
+ req.data.dis_v1.ring = NULL;
+ req.data.dis_v1.mp = NULL;
+ req.data.dis_v1.filter = NULL;
+ }
+
+ ret = pdump_create_client_socket(&req);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP, "client request for pdump enable/disable failed\n");
+ rte_errno = ret;
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+rte_pdump_enable(uint8_t port, uint16_t queue, uint32_t flags,
+ struct rte_ring *ring,
+ struct rte_mempool *mp,
+ void *filter)
+{
+
+ int ret = 0;
+ char name[DEVICE_ID_SIZE];
+
+ ret = pdump_validate_port(port, name);
+ if (ret < 0)
+ return ret;
+ ret = pdump_validate_ring_mp(ring, mp);
+ if (ret < 0)
+ return ret;
+ ret = pdump_validate_flags(flags);
+ if (ret < 0)
+ return ret;
+
+ ret = pdump_prepare_client_request(name, queue, flags,
+ ENABLE, ring, mp, filter);
+
+ return ret;
+}
+
+int
+rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
+ uint32_t flags,
+ struct rte_ring *ring,
+ struct rte_mempool *mp,
+ void *filter)
+{
+ int ret = 0;
+ char domBDF[DEVICE_ID_SIZE];
+
+ ret = pdump_validate_ring_mp(ring, mp);
+ if (ret < 0)
+ return ret;
+ ret = pdump_validate_flags(flags);
+ if (ret < 0)
+ return ret;
+
+ if (pdump_get_dombdf(device_id, domBDF, sizeof(domBDF)) > 0)
+ ret = pdump_prepare_client_request(domBDF, queue, flags,
+ ENABLE, ring, mp, filter);
+ else
+ ret = pdump_prepare_client_request(device_id, queue, flags,
+ ENABLE, ring, mp, filter);
+
+ return ret;
+}
+
+int
+rte_pdump_disable(uint8_t port, uint16_t queue, uint32_t flags)
+{
+ int ret = 0;
+ char name[DEVICE_ID_SIZE];
+
+ ret = pdump_validate_port(port, name);
+ if (ret < 0)
+ return ret;
+ ret = pdump_validate_flags(flags);
+ if (ret < 0)
+ return ret;
+
+ ret = pdump_prepare_client_request(name, queue, flags,
+ DISABLE, NULL, NULL, NULL);
+
+ return ret;
+}
+
+int
+rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
+ uint32_t flags)
+{
+ int ret = 0;
+ char domBDF[DEVICE_ID_SIZE];
+
+ ret = pdump_validate_flags(flags);
+ if (ret < 0)
+ return ret;
+
+ if (pdump_get_dombdf(device_id, domBDF, sizeof(domBDF)) > 0)
+ ret = pdump_prepare_client_request(domBDF, queue, flags,
+ DISABLE, NULL, NULL, NULL);
+ else
+ ret = pdump_prepare_client_request(device_id, queue, flags,
+ DISABLE, NULL, NULL, NULL);
+
+ return ret;
+}
diff --git a/lib/librte_pdump/rte_pdump.h b/lib/librte_pdump/rte_pdump.h
new file mode 100644
index 0000000..ca9333a
--- /dev/null
+++ b/lib/librte_pdump/rte_pdump.h
@@ -0,0 +1,186 @@
+/*-
+ * 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.
+ */
+
+#ifndef _RTE_PDUMP_H_
+#define _RTE_PDUMP_H_
+
+/**
+ * @file
+ * RTE pdump
+ *
+ * packet dump library to provide packet capturing support on dpdk.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RTE_PDUMP_ALL_QUEUES UINT16_MAX
+
+enum {
+ RTE_PDUMP_FLAG_RX = 1, /* receive direction */
+ RTE_PDUMP_FLAG_TX = 2, /* transmit direction */
+ /* both receive and transmit directions */
+ RTE_PDUMP_FLAG_RXTX = (RTE_PDUMP_FLAG_RX|RTE_PDUMP_FLAG_TX)
+};
+
+/**
+ * Initialize packet capturing handling
+ *
+ * Creates pthread and server socket for handling clients
+ * requests to enable/disable rxtx callbacks.
+ *
+ * @return
+ * 0 on success, -1 on error
+ */
+int
+rte_pdump_init(void);
+
+/**
+ * Un initialize packet capturing handling
+ *
+ * Cancels pthread, close server socket, removes server socket address.
+ *
+ * @return
+ * 0 on success, -1 on error
+ */
+int
+rte_pdump_uninit(void);
+
+/**
+ * Enables packet capturing on given port and queue.
+ *
+ * @param port
+ * port on which packet capturing should be enabled.
+ * @param queue
+ * queue of a given port on which packet capturing should be enabled.
+ * users should pass on value UINT16_MAX to enable packet capturing on all
+ * queues of a given port.
+ * @param flags
+ * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
+ * on which packet capturing should be enabled for a given port and queue.
+ * @param ring
+ * ring on which captured packets will be enqueued for user.
+ * @param mp
+ * mempool on to which original packets will be mirrored or duplicated.
+ * @param filter
+ * place holder for packet filtering.
+ *
+ * @return
+ * 0 on success, -1 on error, rte_errno is set accordingly.
+ */
+
+int
+rte_pdump_enable(uint8_t port, uint16_t queue, uint32_t flags,
+ struct rte_ring *ring,
+ struct rte_mempool *mp,
+ void *filter);
+
+/**
+ * Disables packet capturing on given port and queue.
+ *
+ * @param port
+ * port on which packet capturing should be disabled.
+ * @param queue
+ * queue of a given port on which packet capturing should be disabled.
+ * users should pass on value UINT16_MAX to disable packet capturing on all
+ * queues of a given port.
+ * @param flags
+ * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
+ * on which packet capturing should be enabled for a given port and queue.
+ *
+ * @return
+ * 0 on success, -1 on error, rte_errno is set accordingly.
+ */
+
+int
+rte_pdump_disable(uint8_t port, uint16_t queue, uint32_t flags);
+
+/**
+ * Enables packet capturing on given device id and queue.
+ * device_id can be name or pci address of device.
+ *
+ * @param device_id
+ * device id on which packet capturing should be enabled.
+ * @param queue
+ * queue of a given device id on which packet capturing should be enabled.
+ * users should pass on value UINT16_MAX to enable packet capturing on all
+ * queues of a given device id.
+ * @param flags
+ * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
+ * on which packet capturing should be enabled for a given port and queue.
+ * @param ring
+ * ring on which captured packets will be enqueued for user.
+ * @param mp
+ * mempool on to which original packets will be mirrored or duplicated.
+ * @param filter
+ * place holder for packet filtering.
+ *
+ * @return
+ * 0 on success, -1 on error, rte_errno is set accordingly.
+ */
+
+int
+rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
+ uint32_t flags,
+ struct rte_ring *ring,
+ struct rte_mempool *mp,
+ void *filter);
+
+/**
+ * Disables packet capturing on given device_id and queue.
+ * device_id can be name or pci address of device.
+ *
+ * @param device_id
+ * pci address or name of the device on which packet capturing
+ * should be disabled.
+ * @param queue
+ * queue of a given device on which packet capturing should be disabled.
+ * users should pass on value UINT16_MAX to disable packet capturing on all
+ * queues of a given device id.
+ * @param flags
+ * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
+ * on which packet capturing should be enabled for a given port and queue.
+ *
+ * @return
+ * 0 on success, -1 on error, rte_errno is set accordingly.
+ */
+int
+rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
+ uint32_t flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_PDUMP_H_ */
diff --git a/lib/librte_pdump/rte_pdump_version.map b/lib/librte_pdump/rte_pdump_version.map
new file mode 100644
index 0000000..3e744f3
--- /dev/null
+++ b/lib/librte_pdump/rte_pdump_version.map
@@ -0,0 +1,12 @@
+DPDK_16.07 {
+ global:
+
+ rte_pdump_disable;
+ rte_pdump_disable_by_deviceid;
+ rte_pdump_enable;
+ rte_pdump_enable_by_deviceid;
+ rte_pdump_init;
+ rte_pdump_uninit;
+
+ local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index b84b56d..f792f2a 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -61,6 +61,7 @@ _LDLIBS-y += --whole-archive
_LDLIBS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += -lrte_distributor
_LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER) += -lrte_reorder
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PDUMP) += -lrte_pdump
ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
_LDLIBS-$(CONFIG_RTE_LIBRTE_KNI) += -lrte_kni
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v6 5/8] lib/librte_pdump: add new library for packet capturing support
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 5/8] lib/librte_pdump: add new library for packet capturing support Reshma Pattan
@ 2016-06-09 15:59 ` Aaron Conole
2016-06-09 16:05 ` Ananyev, Konstantin
2016-06-10 16:22 ` Pattan, Reshma
0 siblings, 2 replies; 82+ messages in thread
From: Aaron Conole @ 2016-06-09 15:59 UTC (permalink / raw)
To: Reshma Pattan; +Cc: dev
Reshma Pattan <reshma.pattan@intel.com> writes:
> Added new library for packet capturing support.
>
> Added public api rte_pdump_init, applications should call
> this as part of their application setup to have packet
> capturing framework ready.
>
> Added public api rte_pdump_uninit to uninitialize the packet
> capturing framework.
>
> Added public apis rte_pdump_enable and rte_pdump_disable to
> enable and disable packet capturing on specific port and queue.
>
> Added public apis rte_pdump_enable_by_deviceid and
> rte_pdump_disable_by_deviceid to enable and disable packet
> capturing on a specific device (pci address or name) and queue.
>
> Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
> ---
> MAINTAINERS | 4 +
> config/common_base | 5 +
> lib/Makefile | 1 +
> lib/librte_pdump/Makefile | 55 +++
> lib/librte_pdump/rte_pdump.c | 841 +++++++++++++++++++++++++++++++++
> lib/librte_pdump/rte_pdump.h | 186 ++++++++
> lib/librte_pdump/rte_pdump_version.map | 12 +
> mk/rte.app.mk | 1 +
> 8 files changed, 1105 insertions(+)
> create mode 100644 lib/librte_pdump/Makefile
> create mode 100644 lib/librte_pdump/rte_pdump.c
> create mode 100644 lib/librte_pdump/rte_pdump.h
> create mode 100644 lib/librte_pdump/rte_pdump_version.map
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 3e8558f..cc3ffdb 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -432,6 +432,10 @@ F: app/test/test_reorder*
> F: examples/packet_ordering/
> F: doc/guides/sample_app_ug/packet_ordering.rst
>
> +Pdump
> +M: Reshma Pattan <reshma.pattan@intel.com>
> +F: lib/librte_pdump/
> +
> Hierarchical scheduler
> M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
> F: lib/librte_sched/
> diff --git a/config/common_base b/config/common_base
> index 47c26f6..a2d5d72 100644
> --- a/config/common_base
> +++ b/config/common_base
> @@ -484,6 +484,11 @@ CONFIG_RTE_LIBRTE_DISTRIBUTOR=y
> CONFIG_RTE_LIBRTE_REORDER=y
>
> #
> +# Compile the pdump library
> +#
> +CONFIG_RTE_LIBRTE_PDUMP=y
> +
> +#
> # Compile librte_port
> #
> CONFIG_RTE_LIBRTE_PORT=y
> diff --git a/lib/Makefile b/lib/Makefile
> index f254dba..ca7c02f 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -57,6 +57,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
> DIRS-$(CONFIG_RTE_LIBRTE_TABLE) += librte_table
> DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += librte_pipeline
> DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
> +DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += librte_pdump
>
> ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
> DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
> diff --git a/lib/librte_pdump/Makefile b/lib/librte_pdump/Makefile
> new file mode 100644
> index 0000000..af81a28
> --- /dev/null
> +++ b/lib/librte_pdump/Makefile
> @@ -0,0 +1,55 @@
> +# 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_SDK)/mk/rte.vars.mk
> +
> +# library name
> +LIB = librte_pdump.a
> +
> +CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
> +CFLAGS += -D_GNU_SOURCE
> +
> +EXPORT_MAP := rte_pdump_version.map
> +
> +LIBABIVER := 1
> +
> +# all source are stored in SRCS-y
> +SRCS-$(CONFIG_RTE_LIBRTE_PDUMP) := rte_pdump.c
> +
> +# install this header file
> +SYMLINK-$(CONFIG_RTE_LIBRTE_PDUMP)-include := rte_pdump.h
> +
> +# this lib depends upon:
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_mbuf
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_eal
> +DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_ether
> +
> +include $(RTE_SDK)/mk/rte.lib.mk
> diff --git a/lib/librte_pdump/rte_pdump.c b/lib/librte_pdump/rte_pdump.c
> new file mode 100644
> index 0000000..4aff34a
> --- /dev/null
> +++ b/lib/librte_pdump/rte_pdump.c
> @@ -0,0 +1,841 @@
> +/*-
> + * 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 <sys/socket.h>
> +#include <sys/un.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include <pthread.h>
> +#include <stdbool.h>
> +
> +#include <rte_memcpy.h>
> +#include <rte_mbuf.h>
> +#include <rte_ethdev.h>
> +#include <rte_lcore.h>
> +#include <rte_log.h>
> +#include <rte_errno.h>
> +#include <rte_pci.h>
> +
> +#include "rte_pdump.h"
> +
> +#define SOCKET_PATH_VAR_RUN "/var/run/pdump_sockets"
> +#define SOCKET_PATH_HOME "HOME/pdump_sockets"
> +#define SERVER_SOCKET "%s/pdump_server_socket"
> +#define CLIENT_SOCKET "%s/pdump_client_socket_%d_%u"
> +#define DEVICE_ID_SIZE 64
> +/* Macros for printing using RTE_LOG */
> +#define RTE_LOGTYPE_PDUMP RTE_LOGTYPE_USER1
> +
> +enum pdump_operation {
> + DISABLE = 1,
> + ENABLE = 2
> +};
> +
> +enum pdump_socktype {
> + SERVER = 1,
> + CLIENT = 2
> +};
> +
> +enum pdump_version {
> + V1 = 1
> +};
> +
> +static pthread_t pdump_thread;
> +static int pdump_socket_fd;
> +
> +struct pdump_request {
> + uint16_t ver;
> + uint16_t op;
> + uint32_t flags;
> + union pdump_data {
> + struct enable_v1 {
> + char device[DEVICE_ID_SIZE];
> + uint16_t queue;
> + struct rte_ring *ring;
> + struct rte_mempool *mp;
> + void *filter;
> + } en_v1;
> + struct disable_v1 {
> + char device[DEVICE_ID_SIZE];
> + uint16_t queue;
> + struct rte_ring *ring;
> + struct rte_mempool *mp;
> + void *filter;
> + } dis_v1;
> + } data;
> +};
> +
> +struct pdump_response {
> + uint16_t ver;
> + uint16_t res_op;
> + int32_t err_value;
> +};
> +
> +static struct pdump_rxtx_cbs {
> + struct rte_ring *ring;
> + struct rte_mempool *mp;
> + struct rte_eth_rxtx_callback *cb;
> + void *filter;
> +} rx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT],
> +tx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
> +
> +static inline int
> +pdump_pktmbuf_copy_data(struct rte_mbuf *seg, const struct rte_mbuf *m)
> +{
> + if (rte_pktmbuf_tailroom(seg) < m->data_len) {
> + RTE_LOG(ERR, PDUMP, "User mempool: insufficient data_len of
> mbuf\n");
> + return -EINVAL;
> + }
> +
> + seg->port = m->port;
> + seg->vlan_tci = m->vlan_tci;
> + seg->hash = m->hash;
> + seg->tx_offload = m->tx_offload;
> + seg->ol_flags = m->ol_flags;
> + seg->packet_type = m->packet_type;
> + seg->vlan_tci_outer = m->vlan_tci_outer;
> + seg->data_len = m->data_len;
> + seg->pkt_len = seg->data_len;
> + rte_memcpy(rte_pktmbuf_mtod(seg, void *),
> + rte_pktmbuf_mtod(m, void *),
> + rte_pktmbuf_data_len(seg));
> +
> + return 0;
> +}
> +
> +static inline struct rte_mbuf *
> +pdump_pktmbuf_copy(struct rte_mbuf *m, struct rte_mempool *mp)
> +{
> + struct rte_mbuf *m_dup, *seg, **prev;
> + uint32_t pktlen;
> + uint8_t nseg;
> +
> + m_dup = rte_pktmbuf_alloc(mp);
> + if (unlikely(m_dup == NULL))
> + return NULL;
> +
> + seg = m_dup;
> + prev = &seg->next;
> + pktlen = m->pkt_len;
> + nseg = 0;
> +
> + do {
> + nseg++;
> + if (pdump_pktmbuf_copy_data(seg, m) < 0) {
> + rte_pktmbuf_free(m_dup);
> + return NULL;
> + }
> + *prev = seg;
> + prev = &seg->next;
> + } while ((m = m->next) != NULL &&
> + (seg = rte_pktmbuf_alloc(mp)) != NULL);
> +
> + *prev = NULL;
> + m_dup->nb_segs = nseg;
> + m_dup->pkt_len = pktlen;
> +
> + /* Allocation of new indirect segment failed */
> + if (unlikely(seg == NULL)) {
> + rte_pktmbuf_free(m_dup);
> + return NULL;
> + }
> +
> + __rte_mbuf_sanity_check(m_dup, 1);
> + return m_dup;
> +}
> +
> +static inline void
> +pdump_copy(struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
> +{
> + unsigned i;
> + int ring_enq;
> + uint16_t d_pkts = 0;
> + struct rte_mbuf *dup_bufs[nb_pkts];
> + struct pdump_rxtx_cbs *cbs;
> + struct rte_ring *ring;
> + struct rte_mempool *mp;
> + struct rte_mbuf *p;
> +
> + cbs = user_params;
> + ring = cbs->ring;
> + mp = cbs->mp;
> + for (i = 0; i < nb_pkts; i++) {
> + p = pdump_pktmbuf_copy(pkts[i], mp);
> + if (p)
> + dup_bufs[d_pkts++] = p;
> + }
> +
> + ring_enq = rte_ring_enqueue_burst(ring, (void *)dup_bufs, d_pkts);
> + if (unlikely(ring_enq < d_pkts)) {
> + RTE_LOG(DEBUG, PDUMP, "only %d of packets enqueued to ring\n",
> ring_enq);
> + do {
> + rte_pktmbuf_free(dup_bufs[ring_enq]);
> + } while (++ring_enq < d_pkts);
> + }
> +}
> +
> +static uint16_t
> +pdump_rx(uint8_t port __rte_unused, uint16_t qidx __rte_unused,
> + struct rte_mbuf **pkts, uint16_t nb_pkts, uint16_t max_pkts __rte_unused,
> + void *user_params)
> +{
> + pdump_copy(pkts, nb_pkts, user_params);
> + return nb_pkts;
> +}
> +
> +static uint16_t
> +pdump_tx(uint8_t port __rte_unused, uint16_t qidx __rte_unused,
> + struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
> +{
> + pdump_copy(pkts, nb_pkts, user_params);
> + return nb_pkts;
> +}
> +
> +static int
> +pdump_get_dombdf(char *device_id, char *domBDF, size_t len)
> +{
> + int ret;
> + struct rte_pci_addr dev_addr = {0};
> +
> + /* identify if device_id is pci address or name */
> + ret = eal_parse_pci_DomBDF(device_id, &dev_addr);
> + if (ret < 0)
> + return -1;
> +
> + if (dev_addr.domain)
> + ret = snprintf(domBDF, len, "%u:%u:%u.%u", dev_addr.domain,
> + dev_addr.bus, dev_addr.devid, dev_addr.function);
> + else
> + ret = snprintf(domBDF, len, "%u:%u.%u", dev_addr.bus,
> dev_addr.devid,
> + dev_addr.function);
> +
> + return ret;
> +}
> +
> +static int
> +pdump_regitser_rx_callbacks(uint16_t end_q, uint8_t port, uint16_t queue,
> + struct rte_ring *ring, struct rte_mempool *mp,
> + uint16_t operation)
> +{
> + uint16_t qid;
> + struct pdump_rxtx_cbs *cbs = NULL;
> +
> + qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
> + for (; qid < end_q; qid++) {
> + cbs = &rx_cbs[port][qid];
> + if (cbs && operation == ENABLE) {
> + if (cbs->cb) {
> + RTE_LOG(ERR, PDUMP,
> + "failed to add rx callback for port=%d and "
> + "queue=%d, callback already exists\n",
> + port, qid);
> + return -EEXIST;
> + }
> + cbs->ring = ring;
> + cbs->mp = mp;
> + cbs->cb = rte_eth_add_first_rx_callback(port, qid,
> + pdump_rx, cbs);
> + if (cbs->cb == NULL) {
> + RTE_LOG(ERR, PDUMP,
> + "failed to add rx callback, errno=%d\n",
> + rte_errno);
> + return rte_errno;
> + }
> + }
> + if (cbs && operation == DISABLE) {
> + int ret;
> +
> + if (cbs->cb == NULL) {
> + RTE_LOG(ERR, PDUMP,
> + "failed to delete non existing rx callback "
> + "for port=%d and queue=%d\n", port, qid);
> + return -EINVAL;
> + }
> + ret = rte_eth_remove_rx_callback(port, qid, cbs->cb);
> + if (ret < 0) {
> + RTE_LOG(ERR, PDUMP,
> + "failed to remove rx callback, errno=%d\n",
> + rte_errno);
> + return ret;
> + }
> + cbs->cb = NULL;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int
> +pdump_regitser_tx_callbacks(uint16_t end_q, uint8_t port, uint16_t queue,
> + struct rte_ring *ring, struct rte_mempool *mp,
> + uint16_t operation)
> +{
> +
> + uint16_t qid;
> + struct pdump_rxtx_cbs *cbs = NULL;
> +
> + qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
> + for (; qid < end_q; qid++) {
> + cbs = &tx_cbs[port][qid];
> + if (cbs && operation == ENABLE) {
> + if (cbs->cb) {
> + RTE_LOG(ERR, PDUMP,
> + "failed to add tx callback for port=%d and "
> + "queue=%d, callback already exists\n",
> + port, qid);
> + return -EEXIST;
> + }
> + cbs->ring = ring;
> + cbs->mp = mp;
> + cbs->cb = rte_eth_add_tx_callback(port, qid, pdump_tx,
> + cbs);
> + if (cbs->cb == NULL) {
> + RTE_LOG(ERR, PDUMP,
> + "failed to add tx callback, errno=%d\n",
> + rte_errno);
> + return rte_errno;
> + }
> + }
> + if (cbs && operation == DISABLE) {
> + int ret;
> +
> + if (cbs->cb == NULL) {
> + RTE_LOG(ERR, PDUMP,
> + "failed to delete non existing tx callback "
> + "for port=%d and queue=%d\n", port, qid);
> + return -EINVAL;
> + }
> + ret = rte_eth_remove_tx_callback(port, qid, cbs->cb);
> + if (ret < 0) {
> + RTE_LOG(ERR, PDUMP,
> + "failed to remove tx callback, errno=%d\n",
> + rte_errno);
> + return ret;
> + }
> + cbs->cb = NULL;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int
> +set_pdump_rxtx_cbs(struct pdump_request *p)
> +{
> + uint16_t nb_rx_q, nb_tx_q = 0, end_q, queue;
> + uint8_t port;
> + int ret = 0;
> + uint32_t flags;
> + uint16_t operation;
> + struct rte_ring *ring;
> + struct rte_mempool *mp;
> +
> + flags = p->flags;
> + operation = p->op;
> + if (operation == ENABLE) {
> + ret = rte_eth_dev_get_port_by_name(p->data.en_v1.device,
> + &port);
> + if (ret < 0) {
> + RTE_LOG(ERR, PDUMP,
> + "failed to get potid for device id=%s\n",
> + p->data.en_v1.device);
> + return -EINVAL;
> + }
> + queue = p->data.en_v1.queue;
> + ring = p->data.en_v1.ring;
> + mp = p->data.en_v1.mp;
> + } else {
> + ret = rte_eth_dev_get_port_by_name(p->data.dis_v1.device,
> + &port);
> + if (ret < 0) {
> + RTE_LOG(ERR, PDUMP,
> + "failed to get potid for device id=%s\n",
> + p->data.dis_v1.device);
> + return -EINVAL;
> + }
> + queue = p->data.dis_v1.queue;
> + ring = p->data.dis_v1.ring;
> + mp = p->data.dis_v1.mp;
> + }
> +
> + /* validation if packet capture is for all queues */
> + if (queue == RTE_PDUMP_ALL_QUEUES) {
> + struct rte_eth_dev_info dev_info;
> +
> + rte_eth_dev_info_get(port, &dev_info);
> + nb_rx_q = dev_info.nb_rx_queues;
> + nb_tx_q = dev_info.nb_tx_queues;
> + if (nb_rx_q == 0 && flags & RTE_PDUMP_FLAG_RX) {
> + RTE_LOG(ERR, PDUMP, "number of rx queues cannot be 0\n");
> + return -EINVAL;
> + }
> + if (nb_tx_q == 0 && flags & RTE_PDUMP_FLAG_TX) {
> + RTE_LOG(ERR, PDUMP, "number of tx queues cannot be 0\n");
> + return -EINVAL;
> + }
> + if ((nb_tx_q == 0 || nb_rx_q == 0) && flags == RTE_PDUMP_FLAG_RXTX)
> {
> + RTE_LOG(ERR, PDUMP, "both tx&rx queues must be non zero\n");
> + return -EINVAL;
> + }
> + }
> +
> + /* register RX callback */
> + if (flags & RTE_PDUMP_FLAG_RX) {
> + end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_rx_q : queue + 1;
> + ret = pdump_regitser_rx_callbacks(end_q, port, queue, ring, mp,
> + operation);
> + if (ret < 0)
> + return ret;
> + }
> +
> + /* register TX callback */
> + if (flags & RTE_PDUMP_FLAG_TX) {
> + end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_tx_q : queue + 1;
> + ret = pdump_regitser_tx_callbacks(end_q, port, queue, ring, mp,
> + operation);
> + if (ret < 0)
> + return ret;
> + }
> +
> + return ret;
> +}
> +
> +/* get socket path (/var/run if root, $HOME otherwise) */
> +static void
> +pdump_get_socket_path(char *buffer, int bufsz, enum pdump_socktype type)
> +{
> + const char *dir = SOCKET_PATH_VAR_RUN;
> + const char *home_dir = getenv(SOCKET_PATH_HOME);
> +
> + if (getuid() != 0 && home_dir != NULL)
> + dir = home_dir;
> +
> + mkdir(dir, 700);
> + if (type == SERVER)
> + snprintf(buffer, bufsz, SERVER_SOCKET, dir);
> + else
> + snprintf(buffer, bufsz, CLIENT_SOCKET, dir, getpid(),
> + rte_sys_gettid());
> +}
> +
> +static int
> +pdump_create_server_socket(void)
> +{
> + int ret, socket_fd;
> + struct sockaddr_un addr;
> + socklen_t addr_len;
> +
> + pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), SERVER);
> + addr.sun_family = AF_UNIX;
> +
> + /* remove if file already exists */
> + unlink(addr.sun_path);
> +
> + /* set up a server socket */
> + socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
> + if (socket_fd < 0) {
> + RTE_LOG(ERR, PDUMP, "Failed to create server socket: %s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + return -1;
> + }
> +
> + addr_len = sizeof(struct sockaddr_un);
> + ret = bind(socket_fd, (struct sockaddr *) &addr, addr_len);
> + if (ret) {
> + RTE_LOG(ERR, PDUMP, "Failed to bind to server socket: %s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + close(socket_fd);
> + return -1;
> + }
> +
> + /* save the socket in local configuration */
> + pdump_socket_fd = socket_fd;
> +
> + return 0;
> +}
> +
> +static __attribute__((noreturn)) void *
> +pdump_thread_main(__rte_unused void *arg)
> +{
> + struct sockaddr_un cli_addr;
> + socklen_t cli_len;
> + struct pdump_request cli_req;
> + struct pdump_response resp;
> + int n;
> + int ret = 0;
> +
> + /* host thread, never break out */
> + for (;;) {
> + /* recv client requests */
> + cli_len = sizeof(cli_addr);
> + n = recvfrom(pdump_socket_fd, &cli_req, sizeof(struct
> pdump_request), 0,
> + (struct sockaddr *)&cli_addr, &cli_len);
> + if (n < 0) {
> + RTE_LOG(ERR, PDUMP, "failed to recv from client:%s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + continue;
> + }
> +
> + ret = set_pdump_rxtx_cbs(&cli_req);
> +
> + resp.ver = cli_req.ver;
> + resp.res_op = cli_req.op;
> + resp.err_value = ret;
> + n = sendto(pdump_socket_fd, &resp, sizeof(struct pdump_response),
> + 0, (struct sockaddr *)&cli_addr, cli_len);
> + if (n < 0) {
> + RTE_LOG(ERR, PDUMP, "failed to send to client:%s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + }
> + }
> +}
> +
> +int
> +rte_pdump_init(void)
Would you be opposed to having an argument here which takes a path to
the server socket? That way the application can have some control over
the server socket location rather than using the guesses from
pdump_get_socket_path.
> +{
> + int ret = 0;
> + char thread_name[RTE_MAX_THREAD_NAME_LEN];
> +
> + ret = pdump_create_server_socket();
> + if (ret != 0) {
> + RTE_LOG(ERR, PDUMP, "Failed to create server socket:%s:%d\n",
> + __func__, __LINE__);
> + return -1;
> + }
> +
> + /* create the host thread to wait/handle pdump requests */
> + ret = pthread_create(&pdump_thread, NULL, pdump_thread_main, NULL);
> + if (ret != 0) {
> + RTE_LOG(ERR, PDUMP, "Failed to create the pdump thread:%s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + return -1;
> + }
> + /* Set thread_name for aid in debugging. */
> + snprintf(thread_name, RTE_MAX_THREAD_NAME_LEN, "pdump-thread");
> + ret = rte_thread_setname(pdump_thread, thread_name);
> + if (ret != 0) {
> + RTE_LOG(DEBUG, PDUMP,
> + "Failed to set thread name for pdump handling\n");
> + }
> +
> + return 0;
> +}
> +
> +int
> +rte_pdump_uninit(void)
> +{
> + int ret;
> +
> + ret = pthread_cancel(pdump_thread);
> + if (ret != 0) {
> + RTE_LOG(ERR, PDUMP, "Failed to cancel the pdump thread:%s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + return -1;
> + }
> +
> + ret = close(pdump_socket_fd);
> + if (ret != 0) {
> + RTE_LOG(ERR, PDUMP, "Failed to close server socket: %s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + return -1;
> + }
> +
> + struct sockaddr_un addr;
> +
> + pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), SERVER);
> + ret = unlink(addr.sun_path);
> + if (ret != 0) {
> + RTE_LOG(ERR, PDUMP, "Failed to remove server socket addr: %s,
> %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +pdump_create_client_socket(struct pdump_request *p)
> +{
> + int ret, socket_fd;
> + int pid;
> + int n;
> + struct pdump_response server_resp;
> + struct sockaddr_un addr, serv_addr, from;
> + socklen_t addr_len, serv_len;
> +
> + pid = getpid();
> +
> + socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
> + if (socket_fd < 0) {
> + RTE_LOG(ERR, PDUMP, "client socket(): %s:pid(%d):tid(%u), %s:%d\n",
> + strerror(errno), pid, rte_sys_gettid(), __func__, __LINE__);
> + ret = errno;
> + return ret;
> + }
> +
> + pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), CLIENT);
> + addr.sun_family = AF_UNIX;
> + addr_len = sizeof(struct sockaddr_un);
> +
> + do {
> + ret = bind(socket_fd, (struct sockaddr *) &addr, addr_len);
> + if (ret) {
> + RTE_LOG(ERR, PDUMP, "client bind(): %s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + ret = errno;
> + break;
> + }
> +
> + serv_len = sizeof(struct sockaddr_un);
> + memset(&serv_addr, 0, sizeof(serv_addr));
> + pdump_get_socket_path(serv_addr.sun_path,
> sizeof(serv_addr.sun_path),
> + SERVER);
> + serv_addr.sun_family = AF_UNIX;
> +
> + n = sendto(socket_fd, p, sizeof(struct pdump_request), 0,
> + (struct sockaddr *)&serv_addr, serv_len);
> + if (n < 0) {
> + RTE_LOG(ERR, PDUMP, "failed to send to server:%s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + ret = errno;
> + break;
> + }
> +
> + n = recvfrom(socket_fd, &server_resp, sizeof(struct pdump_response),
> 0,
> + (struct sockaddr *)&from, &serv_len);
> + if (n < 0) {
> + RTE_LOG(ERR, PDUMP, "failed to recv from server:%s, %s:%d\n",
> + strerror(errno), __func__, __LINE__);
> + ret = errno;
> + break;
> + }
> + ret = server_resp.err_value;
> + } while (0);
> +
> + close(socket_fd);
> + unlink(addr.sun_path);
> + return ret;
> +}
> +
> +static int
> +pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp)
> +{
> + if (ring == NULL || mp == NULL) {
> + RTE_LOG(ERR, PDUMP, "NULL ring or mempool are passed %s:%d\n",
> + __func__, __LINE__);
> + rte_errno = EINVAL;
> + return -1;
> + }
> + if (mp->flags & MEMPOOL_F_SP_PUT || mp->flags & MEMPOOL_F_SC_GET) {
> + RTE_LOG(ERR, PDUMP, "mempool with either SP or SC settings"
> + " is not valid for pdump, should have MP and MC settings\n");
> + rte_errno = EINVAL;
> + return -1;
> + }
> + if (ring->prod.sp_enqueue || ring->cons.sc_dequeue) {
> + RTE_LOG(ERR, PDUMP, "ring with either SP or SC settings"
> + " is not valid for pdump, should have MP and MC settings\n");
> + rte_errno = EINVAL;
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +pdump_validate_flags(uint32_t flags)
> +{
> + if (flags != RTE_PDUMP_FLAG_RX && flags != RTE_PDUMP_FLAG_TX &&
> + flags != RTE_PDUMP_FLAG_RXTX) {
> + RTE_LOG(ERR, PDUMP, "invalid flags, should be either rx/tx/rxtx\n");
> + rte_errno = EINVAL;
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +pdump_validate_port(uint8_t port, char *name)
> +{
> + int ret = 0;
> +
> + if (port >= RTE_MAX_ETHPORTS) {
> + RTE_LOG(ERR, PDUMP, "Invalid port id %u, %s:%d\n", port,
> + __func__, __LINE__);
> + rte_errno = EINVAL;
> + return -1;
> + }
> +
> + ret = rte_eth_dev_get_name_by_port(port, name);
> + if (ret < 0) {
> + RTE_LOG(ERR, PDUMP,
> + "port id to name mapping failed for port id=%u, %s:%d\n",
> + port, __func__, __LINE__);
> + rte_errno = EINVAL;
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +pdump_prepare_client_request(char *device, uint16_t queue,
> + uint32_t flags,
> + uint16_t operation,
> + struct rte_ring *ring,
> + struct rte_mempool *mp,
> + void *filter)
> +{
> + int ret;
> + struct pdump_request req = {.ver = 1,};
> +
> + req.flags = flags;
> + req.op = operation;
> + if ((operation & ENABLE) != 0) {
> + strncpy(req.data.en_v1.device, device, strlen(device));
> + req.data.en_v1.queue = queue;
> + req.data.en_v1.ring = ring;
> + req.data.en_v1.mp = mp;
> + req.data.en_v1.filter = filter;
> + } else {
> + strncpy(req.data.dis_v1.device, device, strlen(device));
> + req.data.dis_v1.queue = queue;
> + req.data.dis_v1.ring = NULL;
> + req.data.dis_v1.mp = NULL;
> + req.data.dis_v1.filter = NULL;
> + }
> +
> + ret = pdump_create_client_socket(&req);
> + if (ret < 0) {
> + RTE_LOG(ERR, PDUMP, "client request for pdump enable/disable
> failed\n");
> + rte_errno = ret;
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +int
> +rte_pdump_enable(uint8_t port, uint16_t queue, uint32_t flags,
> + struct rte_ring *ring,
> + struct rte_mempool *mp,
> + void *filter)
> +{
> +
> + int ret = 0;
> + char name[DEVICE_ID_SIZE];
> +
> + ret = pdump_validate_port(port, name);
> + if (ret < 0)
> + return ret;
> + ret = pdump_validate_ring_mp(ring, mp);
> + if (ret < 0)
> + return ret;
> + ret = pdump_validate_flags(flags);
> + if (ret < 0)
> + return ret;
> +
> + ret = pdump_prepare_client_request(name, queue, flags,
> + ENABLE, ring, mp, filter);
> +
> + return ret;
> +}
> +
> +int
> +rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
> + uint32_t flags,
> + struct rte_ring *ring,
> + struct rte_mempool *mp,
> + void *filter)
> +{
> + int ret = 0;
> + char domBDF[DEVICE_ID_SIZE];
> +
> + ret = pdump_validate_ring_mp(ring, mp);
> + if (ret < 0)
> + return ret;
> + ret = pdump_validate_flags(flags);
> + if (ret < 0)
> + return ret;
> +
> + if (pdump_get_dombdf(device_id, domBDF, sizeof(domBDF)) > 0)
> + ret = pdump_prepare_client_request(domBDF, queue, flags,
> + ENABLE, ring, mp, filter);
> + else
> + ret = pdump_prepare_client_request(device_id, queue, flags,
> + ENABLE, ring, mp, filter);
> +
> + return ret;
> +}
> +
> +int
> +rte_pdump_disable(uint8_t port, uint16_t queue, uint32_t flags)
> +{
> + int ret = 0;
> + char name[DEVICE_ID_SIZE];
> +
> + ret = pdump_validate_port(port, name);
> + if (ret < 0)
> + return ret;
> + ret = pdump_validate_flags(flags);
> + if (ret < 0)
> + return ret;
> +
> + ret = pdump_prepare_client_request(name, queue, flags,
> + DISABLE, NULL, NULL, NULL);
> +
> + return ret;
> +}
> +
> +int
> +rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
> + uint32_t flags)
> +{
> + int ret = 0;
> + char domBDF[DEVICE_ID_SIZE];
> +
> + ret = pdump_validate_flags(flags);
> + if (ret < 0)
> + return ret;
> +
> + if (pdump_get_dombdf(device_id, domBDF, sizeof(domBDF)) > 0)
> + ret = pdump_prepare_client_request(domBDF, queue, flags,
> + DISABLE, NULL, NULL, NULL);
> + else
> + ret = pdump_prepare_client_request(device_id, queue, flags,
> + DISABLE, NULL, NULL, NULL);
> +
> + return ret;
> +}
> diff --git a/lib/librte_pdump/rte_pdump.h b/lib/librte_pdump/rte_pdump.h
> new file mode 100644
> index 0000000..ca9333a
> --- /dev/null
> +++ b/lib/librte_pdump/rte_pdump.h
> @@ -0,0 +1,186 @@
> +/*-
> + * 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.
> + */
> +
> +#ifndef _RTE_PDUMP_H_
> +#define _RTE_PDUMP_H_
> +
> +/**
> + * @file
> + * RTE pdump
> + *
> + * packet dump library to provide packet capturing support on dpdk.
> + */
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +#define RTE_PDUMP_ALL_QUEUES UINT16_MAX
> +
> +enum {
> + RTE_PDUMP_FLAG_RX = 1, /* receive direction */
> + RTE_PDUMP_FLAG_TX = 2, /* transmit direction */
> + /* both receive and transmit directions */
> + RTE_PDUMP_FLAG_RXTX = (RTE_PDUMP_FLAG_RX|RTE_PDUMP_FLAG_TX)
> +};
> +
> +/**
> + * Initialize packet capturing handling
> + *
> + * Creates pthread and server socket for handling clients
> + * requests to enable/disable rxtx callbacks.
> + *
> + * @return
> + * 0 on success, -1 on error
> + */
> +int
> +rte_pdump_init(void);
> +
> +/**
> + * Un initialize packet capturing handling
> + *
> + * Cancels pthread, close server socket, removes server socket address.
> + *
> + * @return
> + * 0 on success, -1 on error
> + */
> +int
> +rte_pdump_uninit(void);
> +
> +/**
> + * Enables packet capturing on given port and queue.
> + *
> + * @param port
> + * port on which packet capturing should be enabled.
> + * @param queue
> + * queue of a given port on which packet capturing should be enabled.
> + * users should pass on value UINT16_MAX to enable packet capturing on all
> + * queues of a given port.
> + * @param flags
> + * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
> + * on which packet capturing should be enabled for a given port and queue.
> + * @param ring
> + * ring on which captured packets will be enqueued for user.
> + * @param mp
> + * mempool on to which original packets will be mirrored or duplicated.
> + * @param filter
> + * place holder for packet filtering.
> + *
> + * @return
> + * 0 on success, -1 on error, rte_errno is set accordingly.
> + */
> +
> +int
> +rte_pdump_enable(uint8_t port, uint16_t queue, uint32_t flags,
> + struct rte_ring *ring,
> + struct rte_mempool *mp,
> + void *filter);
> +
> +/**
> + * Disables packet capturing on given port and queue.
> + *
> + * @param port
> + * port on which packet capturing should be disabled.
> + * @param queue
> + * queue of a given port on which packet capturing should be disabled.
> + * users should pass on value UINT16_MAX to disable packet capturing on all
> + * queues of a given port.
> + * @param flags
> + * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
> + * on which packet capturing should be enabled for a given port and queue.
> + *
> + * @return
> + * 0 on success, -1 on error, rte_errno is set accordingly.
> + */
> +
> +int
> +rte_pdump_disable(uint8_t port, uint16_t queue, uint32_t flags);
> +
> +/**
> + * Enables packet capturing on given device id and queue.
> + * device_id can be name or pci address of device.
> + *
> + * @param device_id
> + * device id on which packet capturing should be enabled.
> + * @param queue
> + * queue of a given device id on which packet capturing should be enabled.
> + * users should pass on value UINT16_MAX to enable packet capturing on all
> + * queues of a given device id.
> + * @param flags
> + * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
> + * on which packet capturing should be enabled for a given port and queue.
> + * @param ring
> + * ring on which captured packets will be enqueued for user.
> + * @param mp
> + * mempool on to which original packets will be mirrored or duplicated.
> + * @param filter
> + * place holder for packet filtering.
> + *
> + * @return
> + * 0 on success, -1 on error, rte_errno is set accordingly.
> + */
> +
> +int
> +rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
> + uint32_t flags,
> + struct rte_ring *ring,
> + struct rte_mempool *mp,
> + void *filter);
> +
> +/**
> + * Disables packet capturing on given device_id and queue.
> + * device_id can be name or pci address of device.
> + *
> + * @param device_id
> + * pci address or name of the device on which packet capturing
> + * should be disabled.
> + * @param queue
> + * queue of a given device on which packet capturing should be disabled.
> + * users should pass on value UINT16_MAX to disable packet capturing on all
> + * queues of a given device id.
> + * @param flags
> + * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
> + * on which packet capturing should be enabled for a given port and queue.
> + *
> + * @return
> + * 0 on success, -1 on error, rte_errno is set accordingly.
> + */
> +int
> +rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
> + uint32_t flags);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif /* _RTE_PDUMP_H_ */
> diff --git a/lib/librte_pdump/rte_pdump_version.map
> b/lib/librte_pdump/rte_pdump_version.map
> new file mode 100644
> index 0000000..3e744f3
> --- /dev/null
> +++ b/lib/librte_pdump/rte_pdump_version.map
> @@ -0,0 +1,12 @@
> +DPDK_16.07 {
> + global:
> +
> + rte_pdump_disable;
> + rte_pdump_disable_by_deviceid;
> + rte_pdump_enable;
> + rte_pdump_enable_by_deviceid;
> + rte_pdump_init;
> + rte_pdump_uninit;
> +
> + local: *;
> +};
> diff --git a/mk/rte.app.mk b/mk/rte.app.mk
> index b84b56d..f792f2a 100644
> --- a/mk/rte.app.mk
> +++ b/mk/rte.app.mk
> @@ -61,6 +61,7 @@ _LDLIBS-y += --whole-archive
>
> _LDLIBS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += -lrte_distributor
> _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER) += -lrte_reorder
> +_LDLIBS-$(CONFIG_RTE_LIBRTE_PDUMP) += -lrte_pdump
>
> ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
> _LDLIBS-$(CONFIG_RTE_LIBRTE_KNI) += -lrte_kni
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v6 5/8] lib/librte_pdump: add new library for packet capturing support
2016-06-09 15:59 ` Aaron Conole
@ 2016-06-09 16:05 ` Ananyev, Konstantin
2016-06-09 17:23 ` Aaron Conole
2016-06-10 16:22 ` Pattan, Reshma
1 sibling, 1 reply; 82+ messages in thread
From: Ananyev, Konstantin @ 2016-06-09 16:05 UTC (permalink / raw)
To: Aaron Conole, Pattan, Reshma; +Cc: dev
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Aaron Conole
> Sent: Thursday, June 09, 2016 4:59 PM
> To: Pattan, Reshma
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v6 5/8] lib/librte_pdump: add new library for packet capturing support
>
> Reshma Pattan <reshma.pattan@intel.com> writes:
>
> > Added new library for packet capturing support.
> >
> > Added public api rte_pdump_init, applications should call
> > this as part of their application setup to have packet
> > capturing framework ready.
> >
> > Added public api rte_pdump_uninit to uninitialize the packet
> > capturing framework.
> >
> > Added public apis rte_pdump_enable and rte_pdump_disable to
> > enable and disable packet capturing on specific port and queue.
> >
> > Added public apis rte_pdump_enable_by_deviceid and
> > rte_pdump_disable_by_deviceid to enable and disable packet
> > capturing on a specific device (pci address or name) and queue.
> >
> > Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
> > ---
> > MAINTAINERS | 4 +
> > config/common_base | 5 +
> > lib/Makefile | 1 +
> > lib/librte_pdump/Makefile | 55 +++
> > lib/librte_pdump/rte_pdump.c | 841 +++++++++++++++++++++++++++++++++
> > lib/librte_pdump/rte_pdump.h | 186 ++++++++
> > lib/librte_pdump/rte_pdump_version.map | 12 +
> > mk/rte.app.mk | 1 +
> > 8 files changed, 1105 insertions(+)
> > create mode 100644 lib/librte_pdump/Makefile
> > create mode 100644 lib/librte_pdump/rte_pdump.c
> > create mode 100644 lib/librte_pdump/rte_pdump.h
> > create mode 100644 lib/librte_pdump/rte_pdump_version.map
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 3e8558f..cc3ffdb 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -432,6 +432,10 @@ F: app/test/test_reorder*
> > F: examples/packet_ordering/
> > F: doc/guides/sample_app_ug/packet_ordering.rst
> >
> > +Pdump
> > +M: Reshma Pattan <reshma.pattan@intel.com>
> > +F: lib/librte_pdump/
> > +
> > Hierarchical scheduler
> > M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
> > F: lib/librte_sched/
> > diff --git a/config/common_base b/config/common_base
> > index 47c26f6..a2d5d72 100644
> > --- a/config/common_base
> > +++ b/config/common_base
> > @@ -484,6 +484,11 @@ CONFIG_RTE_LIBRTE_DISTRIBUTOR=y
> > CONFIG_RTE_LIBRTE_REORDER=y
> >
> > #
> > +# Compile the pdump library
> > +#
> > +CONFIG_RTE_LIBRTE_PDUMP=y
> > +
> > +#
> > # Compile librte_port
> > #
> > CONFIG_RTE_LIBRTE_PORT=y
> > diff --git a/lib/Makefile b/lib/Makefile
> > index f254dba..ca7c02f 100644
> > --- a/lib/Makefile
> > +++ b/lib/Makefile
> > @@ -57,6 +57,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
> > DIRS-$(CONFIG_RTE_LIBRTE_TABLE) += librte_table
> > DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += librte_pipeline
> > DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
> > +DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += librte_pdump
> >
> > ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
> > DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
> > diff --git a/lib/librte_pdump/Makefile b/lib/librte_pdump/Makefile
> > new file mode 100644
> > index 0000000..af81a28
> > --- /dev/null
> > +++ b/lib/librte_pdump/Makefile
> > @@ -0,0 +1,55 @@
> > +# 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_SDK)/mk/rte.vars.mk
> > +
> > +# library name
> > +LIB = librte_pdump.a
> > +
> > +CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
> > +CFLAGS += -D_GNU_SOURCE
> > +
> > +EXPORT_MAP := rte_pdump_version.map
> > +
> > +LIBABIVER := 1
> > +
> > +# all source are stored in SRCS-y
> > +SRCS-$(CONFIG_RTE_LIBRTE_PDUMP) := rte_pdump.c
> > +
> > +# install this header file
> > +SYMLINK-$(CONFIG_RTE_LIBRTE_PDUMP)-include := rte_pdump.h
> > +
> > +# this lib depends upon:
> > +DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_mbuf
> > +DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_eal
> > +DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_ether
> > +
> > +include $(RTE_SDK)/mk/rte.lib.mk
> > diff --git a/lib/librte_pdump/rte_pdump.c b/lib/librte_pdump/rte_pdump.c
> > new file mode 100644
> > index 0000000..4aff34a
> > --- /dev/null
> > +++ b/lib/librte_pdump/rte_pdump.c
> > @@ -0,0 +1,841 @@
> > +/*-
> > + * 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 <sys/socket.h>
> > +#include <sys/un.h>
> > +#include <sys/stat.h>
> > +#include <unistd.h>
> > +#include <sys/types.h>
> > +#include <pthread.h>
> > +#include <stdbool.h>
> > +
> > +#include <rte_memcpy.h>
> > +#include <rte_mbuf.h>
> > +#include <rte_ethdev.h>
> > +#include <rte_lcore.h>
> > +#include <rte_log.h>
> > +#include <rte_errno.h>
> > +#include <rte_pci.h>
> > +
> > +#include "rte_pdump.h"
> > +
> > +#define SOCKET_PATH_VAR_RUN "/var/run/pdump_sockets"
> > +#define SOCKET_PATH_HOME "HOME/pdump_sockets"
> > +#define SERVER_SOCKET "%s/pdump_server_socket"
> > +#define CLIENT_SOCKET "%s/pdump_client_socket_%d_%u"
> > +#define DEVICE_ID_SIZE 64
> > +/* Macros for printing using RTE_LOG */
> > +#define RTE_LOGTYPE_PDUMP RTE_LOGTYPE_USER1
> > +
> > +enum pdump_operation {
> > + DISABLE = 1,
> > + ENABLE = 2
> > +};
> > +
> > +enum pdump_socktype {
> > + SERVER = 1,
> > + CLIENT = 2
> > +};
> > +
> > +enum pdump_version {
> > + V1 = 1
> > +};
> > +
> > +static pthread_t pdump_thread;
> > +static int pdump_socket_fd;
> > +
> > +struct pdump_request {
> > + uint16_t ver;
> > + uint16_t op;
> > + uint32_t flags;
> > + union pdump_data {
> > + struct enable_v1 {
> > + char device[DEVICE_ID_SIZE];
> > + uint16_t queue;
> > + struct rte_ring *ring;
> > + struct rte_mempool *mp;
> > + void *filter;
> > + } en_v1;
> > + struct disable_v1 {
> > + char device[DEVICE_ID_SIZE];
> > + uint16_t queue;
> > + struct rte_ring *ring;
> > + struct rte_mempool *mp;
> > + void *filter;
> > + } dis_v1;
> > + } data;
> > +};
> > +
> > +struct pdump_response {
> > + uint16_t ver;
> > + uint16_t res_op;
> > + int32_t err_value;
> > +};
> > +
> > +static struct pdump_rxtx_cbs {
> > + struct rte_ring *ring;
> > + struct rte_mempool *mp;
> > + struct rte_eth_rxtx_callback *cb;
> > + void *filter;
> > +} rx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT],
> > +tx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
> > +
> > +static inline int
> > +pdump_pktmbuf_copy_data(struct rte_mbuf *seg, const struct rte_mbuf *m)
> > +{
> > + if (rte_pktmbuf_tailroom(seg) < m->data_len) {
> > + RTE_LOG(ERR, PDUMP, "User mempool: insufficient data_len of
> > mbuf\n");
> > + return -EINVAL;
> > + }
> > +
> > + seg->port = m->port;
> > + seg->vlan_tci = m->vlan_tci;
> > + seg->hash = m->hash;
> > + seg->tx_offload = m->tx_offload;
> > + seg->ol_flags = m->ol_flags;
> > + seg->packet_type = m->packet_type;
> > + seg->vlan_tci_outer = m->vlan_tci_outer;
> > + seg->data_len = m->data_len;
> > + seg->pkt_len = seg->data_len;
> > + rte_memcpy(rte_pktmbuf_mtod(seg, void *),
> > + rte_pktmbuf_mtod(m, void *),
> > + rte_pktmbuf_data_len(seg));
> > +
> > + return 0;
> > +}
> > +
> > +static inline struct rte_mbuf *
> > +pdump_pktmbuf_copy(struct rte_mbuf *m, struct rte_mempool *mp)
> > +{
> > + struct rte_mbuf *m_dup, *seg, **prev;
> > + uint32_t pktlen;
> > + uint8_t nseg;
> > +
> > + m_dup = rte_pktmbuf_alloc(mp);
> > + if (unlikely(m_dup == NULL))
> > + return NULL;
> > +
> > + seg = m_dup;
> > + prev = &seg->next;
> > + pktlen = m->pkt_len;
> > + nseg = 0;
> > +
> > + do {
> > + nseg++;
> > + if (pdump_pktmbuf_copy_data(seg, m) < 0) {
> > + rte_pktmbuf_free(m_dup);
> > + return NULL;
> > + }
> > + *prev = seg;
> > + prev = &seg->next;
> > + } while ((m = m->next) != NULL &&
> > + (seg = rte_pktmbuf_alloc(mp)) != NULL);
> > +
> > + *prev = NULL;
> > + m_dup->nb_segs = nseg;
> > + m_dup->pkt_len = pktlen;
> > +
> > + /* Allocation of new indirect segment failed */
> > + if (unlikely(seg == NULL)) {
> > + rte_pktmbuf_free(m_dup);
> > + return NULL;
> > + }
> > +
> > + __rte_mbuf_sanity_check(m_dup, 1);
> > + return m_dup;
> > +}
> > +
> > +static inline void
> > +pdump_copy(struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
> > +{
> > + unsigned i;
> > + int ring_enq;
> > + uint16_t d_pkts = 0;
> > + struct rte_mbuf *dup_bufs[nb_pkts];
> > + struct pdump_rxtx_cbs *cbs;
> > + struct rte_ring *ring;
> > + struct rte_mempool *mp;
> > + struct rte_mbuf *p;
> > +
> > + cbs = user_params;
> > + ring = cbs->ring;
> > + mp = cbs->mp;
> > + for (i = 0; i < nb_pkts; i++) {
> > + p = pdump_pktmbuf_copy(pkts[i], mp);
> > + if (p)
> > + dup_bufs[d_pkts++] = p;
> > + }
> > +
> > + ring_enq = rte_ring_enqueue_burst(ring, (void *)dup_bufs, d_pkts);
> > + if (unlikely(ring_enq < d_pkts)) {
> > + RTE_LOG(DEBUG, PDUMP, "only %d of packets enqueued to ring\n",
> > ring_enq);
> > + do {
> > + rte_pktmbuf_free(dup_bufs[ring_enq]);
> > + } while (++ring_enq < d_pkts);
> > + }
> > +}
> > +
> > +static uint16_t
> > +pdump_rx(uint8_t port __rte_unused, uint16_t qidx __rte_unused,
> > + struct rte_mbuf **pkts, uint16_t nb_pkts, uint16_t max_pkts __rte_unused,
> > + void *user_params)
> > +{
> > + pdump_copy(pkts, nb_pkts, user_params);
> > + return nb_pkts;
> > +}
> > +
> > +static uint16_t
> > +pdump_tx(uint8_t port __rte_unused, uint16_t qidx __rte_unused,
> > + struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
> > +{
> > + pdump_copy(pkts, nb_pkts, user_params);
> > + return nb_pkts;
> > +}
> > +
> > +static int
> > +pdump_get_dombdf(char *device_id, char *domBDF, size_t len)
> > +{
> > + int ret;
> > + struct rte_pci_addr dev_addr = {0};
> > +
> > + /* identify if device_id is pci address or name */
> > + ret = eal_parse_pci_DomBDF(device_id, &dev_addr);
> > + if (ret < 0)
> > + return -1;
> > +
> > + if (dev_addr.domain)
> > + ret = snprintf(domBDF, len, "%u:%u:%u.%u", dev_addr.domain,
> > + dev_addr.bus, dev_addr.devid, dev_addr.function);
> > + else
> > + ret = snprintf(domBDF, len, "%u:%u.%u", dev_addr.bus,
> > dev_addr.devid,
> > + dev_addr.function);
> > +
> > + return ret;
> > +}
> > +
> > +static int
> > +pdump_regitser_rx_callbacks(uint16_t end_q, uint8_t port, uint16_t queue,
> > + struct rte_ring *ring, struct rte_mempool *mp,
> > + uint16_t operation)
> > +{
> > + uint16_t qid;
> > + struct pdump_rxtx_cbs *cbs = NULL;
> > +
> > + qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
> > + for (; qid < end_q; qid++) {
> > + cbs = &rx_cbs[port][qid];
> > + if (cbs && operation == ENABLE) {
> > + if (cbs->cb) {
> > + RTE_LOG(ERR, PDUMP,
> > + "failed to add rx callback for port=%d and "
> > + "queue=%d, callback already exists\n",
> > + port, qid);
> > + return -EEXIST;
> > + }
> > + cbs->ring = ring;
> > + cbs->mp = mp;
> > + cbs->cb = rte_eth_add_first_rx_callback(port, qid,
> > + pdump_rx, cbs);
> > + if (cbs->cb == NULL) {
> > + RTE_LOG(ERR, PDUMP,
> > + "failed to add rx callback, errno=%d\n",
> > + rte_errno);
> > + return rte_errno;
> > + }
> > + }
> > + if (cbs && operation == DISABLE) {
> > + int ret;
> > +
> > + if (cbs->cb == NULL) {
> > + RTE_LOG(ERR, PDUMP,
> > + "failed to delete non existing rx callback "
> > + "for port=%d and queue=%d\n", port, qid);
> > + return -EINVAL;
> > + }
> > + ret = rte_eth_remove_rx_callback(port, qid, cbs->cb);
> > + if (ret < 0) {
> > + RTE_LOG(ERR, PDUMP,
> > + "failed to remove rx callback, errno=%d\n",
> > + rte_errno);
> > + return ret;
> > + }
> > + cbs->cb = NULL;
> > + }
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int
> > +pdump_regitser_tx_callbacks(uint16_t end_q, uint8_t port, uint16_t queue,
> > + struct rte_ring *ring, struct rte_mempool *mp,
> > + uint16_t operation)
> > +{
> > +
> > + uint16_t qid;
> > + struct pdump_rxtx_cbs *cbs = NULL;
> > +
> > + qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
> > + for (; qid < end_q; qid++) {
> > + cbs = &tx_cbs[port][qid];
> > + if (cbs && operation == ENABLE) {
> > + if (cbs->cb) {
> > + RTE_LOG(ERR, PDUMP,
> > + "failed to add tx callback for port=%d and "
> > + "queue=%d, callback already exists\n",
> > + port, qid);
> > + return -EEXIST;
> > + }
> > + cbs->ring = ring;
> > + cbs->mp = mp;
> > + cbs->cb = rte_eth_add_tx_callback(port, qid, pdump_tx,
> > + cbs);
> > + if (cbs->cb == NULL) {
> > + RTE_LOG(ERR, PDUMP,
> > + "failed to add tx callback, errno=%d\n",
> > + rte_errno);
> > + return rte_errno;
> > + }
> > + }
> > + if (cbs && operation == DISABLE) {
> > + int ret;
> > +
> > + if (cbs->cb == NULL) {
> > + RTE_LOG(ERR, PDUMP,
> > + "failed to delete non existing tx callback "
> > + "for port=%d and queue=%d\n", port, qid);
> > + return -EINVAL;
> > + }
> > + ret = rte_eth_remove_tx_callback(port, qid, cbs->cb);
> > + if (ret < 0) {
> > + RTE_LOG(ERR, PDUMP,
> > + "failed to remove tx callback, errno=%d\n",
> > + rte_errno);
> > + return ret;
> > + }
> > + cbs->cb = NULL;
> > + }
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int
> > +set_pdump_rxtx_cbs(struct pdump_request *p)
> > +{
> > + uint16_t nb_rx_q, nb_tx_q = 0, end_q, queue;
> > + uint8_t port;
> > + int ret = 0;
> > + uint32_t flags;
> > + uint16_t operation;
> > + struct rte_ring *ring;
> > + struct rte_mempool *mp;
> > +
> > + flags = p->flags;
> > + operation = p->op;
> > + if (operation == ENABLE) {
> > + ret = rte_eth_dev_get_port_by_name(p->data.en_v1.device,
> > + &port);
> > + if (ret < 0) {
> > + RTE_LOG(ERR, PDUMP,
> > + "failed to get potid for device id=%s\n",
> > + p->data.en_v1.device);
> > + return -EINVAL;
> > + }
> > + queue = p->data.en_v1.queue;
> > + ring = p->data.en_v1.ring;
> > + mp = p->data.en_v1.mp;
> > + } else {
> > + ret = rte_eth_dev_get_port_by_name(p->data.dis_v1.device,
> > + &port);
> > + if (ret < 0) {
> > + RTE_LOG(ERR, PDUMP,
> > + "failed to get potid for device id=%s\n",
> > + p->data.dis_v1.device);
> > + return -EINVAL;
> > + }
> > + queue = p->data.dis_v1.queue;
> > + ring = p->data.dis_v1.ring;
> > + mp = p->data.dis_v1.mp;
> > + }
> > +
> > + /* validation if packet capture is for all queues */
> > + if (queue == RTE_PDUMP_ALL_QUEUES) {
> > + struct rte_eth_dev_info dev_info;
> > +
> > + rte_eth_dev_info_get(port, &dev_info);
> > + nb_rx_q = dev_info.nb_rx_queues;
> > + nb_tx_q = dev_info.nb_tx_queues;
> > + if (nb_rx_q == 0 && flags & RTE_PDUMP_FLAG_RX) {
> > + RTE_LOG(ERR, PDUMP, "number of rx queues cannot be 0\n");
> > + return -EINVAL;
> > + }
> > + if (nb_tx_q == 0 && flags & RTE_PDUMP_FLAG_TX) {
> > + RTE_LOG(ERR, PDUMP, "number of tx queues cannot be 0\n");
> > + return -EINVAL;
> > + }
> > + if ((nb_tx_q == 0 || nb_rx_q == 0) && flags == RTE_PDUMP_FLAG_RXTX)
> > {
> > + RTE_LOG(ERR, PDUMP, "both tx&rx queues must be non zero\n");
> > + return -EINVAL;
> > + }
> > + }
> > +
> > + /* register RX callback */
> > + if (flags & RTE_PDUMP_FLAG_RX) {
> > + end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_rx_q : queue + 1;
> > + ret = pdump_regitser_rx_callbacks(end_q, port, queue, ring, mp,
> > + operation);
> > + if (ret < 0)
> > + return ret;
> > + }
> > +
> > + /* register TX callback */
> > + if (flags & RTE_PDUMP_FLAG_TX) {
> > + end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_tx_q : queue + 1;
> > + ret = pdump_regitser_tx_callbacks(end_q, port, queue, ring, mp,
> > + operation);
> > + if (ret < 0)
> > + return ret;
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +/* get socket path (/var/run if root, $HOME otherwise) */
> > +static void
> > +pdump_get_socket_path(char *buffer, int bufsz, enum pdump_socktype type)
> > +{
> > + const char *dir = SOCKET_PATH_VAR_RUN;
> > + const char *home_dir = getenv(SOCKET_PATH_HOME);
> > +
> > + if (getuid() != 0 && home_dir != NULL)
> > + dir = home_dir;
> > +
> > + mkdir(dir, 700);
> > + if (type == SERVER)
> > + snprintf(buffer, bufsz, SERVER_SOCKET, dir);
> > + else
> > + snprintf(buffer, bufsz, CLIENT_SOCKET, dir, getpid(),
> > + rte_sys_gettid());
> > +}
> > +
> > +static int
> > +pdump_create_server_socket(void)
> > +{
> > + int ret, socket_fd;
> > + struct sockaddr_un addr;
> > + socklen_t addr_len;
> > +
> > + pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), SERVER);
> > + addr.sun_family = AF_UNIX;
> > +
> > + /* remove if file already exists */
> > + unlink(addr.sun_path);
> > +
> > + /* set up a server socket */
> > + socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
> > + if (socket_fd < 0) {
> > + RTE_LOG(ERR, PDUMP, "Failed to create server socket: %s, %s:%d\n",
> > + strerror(errno), __func__, __LINE__);
> > + return -1;
> > + }
> > +
> > + addr_len = sizeof(struct sockaddr_un);
> > + ret = bind(socket_fd, (struct sockaddr *) &addr, addr_len);
> > + if (ret) {
> > + RTE_LOG(ERR, PDUMP, "Failed to bind to server socket: %s, %s:%d\n",
> > + strerror(errno), __func__, __LINE__);
> > + close(socket_fd);
> > + return -1;
> > + }
> > +
> > + /* save the socket in local configuration */
> > + pdump_socket_fd = socket_fd;
> > +
> > + return 0;
> > +}
> > +
> > +static __attribute__((noreturn)) void *
> > +pdump_thread_main(__rte_unused void *arg)
> > +{
> > + struct sockaddr_un cli_addr;
> > + socklen_t cli_len;
> > + struct pdump_request cli_req;
> > + struct pdump_response resp;
> > + int n;
> > + int ret = 0;
> > +
> > + /* host thread, never break out */
> > + for (;;) {
> > + /* recv client requests */
> > + cli_len = sizeof(cli_addr);
> > + n = recvfrom(pdump_socket_fd, &cli_req, sizeof(struct
> > pdump_request), 0,
> > + (struct sockaddr *)&cli_addr, &cli_len);
> > + if (n < 0) {
> > + RTE_LOG(ERR, PDUMP, "failed to recv from client:%s, %s:%d\n",
> > + strerror(errno), __func__, __LINE__);
> > + continue;
> > + }
> > +
> > + ret = set_pdump_rxtx_cbs(&cli_req);
> > +
> > + resp.ver = cli_req.ver;
> > + resp.res_op = cli_req.op;
> > + resp.err_value = ret;
> > + n = sendto(pdump_socket_fd, &resp, sizeof(struct pdump_response),
> > + 0, (struct sockaddr *)&cli_addr, cli_len);
> > + if (n < 0) {
> > + RTE_LOG(ERR, PDUMP, "failed to send to client:%s, %s:%d\n",
> > + strerror(errno), __func__, __LINE__);
> > + }
> > + }
> > +}
> > +
> > +int
> > +rte_pdump_init(void)
>
> Would you be opposed to having an argument here which takes a path to
> the server socket? That way the application can have some control over
> the server socket location rather than using the guesses from
> pdump_get_socket_path.
I suppose it is better to keep IPC mechanism details internal for the pdump library.
That way upper layer don't need to know what is that and write the code to open/maintain it.
Again, that gives pdump library a freedom to change it (if needed) or possibly introduce some alternatives.
Konstantin
>
> > +{
> > + int ret = 0;
> > + char thread_name[RTE_MAX_THREAD_NAME_LEN];
> > +
> > + ret = pdump_create_server_socket();
> > + if (ret != 0) {
> > + RTE_LOG(ERR, PDUMP, "Failed to create server socket:%s:%d\n",
> > + __func__, __LINE__);
> > + return -1;
> > + }
> > +
> > + /* create the host thread to wait/handle pdump requests */
> > + ret = pthread_create(&pdump_thread, NULL, pdump_thread_main, NULL);
> > + if (ret != 0) {
> > + RTE_LOG(ERR, PDUMP, "Failed to create the pdump thread:%s, %s:%d\n",
> > + strerror(errno), __func__, __LINE__);
> > + return -1;
> > + }
> > + /* Set thread_name for aid in debugging. */
> > + snprintf(thread_name, RTE_MAX_THREAD_NAME_LEN, "pdump-thread");
> > + ret = rte_thread_setname(pdump_thread, thread_name);
> > + if (ret != 0) {
> > + RTE_LOG(DEBUG, PDUMP,
> > + "Failed to set thread name for pdump handling\n");
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +int
> > +rte_pdump_uninit(void)
> > +{
> > + int ret;
> > +
> > + ret = pthread_cancel(pdump_thread);
> > + if (ret != 0) {
> > + RTE_LOG(ERR, PDUMP, "Failed to cancel the pdump thread:%s, %s:%d\n",
> > + strerror(errno), __func__, __LINE__);
> > + return -1;
> > + }
> > +
> > + ret = close(pdump_socket_fd);
> > + if (ret != 0) {
> > + RTE_LOG(ERR, PDUMP, "Failed to close server socket: %s, %s:%d\n",
> > + strerror(errno), __func__, __LINE__);
> > + return -1;
> > + }
> > +
> > + struct sockaddr_un addr;
> > +
> > + pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), SERVER);
> > + ret = unlink(addr.sun_path);
> > + if (ret != 0) {
> > + RTE_LOG(ERR, PDUMP, "Failed to remove server socket addr: %s,
> > %s:%d\n",
> > + strerror(errno), __func__, __LINE__);
> > + return -1;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int
> > +pdump_create_client_socket(struct pdump_request *p)
> > +{
> > + int ret, socket_fd;
> > + int pid;
> > + int n;
> > + struct pdump_response server_resp;
> > + struct sockaddr_un addr, serv_addr, from;
> > + socklen_t addr_len, serv_len;
> > +
> > + pid = getpid();
> > +
> > + socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
> > + if (socket_fd < 0) {
> > + RTE_LOG(ERR, PDUMP, "client socket(): %s:pid(%d):tid(%u), %s:%d\n",
> > + strerror(errno), pid, rte_sys_gettid(), __func__, __LINE__);
> > + ret = errno;
> > + return ret;
> > + }
> > +
> > + pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), CLIENT);
> > + addr.sun_family = AF_UNIX;
> > + addr_len = sizeof(struct sockaddr_un);
> > +
> > + do {
> > + ret = bind(socket_fd, (struct sockaddr *) &addr, addr_len);
> > + if (ret) {
> > + RTE_LOG(ERR, PDUMP, "client bind(): %s, %s:%d\n",
> > + strerror(errno), __func__, __LINE__);
> > + ret = errno;
> > + break;
> > + }
> > +
> > + serv_len = sizeof(struct sockaddr_un);
> > + memset(&serv_addr, 0, sizeof(serv_addr));
> > + pdump_get_socket_path(serv_addr.sun_path,
> > sizeof(serv_addr.sun_path),
> > + SERVER);
> > + serv_addr.sun_family = AF_UNIX;
> > +
> > + n = sendto(socket_fd, p, sizeof(struct pdump_request), 0,
> > + (struct sockaddr *)&serv_addr, serv_len);
> > + if (n < 0) {
> > + RTE_LOG(ERR, PDUMP, "failed to send to server:%s, %s:%d\n",
> > + strerror(errno), __func__, __LINE__);
> > + ret = errno;
> > + break;
> > + }
> > +
> > + n = recvfrom(socket_fd, &server_resp, sizeof(struct pdump_response),
> > 0,
> > + (struct sockaddr *)&from, &serv_len);
> > + if (n < 0) {
> > + RTE_LOG(ERR, PDUMP, "failed to recv from server:%s, %s:%d\n",
> > + strerror(errno), __func__, __LINE__);
> > + ret = errno;
> > + break;
> > + }
> > + ret = server_resp.err_value;
> > + } while (0);
> > +
> > + close(socket_fd);
> > + unlink(addr.sun_path);
> > + return ret;
> > +}
> > +
> > +static int
> > +pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp)
> > +{
> > + if (ring == NULL || mp == NULL) {
> > + RTE_LOG(ERR, PDUMP, "NULL ring or mempool are passed %s:%d\n",
> > + __func__, __LINE__);
> > + rte_errno = EINVAL;
> > + return -1;
> > + }
> > + if (mp->flags & MEMPOOL_F_SP_PUT || mp->flags & MEMPOOL_F_SC_GET) {
> > + RTE_LOG(ERR, PDUMP, "mempool with either SP or SC settings"
> > + " is not valid for pdump, should have MP and MC settings\n");
> > + rte_errno = EINVAL;
> > + return -1;
> > + }
> > + if (ring->prod.sp_enqueue || ring->cons.sc_dequeue) {
> > + RTE_LOG(ERR, PDUMP, "ring with either SP or SC settings"
> > + " is not valid for pdump, should have MP and MC settings\n");
> > + rte_errno = EINVAL;
> > + return -1;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int
> > +pdump_validate_flags(uint32_t flags)
> > +{
> > + if (flags != RTE_PDUMP_FLAG_RX && flags != RTE_PDUMP_FLAG_TX &&
> > + flags != RTE_PDUMP_FLAG_RXTX) {
> > + RTE_LOG(ERR, PDUMP, "invalid flags, should be either rx/tx/rxtx\n");
> > + rte_errno = EINVAL;
> > + return -1;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int
> > +pdump_validate_port(uint8_t port, char *name)
> > +{
> > + int ret = 0;
> > +
> > + if (port >= RTE_MAX_ETHPORTS) {
> > + RTE_LOG(ERR, PDUMP, "Invalid port id %u, %s:%d\n", port,
> > + __func__, __LINE__);
> > + rte_errno = EINVAL;
> > + return -1;
> > + }
> > +
> > + ret = rte_eth_dev_get_name_by_port(port, name);
> > + if (ret < 0) {
> > + RTE_LOG(ERR, PDUMP,
> > + "port id to name mapping failed for port id=%u, %s:%d\n",
> > + port, __func__, __LINE__);
> > + rte_errno = EINVAL;
> > + return -1;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int
> > +pdump_prepare_client_request(char *device, uint16_t queue,
> > + uint32_t flags,
> > + uint16_t operation,
> > + struct rte_ring *ring,
> > + struct rte_mempool *mp,
> > + void *filter)
> > +{
> > + int ret;
> > + struct pdump_request req = {.ver = 1,};
> > +
> > + req.flags = flags;
> > + req.op = operation;
> > + if ((operation & ENABLE) != 0) {
> > + strncpy(req.data.en_v1.device, device, strlen(device));
> > + req.data.en_v1.queue = queue;
> > + req.data.en_v1.ring = ring;
> > + req.data.en_v1.mp = mp;
> > + req.data.en_v1.filter = filter;
> > + } else {
> > + strncpy(req.data.dis_v1.device, device, strlen(device));
> > + req.data.dis_v1.queue = queue;
> > + req.data.dis_v1.ring = NULL;
> > + req.data.dis_v1.mp = NULL;
> > + req.data.dis_v1.filter = NULL;
> > + }
> > +
> > + ret = pdump_create_client_socket(&req);
> > + if (ret < 0) {
> > + RTE_LOG(ERR, PDUMP, "client request for pdump enable/disable
> > failed\n");
> > + rte_errno = ret;
> > + return -1;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +int
> > +rte_pdump_enable(uint8_t port, uint16_t queue, uint32_t flags,
> > + struct rte_ring *ring,
> > + struct rte_mempool *mp,
> > + void *filter)
> > +{
> > +
> > + int ret = 0;
> > + char name[DEVICE_ID_SIZE];
> > +
> > + ret = pdump_validate_port(port, name);
> > + if (ret < 0)
> > + return ret;
> > + ret = pdump_validate_ring_mp(ring, mp);
> > + if (ret < 0)
> > + return ret;
> > + ret = pdump_validate_flags(flags);
> > + if (ret < 0)
> > + return ret;
> > +
> > + ret = pdump_prepare_client_request(name, queue, flags,
> > + ENABLE, ring, mp, filter);
> > +
> > + return ret;
> > +}
> > +
> > +int
> > +rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
> > + uint32_t flags,
> > + struct rte_ring *ring,
> > + struct rte_mempool *mp,
> > + void *filter)
> > +{
> > + int ret = 0;
> > + char domBDF[DEVICE_ID_SIZE];
> > +
> > + ret = pdump_validate_ring_mp(ring, mp);
> > + if (ret < 0)
> > + return ret;
> > + ret = pdump_validate_flags(flags);
> > + if (ret < 0)
> > + return ret;
> > +
> > + if (pdump_get_dombdf(device_id, domBDF, sizeof(domBDF)) > 0)
> > + ret = pdump_prepare_client_request(domBDF, queue, flags,
> > + ENABLE, ring, mp, filter);
> > + else
> > + ret = pdump_prepare_client_request(device_id, queue, flags,
> > + ENABLE, ring, mp, filter);
> > +
> > + return ret;
> > +}
> > +
> > +int
> > +rte_pdump_disable(uint8_t port, uint16_t queue, uint32_t flags)
> > +{
> > + int ret = 0;
> > + char name[DEVICE_ID_SIZE];
> > +
> > + ret = pdump_validate_port(port, name);
> > + if (ret < 0)
> > + return ret;
> > + ret = pdump_validate_flags(flags);
> > + if (ret < 0)
> > + return ret;
> > +
> > + ret = pdump_prepare_client_request(name, queue, flags,
> > + DISABLE, NULL, NULL, NULL);
> > +
> > + return ret;
> > +}
> > +
> > +int
> > +rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
> > + uint32_t flags)
> > +{
> > + int ret = 0;
> > + char domBDF[DEVICE_ID_SIZE];
> > +
> > + ret = pdump_validate_flags(flags);
> > + if (ret < 0)
> > + return ret;
> > +
> > + if (pdump_get_dombdf(device_id, domBDF, sizeof(domBDF)) > 0)
> > + ret = pdump_prepare_client_request(domBDF, queue, flags,
> > + DISABLE, NULL, NULL, NULL);
> > + else
> > + ret = pdump_prepare_client_request(device_id, queue, flags,
> > + DISABLE, NULL, NULL, NULL);
> > +
> > + return ret;
> > +}
> > diff --git a/lib/librte_pdump/rte_pdump.h b/lib/librte_pdump/rte_pdump.h
> > new file mode 100644
> > index 0000000..ca9333a
> > --- /dev/null
> > +++ b/lib/librte_pdump/rte_pdump.h
> > @@ -0,0 +1,186 @@
> > +/*-
> > + * 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.
> > + */
> > +
> > +#ifndef _RTE_PDUMP_H_
> > +#define _RTE_PDUMP_H_
> > +
> > +/**
> > + * @file
> > + * RTE pdump
> > + *
> > + * packet dump library to provide packet capturing support on dpdk.
> > + */
> > +
> > +#ifdef __cplusplus
> > +extern "C" {
> > +#endif
> > +
> > +#define RTE_PDUMP_ALL_QUEUES UINT16_MAX
> > +
> > +enum {
> > + RTE_PDUMP_FLAG_RX = 1, /* receive direction */
> > + RTE_PDUMP_FLAG_TX = 2, /* transmit direction */
> > + /* both receive and transmit directions */
> > + RTE_PDUMP_FLAG_RXTX = (RTE_PDUMP_FLAG_RX|RTE_PDUMP_FLAG_TX)
> > +};
> > +
> > +/**
> > + * Initialize packet capturing handling
> > + *
> > + * Creates pthread and server socket for handling clients
> > + * requests to enable/disable rxtx callbacks.
> > + *
> > + * @return
> > + * 0 on success, -1 on error
> > + */
> > +int
> > +rte_pdump_init(void);
> > +
> > +/**
> > + * Un initialize packet capturing handling
> > + *
> > + * Cancels pthread, close server socket, removes server socket address.
> > + *
> > + * @return
> > + * 0 on success, -1 on error
> > + */
> > +int
> > +rte_pdump_uninit(void);
> > +
> > +/**
> > + * Enables packet capturing on given port and queue.
> > + *
> > + * @param port
> > + * port on which packet capturing should be enabled.
> > + * @param queue
> > + * queue of a given port on which packet capturing should be enabled.
> > + * users should pass on value UINT16_MAX to enable packet capturing on all
> > + * queues of a given port.
> > + * @param flags
> > + * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
> > + * on which packet capturing should be enabled for a given port and queue.
> > + * @param ring
> > + * ring on which captured packets will be enqueued for user.
> > + * @param mp
> > + * mempool on to which original packets will be mirrored or duplicated.
> > + * @param filter
> > + * place holder for packet filtering.
> > + *
> > + * @return
> > + * 0 on success, -1 on error, rte_errno is set accordingly.
> > + */
> > +
> > +int
> > +rte_pdump_enable(uint8_t port, uint16_t queue, uint32_t flags,
> > + struct rte_ring *ring,
> > + struct rte_mempool *mp,
> > + void *filter);
> > +
> > +/**
> > + * Disables packet capturing on given port and queue.
> > + *
> > + * @param port
> > + * port on which packet capturing should be disabled.
> > + * @param queue
> > + * queue of a given port on which packet capturing should be disabled.
> > + * users should pass on value UINT16_MAX to disable packet capturing on all
> > + * queues of a given port.
> > + * @param flags
> > + * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
> > + * on which packet capturing should be enabled for a given port and queue.
> > + *
> > + * @return
> > + * 0 on success, -1 on error, rte_errno is set accordingly.
> > + */
> > +
> > +int
> > +rte_pdump_disable(uint8_t port, uint16_t queue, uint32_t flags);
> > +
> > +/**
> > + * Enables packet capturing on given device id and queue.
> > + * device_id can be name or pci address of device.
> > + *
> > + * @param device_id
> > + * device id on which packet capturing should be enabled.
> > + * @param queue
> > + * queue of a given device id on which packet capturing should be enabled.
> > + * users should pass on value UINT16_MAX to enable packet capturing on all
> > + * queues of a given device id.
> > + * @param flags
> > + * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
> > + * on which packet capturing should be enabled for a given port and queue.
> > + * @param ring
> > + * ring on which captured packets will be enqueued for user.
> > + * @param mp
> > + * mempool on to which original packets will be mirrored or duplicated.
> > + * @param filter
> > + * place holder for packet filtering.
> > + *
> > + * @return
> > + * 0 on success, -1 on error, rte_errno is set accordingly.
> > + */
> > +
> > +int
> > +rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
> > + uint32_t flags,
> > + struct rte_ring *ring,
> > + struct rte_mempool *mp,
> > + void *filter);
> > +
> > +/**
> > + * Disables packet capturing on given device_id and queue.
> > + * device_id can be name or pci address of device.
> > + *
> > + * @param device_id
> > + * pci address or name of the device on which packet capturing
> > + * should be disabled.
> > + * @param queue
> > + * queue of a given device on which packet capturing should be disabled.
> > + * users should pass on value UINT16_MAX to disable packet capturing on all
> > + * queues of a given device id.
> > + * @param flags
> > + * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
> > + * on which packet capturing should be enabled for a given port and queue.
> > + *
> > + * @return
> > + * 0 on success, -1 on error, rte_errno is set accordingly.
> > + */
> > +int
> > +rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
> > + uint32_t flags);
> > +
> > +#ifdef __cplusplus
> > +}
> > +#endif
> > +
> > +#endif /* _RTE_PDUMP_H_ */
> > diff --git a/lib/librte_pdump/rte_pdump_version.map
> > b/lib/librte_pdump/rte_pdump_version.map
> > new file mode 100644
> > index 0000000..3e744f3
> > --- /dev/null
> > +++ b/lib/librte_pdump/rte_pdump_version.map
> > @@ -0,0 +1,12 @@
> > +DPDK_16.07 {
> > + global:
> > +
> > + rte_pdump_disable;
> > + rte_pdump_disable_by_deviceid;
> > + rte_pdump_enable;
> > + rte_pdump_enable_by_deviceid;
> > + rte_pdump_init;
> > + rte_pdump_uninit;
> > +
> > + local: *;
> > +};
> > diff --git a/mk/rte.app.mk b/mk/rte.app.mk
> > index b84b56d..f792f2a 100644
> > --- a/mk/rte.app.mk
> > +++ b/mk/rte.app.mk
> > @@ -61,6 +61,7 @@ _LDLIBS-y += --whole-archive
> >
> > _LDLIBS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += -lrte_distributor
> > _LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER) += -lrte_reorder
> > +_LDLIBS-$(CONFIG_RTE_LIBRTE_PDUMP) += -lrte_pdump
> >
> > ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
> > _LDLIBS-$(CONFIG_RTE_LIBRTE_KNI) += -lrte_kni
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v6 5/8] lib/librte_pdump: add new library for packet capturing support
2016-06-09 16:05 ` Ananyev, Konstantin
@ 2016-06-09 17:23 ` Aaron Conole
2016-06-09 19:32 ` Ananyev, Konstantin
0 siblings, 1 reply; 82+ messages in thread
From: Aaron Conole @ 2016-06-09 17:23 UTC (permalink / raw)
To: Ananyev, Konstantin; +Cc: Pattan, Reshma, dev
"Ananyev, Konstantin" <konstantin.ananyev@intel.com> writes:
>> -----Original Message-----
>> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Aaron Conole
>> Sent: Thursday, June 09, 2016 4:59 PM
>> To: Pattan, Reshma
>> Cc: dev@dpdk.org
>> Subject: Re: [dpdk-dev] [PATCH v6 5/8] lib/librte_pdump: add new
> library for packet capturing support
>>
>> Reshma Pattan <reshma.pattan@intel.com> writes:
>>
>> > Added new library for packet capturing support.
>> >
>> > Added public api rte_pdump_init, applications should call
>> > this as part of their application setup to have packet
>> > capturing framework ready.
>> >
>> > Added public api rte_pdump_uninit to uninitialize the packet
>> > capturing framework.
>> >
>> > Added public apis rte_pdump_enable and rte_pdump_disable to
>> > enable and disable packet capturing on specific port and queue.
>> >
>> > Added public apis rte_pdump_enable_by_deviceid and
>> > rte_pdump_disable_by_deviceid to enable and disable packet
>> > capturing on a specific device (pci address or name) and queue.
>> >
>> > Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
>> > ---
>> > +
>> > +int
>> > +rte_pdump_init(void)
>>
>> Would you be opposed to having an argument here which takes a path to
>> the server socket? That way the application can have some control over
>> the server socket location rather than using the guesses from
>> pdump_get_socket_path.
>
> I suppose it is better to keep IPC mechanism details internal for the
> pdump library.
> That way upper layer don't need to know what is that and write the
> code to open/maintain it.
> Again, that gives pdump library a freedom to change it (if needed) or
> possibly introduce some alternatives.
> Konstantin
>
How does the application change it? The details do matter here, as some
applications (ex: openvswitch) have specific policies on which files
files get opened and where those files exist. That has impact on things
like selinux and other access control technology.
If I missed the API that lets apps redirect the output, please correct me,
but so far I don't think I've missed it. pdump still can change a
default, but it would be good to give a method for guiding the final
choice of file to open.
-Aaron
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v6 5/8] lib/librte_pdump: add new library for packet capturing support
2016-06-09 17:23 ` Aaron Conole
@ 2016-06-09 19:32 ` Ananyev, Konstantin
2016-06-09 19:56 ` Aaron Conole
0 siblings, 1 reply; 82+ messages in thread
From: Ananyev, Konstantin @ 2016-06-09 19:32 UTC (permalink / raw)
To: Aaron Conole; +Cc: Pattan, Reshma, dev
> -----Original Message-----
> From: Aaron Conole [mailto:aconole@redhat.com]
> Sent: Thursday, June 09, 2016 6:24 PM
> To: Ananyev, Konstantin
> Cc: Pattan, Reshma; dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v6 5/8] lib/librte_pdump: add new library for packet capturing support
>
> "Ananyev, Konstantin" <konstantin.ananyev@intel.com> writes:
>
> >> -----Original Message-----
> >> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Aaron Conole
> >> Sent: Thursday, June 09, 2016 4:59 PM
> >> To: Pattan, Reshma
> >> Cc: dev@dpdk.org
> >> Subject: Re: [dpdk-dev] [PATCH v6 5/8] lib/librte_pdump: add new
> > library for packet capturing support
> >>
> >> Reshma Pattan <reshma.pattan@intel.com> writes:
> >>
> >> > Added new library for packet capturing support.
> >> >
> >> > Added public api rte_pdump_init, applications should call
> >> > this as part of their application setup to have packet
> >> > capturing framework ready.
> >> >
> >> > Added public api rte_pdump_uninit to uninitialize the packet
> >> > capturing framework.
> >> >
> >> > Added public apis rte_pdump_enable and rte_pdump_disable to
> >> > enable and disable packet capturing on specific port and queue.
> >> >
> >> > Added public apis rte_pdump_enable_by_deviceid and
> >> > rte_pdump_disable_by_deviceid to enable and disable packet
> >> > capturing on a specific device (pci address or name) and queue.
> >> >
> >> > Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
> >> > ---
> >> > +
> >> > +int
> >> > +rte_pdump_init(void)
> >>
> >> Would you be opposed to having an argument here which takes a path to
> >> the server socket? That way the application can have some control over
> >> the server socket location rather than using the guesses from
> >> pdump_get_socket_path.
> >
> > I suppose it is better to keep IPC mechanism details internal for the
> > pdump library.
> > That way upper layer don't need to know what is that and write the
> > code to open/maintain it.
> > Again, that gives pdump library a freedom to change it (if needed) or
> > possibly introduce some alternatives.
> > Konstantin
> >
>
> How does the application change it? The details do matter here, as some
> applications (ex: openvswitch) have specific policies on which files
> files get opened and where those files exist. That has impact on things
> like selinux and other access control technology.
>
> If I missed the API that lets apps redirect the output, please correct me,
> but so far I don't think I've missed it. pdump still can change a
> default, but it would be good to give a method for guiding the final
> choice of file to open.
No, I think, right now it is not possible to change socket path from the API.
Basically it follows the same logic as generating path for DPDK runtime config, etc:
/var/run for root, or $HOME dir otherwise.
I suppose if openswitch or any other dpdk app is able to start successfully,
then it should be able to open pdump socket too, correct?
Anyway, as I understand what you suggest:
rte_pdump_init(const char *dir)
{
If (sock_name != NULL) {/*open socket at provided dir path*/}
else { /*generate default pathname for the socket*/
and something similar for client side, might be a new function:
rte_pdump_set_dirpath(const char *dir);
Is that right?
Konstantin
>
> -Aaron
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v6 5/8] lib/librte_pdump: add new library for packet capturing support
2016-06-09 19:32 ` Ananyev, Konstantin
@ 2016-06-09 19:56 ` Aaron Conole
0 siblings, 0 replies; 82+ messages in thread
From: Aaron Conole @ 2016-06-09 19:56 UTC (permalink / raw)
To: Ananyev, Konstantin; +Cc: Pattan, Reshma, dev
"Ananyev, Konstantin" <konstantin.ananyev@intel.com> writes:
>> -----Original Message-----
>> From: Aaron Conole [mailto:aconole@redhat.com]
>> Sent: Thursday, June 09, 2016 6:24 PM
>> To: Ananyev, Konstantin
>> Cc: Pattan, Reshma; dev@dpdk.org
>> Subject: Re: [dpdk-dev] [PATCH v6 5/8] lib/librte_pdump: add new
>> library for packet capturing support
>>
>> "Ananyev, Konstantin" <konstantin.ananyev@intel.com> writes:
>>
>> >> -----Original Message-----
>> >> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Aaron Conole
>> >> Sent: Thursday, June 09, 2016 4:59 PM
>> >> To: Pattan, Reshma
>> >> Cc: dev@dpdk.org
>> >> Subject: Re: [dpdk-dev] [PATCH v6 5/8] lib/librte_pdump: add new
>> > library for packet capturing support
>> >>
>> >> Reshma Pattan <reshma.pattan@intel.com> writes:
>> >>
>> >> > Added new library for packet capturing support.
>> >> >
>> >> > Added public api rte_pdump_init, applications should call
>> >> > this as part of their application setup to have packet
>> >> > capturing framework ready.
>> >> >
>> >> > Added public api rte_pdump_uninit to uninitialize the packet
>> >> > capturing framework.
>> >> >
>> >> > Added public apis rte_pdump_enable and rte_pdump_disable to
>> >> > enable and disable packet capturing on specific port and queue.
>> >> >
>> >> > Added public apis rte_pdump_enable_by_deviceid and
>> >> > rte_pdump_disable_by_deviceid to enable and disable packet
>> >> > capturing on a specific device (pci address or name) and queue.
>> >> >
>> >> > Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
>> >> > ---
>> >> > +
>> >> > +int
>> >> > +rte_pdump_init(void)
>> >>
>> >> Would you be opposed to having an argument here which takes a path to
>> >> the server socket? That way the application can have some control over
>> >> the server socket location rather than using the guesses from
>> >> pdump_get_socket_path.
>> >
>> > I suppose it is better to keep IPC mechanism details internal for the
>> > pdump library.
>> > That way upper layer don't need to know what is that and write the
>> > code to open/maintain it.
>> > Again, that gives pdump library a freedom to change it (if needed) or
>> > possibly introduce some alternatives.
>> > Konstantin
>> >
>>
>> How does the application change it? The details do matter here, as some
>> applications (ex: openvswitch) have specific policies on which files
>> files get opened and where those files exist. That has impact on things
>> like selinux and other access control technology.
>>
>> If I missed the API that lets apps redirect the output, please correct me,
>> but so far I don't think I've missed it. pdump still can change a
>> default, but it would be good to give a method for guiding the final
>> choice of file to open.
>
> No, I think, right now it is not possible to change socket path from the API.
> Basically it follows the same logic as generating path for DPDK
> runtime config, etc:
> /var/run for root, or $HOME dir otherwise.
> I suppose if openswitch or any other dpdk app is able to start successfully,
> then it should be able to open pdump socket too, correct?
>
> Anyway, as I understand what you suggest:
>
> rte_pdump_init(const char *dir)
> {
> If (sock_name != NULL) {/*open socket at provided dir path*/}
> else { /*generate default pathname for the socket*/
>
> and something similar for client side, might be a new function:
>
> rte_pdump_set_dirpath(const char *dir);
>
> Is that right?
Something like that, yes.
> Konstantin
>
>>
>> -Aaron
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v6 5/8] lib/librte_pdump: add new library for packet capturing support
2016-06-09 15:59 ` Aaron Conole
2016-06-09 16:05 ` Ananyev, Konstantin
@ 2016-06-10 16:22 ` Pattan, Reshma
1 sibling, 0 replies; 82+ messages in thread
From: Pattan, Reshma @ 2016-06-10 16:22 UTC (permalink / raw)
To: Aaron Conole; +Cc: dev
Hi,
> -----Original Message-----
> From: Aaron Conole [mailto:aconole@redhat.com]
> Sent: Thursday, June 9, 2016 4:59 PM
> To: Pattan, Reshma <reshma.pattan@intel.com>
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v6 5/8] lib/librte_pdump: add new library for
> packet capturing support
>
> > +
> > +int
> > +rte_pdump_init(void)
>
> Would you be opposed to having an argument here which takes a path to the
> server socket? That way the application can have some control over the server
> socket location rather than using the guesses from pdump_get_socket_path.
>
This is fixed in v8 patch set.
Thanks,
Reshma
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v6 6/8] app/pdump: add pdump tool for packet capturing
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 0/8] add packet capture framework Reshma Pattan
` (4 preceding siblings ...)
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 5/8] lib/librte_pdump: add new library for packet capturing support Reshma Pattan
@ 2016-06-09 8:50 ` Reshma Pattan
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 7/8] app/test-pmd: add pdump initialization uninitialization Reshma Pattan
` (2 subsequent siblings)
8 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-09 8:50 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
New tool added for packet capturing on dpdk.
This tool supports command line options.
This tool runs as secondary process by default.
Command line supports various parameters to capture
the packets.
User should pass on a)port and queue (or) b)pci address
and queue (or) c)device name and queue to capture
the packets.
Users also need to pass on either pcap file name or
any linux iface, on to which packets captured from dpdk
ports will be sent on for the users to view using tcpdump.
Users have option to capture packets either a) in RX
direction, b)(or) in TX direction c)(or) from both the
directions.
User can pass on ring_size and mempool parameters using
command line, but these are optional parameters.
These are used to create ring and mempool objects for packet
mirroring from primary application to tool. If user doesn't
provide any values, default values will be used internally
for the creation of the ring and mempool.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
MAINTAINERS | 1 +
app/Makefile | 1 +
app/pdump/Makefile | 45 +++
app/pdump/main.c | 814 +++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 861 insertions(+)
create mode 100644 app/pdump/Makefile
create mode 100644 app/pdump/main.c
diff --git a/MAINTAINERS b/MAINTAINERS
index cc3ffdb..a48c8de 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -435,6 +435,7 @@ F: doc/guides/sample_app_ug/packet_ordering.rst
Pdump
M: Reshma Pattan <reshma.pattan@intel.com>
F: lib/librte_pdump/
+F: app/pdump/
Hierarchical scheduler
M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
diff --git a/app/Makefile b/app/Makefile
index 1151e09..c593efa 100644
--- a/app/Makefile
+++ b/app/Makefile
@@ -37,5 +37,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += test-pipeline
DIRS-$(CONFIG_RTE_TEST_PMD) += test-pmd
DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_test
DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += proc_info
+DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += pdump
include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/app/pdump/Makefile b/app/pdump/Makefile
new file mode 100644
index 0000000..96bb4af
--- /dev/null
+++ b/app/pdump/Makefile
@@ -0,0 +1,45 @@
+# 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_SDK)/mk/rte.vars.mk
+
+APP = dpdk_pdump
+
+CFLAGS += $(WERROR_FLAGS)
+
+# all source are stored in SRCS-y
+
+SRCS-y := main.c
+
+# this application needs libraries first
+DEPDIRS-y += lib
+
+include $(RTE_SDK)/mk/rte.app.mk
diff --git a/app/pdump/main.c b/app/pdump/main.c
new file mode 100644
index 0000000..a4a5ca2
--- /dev/null
+++ b/app/pdump/main.c
@@ -0,0 +1,814 @@
+/*
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <net/if.h>
+
+#include <rte_eal.h>
+#include <rte_common.h>
+#include <rte_debug.h>
+#include <rte_ethdev.h>
+#include <rte_memory.h>
+#include <rte_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_errno.h>
+#include <rte_dev.h>
+#include <rte_kvargs.h>
+#include <rte_mempool.h>
+#include <rte_ring.h>
+#include <rte_pdump.h>
+
+#define PDUMP_PORT_ARG "port"
+#define PDUMP_PCI_ARG "device_id"
+#define PDUMP_QUEUE_ARG "queue"
+#define PDUMP_DIR_ARG "dir"
+#define PDUMP_RX_DEV_ARG "rx-dev"
+#define PDUMP_TX_DEV_ARG "tx-dev"
+#define PDUMP_RING_SIZE_ARG "ring-size"
+#define PDUMP_MSIZE_ARG "mbuf-size"
+#define PDUMP_NUM_MBUFS_ARG "total-num-mbufs"
+
+#define VDEV_PCAP "eth_pcap_%s_%d,tx_pcap=%s"
+#define VDEV_IFACE "eth_pcap_%s_%d,tx_iface=%s"
+#define TX_STREAM_SIZE 64
+
+#define MP_NAME "pdump_pool_%d"
+
+#define RX_RING "rx_ring_%d"
+#define TX_RING "tx_ring_%d"
+
+#define RX_STR "rx"
+#define TX_STR "tx"
+
+/* Maximum long option length for option parsing. */
+#define APP_ARG_TCPDUMP_MAX_TUPLES 54
+#define MBUF_POOL_CACHE_SIZE 250
+#define TX_DESC_PER_QUEUE 512
+#define RX_DESC_PER_QUEUE 128
+#define MBUFS_PER_POOL 65535
+#define MAX_LONG_OPT_SZ 64
+#define RING_SIZE 16384
+#define SIZE 256
+#define BURST_SIZE 32
+#define NUM_VDEVS 2
+
+#define RTE_RING_SZ_MASK (unsigned)(0x0fffffff) /**< Ring size mask */
+/* true if x is a power of 2 */
+#define POWEROF2(x) ((((x)-1) & (x)) == 0)
+
+enum pdump_en_dis {
+ DISABLE = 1,
+ ENABLE = 2
+};
+
+enum pcap_stream {
+ IFACE = 1,
+ PCAP = 2
+};
+
+enum pdump_by {
+ PORT_ID = 1,
+ DEVICE_ID = 2
+};
+
+const char *valid_pdump_arguments[] = {
+ PDUMP_PORT_ARG,
+ PDUMP_PCI_ARG,
+ PDUMP_QUEUE_ARG,
+ PDUMP_DIR_ARG,
+ PDUMP_RX_DEV_ARG,
+ PDUMP_TX_DEV_ARG,
+ PDUMP_RING_SIZE_ARG,
+ PDUMP_MSIZE_ARG,
+ PDUMP_NUM_MBUFS_ARG,
+ NULL
+};
+
+struct pdump_stats {
+ uint64_t dequeue_pkts;
+ uint64_t tx_pkts;
+ uint64_t freed_pkts;
+};
+
+struct pdump_tuples {
+ /* cli params */
+ uint8_t port;
+ char *device_id;
+ uint16_t queue;
+ char rx_dev[TX_STREAM_SIZE];
+ char tx_dev[TX_STREAM_SIZE];
+ uint32_t ring_size;
+ uint16_t mbuf_data_size;
+ uint32_t total_num_mbufs;
+
+ /* params for library API call */
+ uint32_t dir;
+ struct rte_mempool *mp;
+ struct rte_ring *rx_ring;
+ struct rte_ring *tx_ring;
+
+ /* params for packet dumping */
+ enum pdump_by dump_by_type;
+ int rx_vdev_id;
+ int tx_vdev_id;
+ enum pcap_stream rx_vdev_stream_type;
+ enum pcap_stream tx_vdev_stream_type;
+ bool single_pdump_dev;
+
+ /* stats */
+ struct pdump_stats stats;
+} __rte_cache_aligned;
+static struct pdump_tuples pdump_t[APP_ARG_TCPDUMP_MAX_TUPLES];
+
+struct parse_val {
+ uint64_t min;
+ uint64_t max;
+ uint64_t val;
+};
+
+int num_tuples;
+static struct rte_eth_conf port_conf_default;
+volatile uint8_t quit_signal;
+
+/**< display usage */
+static void
+pdump_usage(const char *prgname)
+{
+ printf("usage: %s [EAL options] -- --pdump "
+ "'(port=<port id> | device_id=<pci id or vdev name>),"
+ "(queue=<queue_id>),"
+ "(rx-dev=<iface or pcap file> |"
+ " tx-dev=<iface or pcap file>,"
+ "[ring-size=<ring size>default:16384],"
+ "[mbuf-size=<mbuf data size>default:2176],"
+ "[total-num-mbufs=<number of mbufs>default:65535]"
+ "'\n",
+ prgname);
+}
+
+static int
+parse_device_id(const char *key __rte_unused, const char *value, void *extra_args)
+{
+ struct pdump_tuples *pt = extra_args;
+
+ pt->device_id = strdup(value);
+ pt->dump_by_type = DEVICE_ID;
+
+ return 0;
+}
+
+static int
+parse_queue(const char *key __rte_unused, const char *value, void *extra_args)
+{
+ unsigned long n;
+ struct pdump_tuples *pt = extra_args;
+
+ if (!strcmp(value, "*"))
+ pt->queue = RTE_PDUMP_ALL_QUEUES;
+ else {
+ n = strtoul(value, NULL, 10);
+ pt->queue = (uint16_t) n;
+ }
+ return 0;
+}
+
+static int
+parse_rxtxdev(const char *key, const char *value, void *extra_args)
+{
+
+ struct pdump_tuples *pt = extra_args;
+
+ if (!strcmp(key, PDUMP_RX_DEV_ARG)) {
+ strncpy(pt->rx_dev, value, strlen(value));
+ /* identify the tx stream type for pcap vdev */
+ if (if_nametoindex(pt->rx_dev))
+ pt->rx_vdev_stream_type = IFACE;
+ } else if (!strcmp(key, PDUMP_TX_DEV_ARG)) {
+ strncpy(pt->tx_dev, value, strlen(value));
+ /* identify the tx stream type for pcap vdev */
+ if (if_nametoindex(pt->tx_dev))
+ pt->tx_vdev_stream_type = IFACE;
+ } else {
+ printf("invalid dev type %s, must be rx or tx\n", value);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+parse_uint_value(const char *key, const char *value, void *extra_args)
+{
+ struct parse_val *v;
+ unsigned long t;
+ char *end;
+ int ret = 0;
+
+ errno = 0;
+ v = extra_args;
+ t = strtoul(value, &end, 10);
+
+ if (errno != 0 || end[0] != 0 || t < v->min || t > v->max) {
+ printf("invalid value:\"%s\" for key:\"%s\", "
+ "value must be >= %"PRIu64" and <= %"PRIu64"\n",
+ value, key, v->min, v->max);
+ ret = -EINVAL;
+ }
+ if (!strcmp(key, PDUMP_RING_SIZE_ARG) && !POWEROF2(t)) {
+ printf("invalid value:\"%s\" for key:\"%s\", value must be power of 2\n",
+ value, key);
+ ret = -EINVAL;
+ }
+
+ if (ret != 0)
+ return ret;
+
+ v->val = t;
+ return 0;
+}
+
+static int
+parse_pdump(const char *optarg)
+{
+ struct rte_kvargs *kvlist;
+ int ret = 0, cnt1, cnt2;
+ struct pdump_tuples *pt;
+ struct parse_val v = {0};
+
+ pt = &pdump_t[num_tuples];
+
+ /* initial check for invalid arguments */
+ kvlist = rte_kvargs_parse(optarg, valid_pdump_arguments);
+ if (kvlist == NULL) {
+ printf("--pdump=\"%s\": invalid argument passed\n", optarg);
+ return -1;
+ }
+
+ /* port/device_id parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_PORT_ARG);
+ cnt2 = rte_kvargs_count(kvlist, PDUMP_PCI_ARG);
+ if (!((cnt1 == 1 && cnt2 == 0) || (cnt1 == 0 && cnt2 == 1))) {
+ printf("--pdump=\"%s\": must have either port or device_id argument\n",
+ optarg);
+ ret = -1;
+ goto free_kvlist;
+ } else if (cnt1 == 1) {
+ v.min = 0;
+ v.max = RTE_MAX_ETHPORTS-1;
+ ret = rte_kvargs_process(kvlist, PDUMP_PORT_ARG,
+ &parse_uint_value, &v);
+ if (ret < 0)
+ goto free_kvlist;
+ pt->port = (uint8_t) v.val;
+ pt->dump_by_type = PORT_ID;
+ } else if (cnt2 == 1) {
+ ret = rte_kvargs_process(kvlist, PDUMP_PCI_ARG,
+ &parse_device_id, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ }
+
+ /* queue parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_QUEUE_ARG);
+ if (cnt1 != 1) {
+ printf("--pdump=\"%s\": must have queue argument\n", optarg);
+ ret = -1;
+ goto free_kvlist;
+ }
+ ret = rte_kvargs_process(kvlist, PDUMP_QUEUE_ARG, &parse_queue, pt);
+ if (ret < 0)
+ goto free_kvlist;
+
+ /* rx-dev and tx-dev parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_RX_DEV_ARG);
+ cnt2 = rte_kvargs_count(kvlist, PDUMP_TX_DEV_ARG);
+ if (cnt1 == 0 && cnt2 == 0) {
+ printf("--pdump=\"%s\": must have either rx-dev or tx-dev argument\n",
+ optarg);
+ ret = -1;
+ goto free_kvlist;
+ } else if (cnt1 == 1 && cnt2 == 1) {
+ ret = rte_kvargs_process(kvlist, PDUMP_RX_DEV_ARG, &parse_rxtxdev, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ ret = rte_kvargs_process(kvlist, PDUMP_TX_DEV_ARG, &parse_rxtxdev, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ /* if captured packets has to send to the same vdev */
+ if (!strcmp(pt->rx_dev, pt->tx_dev))
+ pt->single_pdump_dev = true;
+ pt->dir = RTE_PDUMP_FLAG_RXTX;
+ } else if (cnt1 == 1) {
+ ret = rte_kvargs_process(kvlist, PDUMP_RX_DEV_ARG, &parse_rxtxdev, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ pt->dir = RTE_PDUMP_FLAG_RX;
+ } else if (cnt2 == 1) {
+ ret = rte_kvargs_process(kvlist, PDUMP_TX_DEV_ARG, &parse_rxtxdev, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ pt->dir = RTE_PDUMP_FLAG_TX;
+ }
+
+ /* optional */
+ /* ring_size parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_RING_SIZE_ARG);
+ if (cnt1 == 1) {
+ v.min = 2;
+ v.max = RTE_RING_SZ_MASK-1;
+ ret = rte_kvargs_process(kvlist, PDUMP_RING_SIZE_ARG,
+ &parse_uint_value, &v);
+ if (ret < 0)
+ goto free_kvlist;
+ pt->ring_size = (uint16_t) v.val;
+ } else
+ pt->ring_size = RING_SIZE;
+
+ /* mbuf_data_size parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_MSIZE_ARG);
+ if (cnt1 == 1) {
+ v.min = 1;
+ v.max = UINT16_MAX;
+ ret = rte_kvargs_process(kvlist, PDUMP_MSIZE_ARG,
+ &parse_uint_value, &v);
+ if (ret < 0)
+ goto free_kvlist;
+ pt->mbuf_data_size = (uint16_t) v.val;
+ } else
+ pt->mbuf_data_size = RTE_MBUF_DEFAULT_BUF_SIZE;
+
+ /* total_num_mbufs parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_NUM_MBUFS_ARG);
+ if (cnt1 == 1) {
+ v.min = 1025;
+ v.max = UINT16_MAX;
+ ret = rte_kvargs_process(kvlist, PDUMP_NUM_MBUFS_ARG,
+ &parse_uint_value, &v);
+ if (ret < 0)
+ goto free_kvlist;
+ pt->total_num_mbufs = (uint16_t) v.val;
+ } else
+ pt->total_num_mbufs = MBUFS_PER_POOL;
+
+ num_tuples++;
+
+free_kvlist:
+ rte_kvargs_free(kvlist);
+ return ret;
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+launch_args_parse(int argc, char **argv, char *prgname)
+{
+ int opt, ret;
+ int option_index;
+ static struct option long_option[] = {
+ {"pdump", 1, 0, 0},
+ {NULL, 0, 0, 0}
+ };
+
+ if (argc == 1)
+ pdump_usage(prgname);
+
+ /* Parse command line */
+ while ((opt = getopt_long(argc, argv, " ",
+ long_option, &option_index)) != EOF) {
+ switch (opt) {
+ case 0:
+ if (!strncmp(long_option[option_index].name, "pdump",
+ MAX_LONG_OPT_SZ)) {
+ ret = parse_pdump(optarg);
+ if (ret) {
+ pdump_usage(prgname);
+ return -1;
+ }
+ }
+ break;
+ default:
+ pdump_usage(prgname);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static void
+print_pdump_stats(void)
+{
+ int i;
+ struct pdump_tuples *pt;
+
+ for (i = 0; i < num_tuples; i++) {
+ printf("##### PDUMP DEBUG STATS #####\n");
+ pt = &pdump_t[i];
+ printf(" -packets dequeued: %"PRIu64"\n",
+ pt->stats.dequeue_pkts);
+ printf(" -packets transmitted to vdev: %"PRIu64"\n",
+ pt->stats.tx_pkts);
+ printf(" -packets freed: %"PRIu64"\n",
+ pt->stats.freed_pkts);
+ }
+}
+
+static inline void
+disable_pdump(struct pdump_tuples *pt)
+{
+ if (pt->dump_by_type == DEVICE_ID)
+ rte_pdump_disable_by_deviceid(pt->device_id, pt->queue, pt->dir);
+ else if (pt->dump_by_type == PORT_ID)
+ rte_pdump_disable(pt->port, pt->queue, pt->dir);
+}
+
+static inline void
+pdump_rxtx(struct rte_ring *ring, uint8_t vdev_id, struct pdump_stats *stats)
+{
+ /* write input packets of port to vdev for pdump */
+ struct rte_mbuf *rxtx_bufs[BURST_SIZE];
+
+ /* first dequeue packets from ring of primary process */
+ const uint16_t nb_in_deq = rte_ring_dequeue_burst(ring,
+ (void *)rxtx_bufs, BURST_SIZE);
+ stats->dequeue_pkts += nb_in_deq;
+
+ if (nb_in_deq) {
+ /* then sent on vdev */
+ uint16_t nb_in_txd = rte_eth_tx_burst(
+ vdev_id,
+ 0, rxtx_bufs, nb_in_deq);
+ stats->tx_pkts += nb_in_txd;
+
+ if (unlikely(nb_in_txd < nb_in_deq)) {
+ do {
+ rte_pktmbuf_free(rxtx_bufs[nb_in_txd]);
+ stats->freed_pkts++;
+ } while (++nb_in_txd < nb_in_deq);
+ }
+ }
+}
+
+static void
+free_ring_data(struct rte_ring *ring, uint8_t vdev_id, struct pdump_stats *stats)
+{
+ while (rte_ring_count(ring))
+ pdump_rxtx(ring, vdev_id, stats);
+}
+
+static void
+cleanup_pdump_resources(void)
+{
+ int i;
+ struct pdump_tuples *pt;
+
+ /* disable pdump and free the pdump_tuple resources */
+ for (i = 0; i < num_tuples; i++) {
+ pt = &pdump_t[i];
+
+ /* remove callbacks */
+ disable_pdump(pt);
+
+ /*
+ * transmit rest of the enqueued packets of the rings on to the vdev,
+ * in order to release mbufs to the mepool.
+ **/
+ if (pt->dir & RTE_PDUMP_FLAG_RX)
+ free_ring_data(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
+ if (pt->dir & RTE_PDUMP_FLAG_TX)
+ free_ring_data(pt->tx_ring, pt->tx_vdev_id, &pt->stats);
+
+ if (pt->device_id)
+ free(pt->device_id);
+
+ /* free the rings */
+ if (pt->rx_ring)
+ rte_ring_free(pt->rx_ring);
+ if (pt->tx_ring)
+ rte_ring_free(pt->tx_ring);
+ }
+}
+
+static void
+signal_handler(int sig_num)
+{
+ if (sig_num == SIGINT) {
+ printf("\n\nSignal %d received, preparing to exit...\n",
+ sig_num);
+ quit_signal = 1;
+ }
+}
+
+static inline int
+configure_vdev(uint8_t port_id)
+{
+ struct ether_addr addr;
+ const uint16_t rxRings = 0, txRings = 1;
+ const uint8_t nb_ports = rte_eth_dev_count();
+ int ret;
+ uint16_t q;
+
+ if (port_id > nb_ports)
+ return -1;
+
+ ret = rte_eth_dev_configure(port_id, rxRings, txRings, &port_conf_default);
+ if (ret != 0)
+ rte_exit(EXIT_FAILURE, "dev config failed\n");
+
+ for (q = 0; q < txRings; q++) {
+ ret = rte_eth_tx_queue_setup(port_id, q, TX_DESC_PER_QUEUE,
+ rte_eth_dev_socket_id(port_id), NULL);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "queue setup failed\n");
+ }
+
+ ret = rte_eth_dev_start(port_id);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "dev start failed\n");
+
+ rte_eth_macaddr_get(port_id, &addr);
+ printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
+ " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
+ (unsigned)port_id,
+ addr.addr_bytes[0], addr.addr_bytes[1],
+ addr.addr_bytes[2], addr.addr_bytes[3],
+ addr.addr_bytes[4], addr.addr_bytes[5]);
+
+ rte_eth_promiscuous_enable(port_id);
+
+ return 0;
+}
+
+static void
+create_mp_ring_vdev(void)
+{
+ int i;
+ uint8_t portid;
+ struct pdump_tuples *pt = NULL;
+ struct rte_mempool *mbuf_pool = NULL;
+ char vdev_args[SIZE];
+ char ring_name[SIZE];
+ char mempool_name[SIZE];
+
+ for (i = 0; i < num_tuples; i++) {
+ pt = &pdump_t[i];
+ snprintf(mempool_name, SIZE, MP_NAME, i);
+ mbuf_pool = rte_mempool_lookup(mempool_name);
+ if (mbuf_pool == NULL) {
+ /* create mempool */
+ mbuf_pool = rte_pktmbuf_pool_create(mempool_name,
+ pt->total_num_mbufs,
+ MBUF_POOL_CACHE_SIZE, 0, pt->mbuf_data_size,
+ rte_socket_id());
+ if (mbuf_pool == NULL)
+ rte_exit(EXIT_FAILURE, "Mempool creation failed: %s\n",
+ rte_strerror(rte_errno));
+ }
+ pt->mp = mbuf_pool;
+
+ if (pt->dir == RTE_PDUMP_FLAG_RXTX) {
+ /* if captured packets has to send to the same vdev */
+ /* create rx_ring */
+ snprintf(ring_name, SIZE, RX_RING, i);
+ pt->rx_ring = rte_ring_create(ring_name, pt->ring_size,
+ rte_socket_id(), 0);
+ if (pt->rx_ring == NULL)
+ rte_exit(EXIT_FAILURE, "%s:%s:%d\n",
+ rte_strerror(rte_errno),
+ __func__, __LINE__);
+
+ /* create tx_ring */
+ snprintf(ring_name, SIZE, TX_RING, i);
+ pt->tx_ring = rte_ring_create(ring_name, pt->ring_size,
+ rte_socket_id(), 0);
+ if (pt->tx_ring == NULL)
+ rte_exit(EXIT_FAILURE, "%s:%s:%d\n",
+ rte_strerror(rte_errno),
+ __func__, __LINE__);
+
+ /* create vdevs */
+ (pt->rx_vdev_stream_type == IFACE) ? snprintf(vdev_args, SIZE,
+ VDEV_IFACE, RX_STR, i, pt->rx_dev) : snprintf(vdev_args, SIZE,
+ VDEV_PCAP, RX_STR, i, pt->rx_dev);
+ if (rte_eth_dev_attach(vdev_args, &portid) < 0)
+ rte_exit(EXIT_FAILURE, "vdev creation failed:%s:%d\n",
+ __func__, __LINE__);
+ pt->rx_vdev_id = portid;
+
+ /* configure vdev */
+ configure_vdev(pt->rx_vdev_id);
+
+ if (pt->single_pdump_dev)
+ pt->tx_vdev_id = portid;
+ else {
+ (pt->tx_vdev_stream_type == IFACE) ?
+ snprintf(vdev_args, SIZE, VDEV_IFACE, TX_STR, i,
+ pt->tx_dev) :
+ snprintf(vdev_args, SIZE, VDEV_PCAP, TX_STR, i,
+ pt->tx_dev);
+ if (rte_eth_dev_attach(vdev_args, &portid) < 0)
+ rte_exit(EXIT_FAILURE, "vdev creation failed:"
+ "%s:%d\n", __func__, __LINE__);
+ pt->tx_vdev_id = portid;
+
+ /* configure vdev */
+ configure_vdev(pt->tx_vdev_id);
+ }
+ } else if (pt->dir == RTE_PDUMP_FLAG_RX) {
+
+ /* create rx_ring */
+ snprintf(ring_name, SIZE, RX_RING, i);
+ pt->rx_ring = rte_ring_create(ring_name, pt->ring_size,
+ rte_socket_id(), 0);
+ if (pt->rx_ring == NULL)
+ rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno));
+
+ (pt->rx_vdev_stream_type == IFACE) ?
+ snprintf(vdev_args, SIZE, VDEV_IFACE, RX_STR, i, pt->rx_dev) :
+ snprintf(vdev_args, SIZE, VDEV_PCAP, RX_STR, i, pt->rx_dev);
+ if (rte_eth_dev_attach(vdev_args, &portid) < 0)
+ rte_exit(EXIT_FAILURE, "vdev creation failed:%s:%d\n",
+ __func__, __LINE__);
+ pt->rx_vdev_id = portid;
+ /* configure vdev */
+ configure_vdev(pt->rx_vdev_id);
+ } else if (pt->dir == RTE_PDUMP_FLAG_TX) {
+
+ /* create tx_ring */
+ snprintf(ring_name, SIZE, TX_RING, i);
+ pt->tx_ring = rte_ring_create(ring_name, pt->ring_size,
+ rte_socket_id(), 0);
+ if (pt->tx_ring == NULL)
+ rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno));
+
+ (pt->tx_vdev_stream_type == IFACE) ?
+ snprintf(vdev_args, SIZE, VDEV_IFACE, TX_STR, i, pt->tx_dev) :
+ snprintf(vdev_args, SIZE, VDEV_PCAP, TX_STR, i, pt->tx_dev);
+ if (rte_eth_dev_attach(vdev_args, &portid) < 0)
+ rte_exit(EXIT_FAILURE, "vdev creation failed\n");
+ pt->tx_vdev_id = portid;
+
+ /* configure vdev */
+ configure_vdev(pt->tx_vdev_id);
+ }
+ }
+}
+
+static void
+enable_pdump(void)
+{
+ int i;
+ struct pdump_tuples *pt;
+ int ret = 0, ret1 = 0;
+
+ for (i = 0; i < num_tuples; i++) {
+ pt = &pdump_t[i];
+ if (pt->dir == RTE_PDUMP_FLAG_RXTX) {
+ if (pt->dump_by_type == DEVICE_ID) {
+ ret = rte_pdump_enable_by_deviceid(pt->device_id,
+ pt->queue,
+ RTE_PDUMP_FLAG_RX,
+ pt->rx_ring,
+ pt->mp, NULL);
+ ret = rte_pdump_enable_by_deviceid(pt->device_id,
+ pt->queue,
+ RTE_PDUMP_FLAG_TX,
+ pt->tx_ring,
+ pt->mp, NULL);
+ } else if (pt->dump_by_type == PORT_ID) {
+ ret = rte_pdump_enable(pt->port, pt->queue,
+ RTE_PDUMP_FLAG_RX,
+ pt->rx_ring, pt->mp, NULL);
+ ret1 = rte_pdump_enable(pt->port, pt->queue,
+ RTE_PDUMP_FLAG_TX,
+ pt->tx_ring, pt->mp, NULL);
+ }
+ } else if (pt->dir == RTE_PDUMP_FLAG_RX) {
+ if (pt->dump_by_type == DEVICE_ID)
+ ret = rte_pdump_enable_by_deviceid(pt->device_id,
+ pt->queue,
+ pt->dir, pt->rx_ring,
+ pt->mp, NULL);
+ else if (pt->dump_by_type == PORT_ID)
+ ret = rte_pdump_enable(pt->port, pt->queue, pt->dir,
+ pt->rx_ring, pt->mp, NULL);
+ } else if (pt->dir == RTE_PDUMP_FLAG_TX) {
+ if (pt->dump_by_type == DEVICE_ID)
+ ret = rte_pdump_enable_by_deviceid(pt->device_id,
+ pt->queue,
+ pt->dir,
+ pt->tx_ring, pt->mp, NULL);
+ else if (pt->dump_by_type == PORT_ID)
+ ret = rte_pdump_enable(pt->port, pt->queue, pt->dir,
+ pt->tx_ring, pt->mp, NULL);
+ }
+ if (ret < 0 || ret1 < 0) {
+ cleanup_pdump_resources();
+ rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno));
+ }
+ }
+}
+
+static inline void
+dump_packets(void)
+{
+ int i;
+ struct pdump_tuples *pt;
+
+ while (!quit_signal) {
+ for (i = 0; i < num_tuples; i++) {
+ pt = &pdump_t[i];
+ if (pt->dir & RTE_PDUMP_FLAG_RX)
+ pdump_rxtx(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
+ if (pt->dir & RTE_PDUMP_FLAG_TX)
+ pdump_rxtx(pt->tx_ring, pt->tx_vdev_id, &pt->stats);
+ }
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ int diag;
+ int ret;
+ int i;
+
+ char c_flag[] = "-c1";
+ char n_flag[] = "-n4";
+ char mp_flag[] = "--proc-type=secondary";
+ char *argp[argc + 3];
+
+ /* catch ctrl-c so we can print on exit */
+ signal(SIGINT, signal_handler);
+
+ argp[0] = argv[0];
+ argp[1] = c_flag;
+ argp[2] = n_flag;
+ argp[3] = mp_flag;
+
+ for (i = 1; i < argc; i++)
+ argp[i + 3] = argv[i];
+
+ argc += 3;
+
+ diag = rte_eal_init(argc, argp);
+ if (diag < 0)
+ rte_panic("Cannot init EAL\n");
+
+ argc -= diag;
+ argv += (diag - 3);
+
+ /* parse app arguments */
+ if (argc > 1) {
+ ret = launch_args_parse(argc, argv, argp[0]);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Invalid argument\n");
+ }
+
+ /* create mempool, ring and vdevs info */
+ create_mp_ring_vdev();
+ enable_pdump();
+ dump_packets();
+
+ cleanup_pdump_resources();
+ /* dump debug stats */
+ print_pdump_stats();
+
+ return 0;
+}
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v6 7/8] app/test-pmd: add pdump initialization uninitialization
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 0/8] add packet capture framework Reshma Pattan
` (5 preceding siblings ...)
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 6/8] app/pdump: add pdump tool for packet capturing Reshma Pattan
@ 2016-06-09 8:50 ` Reshma Pattan
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 8/8] doc: update doc for packet capture framework Reshma Pattan
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 0/8] add " Reshma Pattan
8 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-09 8:50 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Call rte_pdump_init and rte_pdump_uninit for packet
capturing initialization and uninitialization.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
app/test-pmd/testpmd.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index dd6b046..f6089fa 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -76,6 +76,7 @@
#ifdef RTE_LIBRTE_PMD_XENVIRT
#include <rte_eth_xenvirt.h>
#endif
+#include <rte_pdump.h>
#include "testpmd.h"
@@ -2029,6 +2030,8 @@ signal_handler(int signum)
if (signum == SIGINT || signum == SIGTERM) {
printf("\nSignal %d received, preparing to exit...\n",
signum);
+ /* uninitialize packet capture framework */
+ rte_pdump_uninit();
force_quit();
/* exit with the expected status */
signal(signum, SIG_DFL);
@@ -2049,6 +2052,9 @@ main(int argc, char** argv)
if (diag < 0)
rte_panic("Cannot init EAL\n");
+ /* initialize packet capture framework */
+ rte_pdump_init();
+
nb_ports = (portid_t) rte_eth_dev_count();
if (nb_ports == 0)
RTE_LOG(WARNING, EAL, "No probed ethernet devices\n");
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v6 8/8] doc: update doc for packet capture framework
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 0/8] add packet capture framework Reshma Pattan
` (6 preceding siblings ...)
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 7/8] app/test-pmd: add pdump initialization uninitialization Reshma Pattan
@ 2016-06-09 8:50 ` Reshma Pattan
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 0/8] add " Reshma Pattan
8 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-09 8:50 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Added programmers guide for librte_pdump.
Added sample application guide for app/pdump application.
Updated release note for packet capture framework changes.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
Acked-by: John McNamara <john.mcnamara@intel.com>
---
MAINTAINERS | 3 +
doc/guides/prog_guide/index.rst | 1 +
doc/guides/prog_guide/pdump_library.rst | 107 ++++++++++++++++++++++++++++
doc/guides/rel_notes/release_16_07.rst | 13 ++++
doc/guides/sample_app_ug/index.rst | 1 +
doc/guides/sample_app_ug/pdump.rst | 122 ++++++++++++++++++++++++++++++++
6 files changed, 247 insertions(+)
create mode 100644 doc/guides/prog_guide/pdump_library.rst
create mode 100644 doc/guides/sample_app_ug/pdump.rst
diff --git a/MAINTAINERS b/MAINTAINERS
index a48c8de..ce7c941 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -436,6 +436,9 @@ Pdump
M: Reshma Pattan <reshma.pattan@intel.com>
F: lib/librte_pdump/
F: app/pdump/
+F: doc/guides/prog_guide/pdump_library.rst
+F: doc/guides/sample_app_ug/pdump.rst
+
Hierarchical scheduler
M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
index b862d0c..4caf969 100644
--- a/doc/guides/prog_guide/index.rst
+++ b/doc/guides/prog_guide/index.rst
@@ -71,6 +71,7 @@ Programmer's Guide
writing_efficient_code
profile_app
glossary
+ pdump_library
**Figures**
diff --git a/doc/guides/prog_guide/pdump_library.rst b/doc/guides/prog_guide/pdump_library.rst
new file mode 100644
index 0000000..1809234
--- /dev/null
+++ b/doc/guides/prog_guide/pdump_library.rst
@@ -0,0 +1,107 @@
+.. 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.
+
+.. _pdump_library:
+
+The librte_pdump Library
+========================
+
+The ``librte_pdump`` library provides a framework for packet capturing in DPDK.
+The library provides the following APIs to initialize the packet capture framework, to enable
+or disable the packet capture, and to uninitialize it:
+
+* ``rte_pdump_init()``:
+ This API initializes the packet capture framework.
+
+* ``rte_pdump_enable()``:
+ This API enables the packet capture on a given port and queue.
+ Note: The filter option in the API is a place holder for future enhancements.
+
+* ``rte_pdump_enable_by_deviceid()``:
+ This API enables the packet capture on a given device id (``vdev name or pci address``) and queue.
+ Note: The filter option in the API is a place holder for future enhancements.
+
+* ``rte_pdump_disable()``:
+ This API disables the packet capture on a given port and queue.
+
+* ``rte_pdump_disable_by_deviceid()``:
+ This API disables the packet capture on a given device id (``vdev name or pci address``) and queue.
+
+* ``rte_pdump_uninit()``:
+ This API uninitializes the packet capture framework.
+
+
+Operation
+---------
+
+The ``librte_pdump`` library works on a client/server model. The server is responsible for enabling or
+disabling the packet capture and the clients are responsible for requesting the enabling or disabling of
+the packet capture.
+
+The packet capture framework, as part of its initialization, creates the pthread and the server socket in
+the pthread. The application that calls the framework initialization first will have the server socket created.
+Further calls to the framework initialization by the same application or other applications is not allowed i.e., only
+one server socket is allowed on the system. So the other applications can only request enabling or disabling of
+the packet capture at which point the client socket is created for them to send the request to the server.
+The server socket will listen for client requests for enabling or disabling the packet capture.
+
+
+Implementation Details
+----------------------
+
+The library API ``rte_pdump_init()``, initializes the packet capture framework by creating the pthread and the server
+socket. The server socket in the pthread context will be listening to the client requests to enable or disable the
+packet capture. Whoever calls this API first will have the server socket created, the subsequent calls to this APIs
+will not create any further server socket. i.e. only one server socket is allowed.
+
+The library APIs ``rte_pdump_enable()`` and ``rte_pdump_enable_by_deviceid()`` enables the packet capture.
+On each call to these APIs, the library creates a separate client socket, creates the "pdump enable" request and sends
+the request to the server. The server that is listening on the socket will take the request and enable the packet capture
+by registering the Ethernet RX and TX callbacks for the given port or device_id and queue combinations.
+Then the server will mirror the packets to the new mempool and enqueue them to the rte_ring that clients have passed
+to these APIs. The server also sends the response back to the client about the status of the request that was processed.
+After the response is received from the server, the client socket is closed.
+
+The library APIs ``rte_pdump_disable()`` and ``rte_pdump_disable_by_deviceid()`` disables the packet capture.
+On each call to these APIs, the library creates a separate client socket, creates the "pdump disable" request and sends
+the request to the server. The server that is listening on the socket will take the request and disable the packet
+capture by removing the Ethernet RX and TX callbacks for the given port or device_id and queue combinations. The server
+also sends the response back to the client about the status of the request that was processed. After the response is
+received from the server, the client socket is closed.
+
+The library API ``rte_pdump_uninit()``, uninitializes the packet capture framework by closing the pthread and the
+server socket.
+
+
+Use Case: Packet Capturing
+--------------------------
+
+The DPDK ``app/pdump`` tool is developed based on this library to capture packets in DPDK.
+Users can use this as an example to develop their own packet capturing application.
diff --git a/doc/guides/rel_notes/release_16_07.rst b/doc/guides/rel_notes/release_16_07.rst
index c0f6b02..a4de2a2 100644
--- a/doc/guides/rel_notes/release_16_07.rst
+++ b/doc/guides/rel_notes/release_16_07.rst
@@ -66,6 +66,11 @@ New Features
* Enable RSS per network interface through the configuration file.
* Streamline the CLI code.
+* **Added packet capture framework.**
+
+ * A new library ``librte_pdump`` is added to provide packet capture APIs.
+ * A new ``app/pdump`` tool is added to capture packets in DPDK.
+
Resolved Issues
---------------
@@ -135,6 +140,11 @@ API Changes
ibadcrc, ibadlen, imcasts, fdirmatch, fdirmiss,
tx_pause_xon, rx_pause_xon, tx_pause_xoff, rx_pause_xoff.
+* Function ``rte_eth_dev_get_port_by_name`` changed to a public API.
+
+* Function ``rte_eth_dev_info_get`` updated to return new fields ``nb_rx_queues`` and ``nb_tx_queues``
+ in the ``rte_eth_dev_info`` object.
+
ABI Changes
-----------
@@ -146,6 +156,9 @@ ABI Changes
* The ``rte_port_source_params`` structure has new fields to support PCAP file.
It was already in release 16.04 with ``RTE_NEXT_ABI`` flag.
+* The ``rte_eth_dev_info`` structure has new fields ``nb_rx_queues`` and ``nb_tx_queues``
+ to support number of queues configured by software.
+
Shared Library Versions
-----------------------
diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst
index 930f68c..96bb317 100644
--- a/doc/guides/sample_app_ug/index.rst
+++ b/doc/guides/sample_app_ug/index.rst
@@ -76,6 +76,7 @@ Sample Applications User Guide
ptpclient
performance_thread
ipsec_secgw
+ pdump
**Figures**
diff --git a/doc/guides/sample_app_ug/pdump.rst b/doc/guides/sample_app_ug/pdump.rst
new file mode 100644
index 0000000..96c8709
--- /dev/null
+++ b/doc/guides/sample_app_ug/pdump.rst
@@ -0,0 +1,122 @@
+
+.. 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.
+
+
+dpdk_pdump Application
+======================
+
+The ``dpdk_pdump`` application is a Data Plane Development Kit (DPDK) application that runs as a DPDK secondary process and
+is capable of enabling packet capture on dpdk ports.
+
+
+Running the Application
+-----------------------
+
+The application has a ``--pdump`` command line option with various sub arguments:
+
+.. code-block:: console
+
+ ./build/app/dpdk_pdump --
+ --pdump '(port=<port id> | device_id=<pci id or vdev name>),
+ (queue=<queue_id>),
+ (rx-dev=<iface or pcap file> |
+ tx-dev=<iface or pcap file>),
+ [ring-size=<ring size>],
+ [mbuf-size=<mbuf data size>],
+ [total-num-mbufs=<number of mbufs>]'
+
+Note:
+
+* Parameters inside the parentheses represents mandatory parameters.
+
+* Parameters inside the square brackets represents optional parameters.
+
+Multiple instances of ``--pdump`` can be passed to capture packets on different port and queue combinations.
+
+
+Parameters
+~~~~~~~~~~
+
+``port``:
+Port id of the eth device on which packets should be captured.
+
+``device_id``:
+PCI address (or) name of the eth device on which packets should be captured.
+
+ .. Note::
+
+ * As of now the ``dpdk_pdump`` tool cannot capture the packets of virtual devices
+ in the primary process due to a bug in the ethdev library. Due to this bug, in a multi process context,
+ when the primary and secondary have different ports set, then the secondary process
+ (here the ``dpdk_pdump`` tool) overwrites the ``rte_eth_devices[]`` entries of the primary process.
+
+``queue``:
+Queue id of the eth device on which packets should be captured. The user can pass a queue value of ``*`` to enable
+packet capture on all queues of the eth device.
+
+``rx-dev``:
+Can be either a pcap file name or any Linux iface.
+
+``tx-dev``:
+Can be either a pcap file name or any Linux iface.
+
+ .. Note::
+
+ * To receive ingress packets only, ``rx-dev`` should be passed.
+
+ * To receive egress packets only, ``tx-dev`` should be passed.
+
+ * To receive ingress and egress packets separately ``rx-dev`` and ``tx-dev``
+ should both be passed with the different file names or the Linux iface names.
+
+ * To receive ingress and egress packets separately ``rx-dev`` and ``tx-dev``
+ should both be passed with the same file names or the the Linux iface names.
+
+``ring-size``:
+Size of the ring. This value is used internally for ring creation. The ring will be used to enqueue the packets from
+the primary application to the secondary. This is an optional parameter with default size 16384.
+
+``mbuf-size``:
+Size of the mbuf data. This is used internally for mempool creation. Ideally this value must be same as
+the primary application's mempool's mbuf data size which is used for packet RX. This is an optional parameter with
+default size 2176.
+
+``total-num-mbufs``:
+Total number mbufs in mempool. This is used internally for mempool creation. This is an optional parameter with default
+value 65535.
+
+
+Example
+-------
+
+.. code-block:: console
+
+ $ sudo ./build/app/dpdk_pdump -- --pdump 'port=0,queue=*,rx-dev=/tmp/rx.pcap'
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v7 0/8] add packet capture framework
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 0/8] add packet capture framework Reshma Pattan
` (7 preceding siblings ...)
2016-06-09 8:50 ` [dpdk-dev] [PATCH v6 8/8] doc: update doc for packet capture framework Reshma Pattan
@ 2016-06-09 16:10 ` Reshma Pattan
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 1/8] librte_ether: protect add/remove of rxtx callbacks with spinlocks Reshma Pattan
` (8 more replies)
8 siblings, 9 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-09 16:10 UTC (permalink / raw)
To: dev
This patch set include below changes
1)Changes to librte_ether.
2)A new library librte_pdump added for packet capture framework.
3)A new app/pdump tool added for packet capturing.
4)Test pmd changes done to initialize packet capture framework.
5)Documentation update.
1)librte_pdump
==============
To support packet capturing on dpdk Ethernet devices, a new library librte_pdump
is added.Users can develop their own packet capturing application using new library APIs.
Operation:
----------
Pdump library provides APIs to support packet capturing on dpdk Ethernet devices.
Library provides APIs to initialize the packet capture framework, enable/disable
the packet capture and uninitialize the packet capture framework.
Pdump library works on client/server based model.
Sever is responsible for enabling/disabling the packet captures.
Clients are responsible for requesting enable/disable of the
packet captures.
As part of packet capture framework initialization, pthread and
the server socket is created. Only one server socket is allowed on the system.
As part of enabling/disabling the packet capture, client sockets are created
and multiple client sockets are allowed.
Who ever calls initialization first they will succeed with the initialization,
next subsequent calls of initialization are not allowed. So next users can only
request enabling/disabling the packet capture.
Applications using below APIs need to pass port/device_id, queue, mempool and
ring parameters. Library uses user provided ring and mempool to mirror the rx/tx
packets of the port for users. Users need to dequeue the rings and write the packets
to vdev(pcap/tuntap) to view the packets using any standard tools.
Note:
Mempool and Ring should be mc/mp supportable.
Mempool mbuf size should be big enough to handle the rx/tx packets of a port.
APIs:
-----
rte_pdump_init()
rte_pdump_enable()
rte_pdump_enable_by_deviceid()
rte_pdump_disable()
rte_pdump_disable_by_deviceid()
rte_pdump_uninit()
2)app/pdump tool
================
Tool app/pdump is designed based on librte_pdump for packet capturing in DPDK.
This tool by default runs as secondary process, and provides the support for
the command line options for packet capture.
./build/app/dpdk_pdump --
--pdump '(port=<port id> | device_id=<pci id or vdev name>),
(queue=<queue id>),
(rx-dev=<iface or pcap file> |
tx-dev=<iface or pcap file>),
[ring-size=<ring size>],
[mbuf-size=<mbuf data size>],
[total-num-mbufs=<number of mbufs>]'
Parameters inside the parenthesis represents the mandatory parameters.
Parameters inside the square brackets represents optional parameters.
User has to pass on packet capture parameters under --pdump parameters, multiples of
--pdump can be passed to capture packets on different port and queue combinations
Operation:
----------
*Tool parse the user command line arguments,
creates the mempool, ring and the PCAP PMD vdev with 'tx_stream' as either
of the device passed in rx-dev|tx-dev parameters.
*Then calls the APIs of librte_pdump i.e. rte_pdump_enable()/rte_pdump_enable_by_deviceid()
to enable packet capturing on a specific port/device_id and queue by passing on
port|device_id, queue, mempool and ring info.
*Tool runs in while loop to dequeue the packets from the ring and write them to pcap device.
*Tool can be stopped using SIGINT, upon which tool calls
rte_pdump_disable()/rte_pdump_disable_by_deviceid() and free the allocated resources.
Note:
CONFIG_RTE_LIBRTE_PMD_PCAP flag should be set to yes to compile and run the pdump tool.
3)Test-pmd changes
==================
Changes are done to test-pmd application to initialize/uninitialize the packet capture framework.
So app/pdump tool can be run to see packets of dpdk ports that are used by test-pmd.
Similarly any application which needs packet capture should call initialize/uninitialize APIs of
librte_pdump and use pdump tool to start the capture.
4)Packet capture flow between pdump tool and librte_pdump
=========================================================
* Pdump tool (Secondary process) requests packet capture
for specific port|device_id and queue combinations.
*Library in secondary process context creates client socket and communicates
the port|device_id, queue, ring and mempool to server.
*Library initializes server in primary process 'test-pmd' context and server serves
the client request to enable Ethernet rxtx call-backs for a given port|device_id and queue.
*Copy the rx/tx packets to passed mempool and enqueue the packets to ring for secondary process.
*Pdump tool will dequeue the packets from ring and writes them to PCAPMD vdev,
so ultimately packets will be seen on the device that is passed in rx-dev|tx-dev.
*Once the pdump tool is terminated with SIGINT it will disable the packet capturing.
*Library receives the disable packet capture request, communicate the info to server,
server will remove the Ethernet rxtx call-backs.
*Packet capture can be seen using tcpdump command
"tcpdump -ni <iface>" (or) "tcpdump –nr <pcapfile>"
5)Example command line
======================
./build/app/dpdk_pdump -- --pdump 'device_id=0000:02:0.0,queue=*,tx-dev=/tmp/dt-file.pcap,rx-dev=/tmp/dr-file.pcap,ring-size=8192,mbuf-size=2176,total-num-mbufs=32768' --pdump 'device_id=0000:01:00.0,queue=*,rx-dev=/tmp/d-file.pcap,tx-dev=/tmp/d-file.pcap,ring-size=16384,mbuf-size=2176,total-num-mbufs=32768'
v7:
fixed lines over 90 characters.
v6:
removed below deprecation notice patch from patch set.
http://dpdk.org/dev/patchwork/patch/13372/
v5:
addressed code review comments for below patches
http://dpdk.org/dev/patchwork/patch/12955/
http://dpdk.org/dev/patchwork/patch/12951/
v4:
added missing deprecation notice for ABI changes of rte_eth_dev_info structure.
made doc changes as per doc guidelines.
replaced rte_eal_vdev_init with rte_eth_dev_attach in pdump tool.
removed rxtx-dev parameter from pdump tool command line.
v3:
app/pdump: Moved cleanup code from signal handler to main.
divided librte_ether changes into multiple patches.
example command changed in app/pdump application guide
v2:
fix compilation issues for 4.8.3
fix unnecessary #includes
Reshma Pattan (8):
librte_ether: protect add/remove of rxtx callbacks with spinlocks
librte_ether: add new api rte_eth_add_first_rx_callback
librte_ether: add new fields to rte_eth_dev_info struct
librte_ether: make rte_eth_dev_get_port_by_name
rte_eth_dev_get_name_by_port public
lib/librte_pdump: add new library for packet capturing support
app/pdump: add pdump tool for packet capturing
app/test-pmd: add pdump initialization uninitialization
doc: update doc for packet capture framework
MAINTAINERS | 8 +
app/Makefile | 1 +
app/pdump/Makefile | 45 ++
app/pdump/main.c | 844 +++++++++++++++++++++++++++++++
app/test-pmd/testpmd.c | 6 +
config/common_base | 5 +
doc/guides/prog_guide/index.rst | 1 +
doc/guides/prog_guide/pdump_library.rst | 107 ++++
doc/guides/rel_notes/release_16_07.rst | 13 +
doc/guides/sample_app_ug/index.rst | 1 +
doc/guides/sample_app_ug/pdump.rst | 122 +++++
lib/Makefile | 1 +
lib/librte_ether/rte_ethdev.c | 123 +++--
lib/librte_ether/rte_ethdev.h | 60 +++
lib/librte_ether/rte_ether_version.map | 9 +
lib/librte_pdump/Makefile | 55 ++
lib/librte_pdump/rte_pdump.c | 872 ++++++++++++++++++++++++++++++++
lib/librte_pdump/rte_pdump.h | 186 +++++++
lib/librte_pdump/rte_pdump_version.map | 12 +
mk/rte.app.mk | 1 +
20 files changed, 2428 insertions(+), 44 deletions(-)
create mode 100644 app/pdump/Makefile
create mode 100644 app/pdump/main.c
create mode 100644 doc/guides/prog_guide/pdump_library.rst
create mode 100644 doc/guides/sample_app_ug/pdump.rst
create mode 100644 lib/librte_pdump/Makefile
create mode 100644 lib/librte_pdump/rte_pdump.c
create mode 100644 lib/librte_pdump/rte_pdump.h
create mode 100644 lib/librte_pdump/rte_pdump_version.map
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v7 1/8] librte_ether: protect add/remove of rxtx callbacks with spinlocks
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 0/8] add " Reshma Pattan
@ 2016-06-09 16:10 ` Reshma Pattan
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 2/8] librte_ether: add new api rte_eth_add_first_rx_callback Reshma Pattan
` (7 subsequent siblings)
8 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-09 16:10 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Added spinlocks around add/remove logic of rxtx callbacks to
avoid corruption of callback lists in multithreaded context.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
lib/librte_ether/rte_ethdev.c | 82 +++++++++++++++++++++----------------------
1 file changed, 40 insertions(+), 42 deletions(-)
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index e148028..ce70d58 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -77,6 +77,12 @@ static uint8_t nb_ports;
/* spinlock for eth device callbacks */
static rte_spinlock_t rte_eth_dev_cb_lock = RTE_SPINLOCK_INITIALIZER;
+/* spinlock for add/remove rx callbacks */
+static rte_spinlock_t rte_eth_rx_cb_lock = RTE_SPINLOCK_INITIALIZER;
+
+/* spinlock for add/remove tx callbacks */
+static rte_spinlock_t rte_eth_tx_cb_lock = RTE_SPINLOCK_INITIALIZER;
+
/* store statistics names and its offset in stats structure */
struct rte_eth_xstats_name_off {
char name[RTE_ETH_XSTATS_NAME_SIZE];
@@ -1634,7 +1640,6 @@ rte_eth_dev_set_rx_queue_stats_mapping(uint8_t port_id, uint16_t rx_queue_id,
STAT_QMAP_RX);
}
-
void
rte_eth_dev_info_get(uint8_t port_id, struct rte_eth_dev_info *dev_info)
{
@@ -2905,7 +2910,6 @@ rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
rte_errno = EINVAL;
return NULL;
}
-
struct rte_eth_rxtx_callback *cb = rte_zmalloc(NULL, sizeof(*cb), 0);
if (cb == NULL) {
@@ -2916,6 +2920,7 @@ rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
cb->fn.rx = fn;
cb->param = user_param;
+ rte_spinlock_lock(&rte_eth_rx_cb_lock);
/* Add the callbacks in fifo order. */
struct rte_eth_rxtx_callback *tail =
rte_eth_devices[port_id].post_rx_burst_cbs[queue_id];
@@ -2928,6 +2933,7 @@ rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
tail = tail->next;
tail->next = cb;
}
+ rte_spinlock_unlock(&rte_eth_rx_cb_lock);
return cb;
}
@@ -2957,6 +2963,7 @@ rte_eth_add_tx_callback(uint8_t port_id, uint16_t queue_id,
cb->fn.tx = fn;
cb->param = user_param;
+ rte_spinlock_lock(&rte_eth_tx_cb_lock);
/* Add the callbacks in fifo order. */
struct rte_eth_rxtx_callback *tail =
rte_eth_devices[port_id].pre_tx_burst_cbs[queue_id];
@@ -2969,6 +2976,7 @@ rte_eth_add_tx_callback(uint8_t port_id, uint16_t queue_id,
tail = tail->next;
tail->next = cb;
}
+ rte_spinlock_unlock(&rte_eth_tx_cb_lock);
return cb;
}
@@ -2987,29 +2995,24 @@ rte_eth_remove_rx_callback(uint8_t port_id, uint16_t queue_id,
return -EINVAL;
struct rte_eth_dev *dev = &rte_eth_devices[port_id];
- struct rte_eth_rxtx_callback *cb = dev->post_rx_burst_cbs[queue_id];
- struct rte_eth_rxtx_callback *prev_cb;
-
- /* Reset head pointer and remove user cb if first in the list. */
- if (cb == user_cb) {
- dev->post_rx_burst_cbs[queue_id] = user_cb->next;
- return 0;
- }
-
- /* Remove the user cb from the callback list. */
- do {
- prev_cb = cb;
- cb = cb->next;
-
+ struct rte_eth_rxtx_callback *cb;
+ struct rte_eth_rxtx_callback **prev_cb;
+ int ret = -EINVAL;
+
+ rte_spinlock_lock(&rte_eth_rx_cb_lock);
+ prev_cb = &dev->post_rx_burst_cbs[queue_id];
+ for (; *prev_cb != NULL; prev_cb = &cb->next) {
+ cb = *prev_cb;
if (cb == user_cb) {
- prev_cb->next = user_cb->next;
- return 0;
+ /* Remove the user cb from the callback list. */
+ *prev_cb = cb->next;
+ ret = 0;
+ break;
}
+ }
+ rte_spinlock_unlock(&rte_eth_rx_cb_lock);
- } while (cb != NULL);
-
- /* Callback wasn't found. */
- return -EINVAL;
+ return ret;
}
int
@@ -3026,29 +3029,24 @@ rte_eth_remove_tx_callback(uint8_t port_id, uint16_t queue_id,
return -EINVAL;
struct rte_eth_dev *dev = &rte_eth_devices[port_id];
- struct rte_eth_rxtx_callback *cb = dev->pre_tx_burst_cbs[queue_id];
- struct rte_eth_rxtx_callback *prev_cb;
-
- /* Reset head pointer and remove user cb if first in the list. */
- if (cb == user_cb) {
- dev->pre_tx_burst_cbs[queue_id] = user_cb->next;
- return 0;
- }
-
- /* Remove the user cb from the callback list. */
- do {
- prev_cb = cb;
- cb = cb->next;
-
+ int ret = -EINVAL;
+ struct rte_eth_rxtx_callback *cb;
+ struct rte_eth_rxtx_callback **prev_cb;
+
+ rte_spinlock_lock(&rte_eth_tx_cb_lock);
+ prev_cb = &dev->pre_tx_burst_cbs[queue_id];
+ for (; *prev_cb != NULL; prev_cb = &cb->next) {
+ cb = *prev_cb;
if (cb == user_cb) {
- prev_cb->next = user_cb->next;
- return 0;
+ /* Remove the user cb from the callback list. */
+ *prev_cb = cb->next;
+ ret = 0;
+ break;
}
+ }
+ rte_spinlock_unlock(&rte_eth_tx_cb_lock);
- } while (cb != NULL);
-
- /* Callback wasn't found. */
- return -EINVAL;
+ return ret;
}
int
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v7 2/8] librte_ether: add new api rte_eth_add_first_rx_callback
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 0/8] add " Reshma Pattan
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 1/8] librte_ether: protect add/remove of rxtx callbacks with spinlocks Reshma Pattan
@ 2016-06-09 16:10 ` Reshma Pattan
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 3/8] librte_ether: add new fields to rte_eth_dev_info struct Reshma Pattan
` (6 subsequent siblings)
8 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-09 16:10 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Added new public api rte_eth_add_first_rx_callback to add given
callback as head of list.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
lib/librte_ether/rte_ethdev.c | 35 ++++++++++++++++++++++++++++++++++
lib/librte_ether/rte_ethdev.h | 28 +++++++++++++++++++++++++++
lib/librte_ether/rte_ether_version.map | 6 ++++++
3 files changed, 69 insertions(+)
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index ce70d58..97d167e 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -2939,6 +2939,41 @@ rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
}
void *
+rte_eth_add_first_rx_callback(uint8_t port_id, uint16_t queue_id,
+ rte_rx_callback_fn fn, void *user_param)
+{
+#ifndef RTE_ETHDEV_RXTX_CALLBACKS
+ rte_errno = ENOTSUP;
+ return NULL;
+#endif
+ /* check input parameters */
+ if (!rte_eth_dev_is_valid_port(port_id) || fn == NULL ||
+ queue_id >= rte_eth_devices[port_id].data->nb_rx_queues) {
+ rte_errno = EINVAL;
+ return NULL;
+ }
+
+ struct rte_eth_rxtx_callback *cb = rte_zmalloc(NULL, sizeof(*cb), 0);
+
+ if (cb == NULL) {
+ rte_errno = ENOMEM;
+ return NULL;
+ }
+
+ cb->fn.rx = fn;
+ cb->param = user_param;
+
+ rte_spinlock_lock(&rte_eth_rx_cb_lock);
+ /* Add the callbacks at fisrt position*/
+ cb->next = rte_eth_devices[port_id].post_rx_burst_cbs[queue_id];
+ rte_smp_wmb();
+ rte_eth_devices[port_id].post_rx_burst_cbs[queue_id] = cb;
+ rte_spinlock_unlock(&rte_eth_rx_cb_lock);
+
+ return cb;
+}
+
+void *
rte_eth_add_tx_callback(uint8_t port_id, uint16_t queue_id,
rte_tx_callback_fn fn, void *user_param)
{
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 2757510..237e6ef 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -3825,6 +3825,34 @@ int rte_eth_dev_get_dcb_info(uint8_t port_id,
void *rte_eth_add_rx_callback(uint8_t port_id, uint16_t queue_id,
rte_rx_callback_fn fn, void *user_param);
+/*
+* Add a callback that must be called first on packet RX on a given port
+* and queue.
+*
+* This API configures a first function to be called for each burst of
+* packets received on a given NIC port queue. The return value is a pointer
+* that can be used to later remove the callback using
+* rte_eth_remove_rx_callback().
+*
+* Multiple functions are called in the order that they are added.
+*
+* @param port_id
+* The port identifier of the Ethernet device.
+* @param queue_id
+* The queue on the Ethernet device on which the callback is to be added.
+* @param fn
+* The callback function
+* @param user_param
+* A generic pointer parameter which will be passed to each invocation of the
+* callback function on this port and queue.
+*
+* @return
+* NULL on error.
+* On success, a pointer value which can later be used to remove the callback.
+*/
+void *rte_eth_add_first_rx_callback(uint8_t port_id, uint16_t queue_id,
+ rte_rx_callback_fn fn, void *user_param);
+
/**
* Add a callback to be called on packet TX on a given port and queue.
*
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index 214ecc7..c990b04 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -132,3 +132,9 @@ DPDK_16.04 {
rte_eth_tx_buffer_set_err_callback;
} DPDK_2.2;
+
+DPDK_16.07 {
+ global:
+
+ rte_eth_add_first_rx_callback;
+} DPDK_16.04;
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v7 3/8] librte_ether: add new fields to rte_eth_dev_info struct
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 0/8] add " Reshma Pattan
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 1/8] librte_ether: protect add/remove of rxtx callbacks with spinlocks Reshma Pattan
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 2/8] librte_ether: add new api rte_eth_add_first_rx_callback Reshma Pattan
@ 2016-06-09 16:10 ` Reshma Pattan
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 4/8] librte_ether: make rte_eth_dev_get_port_by_name rte_eth_dev_get_name_by_port public Reshma Pattan
` (5 subsequent siblings)
8 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-09 16:10 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
New fields nb_rx_queues and nb_tx_queues are added to
rte_eth_dev_info structure.
Changes to API rte_eth_dev_info_get() are done to update
these new fields to rte_eth_dev_info object.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
lib/librte_ether/rte_ethdev.c | 2 ++
lib/librte_ether/rte_ethdev.h | 3 +++
lib/librte_ether/rte_ether_version.map | 1 +
3 files changed, 6 insertions(+)
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 97d167e..1f634c9 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -1661,6 +1661,8 @@ rte_eth_dev_info_get(uint8_t port_id, struct rte_eth_dev_info *dev_info)
(*dev->dev_ops->dev_infos_get)(dev, dev_info);
dev_info->pci_dev = dev->pci_dev;
dev_info->driver_name = dev->data->drv_name;
+ dev_info->nb_rx_queues = dev->data->nb_rx_queues;
+ dev_info->nb_tx_queues = dev->data->nb_tx_queues;
}
int
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 237e6ef..8ad7c01 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -882,6 +882,9 @@ struct rte_eth_dev_info {
struct rte_eth_desc_lim rx_desc_lim; /**< RX descriptors limits */
struct rte_eth_desc_lim tx_desc_lim; /**< TX descriptors limits */
uint32_t speed_capa; /**< Supported speeds bitmap (ETH_LINK_SPEED_). */
+ /** Configured number of rx/tx queues */
+ uint16_t nb_rx_queues; /**< Number of RX queues. */
+ uint16_t nb_tx_queues; /**< Number of TX queues. */
};
/**
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index c990b04..d06d648 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -137,4 +137,5 @@ DPDK_16.07 {
global:
rte_eth_add_first_rx_callback;
+ rte_eth_dev_info_get;
} DPDK_16.04;
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v7 4/8] librte_ether: make rte_eth_dev_get_port_by_name rte_eth_dev_get_name_by_port public
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 0/8] add " Reshma Pattan
` (2 preceding siblings ...)
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 3/8] librte_ether: add new fields to rte_eth_dev_info struct Reshma Pattan
@ 2016-06-09 16:10 ` Reshma Pattan
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 5/8] lib/librte_pdump: add new library for packet capturing support Reshma Pattan
` (4 subsequent siblings)
8 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-09 16:10 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Converted rte_eth_dev_get_port_by_name to a public API.
Converted rte_eth_dev_get_name_by_port to a public API.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
lib/librte_ether/rte_ethdev.c | 4 ++--
lib/librte_ether/rte_ethdev.h | 29 +++++++++++++++++++++++++++++
lib/librte_ether/rte_ether_version.map | 2 ++
3 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 1f634c9..0b19569 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -406,7 +406,7 @@ rte_eth_dev_get_addr_by_port(uint8_t port_id, struct rte_pci_addr *addr)
return 0;
}
-static int
+int
rte_eth_dev_get_name_by_port(uint8_t port_id, char *name)
{
char *tmp;
@@ -425,7 +425,7 @@ rte_eth_dev_get_name_by_port(uint8_t port_id, char *name)
return 0;
}
-static int
+int
rte_eth_dev_get_port_by_name(const char *name, uint8_t *port_id)
{
int i;
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 8ad7c01..fab281e 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -4284,6 +4284,35 @@ rte_eth_dev_l2_tunnel_offload_set(uint8_t port_id,
uint32_t mask,
uint8_t en);
+/**
+* Get the port id from pci adrress or device name
+* Ex: 0000:2:00.0 or vdev name eth_pcap0
+*
+* @param name
+* pci address or name of the device
+* @param port_id
+* pointer to port identifier of the device
+* @return
+* - (0) if successful.
+* - (-ENODEV or -EINVAL) on failure.
+*/
+int
+rte_eth_dev_get_port_by_name(const char *name, uint8_t *port_id);
+
+/**
+* Get the device name from port id
+*
+* @param port_id
+* pointer to port identifier of the device
+* @param name
+* pci address or name of the device
+* @return
+* - (0) if successful.
+* - (-EINVAL) on failure.
+*/
+int
+rte_eth_dev_get_name_by_port(uint8_t port_id, char *name);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index d06d648..73e730d 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -137,5 +137,7 @@ DPDK_16.07 {
global:
rte_eth_add_first_rx_callback;
+ rte_eth_dev_get_name_by_port;
+ rte_eth_dev_get_port_by_name;
rte_eth_dev_info_get;
} DPDK_16.04;
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v7 5/8] lib/librte_pdump: add new library for packet capturing support
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 0/8] add " Reshma Pattan
` (3 preceding siblings ...)
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 4/8] librte_ether: make rte_eth_dev_get_port_by_name rte_eth_dev_get_name_by_port public Reshma Pattan
@ 2016-06-09 16:10 ` Reshma Pattan
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 6/8] app/pdump: add pdump tool for packet capturing Reshma Pattan
` (3 subsequent siblings)
8 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-09 16:10 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Added new library for packet capturing support.
Added public api rte_pdump_init, applications should call
this as part of their application setup to have packet
capturing framework ready.
Added public api rte_pdump_uninit to uninitialize the packet
capturing framework.
Added public apis rte_pdump_enable and rte_pdump_disable to
enable and disable packet capturing on specific port and queue.
Added public apis rte_pdump_enable_by_deviceid and
rte_pdump_disable_by_deviceid to enable and disable packet
capturing on a specific device (pci address or name) and queue.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
MAINTAINERS | 4 +
config/common_base | 5 +
lib/Makefile | 1 +
lib/librte_pdump/Makefile | 55 +++
lib/librte_pdump/rte_pdump.c | 872 +++++++++++++++++++++++++++++++++
lib/librte_pdump/rte_pdump.h | 186 +++++++
lib/librte_pdump/rte_pdump_version.map | 12 +
mk/rte.app.mk | 1 +
8 files changed, 1136 insertions(+)
create mode 100644 lib/librte_pdump/Makefile
create mode 100644 lib/librte_pdump/rte_pdump.c
create mode 100644 lib/librte_pdump/rte_pdump.h
create mode 100644 lib/librte_pdump/rte_pdump_version.map
diff --git a/MAINTAINERS b/MAINTAINERS
index 3e8558f..cc3ffdb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -432,6 +432,10 @@ F: app/test/test_reorder*
F: examples/packet_ordering/
F: doc/guides/sample_app_ug/packet_ordering.rst
+Pdump
+M: Reshma Pattan <reshma.pattan@intel.com>
+F: lib/librte_pdump/
+
Hierarchical scheduler
M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
F: lib/librte_sched/
diff --git a/config/common_base b/config/common_base
index 47c26f6..a2d5d72 100644
--- a/config/common_base
+++ b/config/common_base
@@ -484,6 +484,11 @@ CONFIG_RTE_LIBRTE_DISTRIBUTOR=y
CONFIG_RTE_LIBRTE_REORDER=y
#
+# Compile the pdump library
+#
+CONFIG_RTE_LIBRTE_PDUMP=y
+
+#
# Compile librte_port
#
CONFIG_RTE_LIBRTE_PORT=y
diff --git a/lib/Makefile b/lib/Makefile
index f254dba..ca7c02f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -57,6 +57,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
DIRS-$(CONFIG_RTE_LIBRTE_TABLE) += librte_table
DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += librte_pipeline
DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder
+DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += librte_pdump
ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
diff --git a/lib/librte_pdump/Makefile b/lib/librte_pdump/Makefile
new file mode 100644
index 0000000..af81a28
--- /dev/null
+++ b/lib/librte_pdump/Makefile
@@ -0,0 +1,55 @@
+# 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_SDK)/mk/rte.vars.mk
+
+# library name
+LIB = librte_pdump.a
+
+CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
+CFLAGS += -D_GNU_SOURCE
+
+EXPORT_MAP := rte_pdump_version.map
+
+LIBABIVER := 1
+
+# all source are stored in SRCS-y
+SRCS-$(CONFIG_RTE_LIBRTE_PDUMP) := rte_pdump.c
+
+# install this header file
+SYMLINK-$(CONFIG_RTE_LIBRTE_PDUMP)-include := rte_pdump.h
+
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += lib/librte_ether
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pdump/rte_pdump.c b/lib/librte_pdump/rte_pdump.c
new file mode 100644
index 0000000..90d1b03
--- /dev/null
+++ b/lib/librte_pdump/rte_pdump.c
@@ -0,0 +1,872 @@
+/*-
+ * 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 <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <stdbool.h>
+
+#include <rte_memcpy.h>
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_lcore.h>
+#include <rte_log.h>
+#include <rte_errno.h>
+#include <rte_pci.h>
+
+#include "rte_pdump.h"
+
+#define SOCKET_PATH_VAR_RUN "/var/run/pdump_sockets"
+#define SOCKET_PATH_HOME "HOME/pdump_sockets"
+#define SERVER_SOCKET "%s/pdump_server_socket"
+#define CLIENT_SOCKET "%s/pdump_client_socket_%d_%u"
+#define DEVICE_ID_SIZE 64
+/* Macros for printing using RTE_LOG */
+#define RTE_LOGTYPE_PDUMP RTE_LOGTYPE_USER1
+
+enum pdump_operation {
+ DISABLE = 1,
+ ENABLE = 2
+};
+
+enum pdump_socktype {
+ SERVER = 1,
+ CLIENT = 2
+};
+
+enum pdump_version {
+ V1 = 1
+};
+
+static pthread_t pdump_thread;
+static int pdump_socket_fd;
+
+struct pdump_request {
+ uint16_t ver;
+ uint16_t op;
+ uint32_t flags;
+ union pdump_data {
+ struct enable_v1 {
+ char device[DEVICE_ID_SIZE];
+ uint16_t queue;
+ struct rte_ring *ring;
+ struct rte_mempool *mp;
+ void *filter;
+ } en_v1;
+ struct disable_v1 {
+ char device[DEVICE_ID_SIZE];
+ uint16_t queue;
+ struct rte_ring *ring;
+ struct rte_mempool *mp;
+ void *filter;
+ } dis_v1;
+ } data;
+};
+
+struct pdump_response {
+ uint16_t ver;
+ uint16_t res_op;
+ int32_t err_value;
+};
+
+static struct pdump_rxtx_cbs {
+ struct rte_ring *ring;
+ struct rte_mempool *mp;
+ struct rte_eth_rxtx_callback *cb;
+ void *filter;
+} rx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT],
+tx_cbs[RTE_MAX_ETHPORTS][RTE_MAX_QUEUES_PER_PORT];
+
+static inline int
+pdump_pktmbuf_copy_data(struct rte_mbuf *seg, const struct rte_mbuf *m)
+{
+ if (rte_pktmbuf_tailroom(seg) < m->data_len) {
+ RTE_LOG(ERR, PDUMP,
+ "User mempool: insufficient data_len of mbuf\n");
+ return -EINVAL;
+ }
+
+ seg->port = m->port;
+ seg->vlan_tci = m->vlan_tci;
+ seg->hash = m->hash;
+ seg->tx_offload = m->tx_offload;
+ seg->ol_flags = m->ol_flags;
+ seg->packet_type = m->packet_type;
+ seg->vlan_tci_outer = m->vlan_tci_outer;
+ seg->data_len = m->data_len;
+ seg->pkt_len = seg->data_len;
+ rte_memcpy(rte_pktmbuf_mtod(seg, void *),
+ rte_pktmbuf_mtod(m, void *),
+ rte_pktmbuf_data_len(seg));
+
+ return 0;
+}
+
+static inline struct rte_mbuf *
+pdump_pktmbuf_copy(struct rte_mbuf *m, struct rte_mempool *mp)
+{
+ struct rte_mbuf *m_dup, *seg, **prev;
+ uint32_t pktlen;
+ uint8_t nseg;
+
+ m_dup = rte_pktmbuf_alloc(mp);
+ if (unlikely(m_dup == NULL))
+ return NULL;
+
+ seg = m_dup;
+ prev = &seg->next;
+ pktlen = m->pkt_len;
+ nseg = 0;
+
+ do {
+ nseg++;
+ if (pdump_pktmbuf_copy_data(seg, m) < 0) {
+ rte_pktmbuf_free(m_dup);
+ return NULL;
+ }
+ *prev = seg;
+ prev = &seg->next;
+ } while ((m = m->next) != NULL &&
+ (seg = rte_pktmbuf_alloc(mp)) != NULL);
+
+ *prev = NULL;
+ m_dup->nb_segs = nseg;
+ m_dup->pkt_len = pktlen;
+
+ /* Allocation of new indirect segment failed */
+ if (unlikely(seg == NULL)) {
+ rte_pktmbuf_free(m_dup);
+ return NULL;
+ }
+
+ __rte_mbuf_sanity_check(m_dup, 1);
+ return m_dup;
+}
+
+static inline void
+pdump_copy(struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
+{
+ unsigned i;
+ int ring_enq;
+ uint16_t d_pkts = 0;
+ struct rte_mbuf *dup_bufs[nb_pkts];
+ struct pdump_rxtx_cbs *cbs;
+ struct rte_ring *ring;
+ struct rte_mempool *mp;
+ struct rte_mbuf *p;
+
+ cbs = user_params;
+ ring = cbs->ring;
+ mp = cbs->mp;
+ for (i = 0; i < nb_pkts; i++) {
+ p = pdump_pktmbuf_copy(pkts[i], mp);
+ if (p)
+ dup_bufs[d_pkts++] = p;
+ }
+
+ ring_enq = rte_ring_enqueue_burst(ring, (void *)dup_bufs, d_pkts);
+ if (unlikely(ring_enq < d_pkts)) {
+ RTE_LOG(DEBUG, PDUMP,
+ "only %d of packets enqueued to ring\n", ring_enq);
+ do {
+ rte_pktmbuf_free(dup_bufs[ring_enq]);
+ } while (++ring_enq < d_pkts);
+ }
+}
+
+static uint16_t
+pdump_rx(uint8_t port __rte_unused, uint16_t qidx __rte_unused,
+ struct rte_mbuf **pkts, uint16_t nb_pkts,
+ uint16_t max_pkts __rte_unused,
+ void *user_params)
+{
+ pdump_copy(pkts, nb_pkts, user_params);
+ return nb_pkts;
+}
+
+static uint16_t
+pdump_tx(uint8_t port __rte_unused, uint16_t qidx __rte_unused,
+ struct rte_mbuf **pkts, uint16_t nb_pkts, void *user_params)
+{
+ pdump_copy(pkts, nb_pkts, user_params);
+ return nb_pkts;
+}
+
+static int
+pdump_get_dombdf(char *device_id, char *domBDF, size_t len)
+{
+ int ret;
+ struct rte_pci_addr dev_addr = {0};
+
+ /* identify if device_id is pci address or name */
+ ret = eal_parse_pci_DomBDF(device_id, &dev_addr);
+ if (ret < 0)
+ return -1;
+
+ if (dev_addr.domain)
+ ret = snprintf(domBDF, len, "%u:%u:%u.%u", dev_addr.domain,
+ dev_addr.bus, dev_addr.devid,
+ dev_addr.function);
+ else
+ ret = snprintf(domBDF, len, "%u:%u.%u", dev_addr.bus,
+ dev_addr.devid,
+ dev_addr.function);
+
+ return ret;
+}
+
+static int
+pdump_regitser_rx_callbacks(uint16_t end_q, uint8_t port, uint16_t queue,
+ struct rte_ring *ring, struct rte_mempool *mp,
+ uint16_t operation)
+{
+ uint16_t qid;
+ struct pdump_rxtx_cbs *cbs = NULL;
+
+ qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
+ for (; qid < end_q; qid++) {
+ cbs = &rx_cbs[port][qid];
+ if (cbs && operation == ENABLE) {
+ if (cbs->cb) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to add rx callback for port=%d "
+ "and queue=%d, callback already exists\n",
+ port, qid);
+ return -EEXIST;
+ }
+ cbs->ring = ring;
+ cbs->mp = mp;
+ cbs->cb = rte_eth_add_first_rx_callback(port, qid,
+ pdump_rx, cbs);
+ if (cbs->cb == NULL) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to add rx callback, errno=%d\n",
+ rte_errno);
+ return rte_errno;
+ }
+ }
+ if (cbs && operation == DISABLE) {
+ int ret;
+
+ if (cbs->cb == NULL) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to delete non existing rx "
+ "callback for port=%d and queue=%d\n",
+ port, qid);
+ return -EINVAL;
+ }
+ ret = rte_eth_remove_rx_callback(port, qid, cbs->cb);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to remove rx callback, errno=%d\n",
+ rte_errno);
+ return ret;
+ }
+ cbs->cb = NULL;
+ }
+ }
+
+ return 0;
+}
+
+static int
+pdump_regitser_tx_callbacks(uint16_t end_q, uint8_t port, uint16_t queue,
+ struct rte_ring *ring, struct rte_mempool *mp,
+ uint16_t operation)
+{
+
+ uint16_t qid;
+ struct pdump_rxtx_cbs *cbs = NULL;
+
+ qid = (queue == RTE_PDUMP_ALL_QUEUES) ? 0 : queue;
+ for (; qid < end_q; qid++) {
+ cbs = &tx_cbs[port][qid];
+ if (cbs && operation == ENABLE) {
+ if (cbs->cb) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to add tx callback for port=%d "
+ "and queue=%d, callback already exists\n",
+ port, qid);
+ return -EEXIST;
+ }
+ cbs->ring = ring;
+ cbs->mp = mp;
+ cbs->cb = rte_eth_add_tx_callback(port, qid, pdump_tx,
+ cbs);
+ if (cbs->cb == NULL) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to add tx callback, errno=%d\n",
+ rte_errno);
+ return rte_errno;
+ }
+ }
+ if (cbs && operation == DISABLE) {
+ int ret;
+
+ if (cbs->cb == NULL) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to delete non existing tx "
+ "callback for port=%d and queue=%d\n",
+ port, qid);
+ return -EINVAL;
+ }
+ ret = rte_eth_remove_tx_callback(port, qid, cbs->cb);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to remove tx callback, errno=%d\n",
+ rte_errno);
+ return ret;
+ }
+ cbs->cb = NULL;
+ }
+ }
+
+ return 0;
+}
+
+static int
+set_pdump_rxtx_cbs(struct pdump_request *p)
+{
+ uint16_t nb_rx_q, nb_tx_q = 0, end_q, queue;
+ uint8_t port;
+ int ret = 0;
+ uint32_t flags;
+ uint16_t operation;
+ struct rte_ring *ring;
+ struct rte_mempool *mp;
+
+ flags = p->flags;
+ operation = p->op;
+ if (operation == ENABLE) {
+ ret = rte_eth_dev_get_port_by_name(p->data.en_v1.device,
+ &port);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to get potid for device id=%s\n",
+ p->data.en_v1.device);
+ return -EINVAL;
+ }
+ queue = p->data.en_v1.queue;
+ ring = p->data.en_v1.ring;
+ mp = p->data.en_v1.mp;
+ } else {
+ ret = rte_eth_dev_get_port_by_name(p->data.dis_v1.device,
+ &port);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to get potid for device id=%s\n",
+ p->data.dis_v1.device);
+ return -EINVAL;
+ }
+ queue = p->data.dis_v1.queue;
+ ring = p->data.dis_v1.ring;
+ mp = p->data.dis_v1.mp;
+ }
+
+ /* validation if packet capture is for all queues */
+ if (queue == RTE_PDUMP_ALL_QUEUES) {
+ struct rte_eth_dev_info dev_info;
+
+ rte_eth_dev_info_get(port, &dev_info);
+ nb_rx_q = dev_info.nb_rx_queues;
+ nb_tx_q = dev_info.nb_tx_queues;
+ if (nb_rx_q == 0 && flags & RTE_PDUMP_FLAG_RX) {
+ RTE_LOG(ERR, PDUMP,
+ "number of rx queues cannot be 0\n");
+ return -EINVAL;
+ }
+ if (nb_tx_q == 0 && flags & RTE_PDUMP_FLAG_TX) {
+ RTE_LOG(ERR, PDUMP,
+ "number of tx queues cannot be 0\n");
+ return -EINVAL;
+ }
+ if ((nb_tx_q == 0 || nb_rx_q == 0) &&
+ flags == RTE_PDUMP_FLAG_RXTX) {
+ RTE_LOG(ERR, PDUMP,
+ "both tx&rx queues must be non zero\n");
+ return -EINVAL;
+ }
+ }
+
+ /* register RX callback */
+ if (flags & RTE_PDUMP_FLAG_RX) {
+ end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_rx_q : queue + 1;
+ ret = pdump_regitser_rx_callbacks(end_q, port, queue, ring, mp,
+ operation);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* register TX callback */
+ if (flags & RTE_PDUMP_FLAG_TX) {
+ end_q = (queue == RTE_PDUMP_ALL_QUEUES) ? nb_tx_q : queue + 1;
+ ret = pdump_regitser_tx_callbacks(end_q, port, queue, ring, mp,
+ operation);
+ if (ret < 0)
+ return ret;
+ }
+
+ return ret;
+}
+
+/* get socket path (/var/run if root, $HOME otherwise) */
+static void
+pdump_get_socket_path(char *buffer, int bufsz, enum pdump_socktype type)
+{
+ const char *dir = SOCKET_PATH_VAR_RUN;
+ const char *home_dir = getenv(SOCKET_PATH_HOME);
+
+ if (getuid() != 0 && home_dir != NULL)
+ dir = home_dir;
+
+ mkdir(dir, 700);
+ if (type == SERVER)
+ snprintf(buffer, bufsz, SERVER_SOCKET, dir);
+ else
+ snprintf(buffer, bufsz, CLIENT_SOCKET, dir, getpid(),
+ rte_sys_gettid());
+}
+
+static int
+pdump_create_server_socket(void)
+{
+ int ret, socket_fd;
+ struct sockaddr_un addr;
+ socklen_t addr_len;
+
+ pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), SERVER);
+ addr.sun_family = AF_UNIX;
+
+ /* remove if file already exists */
+ unlink(addr.sun_path);
+
+ /* set up a server socket */
+ socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (socket_fd < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "Failed to create server socket: %s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ return -1;
+ }
+
+ addr_len = sizeof(struct sockaddr_un);
+ ret = bind(socket_fd, (struct sockaddr *) &addr, addr_len);
+ if (ret) {
+ RTE_LOG(ERR, PDUMP,
+ "Failed to bind to server socket: %s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ close(socket_fd);
+ return -1;
+ }
+
+ /* save the socket in local configuration */
+ pdump_socket_fd = socket_fd;
+
+ return 0;
+}
+
+static __attribute__((noreturn)) void *
+pdump_thread_main(__rte_unused void *arg)
+{
+ struct sockaddr_un cli_addr;
+ socklen_t cli_len;
+ struct pdump_request cli_req;
+ struct pdump_response resp;
+ int n;
+ int ret = 0;
+
+ /* host thread, never break out */
+ for (;;) {
+ /* recv client requests */
+ cli_len = sizeof(cli_addr);
+ n = recvfrom(pdump_socket_fd, &cli_req,
+ sizeof(struct pdump_request), 0,
+ (struct sockaddr *)&cli_addr, &cli_len);
+ if (n < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to recv from client:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ continue;
+ }
+
+ ret = set_pdump_rxtx_cbs(&cli_req);
+
+ resp.ver = cli_req.ver;
+ resp.res_op = cli_req.op;
+ resp.err_value = ret;
+ n = sendto(pdump_socket_fd, &resp,
+ sizeof(struct pdump_response),
+ 0, (struct sockaddr *)&cli_addr, cli_len);
+ if (n < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to send to client:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ }
+ }
+}
+
+int
+rte_pdump_init(void)
+{
+ int ret = 0;
+ char thread_name[RTE_MAX_THREAD_NAME_LEN];
+
+ ret = pdump_create_server_socket();
+ if (ret != 0) {
+ RTE_LOG(ERR, PDUMP,
+ "Failed to create server socket:%s:%d\n",
+ __func__, __LINE__);
+ return -1;
+ }
+
+ /* create the host thread to wait/handle pdump requests */
+ ret = pthread_create(&pdump_thread, NULL, pdump_thread_main, NULL);
+ if (ret != 0) {
+ RTE_LOG(ERR, PDUMP,
+ "Failed to create the pdump thread:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ return -1;
+ }
+ /* Set thread_name for aid in debugging. */
+ snprintf(thread_name, RTE_MAX_THREAD_NAME_LEN, "pdump-thread");
+ ret = rte_thread_setname(pdump_thread, thread_name);
+ if (ret != 0) {
+ RTE_LOG(DEBUG, PDUMP,
+ "Failed to set thread name for pdump handling\n");
+ }
+
+ return 0;
+}
+
+int
+rte_pdump_uninit(void)
+{
+ int ret;
+
+ ret = pthread_cancel(pdump_thread);
+ if (ret != 0) {
+ RTE_LOG(ERR, PDUMP,
+ "Failed to cancel the pdump thread:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ return -1;
+ }
+
+ ret = close(pdump_socket_fd);
+ if (ret != 0) {
+ RTE_LOG(ERR, PDUMP,
+ "Failed to close server socket: %s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ return -1;
+ }
+
+ struct sockaddr_un addr;
+
+ pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), SERVER);
+ ret = unlink(addr.sun_path);
+ if (ret != 0) {
+ RTE_LOG(ERR, PDUMP,
+ "Failed to remove server socket addr: %s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+pdump_create_client_socket(struct pdump_request *p)
+{
+ int ret, socket_fd;
+ int pid;
+ int n;
+ struct pdump_response server_resp;
+ struct sockaddr_un addr, serv_addr, from;
+ socklen_t addr_len, serv_len;
+
+ pid = getpid();
+
+ socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (socket_fd < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "client socket(): %s:pid(%d):tid(%u), %s:%d\n",
+ strerror(errno), pid, rte_sys_gettid(),
+ __func__, __LINE__);
+ ret = errno;
+ return ret;
+ }
+
+ pdump_get_socket_path(addr.sun_path, sizeof(addr.sun_path), CLIENT);
+ addr.sun_family = AF_UNIX;
+ addr_len = sizeof(struct sockaddr_un);
+
+ do {
+ ret = bind(socket_fd, (struct sockaddr *) &addr, addr_len);
+ if (ret) {
+ RTE_LOG(ERR, PDUMP,
+ "client bind(): %s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ ret = errno;
+ break;
+ }
+
+ serv_len = sizeof(struct sockaddr_un);
+ memset(&serv_addr, 0, sizeof(serv_addr));
+ pdump_get_socket_path(serv_addr.sun_path,
+ sizeof(serv_addr.sun_path),
+ SERVER);
+ serv_addr.sun_family = AF_UNIX;
+
+ n = sendto(socket_fd, p, sizeof(struct pdump_request), 0,
+ (struct sockaddr *)&serv_addr, serv_len);
+ if (n < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to send to server:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ ret = errno;
+ break;
+ }
+
+ n = recvfrom(socket_fd, &server_resp,
+ sizeof(struct pdump_response), 0,
+ (struct sockaddr *)&from, &serv_len);
+ if (n < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "failed to recv from server:%s, %s:%d\n",
+ strerror(errno), __func__, __LINE__);
+ ret = errno;
+ break;
+ }
+ ret = server_resp.err_value;
+ } while (0);
+
+ close(socket_fd);
+ unlink(addr.sun_path);
+ return ret;
+}
+
+static int
+pdump_validate_ring_mp(struct rte_ring *ring, struct rte_mempool *mp)
+{
+ if (ring == NULL || mp == NULL) {
+ RTE_LOG(ERR, PDUMP, "NULL ring or mempool are passed %s:%d\n",
+ __func__, __LINE__);
+ rte_errno = EINVAL;
+ return -1;
+ }
+ if (mp->flags & MEMPOOL_F_SP_PUT || mp->flags & MEMPOOL_F_SC_GET) {
+ RTE_LOG(ERR, PDUMP, "mempool with either SP or SC settings"
+ " is not valid for pdump, should have MP and MC settings\n");
+ rte_errno = EINVAL;
+ return -1;
+ }
+ if (ring->prod.sp_enqueue || ring->cons.sc_dequeue) {
+ RTE_LOG(ERR, PDUMP, "ring with either SP or SC settings"
+ " is not valid for pdump, should have MP and MC settings\n");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+pdump_validate_flags(uint32_t flags)
+{
+ if (flags != RTE_PDUMP_FLAG_RX && flags != RTE_PDUMP_FLAG_TX &&
+ flags != RTE_PDUMP_FLAG_RXTX) {
+ RTE_LOG(ERR, PDUMP,
+ "invalid flags, should be either rx/tx/rxtx\n");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+pdump_validate_port(uint8_t port, char *name)
+{
+ int ret = 0;
+
+ if (port >= RTE_MAX_ETHPORTS) {
+ RTE_LOG(ERR, PDUMP, "Invalid port id %u, %s:%d\n", port,
+ __func__, __LINE__);
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ ret = rte_eth_dev_get_name_by_port(port, name);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "port id to name mapping failed for port id=%u, %s:%d\n",
+ port, __func__, __LINE__);
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+pdump_prepare_client_request(char *device, uint16_t queue,
+ uint32_t flags,
+ uint16_t operation,
+ struct rte_ring *ring,
+ struct rte_mempool *mp,
+ void *filter)
+{
+ int ret;
+ struct pdump_request req = {.ver = 1,};
+
+ req.flags = flags;
+ req.op = operation;
+ if ((operation & ENABLE) != 0) {
+ strncpy(req.data.en_v1.device, device, strlen(device));
+ req.data.en_v1.queue = queue;
+ req.data.en_v1.ring = ring;
+ req.data.en_v1.mp = mp;
+ req.data.en_v1.filter = filter;
+ } else {
+ strncpy(req.data.dis_v1.device, device, strlen(device));
+ req.data.dis_v1.queue = queue;
+ req.data.dis_v1.ring = NULL;
+ req.data.dis_v1.mp = NULL;
+ req.data.dis_v1.filter = NULL;
+ }
+
+ ret = pdump_create_client_socket(&req);
+ if (ret < 0) {
+ RTE_LOG(ERR, PDUMP,
+ "client request for pdump enable/disable failed\n");
+ rte_errno = ret;
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+rte_pdump_enable(uint8_t port, uint16_t queue, uint32_t flags,
+ struct rte_ring *ring,
+ struct rte_mempool *mp,
+ void *filter)
+{
+
+ int ret = 0;
+ char name[DEVICE_ID_SIZE];
+
+ ret = pdump_validate_port(port, name);
+ if (ret < 0)
+ return ret;
+ ret = pdump_validate_ring_mp(ring, mp);
+ if (ret < 0)
+ return ret;
+ ret = pdump_validate_flags(flags);
+ if (ret < 0)
+ return ret;
+
+ ret = pdump_prepare_client_request(name, queue, flags,
+ ENABLE, ring, mp, filter);
+
+ return ret;
+}
+
+int
+rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
+ uint32_t flags,
+ struct rte_ring *ring,
+ struct rte_mempool *mp,
+ void *filter)
+{
+ int ret = 0;
+ char domBDF[DEVICE_ID_SIZE];
+
+ ret = pdump_validate_ring_mp(ring, mp);
+ if (ret < 0)
+ return ret;
+ ret = pdump_validate_flags(flags);
+ if (ret < 0)
+ return ret;
+
+ if (pdump_get_dombdf(device_id, domBDF, sizeof(domBDF)) > 0)
+ ret = pdump_prepare_client_request(domBDF, queue, flags,
+ ENABLE, ring, mp, filter);
+ else
+ ret = pdump_prepare_client_request(device_id, queue, flags,
+ ENABLE, ring, mp, filter);
+
+ return ret;
+}
+
+int
+rte_pdump_disable(uint8_t port, uint16_t queue, uint32_t flags)
+{
+ int ret = 0;
+ char name[DEVICE_ID_SIZE];
+
+ ret = pdump_validate_port(port, name);
+ if (ret < 0)
+ return ret;
+ ret = pdump_validate_flags(flags);
+ if (ret < 0)
+ return ret;
+
+ ret = pdump_prepare_client_request(name, queue, flags,
+ DISABLE, NULL, NULL, NULL);
+
+ return ret;
+}
+
+int
+rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
+ uint32_t flags)
+{
+ int ret = 0;
+ char domBDF[DEVICE_ID_SIZE];
+
+ ret = pdump_validate_flags(flags);
+ if (ret < 0)
+ return ret;
+
+ if (pdump_get_dombdf(device_id, domBDF, sizeof(domBDF)) > 0)
+ ret = pdump_prepare_client_request(domBDF, queue, flags,
+ DISABLE, NULL, NULL, NULL);
+ else
+ ret = pdump_prepare_client_request(device_id, queue, flags,
+ DISABLE, NULL, NULL, NULL);
+
+ return ret;
+}
diff --git a/lib/librte_pdump/rte_pdump.h b/lib/librte_pdump/rte_pdump.h
new file mode 100644
index 0000000..ca9333a
--- /dev/null
+++ b/lib/librte_pdump/rte_pdump.h
@@ -0,0 +1,186 @@
+/*-
+ * 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.
+ */
+
+#ifndef _RTE_PDUMP_H_
+#define _RTE_PDUMP_H_
+
+/**
+ * @file
+ * RTE pdump
+ *
+ * packet dump library to provide packet capturing support on dpdk.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RTE_PDUMP_ALL_QUEUES UINT16_MAX
+
+enum {
+ RTE_PDUMP_FLAG_RX = 1, /* receive direction */
+ RTE_PDUMP_FLAG_TX = 2, /* transmit direction */
+ /* both receive and transmit directions */
+ RTE_PDUMP_FLAG_RXTX = (RTE_PDUMP_FLAG_RX|RTE_PDUMP_FLAG_TX)
+};
+
+/**
+ * Initialize packet capturing handling
+ *
+ * Creates pthread and server socket for handling clients
+ * requests to enable/disable rxtx callbacks.
+ *
+ * @return
+ * 0 on success, -1 on error
+ */
+int
+rte_pdump_init(void);
+
+/**
+ * Un initialize packet capturing handling
+ *
+ * Cancels pthread, close server socket, removes server socket address.
+ *
+ * @return
+ * 0 on success, -1 on error
+ */
+int
+rte_pdump_uninit(void);
+
+/**
+ * Enables packet capturing on given port and queue.
+ *
+ * @param port
+ * port on which packet capturing should be enabled.
+ * @param queue
+ * queue of a given port on which packet capturing should be enabled.
+ * users should pass on value UINT16_MAX to enable packet capturing on all
+ * queues of a given port.
+ * @param flags
+ * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
+ * on which packet capturing should be enabled for a given port and queue.
+ * @param ring
+ * ring on which captured packets will be enqueued for user.
+ * @param mp
+ * mempool on to which original packets will be mirrored or duplicated.
+ * @param filter
+ * place holder for packet filtering.
+ *
+ * @return
+ * 0 on success, -1 on error, rte_errno is set accordingly.
+ */
+
+int
+rte_pdump_enable(uint8_t port, uint16_t queue, uint32_t flags,
+ struct rte_ring *ring,
+ struct rte_mempool *mp,
+ void *filter);
+
+/**
+ * Disables packet capturing on given port and queue.
+ *
+ * @param port
+ * port on which packet capturing should be disabled.
+ * @param queue
+ * queue of a given port on which packet capturing should be disabled.
+ * users should pass on value UINT16_MAX to disable packet capturing on all
+ * queues of a given port.
+ * @param flags
+ * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
+ * on which packet capturing should be enabled for a given port and queue.
+ *
+ * @return
+ * 0 on success, -1 on error, rte_errno is set accordingly.
+ */
+
+int
+rte_pdump_disable(uint8_t port, uint16_t queue, uint32_t flags);
+
+/**
+ * Enables packet capturing on given device id and queue.
+ * device_id can be name or pci address of device.
+ *
+ * @param device_id
+ * device id on which packet capturing should be enabled.
+ * @param queue
+ * queue of a given device id on which packet capturing should be enabled.
+ * users should pass on value UINT16_MAX to enable packet capturing on all
+ * queues of a given device id.
+ * @param flags
+ * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
+ * on which packet capturing should be enabled for a given port and queue.
+ * @param ring
+ * ring on which captured packets will be enqueued for user.
+ * @param mp
+ * mempool on to which original packets will be mirrored or duplicated.
+ * @param filter
+ * place holder for packet filtering.
+ *
+ * @return
+ * 0 on success, -1 on error, rte_errno is set accordingly.
+ */
+
+int
+rte_pdump_enable_by_deviceid(char *device_id, uint16_t queue,
+ uint32_t flags,
+ struct rte_ring *ring,
+ struct rte_mempool *mp,
+ void *filter);
+
+/**
+ * Disables packet capturing on given device_id and queue.
+ * device_id can be name or pci address of device.
+ *
+ * @param device_id
+ * pci address or name of the device on which packet capturing
+ * should be disabled.
+ * @param queue
+ * queue of a given device on which packet capturing should be disabled.
+ * users should pass on value UINT16_MAX to disable packet capturing on all
+ * queues of a given device id.
+ * @param flags
+ * flags specifies RTE_PDUMP_FLAG_RX/RTE_PDUMP_FLAG_TX/RTE_PDUMP_FLAG_RXTX
+ * on which packet capturing should be enabled for a given port and queue.
+ *
+ * @return
+ * 0 on success, -1 on error, rte_errno is set accordingly.
+ */
+int
+rte_pdump_disable_by_deviceid(char *device_id, uint16_t queue,
+ uint32_t flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_PDUMP_H_ */
diff --git a/lib/librte_pdump/rte_pdump_version.map b/lib/librte_pdump/rte_pdump_version.map
new file mode 100644
index 0000000..3e744f3
--- /dev/null
+++ b/lib/librte_pdump/rte_pdump_version.map
@@ -0,0 +1,12 @@
+DPDK_16.07 {
+ global:
+
+ rte_pdump_disable;
+ rte_pdump_disable_by_deviceid;
+ rte_pdump_enable;
+ rte_pdump_enable_by_deviceid;
+ rte_pdump_init;
+ rte_pdump_uninit;
+
+ local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index b84b56d..f792f2a 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -61,6 +61,7 @@ _LDLIBS-y += --whole-archive
_LDLIBS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += -lrte_distributor
_LDLIBS-$(CONFIG_RTE_LIBRTE_REORDER) += -lrte_reorder
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PDUMP) += -lrte_pdump
ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
_LDLIBS-$(CONFIG_RTE_LIBRTE_KNI) += -lrte_kni
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v7 6/8] app/pdump: add pdump tool for packet capturing
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 0/8] add " Reshma Pattan
` (4 preceding siblings ...)
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 5/8] lib/librte_pdump: add new library for packet capturing support Reshma Pattan
@ 2016-06-09 16:10 ` Reshma Pattan
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 7/8] app/test-pmd: add pdump initialization uninitialization Reshma Pattan
` (2 subsequent siblings)
8 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-09 16:10 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
New tool added for packet capturing on dpdk.
This tool supports command line options.
This tool runs as secondary process by default.
Command line supports various parameters to capture
the packets.
User should pass on a)port and queue (or) b)pci address
and queue (or) c)device name and queue to capture
the packets.
Users also need to pass on either pcap file name or
any linux iface, on to which packets captured from dpdk
ports will be sent on for the users to view using tcpdump.
Users have option to capture packets either a) in RX
direction, b)(or) in TX direction c)(or) from both the
directions.
User can pass on ring_size and mempool parameters using
command line, but these are optional parameters.
These are used to create ring and mempool objects for packet
mirroring from primary application to tool. If user doesn't
provide any values, default values will be used internally
for the creation of the ring and mempool.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
MAINTAINERS | 1 +
app/Makefile | 1 +
app/pdump/Makefile | 45 +++
app/pdump/main.c | 844 +++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 891 insertions(+)
create mode 100644 app/pdump/Makefile
create mode 100644 app/pdump/main.c
diff --git a/MAINTAINERS b/MAINTAINERS
index cc3ffdb..a48c8de 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -435,6 +435,7 @@ F: doc/guides/sample_app_ug/packet_ordering.rst
Pdump
M: Reshma Pattan <reshma.pattan@intel.com>
F: lib/librte_pdump/
+F: app/pdump/
Hierarchical scheduler
M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
diff --git a/app/Makefile b/app/Makefile
index 1151e09..c593efa 100644
--- a/app/Makefile
+++ b/app/Makefile
@@ -37,5 +37,6 @@ DIRS-$(CONFIG_RTE_LIBRTE_PIPELINE) += test-pipeline
DIRS-$(CONFIG_RTE_TEST_PMD) += test-pmd
DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_test
DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += proc_info
+DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += pdump
include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/app/pdump/Makefile b/app/pdump/Makefile
new file mode 100644
index 0000000..96bb4af
--- /dev/null
+++ b/app/pdump/Makefile
@@ -0,0 +1,45 @@
+# 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_SDK)/mk/rte.vars.mk
+
+APP = dpdk_pdump
+
+CFLAGS += $(WERROR_FLAGS)
+
+# all source are stored in SRCS-y
+
+SRCS-y := main.c
+
+# this application needs libraries first
+DEPDIRS-y += lib
+
+include $(RTE_SDK)/mk/rte.app.mk
diff --git a/app/pdump/main.c b/app/pdump/main.c
new file mode 100644
index 0000000..f8923b9
--- /dev/null
+++ b/app/pdump/main.c
@@ -0,0 +1,844 @@
+/*
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <net/if.h>
+
+#include <rte_eal.h>
+#include <rte_common.h>
+#include <rte_debug.h>
+#include <rte_ethdev.h>
+#include <rte_memory.h>
+#include <rte_lcore.h>
+#include <rte_branch_prediction.h>
+#include <rte_errno.h>
+#include <rte_dev.h>
+#include <rte_kvargs.h>
+#include <rte_mempool.h>
+#include <rte_ring.h>
+#include <rte_pdump.h>
+
+#define PDUMP_PORT_ARG "port"
+#define PDUMP_PCI_ARG "device_id"
+#define PDUMP_QUEUE_ARG "queue"
+#define PDUMP_DIR_ARG "dir"
+#define PDUMP_RX_DEV_ARG "rx-dev"
+#define PDUMP_TX_DEV_ARG "tx-dev"
+#define PDUMP_RING_SIZE_ARG "ring-size"
+#define PDUMP_MSIZE_ARG "mbuf-size"
+#define PDUMP_NUM_MBUFS_ARG "total-num-mbufs"
+
+#define VDEV_PCAP "eth_pcap_%s_%d,tx_pcap=%s"
+#define VDEV_IFACE "eth_pcap_%s_%d,tx_iface=%s"
+#define TX_STREAM_SIZE 64
+
+#define MP_NAME "pdump_pool_%d"
+
+#define RX_RING "rx_ring_%d"
+#define TX_RING "tx_ring_%d"
+
+#define RX_STR "rx"
+#define TX_STR "tx"
+
+/* Maximum long option length for option parsing. */
+#define APP_ARG_TCPDUMP_MAX_TUPLES 54
+#define MBUF_POOL_CACHE_SIZE 250
+#define TX_DESC_PER_QUEUE 512
+#define RX_DESC_PER_QUEUE 128
+#define MBUFS_PER_POOL 65535
+#define MAX_LONG_OPT_SZ 64
+#define RING_SIZE 16384
+#define SIZE 256
+#define BURST_SIZE 32
+#define NUM_VDEVS 2
+
+#define RTE_RING_SZ_MASK (unsigned)(0x0fffffff) /**< Ring size mask */
+/* true if x is a power of 2 */
+#define POWEROF2(x) ((((x)-1) & (x)) == 0)
+
+enum pdump_en_dis {
+ DISABLE = 1,
+ ENABLE = 2
+};
+
+enum pcap_stream {
+ IFACE = 1,
+ PCAP = 2
+};
+
+enum pdump_by {
+ PORT_ID = 1,
+ DEVICE_ID = 2
+};
+
+const char *valid_pdump_arguments[] = {
+ PDUMP_PORT_ARG,
+ PDUMP_PCI_ARG,
+ PDUMP_QUEUE_ARG,
+ PDUMP_DIR_ARG,
+ PDUMP_RX_DEV_ARG,
+ PDUMP_TX_DEV_ARG,
+ PDUMP_RING_SIZE_ARG,
+ PDUMP_MSIZE_ARG,
+ PDUMP_NUM_MBUFS_ARG,
+ NULL
+};
+
+struct pdump_stats {
+ uint64_t dequeue_pkts;
+ uint64_t tx_pkts;
+ uint64_t freed_pkts;
+};
+
+struct pdump_tuples {
+ /* cli params */
+ uint8_t port;
+ char *device_id;
+ uint16_t queue;
+ char rx_dev[TX_STREAM_SIZE];
+ char tx_dev[TX_STREAM_SIZE];
+ uint32_t ring_size;
+ uint16_t mbuf_data_size;
+ uint32_t total_num_mbufs;
+
+ /* params for library API call */
+ uint32_t dir;
+ struct rte_mempool *mp;
+ struct rte_ring *rx_ring;
+ struct rte_ring *tx_ring;
+
+ /* params for packet dumping */
+ enum pdump_by dump_by_type;
+ int rx_vdev_id;
+ int tx_vdev_id;
+ enum pcap_stream rx_vdev_stream_type;
+ enum pcap_stream tx_vdev_stream_type;
+ bool single_pdump_dev;
+
+ /* stats */
+ struct pdump_stats stats;
+} __rte_cache_aligned;
+static struct pdump_tuples pdump_t[APP_ARG_TCPDUMP_MAX_TUPLES];
+
+struct parse_val {
+ uint64_t min;
+ uint64_t max;
+ uint64_t val;
+};
+
+int num_tuples;
+static struct rte_eth_conf port_conf_default;
+volatile uint8_t quit_signal;
+
+/**< display usage */
+static void
+pdump_usage(const char *prgname)
+{
+ printf("usage: %s [EAL options] -- --pdump "
+ "'(port=<port id> | device_id=<pci id or vdev name>),"
+ "(queue=<queue_id>),"
+ "(rx-dev=<iface or pcap file> |"
+ " tx-dev=<iface or pcap file>,"
+ "[ring-size=<ring size>default:16384],"
+ "[mbuf-size=<mbuf data size>default:2176],"
+ "[total-num-mbufs=<number of mbufs>default:65535]"
+ "'\n",
+ prgname);
+}
+
+static int
+parse_device_id(const char *key __rte_unused, const char *value,
+ void *extra_args)
+{
+ struct pdump_tuples *pt = extra_args;
+
+ pt->device_id = strdup(value);
+ pt->dump_by_type = DEVICE_ID;
+
+ return 0;
+}
+
+static int
+parse_queue(const char *key __rte_unused, const char *value, void *extra_args)
+{
+ unsigned long n;
+ struct pdump_tuples *pt = extra_args;
+
+ if (!strcmp(value, "*"))
+ pt->queue = RTE_PDUMP_ALL_QUEUES;
+ else {
+ n = strtoul(value, NULL, 10);
+ pt->queue = (uint16_t) n;
+ }
+ return 0;
+}
+
+static int
+parse_rxtxdev(const char *key, const char *value, void *extra_args)
+{
+
+ struct pdump_tuples *pt = extra_args;
+
+ if (!strcmp(key, PDUMP_RX_DEV_ARG)) {
+ strncpy(pt->rx_dev, value, strlen(value));
+ /* identify the tx stream type for pcap vdev */
+ if (if_nametoindex(pt->rx_dev))
+ pt->rx_vdev_stream_type = IFACE;
+ } else if (!strcmp(key, PDUMP_TX_DEV_ARG)) {
+ strncpy(pt->tx_dev, value, strlen(value));
+ /* identify the tx stream type for pcap vdev */
+ if (if_nametoindex(pt->tx_dev))
+ pt->tx_vdev_stream_type = IFACE;
+ } else {
+ printf("invalid dev type %s, must be rx or tx\n", value);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+parse_uint_value(const char *key, const char *value, void *extra_args)
+{
+ struct parse_val *v;
+ unsigned long t;
+ char *end;
+ int ret = 0;
+
+ errno = 0;
+ v = extra_args;
+ t = strtoul(value, &end, 10);
+
+ if (errno != 0 || end[0] != 0 || t < v->min || t > v->max) {
+ printf("invalid value:\"%s\" for key:\"%s\", "
+ "value must be >= %"PRIu64" and <= %"PRIu64"\n",
+ value, key, v->min, v->max);
+ ret = -EINVAL;
+ }
+ if (!strcmp(key, PDUMP_RING_SIZE_ARG) && !POWEROF2(t)) {
+ printf("invalid value:\"%s\" for key:\"%s\", "
+ "value must be power of 2\n", value, key);
+ ret = -EINVAL;
+ }
+
+ if (ret != 0)
+ return ret;
+
+ v->val = t;
+ return 0;
+}
+
+static int
+parse_pdump(const char *optarg)
+{
+ struct rte_kvargs *kvlist;
+ int ret = 0, cnt1, cnt2;
+ struct pdump_tuples *pt;
+ struct parse_val v = {0};
+
+ pt = &pdump_t[num_tuples];
+
+ /* initial check for invalid arguments */
+ kvlist = rte_kvargs_parse(optarg, valid_pdump_arguments);
+ if (kvlist == NULL) {
+ printf("--pdump=\"%s\": invalid argument passed\n", optarg);
+ return -1;
+ }
+
+ /* port/device_id parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_PORT_ARG);
+ cnt2 = rte_kvargs_count(kvlist, PDUMP_PCI_ARG);
+ if (!((cnt1 == 1 && cnt2 == 0) || (cnt1 == 0 && cnt2 == 1))) {
+ printf("--pdump=\"%s\": must have either port or "
+ "device_id argument\n", optarg);
+ ret = -1;
+ goto free_kvlist;
+ } else if (cnt1 == 1) {
+ v.min = 0;
+ v.max = RTE_MAX_ETHPORTS-1;
+ ret = rte_kvargs_process(kvlist, PDUMP_PORT_ARG,
+ &parse_uint_value, &v);
+ if (ret < 0)
+ goto free_kvlist;
+ pt->port = (uint8_t) v.val;
+ pt->dump_by_type = PORT_ID;
+ } else if (cnt2 == 1) {
+ ret = rte_kvargs_process(kvlist, PDUMP_PCI_ARG,
+ &parse_device_id, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ }
+
+ /* queue parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_QUEUE_ARG);
+ if (cnt1 != 1) {
+ printf("--pdump=\"%s\": must have queue argument\n", optarg);
+ ret = -1;
+ goto free_kvlist;
+ }
+ ret = rte_kvargs_process(kvlist, PDUMP_QUEUE_ARG, &parse_queue, pt);
+ if (ret < 0)
+ goto free_kvlist;
+
+ /* rx-dev and tx-dev parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_RX_DEV_ARG);
+ cnt2 = rte_kvargs_count(kvlist, PDUMP_TX_DEV_ARG);
+ if (cnt1 == 0 && cnt2 == 0) {
+ printf("--pdump=\"%s\": must have either rx-dev or "
+ "tx-dev argument\n", optarg);
+ ret = -1;
+ goto free_kvlist;
+ } else if (cnt1 == 1 && cnt2 == 1) {
+ ret = rte_kvargs_process(kvlist, PDUMP_RX_DEV_ARG,
+ &parse_rxtxdev, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ ret = rte_kvargs_process(kvlist, PDUMP_TX_DEV_ARG,
+ &parse_rxtxdev, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ /* if captured packets has to send to the same vdev */
+ if (!strcmp(pt->rx_dev, pt->tx_dev))
+ pt->single_pdump_dev = true;
+ pt->dir = RTE_PDUMP_FLAG_RXTX;
+ } else if (cnt1 == 1) {
+ ret = rte_kvargs_process(kvlist, PDUMP_RX_DEV_ARG,
+ &parse_rxtxdev, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ pt->dir = RTE_PDUMP_FLAG_RX;
+ } else if (cnt2 == 1) {
+ ret = rte_kvargs_process(kvlist, PDUMP_TX_DEV_ARG,
+ &parse_rxtxdev, pt);
+ if (ret < 0)
+ goto free_kvlist;
+ pt->dir = RTE_PDUMP_FLAG_TX;
+ }
+
+ /* optional */
+ /* ring_size parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_RING_SIZE_ARG);
+ if (cnt1 == 1) {
+ v.min = 2;
+ v.max = RTE_RING_SZ_MASK-1;
+ ret = rte_kvargs_process(kvlist, PDUMP_RING_SIZE_ARG,
+ &parse_uint_value, &v);
+ if (ret < 0)
+ goto free_kvlist;
+ pt->ring_size = (uint16_t) v.val;
+ } else
+ pt->ring_size = RING_SIZE;
+
+ /* mbuf_data_size parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_MSIZE_ARG);
+ if (cnt1 == 1) {
+ v.min = 1;
+ v.max = UINT16_MAX;
+ ret = rte_kvargs_process(kvlist, PDUMP_MSIZE_ARG,
+ &parse_uint_value, &v);
+ if (ret < 0)
+ goto free_kvlist;
+ pt->mbuf_data_size = (uint16_t) v.val;
+ } else
+ pt->mbuf_data_size = RTE_MBUF_DEFAULT_BUF_SIZE;
+
+ /* total_num_mbufs parsing and validation */
+ cnt1 = rte_kvargs_count(kvlist, PDUMP_NUM_MBUFS_ARG);
+ if (cnt1 == 1) {
+ v.min = 1025;
+ v.max = UINT16_MAX;
+ ret = rte_kvargs_process(kvlist, PDUMP_NUM_MBUFS_ARG,
+ &parse_uint_value, &v);
+ if (ret < 0)
+ goto free_kvlist;
+ pt->total_num_mbufs = (uint16_t) v.val;
+ } else
+ pt->total_num_mbufs = MBUFS_PER_POOL;
+
+ num_tuples++;
+
+free_kvlist:
+ rte_kvargs_free(kvlist);
+ return ret;
+}
+
+/* Parse the argument given in the command line of the application */
+static int
+launch_args_parse(int argc, char **argv, char *prgname)
+{
+ int opt, ret;
+ int option_index;
+ static struct option long_option[] = {
+ {"pdump", 1, 0, 0},
+ {NULL, 0, 0, 0}
+ };
+
+ if (argc == 1)
+ pdump_usage(prgname);
+
+ /* Parse command line */
+ while ((opt = getopt_long(argc, argv, " ",
+ long_option, &option_index)) != EOF) {
+ switch (opt) {
+ case 0:
+ if (!strncmp(long_option[option_index].name, "pdump",
+ MAX_LONG_OPT_SZ)) {
+ ret = parse_pdump(optarg);
+ if (ret) {
+ pdump_usage(prgname);
+ return -1;
+ }
+ }
+ break;
+ default:
+ pdump_usage(prgname);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static void
+print_pdump_stats(void)
+{
+ int i;
+ struct pdump_tuples *pt;
+
+ for (i = 0; i < num_tuples; i++) {
+ printf("##### PDUMP DEBUG STATS #####\n");
+ pt = &pdump_t[i];
+ printf(" -packets dequeued: %"PRIu64"\n",
+ pt->stats.dequeue_pkts);
+ printf(" -packets transmitted to vdev: %"PRIu64"\n",
+ pt->stats.tx_pkts);
+ printf(" -packets freed: %"PRIu64"\n",
+ pt->stats.freed_pkts);
+ }
+}
+
+static inline void
+disable_pdump(struct pdump_tuples *pt)
+{
+ if (pt->dump_by_type == DEVICE_ID)
+ rte_pdump_disable_by_deviceid(pt->device_id, pt->queue,
+ pt->dir);
+ else if (pt->dump_by_type == PORT_ID)
+ rte_pdump_disable(pt->port, pt->queue, pt->dir);
+}
+
+static inline void
+pdump_rxtx(struct rte_ring *ring, uint8_t vdev_id, struct pdump_stats *stats)
+{
+ /* write input packets of port to vdev for pdump */
+ struct rte_mbuf *rxtx_bufs[BURST_SIZE];
+
+ /* first dequeue packets from ring of primary process */
+ const uint16_t nb_in_deq = rte_ring_dequeue_burst(ring,
+ (void *)rxtx_bufs, BURST_SIZE);
+ stats->dequeue_pkts += nb_in_deq;
+
+ if (nb_in_deq) {
+ /* then sent on vdev */
+ uint16_t nb_in_txd = rte_eth_tx_burst(
+ vdev_id,
+ 0, rxtx_bufs, nb_in_deq);
+ stats->tx_pkts += nb_in_txd;
+
+ if (unlikely(nb_in_txd < nb_in_deq)) {
+ do {
+ rte_pktmbuf_free(rxtx_bufs[nb_in_txd]);
+ stats->freed_pkts++;
+ } while (++nb_in_txd < nb_in_deq);
+ }
+ }
+}
+
+static void
+free_ring_data(struct rte_ring *ring, uint8_t vdev_id,
+ struct pdump_stats *stats)
+{
+ while (rte_ring_count(ring))
+ pdump_rxtx(ring, vdev_id, stats);
+}
+
+static void
+cleanup_pdump_resources(void)
+{
+ int i;
+ struct pdump_tuples *pt;
+
+ /* disable pdump and free the pdump_tuple resources */
+ for (i = 0; i < num_tuples; i++) {
+ pt = &pdump_t[i];
+
+ /* remove callbacks */
+ disable_pdump(pt);
+
+ /*
+ * transmit rest of the enqueued packets of the rings on to
+ * the vdev, in order to release mbufs to the mepool.
+ **/
+ if (pt->dir & RTE_PDUMP_FLAG_RX)
+ free_ring_data(pt->rx_ring, pt->rx_vdev_id, &pt->stats);
+ if (pt->dir & RTE_PDUMP_FLAG_TX)
+ free_ring_data(pt->tx_ring, pt->tx_vdev_id, &pt->stats);
+
+ if (pt->device_id)
+ free(pt->device_id);
+
+ /* free the rings */
+ if (pt->rx_ring)
+ rte_ring_free(pt->rx_ring);
+ if (pt->tx_ring)
+ rte_ring_free(pt->tx_ring);
+ }
+}
+
+static void
+signal_handler(int sig_num)
+{
+ if (sig_num == SIGINT) {
+ printf("\n\nSignal %d received, preparing to exit...\n",
+ sig_num);
+ quit_signal = 1;
+ }
+}
+
+static inline int
+configure_vdev(uint8_t port_id)
+{
+ struct ether_addr addr;
+ const uint16_t rxRings = 0, txRings = 1;
+ const uint8_t nb_ports = rte_eth_dev_count();
+ int ret;
+ uint16_t q;
+
+ if (port_id > nb_ports)
+ return -1;
+
+ ret = rte_eth_dev_configure(port_id, rxRings, txRings,
+ &port_conf_default);
+ if (ret != 0)
+ rte_exit(EXIT_FAILURE, "dev config failed\n");
+
+ for (q = 0; q < txRings; q++) {
+ ret = rte_eth_tx_queue_setup(port_id, q, TX_DESC_PER_QUEUE,
+ rte_eth_dev_socket_id(port_id), NULL);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "queue setup failed\n");
+ }
+
+ ret = rte_eth_dev_start(port_id);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "dev start failed\n");
+
+ rte_eth_macaddr_get(port_id, &addr);
+ printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
+ " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
+ (unsigned)port_id,
+ addr.addr_bytes[0], addr.addr_bytes[1],
+ addr.addr_bytes[2], addr.addr_bytes[3],
+ addr.addr_bytes[4], addr.addr_bytes[5]);
+
+ rte_eth_promiscuous_enable(port_id);
+
+ return 0;
+}
+
+static void
+create_mp_ring_vdev(void)
+{
+ int i;
+ uint8_t portid;
+ struct pdump_tuples *pt = NULL;
+ struct rte_mempool *mbuf_pool = NULL;
+ char vdev_args[SIZE];
+ char ring_name[SIZE];
+ char mempool_name[SIZE];
+
+ for (i = 0; i < num_tuples; i++) {
+ pt = &pdump_t[i];
+ snprintf(mempool_name, SIZE, MP_NAME, i);
+ mbuf_pool = rte_mempool_lookup(mempool_name);
+ if (mbuf_pool == NULL) {
+ /* create mempool */
+ mbuf_pool = rte_pktmbuf_pool_create(mempool_name,
+ pt->total_num_mbufs,
+ MBUF_POOL_CACHE_SIZE, 0,
+ pt->mbuf_data_size,
+ rte_socket_id());
+ if (mbuf_pool == NULL)
+ rte_exit(EXIT_FAILURE,
+ "Mempool creation failed: %s\n",
+ rte_strerror(rte_errno));
+ }
+ pt->mp = mbuf_pool;
+
+ if (pt->dir == RTE_PDUMP_FLAG_RXTX) {
+ /* if captured packets has to send to the same vdev */
+ /* create rx_ring */
+ snprintf(ring_name, SIZE, RX_RING, i);
+ pt->rx_ring = rte_ring_create(ring_name, pt->ring_size,
+ rte_socket_id(), 0);
+ if (pt->rx_ring == NULL)
+ rte_exit(EXIT_FAILURE, "%s:%s:%d\n",
+ rte_strerror(rte_errno),
+ __func__, __LINE__);
+
+ /* create tx_ring */
+ snprintf(ring_name, SIZE, TX_RING, i);
+ pt->tx_ring = rte_ring_create(ring_name, pt->ring_size,
+ rte_socket_id(), 0);
+ if (pt->tx_ring == NULL)
+ rte_exit(EXIT_FAILURE, "%s:%s:%d\n",
+ rte_strerror(rte_errno),
+ __func__, __LINE__);
+
+ /* create vdevs */
+ (pt->rx_vdev_stream_type == IFACE) ?
+ snprintf(vdev_args, SIZE, VDEV_IFACE, RX_STR, i,
+ pt->rx_dev) :
+ snprintf(vdev_args, SIZE, VDEV_PCAP, RX_STR, i,
+ pt->rx_dev);
+ if (rte_eth_dev_attach(vdev_args, &portid) < 0)
+ rte_exit(EXIT_FAILURE,
+ "vdev creation failed:%s:%d\n",
+ __func__, __LINE__);
+ pt->rx_vdev_id = portid;
+
+ /* configure vdev */
+ configure_vdev(pt->rx_vdev_id);
+
+ if (pt->single_pdump_dev)
+ pt->tx_vdev_id = portid;
+ else {
+ (pt->tx_vdev_stream_type == IFACE) ?
+ snprintf(vdev_args, SIZE, VDEV_IFACE, TX_STR, i,
+ pt->tx_dev) :
+ snprintf(vdev_args, SIZE, VDEV_PCAP, TX_STR, i,
+ pt->tx_dev);
+ if (rte_eth_dev_attach(vdev_args, &portid) < 0)
+ rte_exit(EXIT_FAILURE,
+ "vdev creation failed:"
+ "%s:%d\n", __func__, __LINE__);
+ pt->tx_vdev_id = portid;
+
+ /* configure vdev */
+ configure_vdev(pt->tx_vdev_id);
+ }
+ } else if (pt->dir == RTE_PDUMP_FLAG_RX) {
+
+ /* create rx_ring */
+ snprintf(ring_name, SIZE, RX_RING, i);
+ pt->rx_ring = rte_ring_create(ring_name, pt->ring_size,
+ rte_socket_id(), 0);
+ if (pt->rx_ring == NULL)
+ rte_exit(EXIT_FAILURE, "%s\n",
+ rte_strerror(rte_errno));
+
+ (pt->rx_vdev_stream_type == IFACE) ?
+ snprintf(vdev_args, SIZE, VDEV_IFACE, RX_STR, i,
+ pt->rx_dev) :
+ snprintf(vdev_args, SIZE, VDEV_PCAP, RX_STR, i,
+ pt->rx_dev);
+ if (rte_eth_dev_attach(vdev_args, &portid) < 0)
+ rte_exit(EXIT_FAILURE,
+ "vdev creation failed:%s:%d\n",
+ __func__, __LINE__);
+ pt->rx_vdev_id = portid;
+ /* configure vdev */
+ configure_vdev(pt->rx_vdev_id);
+ } else if (pt->dir == RTE_PDUMP_FLAG_TX) {
+
+ /* create tx_ring */
+ snprintf(ring_name, SIZE, TX_RING, i);
+ pt->tx_ring = rte_ring_create(ring_name, pt->ring_size,
+ rte_socket_id(), 0);
+ if (pt->tx_ring == NULL)
+ rte_exit(EXIT_FAILURE, "%s\n",
+ rte_strerror(rte_errno));
+
+ (pt->tx_vdev_stream_type == IFACE) ?
+ snprintf(vdev_args, SIZE, VDEV_IFACE, TX_STR, i,
+ pt->tx_dev) :
+ snprintf(vdev_args, SIZE, VDEV_PCAP, TX_STR, i,
+ pt->tx_dev);
+ if (rte_eth_dev_attach(vdev_args, &portid) < 0)
+ rte_exit(EXIT_FAILURE,
+ "vdev creation failed\n");
+ pt->tx_vdev_id = portid;
+
+ /* configure vdev */
+ configure_vdev(pt->tx_vdev_id);
+ }
+ }
+}
+
+static void
+enable_pdump(void)
+{
+ int i;
+ struct pdump_tuples *pt;
+ int ret = 0, ret1 = 0;
+
+ for (i = 0; i < num_tuples; i++) {
+ pt = &pdump_t[i];
+ if (pt->dir == RTE_PDUMP_FLAG_RXTX) {
+ if (pt->dump_by_type == DEVICE_ID) {
+ ret = rte_pdump_enable_by_deviceid(
+ pt->device_id,
+ pt->queue,
+ RTE_PDUMP_FLAG_RX,
+ pt->rx_ring,
+ pt->mp, NULL);
+ ret = rte_pdump_enable_by_deviceid(
+ pt->device_id,
+ pt->queue,
+ RTE_PDUMP_FLAG_TX,
+ pt->tx_ring,
+ pt->mp, NULL);
+ } else if (pt->dump_by_type == PORT_ID) {
+ ret = rte_pdump_enable(pt->port, pt->queue,
+ RTE_PDUMP_FLAG_RX,
+ pt->rx_ring, pt->mp, NULL);
+ ret1 = rte_pdump_enable(pt->port, pt->queue,
+ RTE_PDUMP_FLAG_TX,
+ pt->tx_ring, pt->mp, NULL);
+ }
+ } else if (pt->dir == RTE_PDUMP_FLAG_RX) {
+ if (pt->dump_by_type == DEVICE_ID)
+ ret = rte_pdump_enable_by_deviceid(
+ pt->device_id,
+ pt->queue,
+ pt->dir, pt->rx_ring,
+ pt->mp, NULL);
+ else if (pt->dump_by_type == PORT_ID)
+ ret = rte_pdump_enable(pt->port, pt->queue,
+ pt->dir,
+ pt->rx_ring, pt->mp, NULL);
+ } else if (pt->dir == RTE_PDUMP_FLAG_TX) {
+ if (pt->dump_by_type == DEVICE_ID)
+ ret = rte_pdump_enable_by_deviceid(
+ pt->device_id,
+ pt->queue,
+ pt->dir,
+ pt->tx_ring, pt->mp, NULL);
+ else if (pt->dump_by_type == PORT_ID)
+ ret = rte_pdump_enable(pt->port, pt->queue,
+ pt->dir,
+ pt->tx_ring, pt->mp, NULL);
+ }
+ if (ret < 0 || ret1 < 0) {
+ cleanup_pdump_resources();
+ rte_exit(EXIT_FAILURE, "%s\n", rte_strerror(rte_errno));
+ }
+ }
+}
+
+static inline void
+dump_packets(void)
+{
+ int i;
+ struct pdump_tuples *pt;
+
+ while (!quit_signal) {
+ for (i = 0; i < num_tuples; i++) {
+ pt = &pdump_t[i];
+ if (pt->dir & RTE_PDUMP_FLAG_RX)
+ pdump_rxtx(pt->rx_ring, pt->rx_vdev_id,
+ &pt->stats);
+ if (pt->dir & RTE_PDUMP_FLAG_TX)
+ pdump_rxtx(pt->tx_ring, pt->tx_vdev_id,
+ &pt->stats);
+ }
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ int diag;
+ int ret;
+ int i;
+
+ char c_flag[] = "-c1";
+ char n_flag[] = "-n4";
+ char mp_flag[] = "--proc-type=secondary";
+ char *argp[argc + 3];
+
+ /* catch ctrl-c so we can print on exit */
+ signal(SIGINT, signal_handler);
+
+ argp[0] = argv[0];
+ argp[1] = c_flag;
+ argp[2] = n_flag;
+ argp[3] = mp_flag;
+
+ for (i = 1; i < argc; i++)
+ argp[i + 3] = argv[i];
+
+ argc += 3;
+
+ diag = rte_eal_init(argc, argp);
+ if (diag < 0)
+ rte_panic("Cannot init EAL\n");
+
+ argc -= diag;
+ argv += (diag - 3);
+
+ /* parse app arguments */
+ if (argc > 1) {
+ ret = launch_args_parse(argc, argv, argp[0]);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE, "Invalid argument\n");
+ }
+
+ /* create mempool, ring and vdevs info */
+ create_mp_ring_vdev();
+ enable_pdump();
+ dump_packets();
+
+ cleanup_pdump_resources();
+ /* dump debug stats */
+ print_pdump_stats();
+
+ return 0;
+}
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v7 7/8] app/test-pmd: add pdump initialization uninitialization
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 0/8] add " Reshma Pattan
` (5 preceding siblings ...)
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 6/8] app/pdump: add pdump tool for packet capturing Reshma Pattan
@ 2016-06-09 16:10 ` Reshma Pattan
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 8/8] doc: update doc for packet capture framework Reshma Pattan
2016-06-09 17:34 ` [dpdk-dev] [PATCH v7 0/8] add " Ananyev, Konstantin
8 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-09 16:10 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Call rte_pdump_init and rte_pdump_uninit for packet
capturing initialization and uninitialization.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
---
app/test-pmd/testpmd.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index dd6b046..f6089fa 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -76,6 +76,7 @@
#ifdef RTE_LIBRTE_PMD_XENVIRT
#include <rte_eth_xenvirt.h>
#endif
+#include <rte_pdump.h>
#include "testpmd.h"
@@ -2029,6 +2030,8 @@ signal_handler(int signum)
if (signum == SIGINT || signum == SIGTERM) {
printf("\nSignal %d received, preparing to exit...\n",
signum);
+ /* uninitialize packet capture framework */
+ rte_pdump_uninit();
force_quit();
/* exit with the expected status */
signal(signum, SIG_DFL);
@@ -2049,6 +2052,9 @@ main(int argc, char** argv)
if (diag < 0)
rte_panic("Cannot init EAL\n");
+ /* initialize packet capture framework */
+ rte_pdump_init();
+
nb_ports = (portid_t) rte_eth_dev_count();
if (nb_ports == 0)
RTE_LOG(WARNING, EAL, "No probed ethernet devices\n");
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [dpdk-dev] [PATCH v7 8/8] doc: update doc for packet capture framework
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 0/8] add " Reshma Pattan
` (6 preceding siblings ...)
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 7/8] app/test-pmd: add pdump initialization uninitialization Reshma Pattan
@ 2016-06-09 16:10 ` Reshma Pattan
2016-06-09 17:34 ` [dpdk-dev] [PATCH v7 0/8] add " Ananyev, Konstantin
8 siblings, 0 replies; 82+ messages in thread
From: Reshma Pattan @ 2016-06-09 16:10 UTC (permalink / raw)
To: dev; +Cc: Reshma Pattan
Added programmers guide for librte_pdump.
Added sample application guide for app/pdump application.
Updated release note for packet capture framework changes.
Signed-off-by: Reshma Pattan <reshma.pattan@intel.com>
Acked-by: John McNamara <john.mcnamara@intel.com>
---
MAINTAINERS | 3 +
doc/guides/prog_guide/index.rst | 1 +
doc/guides/prog_guide/pdump_library.rst | 107 ++++++++++++++++++++++++++++
doc/guides/rel_notes/release_16_07.rst | 13 ++++
doc/guides/sample_app_ug/index.rst | 1 +
doc/guides/sample_app_ug/pdump.rst | 122 ++++++++++++++++++++++++++++++++
6 files changed, 247 insertions(+)
create mode 100644 doc/guides/prog_guide/pdump_library.rst
create mode 100644 doc/guides/sample_app_ug/pdump.rst
diff --git a/MAINTAINERS b/MAINTAINERS
index a48c8de..ce7c941 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -436,6 +436,9 @@ Pdump
M: Reshma Pattan <reshma.pattan@intel.com>
F: lib/librte_pdump/
F: app/pdump/
+F: doc/guides/prog_guide/pdump_library.rst
+F: doc/guides/sample_app_ug/pdump.rst
+
Hierarchical scheduler
M: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
diff --git a/doc/guides/prog_guide/index.rst b/doc/guides/prog_guide/index.rst
index b862d0c..4caf969 100644
--- a/doc/guides/prog_guide/index.rst
+++ b/doc/guides/prog_guide/index.rst
@@ -71,6 +71,7 @@ Programmer's Guide
writing_efficient_code
profile_app
glossary
+ pdump_library
**Figures**
diff --git a/doc/guides/prog_guide/pdump_library.rst b/doc/guides/prog_guide/pdump_library.rst
new file mode 100644
index 0000000..1809234
--- /dev/null
+++ b/doc/guides/prog_guide/pdump_library.rst
@@ -0,0 +1,107 @@
+.. 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.
+
+.. _pdump_library:
+
+The librte_pdump Library
+========================
+
+The ``librte_pdump`` library provides a framework for packet capturing in DPDK.
+The library provides the following APIs to initialize the packet capture framework, to enable
+or disable the packet capture, and to uninitialize it:
+
+* ``rte_pdump_init()``:
+ This API initializes the packet capture framework.
+
+* ``rte_pdump_enable()``:
+ This API enables the packet capture on a given port and queue.
+ Note: The filter option in the API is a place holder for future enhancements.
+
+* ``rte_pdump_enable_by_deviceid()``:
+ This API enables the packet capture on a given device id (``vdev name or pci address``) and queue.
+ Note: The filter option in the API is a place holder for future enhancements.
+
+* ``rte_pdump_disable()``:
+ This API disables the packet capture on a given port and queue.
+
+* ``rte_pdump_disable_by_deviceid()``:
+ This API disables the packet capture on a given device id (``vdev name or pci address``) and queue.
+
+* ``rte_pdump_uninit()``:
+ This API uninitializes the packet capture framework.
+
+
+Operation
+---------
+
+The ``librte_pdump`` library works on a client/server model. The server is responsible for enabling or
+disabling the packet capture and the clients are responsible for requesting the enabling or disabling of
+the packet capture.
+
+The packet capture framework, as part of its initialization, creates the pthread and the server socket in
+the pthread. The application that calls the framework initialization first will have the server socket created.
+Further calls to the framework initialization by the same application or other applications is not allowed i.e., only
+one server socket is allowed on the system. So the other applications can only request enabling or disabling of
+the packet capture at which point the client socket is created for them to send the request to the server.
+The server socket will listen for client requests for enabling or disabling the packet capture.
+
+
+Implementation Details
+----------------------
+
+The library API ``rte_pdump_init()``, initializes the packet capture framework by creating the pthread and the server
+socket. The server socket in the pthread context will be listening to the client requests to enable or disable the
+packet capture. Whoever calls this API first will have the server socket created, the subsequent calls to this APIs
+will not create any further server socket. i.e. only one server socket is allowed.
+
+The library APIs ``rte_pdump_enable()`` and ``rte_pdump_enable_by_deviceid()`` enables the packet capture.
+On each call to these APIs, the library creates a separate client socket, creates the "pdump enable" request and sends
+the request to the server. The server that is listening on the socket will take the request and enable the packet capture
+by registering the Ethernet RX and TX callbacks for the given port or device_id and queue combinations.
+Then the server will mirror the packets to the new mempool and enqueue them to the rte_ring that clients have passed
+to these APIs. The server also sends the response back to the client about the status of the request that was processed.
+After the response is received from the server, the client socket is closed.
+
+The library APIs ``rte_pdump_disable()`` and ``rte_pdump_disable_by_deviceid()`` disables the packet capture.
+On each call to these APIs, the library creates a separate client socket, creates the "pdump disable" request and sends
+the request to the server. The server that is listening on the socket will take the request and disable the packet
+capture by removing the Ethernet RX and TX callbacks for the given port or device_id and queue combinations. The server
+also sends the response back to the client about the status of the request that was processed. After the response is
+received from the server, the client socket is closed.
+
+The library API ``rte_pdump_uninit()``, uninitializes the packet capture framework by closing the pthread and the
+server socket.
+
+
+Use Case: Packet Capturing
+--------------------------
+
+The DPDK ``app/pdump`` tool is developed based on this library to capture packets in DPDK.
+Users can use this as an example to develop their own packet capturing application.
diff --git a/doc/guides/rel_notes/release_16_07.rst b/doc/guides/rel_notes/release_16_07.rst
index c0f6b02..a4de2a2 100644
--- a/doc/guides/rel_notes/release_16_07.rst
+++ b/doc/guides/rel_notes/release_16_07.rst
@@ -66,6 +66,11 @@ New Features
* Enable RSS per network interface through the configuration file.
* Streamline the CLI code.
+* **Added packet capture framework.**
+
+ * A new library ``librte_pdump`` is added to provide packet capture APIs.
+ * A new ``app/pdump`` tool is added to capture packets in DPDK.
+
Resolved Issues
---------------
@@ -135,6 +140,11 @@ API Changes
ibadcrc, ibadlen, imcasts, fdirmatch, fdirmiss,
tx_pause_xon, rx_pause_xon, tx_pause_xoff, rx_pause_xoff.
+* Function ``rte_eth_dev_get_port_by_name`` changed to a public API.
+
+* Function ``rte_eth_dev_info_get`` updated to return new fields ``nb_rx_queues`` and ``nb_tx_queues``
+ in the ``rte_eth_dev_info`` object.
+
ABI Changes
-----------
@@ -146,6 +156,9 @@ ABI Changes
* The ``rte_port_source_params`` structure has new fields to support PCAP file.
It was already in release 16.04 with ``RTE_NEXT_ABI`` flag.
+* The ``rte_eth_dev_info`` structure has new fields ``nb_rx_queues`` and ``nb_tx_queues``
+ to support number of queues configured by software.
+
Shared Library Versions
-----------------------
diff --git a/doc/guides/sample_app_ug/index.rst b/doc/guides/sample_app_ug/index.rst
index 930f68c..96bb317 100644
--- a/doc/guides/sample_app_ug/index.rst
+++ b/doc/guides/sample_app_ug/index.rst
@@ -76,6 +76,7 @@ Sample Applications User Guide
ptpclient
performance_thread
ipsec_secgw
+ pdump
**Figures**
diff --git a/doc/guides/sample_app_ug/pdump.rst b/doc/guides/sample_app_ug/pdump.rst
new file mode 100644
index 0000000..96c8709
--- /dev/null
+++ b/doc/guides/sample_app_ug/pdump.rst
@@ -0,0 +1,122 @@
+
+.. 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.
+
+
+dpdk_pdump Application
+======================
+
+The ``dpdk_pdump`` application is a Data Plane Development Kit (DPDK) application that runs as a DPDK secondary process and
+is capable of enabling packet capture on dpdk ports.
+
+
+Running the Application
+-----------------------
+
+The application has a ``--pdump`` command line option with various sub arguments:
+
+.. code-block:: console
+
+ ./build/app/dpdk_pdump --
+ --pdump '(port=<port id> | device_id=<pci id or vdev name>),
+ (queue=<queue_id>),
+ (rx-dev=<iface or pcap file> |
+ tx-dev=<iface or pcap file>),
+ [ring-size=<ring size>],
+ [mbuf-size=<mbuf data size>],
+ [total-num-mbufs=<number of mbufs>]'
+
+Note:
+
+* Parameters inside the parentheses represents mandatory parameters.
+
+* Parameters inside the square brackets represents optional parameters.
+
+Multiple instances of ``--pdump`` can be passed to capture packets on different port and queue combinations.
+
+
+Parameters
+~~~~~~~~~~
+
+``port``:
+Port id of the eth device on which packets should be captured.
+
+``device_id``:
+PCI address (or) name of the eth device on which packets should be captured.
+
+ .. Note::
+
+ * As of now the ``dpdk_pdump`` tool cannot capture the packets of virtual devices
+ in the primary process due to a bug in the ethdev library. Due to this bug, in a multi process context,
+ when the primary and secondary have different ports set, then the secondary process
+ (here the ``dpdk_pdump`` tool) overwrites the ``rte_eth_devices[]`` entries of the primary process.
+
+``queue``:
+Queue id of the eth device on which packets should be captured. The user can pass a queue value of ``*`` to enable
+packet capture on all queues of the eth device.
+
+``rx-dev``:
+Can be either a pcap file name or any Linux iface.
+
+``tx-dev``:
+Can be either a pcap file name or any Linux iface.
+
+ .. Note::
+
+ * To receive ingress packets only, ``rx-dev`` should be passed.
+
+ * To receive egress packets only, ``tx-dev`` should be passed.
+
+ * To receive ingress and egress packets separately ``rx-dev`` and ``tx-dev``
+ should both be passed with the different file names or the Linux iface names.
+
+ * To receive ingress and egress packets separately ``rx-dev`` and ``tx-dev``
+ should both be passed with the same file names or the the Linux iface names.
+
+``ring-size``:
+Size of the ring. This value is used internally for ring creation. The ring will be used to enqueue the packets from
+the primary application to the secondary. This is an optional parameter with default size 16384.
+
+``mbuf-size``:
+Size of the mbuf data. This is used internally for mempool creation. Ideally this value must be same as
+the primary application's mempool's mbuf data size which is used for packet RX. This is an optional parameter with
+default size 2176.
+
+``total-num-mbufs``:
+Total number mbufs in mempool. This is used internally for mempool creation. This is an optional parameter with default
+value 65535.
+
+
+Example
+-------
+
+.. code-block:: console
+
+ $ sudo ./build/app/dpdk_pdump -- --pdump 'port=0,queue=*,rx-dev=/tmp/rx.pcap'
--
2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [dpdk-dev] [PATCH v7 0/8] add packet capture framework
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 0/8] add " Reshma Pattan
` (7 preceding siblings ...)
2016-06-09 16:10 ` [dpdk-dev] [PATCH v7 8/8] doc: update doc for packet capture framework Reshma Pattan
@ 2016-06-09 17:34 ` Ananyev, Konstantin
8 siblings, 0 replies; 82+ messages in thread
From: Ananyev, Konstantin @ 2016-06-09 17:34 UTC (permalink / raw)
To: Pattan, Reshma, dev
>
> This patch set include below changes
>
> 1)Changes to librte_ether.
> 2)A new library librte_pdump added for packet capture framework.
> 3)A new app/pdump tool added for packet capturing.
> 4)Test pmd changes done to initialize packet capture framework.
> 5)Documentation update.
>
> 1)librte_pdump
> ==============
> To support packet capturing on dpdk Ethernet devices, a new library librte_pdump
> is added.Users can develop their own packet capturing application using new library APIs.
>
> Operation:
> ----------
> Pdump library provides APIs to support packet capturing on dpdk Ethernet devices.
> Library provides APIs to initialize the packet capture framework, enable/disable
> the packet capture and uninitialize the packet capture framework.
>
> Pdump library works on client/server based model.
>
> Sever is responsible for enabling/disabling the packet captures.
> Clients are responsible for requesting enable/disable of the
> packet captures.
>
> As part of packet capture framework initialization, pthread and
> the server socket is created. Only one server socket is allowed on the system.
> As part of enabling/disabling the packet capture, client sockets are created
> and multiple client sockets are allowed.
> Who ever calls initialization first they will succeed with the initialization,
> next subsequent calls of initialization are not allowed. So next users can only
> request enabling/disabling the packet capture.
>
> Applications using below APIs need to pass port/device_id, queue, mempool and
> ring parameters. Library uses user provided ring and mempool to mirror the rx/tx
> packets of the port for users. Users need to dequeue the rings and write the packets
> to vdev(pcap/tuntap) to view the packets using any standard tools.
>
> Note:
> Mempool and Ring should be mc/mp supportable.
> Mempool mbuf size should be big enough to handle the rx/tx packets of a port.
>
> APIs:
> -----
> rte_pdump_init()
> rte_pdump_enable()
> rte_pdump_enable_by_deviceid()
> rte_pdump_disable()
> rte_pdump_disable_by_deviceid()
> rte_pdump_uninit()
>
> 2)app/pdump tool
> ================
> Tool app/pdump is designed based on librte_pdump for packet capturing in DPDK.
> This tool by default runs as secondary process, and provides the support for
> the command line options for packet capture.
>
> ./build/app/dpdk_pdump --
> --pdump '(port=<port id> | device_id=<pci id or vdev name>),
> (queue=<queue id>),
> (rx-dev=<iface or pcap file> |
> tx-dev=<iface or pcap file>),
> [ring-size=<ring size>],
> [mbuf-size=<mbuf data size>],
> [total-num-mbufs=<number of mbufs>]'
>
> Parameters inside the parenthesis represents the mandatory parameters.
> Parameters inside the square brackets represents optional parameters.
> User has to pass on packet capture parameters under --pdump parameters, multiples of
> --pdump can be passed to capture packets on different port and queue combinations
>
> Operation:
> ----------
> *Tool parse the user command line arguments,
> creates the mempool, ring and the PCAP PMD vdev with 'tx_stream' as either
> of the device passed in rx-dev|tx-dev parameters.
>
> *Then calls the APIs of librte_pdump i.e. rte_pdump_enable()/rte_pdump_enable_by_deviceid()
> to enable packet capturing on a specific port/device_id and queue by passing on
> port|device_id, queue, mempool and ring info.
>
> *Tool runs in while loop to dequeue the packets from the ring and write them to pcap device.
>
> *Tool can be stopped using SIGINT, upon which tool calls
> rte_pdump_disable()/rte_pdump_disable_by_deviceid() and free the allocated resources.
>
> Note:
> CONFIG_RTE_LIBRTE_PMD_PCAP flag should be set to yes to compile and run the pdump tool.
>
> 3)Test-pmd changes
> ==================
> Changes are done to test-pmd application to initialize/uninitialize the packet capture framework.
> So app/pdump tool can be run to see packets of dpdk ports that are used by test-pmd.
>
> Similarly any application which needs packet capture should call initialize/uninitialize APIs of
> librte_pdump and use pdump tool to start the capture.
>
> 4)Packet capture flow between pdump tool and librte_pdump
> =========================================================
> * Pdump tool (Secondary process) requests packet capture
> for specific port|device_id and queue combinations.
>
> *Library in secondary process context creates client socket and communicates
> the port|device_id, queue, ring and mempool to server.
>
> *Library initializes server in primary process 'test-pmd' context and server serves
> the client request to enable Ethernet rxtx call-backs for a given port|device_id and queue.
>
> *Copy the rx/tx packets to passed mempool and enqueue the packets to ring for secondary process.
>
> *Pdump tool will dequeue the packets from ring and writes them to PCAPMD vdev,
> so ultimately packets will be seen on the device that is passed in rx-dev|tx-dev.
>
> *Once the pdump tool is terminated with SIGINT it will disable the packet capturing.
>
> *Library receives the disable packet capture request, communicate the info to server,
> server will remove the Ethernet rxtx call-backs.
>
> *Packet capture can be seen using tcpdump command
> "tcpdump -ni <iface>" (or) "tcpdump –nr <pcapfile>"
>
> 5)Example command line
> ======================
> ./build/app/dpdk_pdump -- --pdump 'device_id=0000:02:0.0,queue=*,tx-dev=/tmp/dt-file.pcap,rx-dev=/tmp/dr-file.pcap,ring-
> size=8192,mbuf-size=2176,total-num-mbufs=32768' --pdump 'device_id=0000:01:00.0,queue=*,rx-dev=/tmp/d-file.pcap,tx-
> dev=/tmp/d-file.pcap,ring-size=16384,mbuf-size=2176,total-num-mbufs=32768'
>
> v7:
> fixed lines over 90 characters.
>
> v6:
> removed below deprecation notice patch from patch set.
> http://dpdk.org/dev/patchwork/patch/13372/
>
> v5:
> addressed code review comments for below patches
> http://dpdk.org/dev/patchwork/patch/12955/
> http://dpdk.org/dev/patchwork/patch/12951/
>
> v4:
> added missing deprecation notice for ABI changes of rte_eth_dev_info structure.
> made doc changes as per doc guidelines.
> replaced rte_eal_vdev_init with rte_eth_dev_attach in pdump tool.
> removed rxtx-dev parameter from pdump tool command line.
>
> v3:
> app/pdump: Moved cleanup code from signal handler to main.
> divided librte_ether changes into multiple patches.
> example command changed in app/pdump application guide
>
> v2:
> fix compilation issues for 4.8.3
> fix unnecessary #includes
>
>
> Reshma Pattan (8):
> librte_ether: protect add/remove of rxtx callbacks with spinlocks
> librte_ether: add new api rte_eth_add_first_rx_callback
> librte_ether: add new fields to rte_eth_dev_info struct
> librte_ether: make rte_eth_dev_get_port_by_name
> rte_eth_dev_get_name_by_port public
> lib/librte_pdump: add new library for packet capturing support
> app/pdump: add pdump tool for packet capturing
> app/test-pmd: add pdump initialization uninitialization
> doc: update doc for packet capture framework
>
Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
> --
> 2.5.0
^ permalink raw reply [flat|nested] 82+ messages in thread