From: x-fn-spp@sl.ntt-tx.co.jp
To: ferruh.yigit@intel.com, ogawa.yasufumi@lab.ntt.co.jp
Cc: spp@dpdk.org
Subject: [spp] [PATCH v2 3/7] spp_pcap: add management function
Date: Fri, 8 Feb 2019 17:44:34 +0900 [thread overview]
Message-ID: <201902080844.x188ic6d030814@imss04.silk.ntt-tx.co.jp> (raw)
In-Reply-To: <20190208084438.7952-1-x-fn-spp@sl.ntt-tx.co.jp>
From: Hideyuki Yamashita <yamashita.hideyuki@po.ntt-tx.co.jp>
Add data or interface management function for spp_pcap.
Signed-off-by: Hideyuki Yamashita <yamashita.hideyuki@po.ntt-tx.co.jp>
Signed-off-by: Naoki Takada <takada.naoki@lab.ntt.co.jp>
---
src/pcap/spp_proc.c | 289 ++++++++++++++++++++++++++++++++
src/pcap/spp_proc.h | 389 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 678 insertions(+)
create mode 100644 src/pcap/spp_proc.c
create mode 100644 src/pcap/spp_proc.h
diff --git a/src/pcap/spp_proc.c b/src/pcap/spp_proc.c
new file mode 100644
index 0000000..ab08337
--- /dev/null
+++ b/src/pcap/spp_proc.c
@@ -0,0 +1,289 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Nippon Telegraph and Telephone Corporation
+ */
+
+#include <unistd.h>
+#include <string.h>
+
+#include <rte_eth_ring.h>
+#include <rte_log.h>
+
+#include "spp_proc.h"
+
+#define RTE_LOGTYPE_SPP_PROC RTE_LOGTYPE_USER2
+
+/* Manage data to addoress */
+struct manage_data_addr_info {
+ struct startup_param *p_startup_param;
+ struct iface_info *p_iface_info;
+ struct core_mng_info *p_core_info;
+ int *p_capture_request;
+ int *p_capture_status;
+ unsigned int main_lcore_id;
+};
+
+/* Declare global variables */
+/* Logical core ID for main process */
+static struct manage_data_addr_info g_mng_data_addr;
+
+/* generation of the ring port */
+int
+add_ring_pmd(int ring_id)
+{
+ struct rte_ring *ring;
+ int ring_port_id;
+
+ /* Lookup ring of given id */
+ ring = rte_ring_lookup(get_rx_queue_name(ring_id));
+ if (unlikely(ring == NULL)) {
+ RTE_LOG(ERR, SPP_PROC,
+ "Cannot get RX ring - is server process running?\n");
+ return SPP_RET_NG;
+ }
+
+ /* Create ring pmd */
+ ring_port_id = rte_eth_from_ring(ring);
+ RTE_LOG(INFO, SPP_PROC, "ring port add. (no = %d / port = %d)\n",
+ ring_id, ring_port_id);
+ return ring_port_id;
+}
+
+/* Get core status */
+enum spp_core_status
+spp_get_core_status(unsigned int lcore_id)
+{
+ return (g_mng_data_addr.p_core_info + lcore_id)->status;
+}
+
+/**
+ * Check status of all of cores is same as given
+ *
+ * It returns SPP_RET_NG as status mismatch if status is not same.
+ * If core is in use, status will be checked.
+ */
+static int
+check_core_status(enum spp_core_status status)
+{
+ unsigned int lcore_id = 0;
+ RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+ if ((g_mng_data_addr.p_core_info + lcore_id)->status !=
+ status) {
+ /* Status is mismatched */
+ return SPP_RET_NG;
+ }
+ }
+ return SPP_RET_OK;
+}
+
+int
+check_core_status_wait(enum spp_core_status status)
+{
+ int cnt = 0;
+ for (cnt = 0; cnt < SPP_CORE_STATUS_CHECK_MAX; cnt++) {
+ sleep(1);
+ int ret = check_core_status(status);
+ if (ret == 0)
+ return SPP_RET_OK;
+ }
+
+ RTE_LOG(ERR, SPP_PROC,
+ "Status check time out. (status = %d)\n", status);
+ return SPP_RET_NG;
+}
+
+/* Set core status */
+void
+set_core_status(unsigned int lcore_id,
+ enum spp_core_status status)
+{
+ (g_mng_data_addr.p_core_info + lcore_id)->status = status;
+}
+
+/* Set all core to given status */
+void
+set_all_core_status(enum spp_core_status status)
+{
+ unsigned int lcore_id = 0;
+ RTE_LCORE_FOREACH_SLAVE(lcore_id) {
+ (g_mng_data_addr.p_core_info + lcore_id)->status = status;
+ }
+}
+
+/**
+ * Set all of component status to SPP_CORE_STOP_REQUEST if received signal
+ * is SIGTERM or SIGINT
+ */
+void
+stop_process(int signal)
+{
+ if (unlikely(signal != SIGTERM) &&
+ unlikely(signal != SIGINT)) {
+ return;
+ }
+
+ (g_mng_data_addr.p_core_info + g_mng_data_addr.main_lcore_id)->status =
+ SPP_CORE_STOP_REQUEST;
+ set_all_core_status(SPP_CORE_STOP_REQUEST);
+}
+
+/**
+ * Return port info of given type and num of interface
+ *
+ * It returns NULL value if given type is invalid.
+ */
+struct spp_port_info *
+get_iface_info(enum port_type iface_type, int iface_no)
+{
+ struct iface_info *iface_info = g_mng_data_addr.p_iface_info;
+
+ switch (iface_type) {
+ case PHY:
+ return &iface_info->nic[iface_no];
+ case RING:
+ return &iface_info->ring[iface_no];
+ default:
+ return NULL;
+ }
+}
+
+/**
+ * Initialize g_iface_info
+ *
+ * Clear g_iface_info and set initial value.
+ */
+static void
+init_iface_info(void)
+{
+ int port_cnt; /* increment ether ports */
+ struct iface_info *p_iface_info = g_mng_data_addr.p_iface_info;
+ memset(p_iface_info, 0x00, sizeof(struct iface_info));
+ for (port_cnt = 0; port_cnt < RTE_MAX_ETHPORTS; port_cnt++) {
+ p_iface_info->nic[port_cnt].iface_type = UNDEF;
+ p_iface_info->nic[port_cnt].iface_no = port_cnt;
+ p_iface_info->nic[port_cnt].dpdk_port = -1;
+ p_iface_info->nic[port_cnt].class_id.vlantag.vid =
+ ETH_VLAN_ID_MAX;
+ p_iface_info->ring[port_cnt].iface_type = UNDEF;
+ p_iface_info->ring[port_cnt].iface_no = port_cnt;
+ p_iface_info->ring[port_cnt].dpdk_port = -1;
+ p_iface_info->ring[port_cnt].class_id.vlantag.vid =
+ ETH_VLAN_ID_MAX;
+ }
+}
+
+/* Initialize g_core_info */
+static void
+init_core_info(void)
+{
+ struct core_mng_info *p_core_info = g_mng_data_addr.p_core_info;
+ memset(p_core_info, 0x00,
+ sizeof(struct core_mng_info)*RTE_MAX_LCORE);
+ set_all_core_status(SPP_CORE_STOP);
+ *g_mng_data_addr.p_capture_request = SPP_CAPTURE_IDLE;
+ *g_mng_data_addr.p_capture_status = SPP_CAPTURE_IDLE;
+}
+
+/* Setup port info of port on host */
+static int
+set_nic_interface(void)
+{
+ int nic_cnt = 0;
+ struct iface_info *p_iface_info = g_mng_data_addr.p_iface_info;
+
+ /* NIC Setting */
+ p_iface_info->num_nic = rte_eth_dev_count_avail();
+ if (p_iface_info->num_nic > RTE_MAX_ETHPORTS)
+ p_iface_info->num_nic = RTE_MAX_ETHPORTS;
+
+ for (nic_cnt = 0; nic_cnt < p_iface_info->num_nic; nic_cnt++) {
+ p_iface_info->nic[nic_cnt].iface_type = PHY;
+ p_iface_info->nic[nic_cnt].dpdk_port = nic_cnt;
+ }
+
+ return SPP_RET_OK;
+}
+
+/* Setup management info for spp_pcap */
+int
+init_mng_data(void)
+{
+ /* Initialize interface and core information */
+ init_iface_info();
+ init_core_info();
+
+ int ret_nic = set_nic_interface();
+ if (unlikely(ret_nic != SPP_RET_OK))
+ return SPP_RET_NG;
+
+ return SPP_RET_OK;
+}
+
+/**
+ * Generate a formatted string of combination from interface type and
+ * number and assign to given 'port'
+ */
+int spp_format_port_string(char *port, enum port_type iface_type, int iface_no)
+{
+ const char *iface_type_str;
+
+ switch (iface_type) {
+ case PHY:
+ iface_type_str = SPP_IFTYPE_NIC_STR;
+ break;
+ case RING:
+ iface_type_str = SPP_IFTYPE_RING_STR;
+ break;
+ default:
+ return SPP_RET_NG;
+ }
+
+ sprintf(port, "%s:%d", iface_type_str, iface_no);
+
+ return SPP_RET_OK;
+}
+
+/* Set mange data address */
+int spp_set_mng_data_addr(struct startup_param *startup_param_addr,
+ struct iface_info *iface_addr,
+ struct core_mng_info *core_mng_addr,
+ int *capture_request_addr,
+ int *capture_status_addr,
+ unsigned int main_lcore_id)
+{
+ if (startup_param_addr == NULL || iface_addr == NULL ||
+ core_mng_addr == NULL ||
+ capture_request_addr == NULL ||
+ capture_status_addr == NULL ||
+ main_lcore_id == 0xffffffff)
+ return SPP_RET_NG;
+
+ g_mng_data_addr.p_startup_param = startup_param_addr;
+ g_mng_data_addr.p_iface_info = iface_addr;
+ g_mng_data_addr.p_core_info = core_mng_addr;
+ g_mng_data_addr.p_capture_request = capture_request_addr;
+ g_mng_data_addr.p_capture_status = capture_status_addr;
+ g_mng_data_addr.main_lcore_id = main_lcore_id;
+
+ return SPP_RET_OK;
+}
+
+/* Get manage data address */
+void spp_get_mng_data_addr(struct startup_param **startup_param_addr,
+ struct iface_info **iface_addr,
+ struct core_mng_info **core_mng_addr,
+ int **capture_request_addr,
+ int **capture_status_addr)
+{
+
+ if (startup_param_addr != NULL)
+ *startup_param_addr = g_mng_data_addr.p_startup_param;
+ if (iface_addr != NULL)
+ *iface_addr = g_mng_data_addr.p_iface_info;
+ if (core_mng_addr != NULL)
+ *core_mng_addr = g_mng_data_addr.p_core_info;
+ if (capture_request_addr != NULL)
+ *capture_request_addr = g_mng_data_addr.p_capture_request;
+ if (capture_status_addr != NULL)
+ *capture_status_addr = g_mng_data_addr.p_capture_status;
+
+}
diff --git a/src/pcap/spp_proc.h b/src/pcap/spp_proc.h
new file mode 100644
index 0000000..6da5c5e
--- /dev/null
+++ b/src/pcap/spp_proc.h
@@ -0,0 +1,389 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Nippon Telegraph and Telephone Corporation
+ */
+
+#ifndef _SPP_PROC_H_
+#define _SPP_PROC_H_
+
+/**
+ * @file
+ * SPP process
+ *
+ * SPP component common function.
+ */
+
+#include <netinet/in.h>
+#include "shared/common.h"
+
+/* Max number of core status check */
+#define SPP_CORE_STATUS_CHECK_MAX 5
+
+/** The length of shortest character string */
+#define SPP_MIN_STR_LEN 32
+
+/** The length of NAME string */
+#define SPP_NAME_STR_LEN 128
+
+/** Maximum number of port abilities available */
+#define SPP_PORT_ABILITY_MAX 4
+
+/** Identifier string for each interface */
+#define SPP_IFTYPE_NIC_STR "phy"
+#define SPP_IFTYPE_RING_STR "ring"
+
+/* State on core */
+enum spp_core_status {
+ SPP_CORE_UNUSE, /**< Not used */
+ SPP_CORE_STOP, /**< Stopped */
+ SPP_CORE_IDLE, /**< Idling */
+ SPP_CORE_FORWARD, /**< Forwarding */
+ SPP_CORE_STOP_REQUEST, /**< Request stopping */
+ SPP_CORE_IDLE_REQUEST /**< Request idling */
+};
+
+/* State on capture */
+enum spp_capture_status {
+ SPP_CAPTURE_IDLE, /* Idling */
+ SPP_CAPTURE_RUNNING /* Running */
+};
+
+enum spp_return_value {
+ SPP_RET_OK = 0, /**< succeeded */
+ SPP_RET_NG = -1, /**< failed */
+};
+
+/**
+ * Port type (rx or tx) to indicate which direction packet goes
+ * (e.g. receiving or transmitting)
+ */
+enum spp_port_rxtx {
+ SPP_PORT_RXTX_NONE, /**< none */
+ SPP_PORT_RXTX_RX, /**< rx port */
+ SPP_PORT_RXTX_TX, /**< tx port */
+ SPP_PORT_RXTX_ALL, /**< rx/tx port */
+};
+
+/* Process type for each component */
+enum spp_component_type {
+ SPP_COMPONENT_UNUSE, /**< Not used */
+ SPP_COMPONENT_CLASSIFIER_MAC, /**< Classifier_mac */
+ SPP_COMPONENT_MERGE, /**< Merger */
+ SPP_COMPONENT_FORWARD, /**< Forwarder */
+ SPP_COMPONENT_MIRROR, /**< Mirror */
+};
+
+/**
+ * Port ability operation which indicates vlan tag operation on the port
+ * (e.g. add vlan tag or delete vlan tag)
+ */
+enum spp_port_ability_ope {
+ SPP_PORT_ABILITY_OPE_NONE, /**< none */
+ SPP_PORT_ABILITY_OPE_ADD_VLANTAG, /**< add VLAN tag */
+ SPP_PORT_ABILITY_OPE_DEL_VLANTAG, /**< delete VLAN tag */
+};
+
+/* getopt_long return value for long option */
+enum SPP_LONGOPT_RETVAL {
+ SPP_LONGOPT_RETVAL__ = 127,
+
+ /*
+ * Return value definition for getopt_long()
+ * Only for long option
+ */
+ SPP_LONGOPT_RETVAL_CLIENT_ID, /* --client-id */
+ SPP_LONGOPT_RETVAL_OUTPUT, /* --output */
+ SPP_LONGOPT_RETVAL_LIMIT_FILE_SIZE /* --limit_file_size */
+};
+
+/* Interface information structure */
+struct spp_port_index {
+ enum port_type iface_type; /**< Interface type (phy/ring) */
+ int iface_no; /**< Interface number */
+};
+
+/** VLAN tag information */
+struct spp_vlantag_info {
+ int vid; /**< VLAN ID */
+ int pcp; /**< Priority Code Point */
+ int tci; /**< Tag Control Information */
+};
+
+/**
+ * Data for each port ability which indicates vlantag related information
+ * for the port
+ */
+union spp_ability_data {
+ /** VLAN tag information */
+ struct spp_vlantag_info vlantag;
+};
+
+/** Port ability information */
+struct spp_port_ability {
+ enum spp_port_ability_ope ope; /**< Operation */
+ enum spp_port_rxtx rxtx; /**< rx/tx identifier */
+ union spp_ability_data data; /**< Port ability data */
+};
+
+/** Port class identifier for classifying */
+struct spp_port_class_identifier {
+ uint64_t mac_addr; /**< Mac address (binary) */
+ char mac_addr_str[SPP_MIN_STR_LEN]; /**< Mac address (text) */
+ struct spp_vlantag_info vlantag; /**< VLAN tag information */
+};
+
+/* Port info */
+struct spp_port_info {
+ enum port_type iface_type; /**< Interface type (phy/vhost/ring) */
+ int iface_no; /**< Interface number */
+ int dpdk_port; /**< DPDK port number */
+ struct spp_port_class_identifier class_id;
+ /**< Port class identifier */
+ struct spp_port_ability ability[SPP_PORT_ABILITY_MAX];
+ /**< Port ability */
+};
+
+/* Component info */
+struct spp_component_info {
+ char name[SPP_NAME_STR_LEN]; /**< Component name */
+ enum spp_component_type type; /**< Component type */
+ unsigned int lcore_id; /**< Logical core ID for component */
+ int component_id; /**< Component ID */
+ int num_rx_port; /**< The number of rx ports */
+ int num_tx_port; /**< The number of tx ports */
+ struct spp_port_info *rx_ports[RTE_MAX_ETHPORTS];
+ /**< Array of pointers to rx ports */
+ struct spp_port_info *tx_ports[RTE_MAX_ETHPORTS];
+ /**< Array of pointers to tx ports */
+};
+
+/* Manage given options as global variable */
+struct startup_param {
+ int client_id; /* Client ID */
+ char server_ip[INET_ADDRSTRLEN];
+ /* IP address stiring of spp-ctl */
+ int server_port; /* Port Number of spp-ctl */
+};
+
+/* Manage interfaces and port information as global variable */
+struct iface_info {
+ int num_nic; /* The number of phy */
+ int num_ring; /* The number of ring */
+ struct spp_port_info nic[RTE_MAX_ETHPORTS];
+ /* Port information of phy */
+ struct spp_port_info ring[RTE_MAX_ETHPORTS];
+ /* Port information of ring */
+};
+
+/* Manage core status and component information as global variable */
+struct core_mng_info {
+ /* Status of cpu core */
+ volatile enum spp_core_status status;
+};
+
+struct spp_iterate_core_params;
+/**
+ * definition of iterated core element procedure function
+ * which is member of spp_iterate_core_params structure.
+ * Above structure is used when listing core information
+ * (e.g) create resonse to status command.
+ */
+typedef int (*spp_iterate_core_element_proc)(
+ struct spp_iterate_core_params *params,
+ const unsigned int lcore_id,
+ const char *name,
+ const char *type,
+ const int num_rx,
+ const struct spp_port_index *rx_ports,
+ const int num_tx,
+ const struct spp_port_index *tx_ports);
+
+/**
+ * iterate core table parameters which is
+ * used when listing core table content
+ * (e.g.) create response to status command.
+ */
+struct spp_iterate_core_params {
+ /** Output buffer */
+ char *output;
+
+ /** The function for creating core information */
+ spp_iterate_core_element_proc element_proc;
+};
+
+/**
+ * added ring_pmd
+ *
+ * @param ring_id
+ * added ring id.
+ *
+ * @retval 0~ ring_port_id.
+ * @retval -1 failed.
+ */
+int add_ring_pmd(int ring_id);
+
+/**
+ * Get core status
+ *
+ * @param lcore_id
+ * Logical core ID.
+ *
+ * @return
+ * Status of specified logical core.
+ */
+enum spp_core_status spp_get_core_status(unsigned int lcore_id);
+
+/**
+ * Run check_core_status() for SPP_CORE_STATUS_CHECK_MAX times with
+ * interval time (1sec)
+ *
+ * @param status
+ * wait check status.
+ *
+ * @retval 0 succeeded.
+ * @retval -1 failed.
+ */
+int check_core_status_wait(enum spp_core_status status);
+
+/**
+ * Set core status
+ *
+ * @param lcore_id
+ * Logical core ID.
+ * @param status
+ * set status.
+ *
+ */
+void set_core_status(unsigned int lcore_id, enum spp_core_status status);
+
+/**
+ * Set all core status to given
+ *
+ * @param status
+ * set status.
+ *
+ */
+void set_all_core_status(enum spp_core_status status);
+
+/**
+ * Set all of component status to SPP_CORE_STOP_REQUEST if received signal
+ * is SIGTERM or SIGINT
+ *
+ * @param signl
+ * received signal.
+ *
+ */
+void stop_process(int signal);
+
+/**
+ * Return port info of given type and num of interface
+ *
+ * @param iface_type
+ * Interface type to be validated.
+ * @param iface_no
+ * Interface number to be validated.
+ *
+ * @retval !NULL spp_port_info.
+ * @retval NULL failed.
+ */
+struct spp_port_info *
+get_iface_info(enum port_type iface_type, int iface_no);
+
+/**
+ * Setup management info for spp_vf
+ */
+int init_mng_data(void);
+
+/**
+ * Get component type of target core
+ *
+ * @param lcore_id
+ * Logical core ID.
+ *
+ * @return
+ * Type of component executed on specified logical core
+ */
+enum spp_component_type
+spp_get_component_type(unsigned int lcore_id);
+
+/* Get core information which is in use */
+struct core_info *get_core_info(unsigned int lcore_id);
+
+/**
+ * Port type to string
+ *
+ * @param port
+ * Character string of Port type to be converted.
+ * @param iface_type
+ * port interface type
+ * @param iface_no
+ * interface no
+ *
+ * @retval SPP_RET_OK succeeded.
+ * @retval SPP_RET_NG failed.
+ */
+int
+spp_format_port_string(char *port, enum port_type iface_type, int iface_no);
+
+/**
+ * Port type to string
+ *
+ * @param port
+ * Character string of Port type to be converted.
+ * @param iface_type
+ * port interface type
+ * @param iface_no
+ * interface no
+ *
+ * @retval SPP_RET_OK succeeded.
+ * @retval SPP_RET_NG failed.
+ */
+int
+spp_format_port_string(char *port, enum port_type iface_type, int iface_no);
+
+/**
+ * Set mange data address
+ *
+ * @param startup_param_addr
+ * g_startup_param address
+ * @param iface_addr
+ * g_iface_info address
+ * @param core_mng_addr
+ * g_core_info address
+ * @param capture_request_addr
+ * g_capture_request address
+ * @param capture_status_addr
+ * g_capture_status address
+ * @param main_lcore_id
+ * main_lcore_id mask
+ *
+ * @retval SPP_RET_OK succeeded.
+ * @retval SPP_RET_NG failed.
+ */
+int spp_set_mng_data_addr(struct startup_param *startup_param_addr,
+ struct iface_info *iface_addr,
+ struct core_mng_info *core_mng_addr,
+ int *capture_request_addr,
+ int *capture_status_addr,
+ unsigned int main_lcore_id);
+
+/**
+ * Get mange data address
+ *
+ * @param iface_addr
+ * g_startup_param write address
+ * @param iface_addr
+ * g_iface_info write address
+ * @param core_mng_addr
+ * g_core_mng_info write address
+ * @param change_core_addr
+ * g_capture_request write address
+ * @param change_component_addr
+ * g_capture_status write address
+ */
+void spp_get_mng_data_addr(struct startup_param **startup_param_addr,
+ struct iface_info **iface_addr,
+ struct core_mng_info **core_mng_addr,
+ int **capture_request_addr,
+ int **capture_status_addr);
+
+#endif /* _SPP_PROC_H_ */
--
2.17.1
next prev parent reply other threads:[~2019-02-08 8:46 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20190208084438.7952-1-x-fn-spp@sl.ntt-tx.co.jp>
2019-02-08 8:44 ` [spp] [PATCH v2 1/7] spp_pcap: add command main x-fn-spp
2019-02-08 8:44 ` [spp] [PATCH v2 2/7] spp_pcap: add command decode x-fn-spp
2019-02-08 8:44 ` x-fn-spp [this message]
2019-02-08 8:44 ` [spp] [PATCH v2 4/7] spp_pcap: add spp_pcap main function x-fn-spp
2019-02-08 8:44 ` [spp] [PATCH v2 5/7] spp_pcap: add Makefile for spp_pcap x-fn-spp
2019-02-08 8:44 ` [spp] [PATCH v2 6/7] controller: add SppPcap class x-fn-spp
2019-02-08 8:44 ` [spp] [PATCH v2 7/7] controller: add pcap command to SPP controller x-fn-spp
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=201902080844.x188ic6d030814@imss04.silk.ntt-tx.co.jp \
--to=x-fn-spp@sl.ntt-tx.co.jp \
--cc=ferruh.yigit@intel.com \
--cc=ogawa.yasufumi@lab.ntt.co.jp \
--cc=spp@dpdk.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).