All of lore.kernel.org
 help / color / mirror / Atom feed
From: lin li <chuckylinchuckylin@gmail.com>
To: tiwei.bie@intel.com, maxime.coquelin@redhat.com, zhihong.wang@intel.com
Cc: dev@dpdk.org, dariusz.stojaczyk@intel.com,
	changpeng.liu@intel.com,  james.r.harris@intel.com,
	lilin24 <lilin24@baidu.com>, Ni Xun <nixun@baidu.com>,
	Zhang Yu <zhangyu31@baidu.com>
Subject: Re: [dpdk-dev] [PATCH] [resend] vhost: support inflight share memory protocol feature
Date: Thu, 25 Apr 2019 18:56:04 +0800	[thread overview]
Message-ID: <CAF+hgq3gToAOB6+S8PxN19HgfBnAdjy=NCNPYZqGa6OmYfS4Zg@mail.gmail.com> (raw)
In-Reply-To: <1556179018-7865-1-git-send-email-chuckylinchuckylin@gmail.com>

Li Lin <chuckylinchuckylin@gmail.com> 于2019年4月25日周四 下午3:57写道:
>
> From: lilin24 <lilin24@baidu.com>
>
> This patch introduces two new messages VHOST_USER_GET_INFLIGHT_FD
> and VHOST_USER_SET_INFLIGHT_FD to support transferring a shared
> buffer between qemu and backend.
>
> Firstly, qemu uses VHOST_USER_GET_INFLIGHT_FD to get the
> shared buffer from backend. Then qemu should send it back
> through VHOST_USER_SET_INFLIGHT_FD each time we start vhost-user.
>
> This shared buffer is used to process inflight I/O when backend
> reconnect.
>
> Signed-off-by: lilin24 <lilin24@baidu.com>
> Signed-off-by: Ni Xun <nixun@baidu.com>
> Signed-off-by: Zhang Yu <zhangyu31@baidu.com>
> ---
>  lib/librte_vhost/rte_vhost.h  |  19 ++++
>  lib/librte_vhost/vhost.c      |  10 ++
>  lib/librte_vhost/vhost.h      |  12 ++
>  lib/librte_vhost/vhost_user.c | 248 ++++++++++++++++++++++++++++++++++++++++++
>  lib/librte_vhost/vhost_user.h |  16 ++-
>  5 files changed, 303 insertions(+), 2 deletions(-)
>
> diff --git a/lib/librte_vhost/rte_vhost.h b/lib/librte_vhost/rte_vhost.h
> index d2c0c93f4..9993b7ce5 100644
> --- a/lib/librte_vhost/rte_vhost.h
> +++ b/lib/librte_vhost/rte_vhost.h
> @@ -71,6 +71,10 @@ extern "C" {
>  #define VHOST_USER_PROTOCOL_F_HOST_NOTIFIER 11
>  #endif
>
> +#ifndef VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD
> +#define VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD 12
> +#endif
> +
>  /** Indicate whether protocol features negotiation is supported. */
>  #ifndef VHOST_USER_F_PROTOCOL_FEATURES
>  #define VHOST_USER_F_PROTOCOL_FEATURES 30
> @@ -98,12 +102,27 @@ struct rte_vhost_memory {
>         struct rte_vhost_mem_region regions[];
>  };
>
> +typedef struct VhostUserInflightEntry {
> +       uint8_t inflight;
> +} VhostUserInflightEntry;
> +
> +typedef struct VhostInflightInfo {
> +       uint16_t version;
> +       uint16_t last_inflight_io;
> +       uint16_t used_idx;
> +       VhostUserInflightEntry desc[0];
> +} VhostInflightInfo;
> +
>  struct rte_vhost_vring {
>         struct vring_desc       *desc;
>         struct vring_avail      *avail;
>         struct vring_used       *used;
>         uint64_t                log_guest_addr;
>
> +       VhostInflightInfo       *inflight;
> +       uint16_t                *inflight_reqs;
> +       uint16_t                inflight_cnt;
> +
>         /** Deprecated, use rte_vhost_vring_call() instead. */
>         int                     callfd;
>
> diff --git a/lib/librte_vhost/vhost.c b/lib/librte_vhost/vhost.c
> index 163f4595e..e7d9eabec 100644
> --- a/lib/librte_vhost/vhost.c
> +++ b/lib/librte_vhost/vhost.c
> @@ -76,6 +76,8 @@ cleanup_vq(struct vhost_virtqueue *vq, int destroy)
>                 close(vq->callfd);
>         if (vq->kickfd >= 0)
>                 close(vq->kickfd);
> +       if (vq->inflight)
> +               vq->inflight = NULL;
>  }
>
>  /*
> @@ -589,6 +591,14 @@ rte_vhost_get_vhost_vring(int vid, uint16_t vring_idx,
>         vring->kickfd  = vq->kickfd;
>         vring->size    = vq->size;
>
> +       vring->inflight = vq->inflight;
> +
> +       vring->inflight_reqs = vq->inflight_reqs;
> +       vq->inflight_reqs = NULL;
> +
> +       vring->inflight_cnt = vq->inflight_cnt;
> +       vq->inflight_cnt = 0;
> +
>         return 0;
>  }
>
> diff --git a/lib/librte_vhost/vhost.h b/lib/librte_vhost/vhost.h
> index e9138dfab..2ab9d6892 100644
> --- a/lib/librte_vhost/vhost.h
> +++ b/lib/librte_vhost/vhost.h
> @@ -128,6 +128,11 @@ struct vhost_virtqueue {
>         /* Physical address of used ring, for logging */
>         uint64_t                log_guest_addr;
>
> +       /* Inflight share memory info */
> +       VhostInflightInfo       *inflight;
> +       uint16_t                *inflight_reqs;
> +       uint16_t                inflight_cnt;
> +
>         uint16_t                nr_zmbuf;
>         uint16_t                zmbuf_size;
>         uint16_t                last_zmbuf_idx;
> @@ -286,6 +291,12 @@ struct guest_page {
>         uint64_t size;
>  };
>
> +typedef struct VuDevInflightInfo {
> +       int fd;
> +       void *addr;
> +       uint64_t size;
> +} VuDevInflightInfo;
> +
>  /**
>   * Device structure contains all configuration information relating
>   * to the device.
> @@ -303,6 +314,7 @@ struct virtio_net {
>         uint32_t                nr_vring;
>         int                     dequeue_zero_copy;
>         struct vhost_virtqueue  *virtqueue[VHOST_MAX_QUEUE_PAIRS * 2];
> +       VuDevInflightInfo inflight_info;
>  #define IF_NAME_SZ (PATH_MAX > IFNAMSIZ ? PATH_MAX : IFNAMSIZ)
>         char                    ifname[IF_NAME_SZ];
>         uint64_t                log_size;
> diff --git a/lib/librte_vhost/vhost_user.c b/lib/librte_vhost/vhost_user.c
> index c9e29ece8..c4b64137c 100644
> --- a/lib/librte_vhost/vhost_user.c
> +++ b/lib/librte_vhost/vhost_user.c
> @@ -31,6 +31,8 @@
>  #include <sys/stat.h>
>  #include <sys/syscall.h>
>  #include <assert.h>
> +#include <sys/syscall.h>
> +#include <asm/unistd.h>
>  #ifdef RTE_LIBRTE_VHOST_NUMA
>  #include <numaif.h>
>  #endif
> @@ -49,6 +51,14 @@
>  #define VIRTIO_MIN_MTU 68
>  #define VIRTIO_MAX_MTU 65535
>
> +#define INFLIGHT_ALIGNMENT 64
> +#define INFLIGHT_VERSION 0xabcd
> +
> +#define CLOEXEC 0x0001U
> +
> +#define ALIGN_DOWN(n, m) ((n) / (m) * (m))
> +#define ALIGN_UP(n, m) ALIGN_DOWN((n) + (m) - 1, (m))
> +
>  static const char *vhost_message_str[VHOST_USER_MAX] = {
>         [VHOST_USER_NONE] = "VHOST_USER_NONE",
>         [VHOST_USER_GET_FEATURES] = "VHOST_USER_GET_FEATURES",
> @@ -78,6 +88,8 @@ static const char *vhost_message_str[VHOST_USER_MAX] = {
>         [VHOST_USER_POSTCOPY_ADVISE]  = "VHOST_USER_POSTCOPY_ADVISE",
>         [VHOST_USER_POSTCOPY_LISTEN]  = "VHOST_USER_POSTCOPY_LISTEN",
>         [VHOST_USER_POSTCOPY_END]  = "VHOST_USER_POSTCOPY_END",
> +       [VHOST_USER_GET_INFLIGHT_FD] = "VHOST_USER_GET_INFLIGHT_FD",
> +       [VHOST_USER_SET_INFLIGHT_FD] = "VHOST_USER_SET_INFLIGHT_FD",
>  };
>
>  static int send_vhost_reply(int sockfd, struct VhostUserMsg *msg);
> @@ -160,6 +172,16 @@ vhost_backend_cleanup(struct virtio_net *dev)
>                 dev->log_addr = 0;
>         }
>
> +       if (dev->inflight_info.addr) {
> +               munmap(dev->inflight_info.addr, dev->inflight_info.size);
> +               dev->inflight_info.addr = NULL;
> +       }
> +
> +       if (dev->inflight_info.fd > 0) {
> +               close(dev->inflight_info.fd);
> +               dev->inflight_info.fd = -1;
> +       }
> +
>         if (dev->slave_req_fd >= 0) {
>                 close(dev->slave_req_fd);
>                 dev->slave_req_fd = -1;
> @@ -1165,6 +1187,184 @@ virtio_is_ready(struct virtio_net *dev)
>         return 1;
>  }
>
> +static int mem_create(const char *name, unsigned int flags)
> +{
> +#ifdef __NR_memfd_create
> +       return syscall(__NR_memfd_create, name, flags);
> +#else
> +       return -1;
> +#endif
> +}
> +
> +void *inflight_mem_alloc(const char *name, size_t size, int *fd)
> +{
> +       void *ptr;
> +       int mfd = -1;
> +       char fname[20] = "/tmp/memfd-XXXXXX";
> +
> +       *fd = -1;
> +       mfd = mem_create(name, CLOEXEC);
> +       if (mfd != -1) {
> +               if (ftruncate(mfd, size) == -1) {
> +                       RTE_LOG(ERR, VHOST_CONFIG,
> +                                       "ftruncate fail for alloc inflight buffer\n");
> +                       close(mfd);
> +                       return NULL;
> +               }
> +       } else {
> +               mfd = mkstemp(fname);
> +               unlink(fname);
> +
> +               if (mfd == -1) {
> +                       RTE_LOG(ERR, VHOST_CONFIG,
> +                                       "mkstemp fail for alloc inflight buffer\n");
> +                       return NULL;
> +               }
> +
> +               if (ftruncate(mfd, size) == -1) {
> +                       RTE_LOG(ERR, VHOST_CONFIG,
> +                                       "ftruncate fail for alloc inflight buffer\n");
> +                       close(mfd);
> +                       return NULL;
> +               }
> +       }
> +
> +       ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, mfd, 0);
> +       if (ptr == MAP_FAILED) {
> +               RTE_LOG(ERR, VHOST_CONFIG,
> +                               "mmap fail for alloc inflight buffer\n");
> +               close(mfd);
> +               return NULL;
> +       }
> +
> +       *fd = mfd;
> +       return ptr;
> +}
> +
> +static uint32_t get_pervq_shm_size(uint16_t queue_size)
> +{
> +       return ALIGN_UP(sizeof(VhostUserInflightEntry) * queue_size +
> +               sizeof(uint16_t) * 3, INFLIGHT_ALIGNMENT);
> +}
> +
> +static int
> +vhost_user_get_inflight_fd(struct virtio_net **pdev, VhostUserMsg *msg,
> +               int main_fd __rte_unused)
> +{
> +       int fd;
> +       uint64_t mmap_size;
> +       void *addr;
> +       uint16_t num_queues, queue_size;
> +       struct virtio_net *dev = *pdev;
> +
> +       if (msg->size != sizeof(msg->payload.inflight)) {
> +               RTE_LOG(ERR, VHOST_CONFIG,
> +                       "Invalid get_inflight_fd message size is %d",
> +                       msg->size);
> +               msg->payload.inflight.mmap_size = 0;
> +               return 0;
> +       }
> +
> +       num_queues = msg->payload.inflight.num_queues;
> +       queue_size = msg->payload.inflight.queue_size;
> +
> +       RTE_LOG(INFO, VHOST_CONFIG, "get_inflight_fd num_queues: %u\n",
> +                       msg->payload.inflight.num_queues);
> +       RTE_LOG(INFO, VHOST_CONFIG, "get_inflight_fd queue_size: %u\n",
> +                       msg->payload.inflight.queue_size);
> +       mmap_size = num_queues * get_pervq_shm_size(queue_size);
> +
> +       addr = inflight_mem_alloc("vhost-inflight", mmap_size, &fd);
> +       if (!addr) {
> +               RTE_LOG(ERR, VHOST_CONFIG, "Failed to alloc vhost inflight area");
> +                       msg->payload.inflight.mmap_size = 0;
> +               return 0;
> +       }
> +       memset(addr, 0, mmap_size);
> +
> +       dev->inflight_info.addr = addr;
> +       dev->inflight_info.size = msg->payload.inflight.mmap_size = mmap_size;
> +       dev->inflight_info.fd = msg->fds[0] = fd;
> +       msg->payload.inflight.mmap_offset = 0;
> +       msg->fd_num = 1;
> +
> +       RTE_LOG(INFO, VHOST_CONFIG,
> +                       "send inflight mmap_size: %lu\n",
> +                       msg->payload.inflight.mmap_size);
> +       RTE_LOG(INFO, VHOST_CONFIG,
> +                       "send inflight mmap_offset: %lu\n",
> +                       msg->payload.inflight.mmap_offset);
> +       RTE_LOG(INFO, VHOST_CONFIG,
> +                       "send inflight fd: %d\n", msg->fds[0]);
> +
> +       return RTE_VHOST_MSG_RESULT_REPLY;
> +}
> +
> +static int
> +vhost_user_set_inflight_fd(struct virtio_net **pdev, VhostUserMsg *msg,
> +               int main_fd __rte_unused)
> +{
> +       int fd, i;
> +       uint64_t mmap_size, mmap_offset;
> +       uint16_t num_queues, queue_size;
> +       uint32_t pervq_inflight_size;
> +       void *rc;
> +       struct vhost_virtqueue *vq;
> +       struct virtio_net *dev = *pdev;
> +
> +       fd = msg->fds[0];
> +       if (msg->size != sizeof(msg->payload.inflight) || fd < 0) {
> +               RTE_LOG(ERR, VHOST_CONFIG, "Invalid set_inflight_fd message size is %d,fd is %d\n",
> +                       msg->size, fd);
> +               return -1;
> +       }
> +
> +       mmap_size = msg->payload.inflight.mmap_size;
> +       mmap_offset = msg->payload.inflight.mmap_offset;
> +       num_queues = msg->payload.inflight.num_queues;
> +       queue_size = msg->payload.inflight.queue_size;
> +       pervq_inflight_size = get_pervq_shm_size(queue_size);
> +
> +       RTE_LOG(INFO, VHOST_CONFIG,
> +               "set_inflight_fd mmap_size: %lu\n", mmap_size);
> +       RTE_LOG(INFO, VHOST_CONFIG,
> +               "set_inflight_fd mmap_offset: %lu\n", mmap_offset);
> +       RTE_LOG(INFO, VHOST_CONFIG,
> +               "set_inflight_fd num_queues: %u\n", num_queues);
> +       RTE_LOG(INFO, VHOST_CONFIG,
> +               "set_inflight_fd queue_size: %u\n", queue_size);
> +       RTE_LOG(INFO, VHOST_CONFIG,
> +               "set_inflight_fd fd: %d\n", fd);
> +       RTE_LOG(INFO, VHOST_CONFIG,
> +               "set_inflight_fd pervq_inflight_size: %d\n",
> +               pervq_inflight_size);
> +
> +       if (dev->inflight_info.addr)
> +               munmap(dev->inflight_info.addr, dev->inflight_info.size);
> +
> +       rc = mmap(0, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED,
> +                       fd, mmap_offset);
> +       if (rc == MAP_FAILED) {
> +               RTE_LOG(ERR, VHOST_CONFIG, "failed to mmap share memory.\n");
> +               return -1;
> +       }
> +
> +       if (dev->inflight_info.fd)
> +               close(dev->inflight_info.fd);
> +
> +       dev->inflight_info.fd = fd;
> +       dev->inflight_info.addr = rc;
> +       dev->inflight_info.size = mmap_size;
> +
> +       for (i = 0; i < num_queues; i++) {
> +               vq = dev->virtqueue[i];
> +               vq->inflight = (VhostInflightInfo *)rc;
> +               rc = (void *)((char *)rc + pervq_inflight_size);
> +       }
> +
> +       return RTE_VHOST_MSG_RESULT_OK;
> +}
> +
>  static int
>  vhost_user_set_vring_call(struct virtio_net **pdev, struct VhostUserMsg *msg,
>                         int main_fd __rte_unused)
> @@ -1202,6 +1402,47 @@ static int vhost_user_set_vring_err(struct virtio_net **pdev __rte_unused,
>  }
>
>  static int
> +vhost_check_queue_inflights(struct vhost_virtqueue *vq)
> +{
> +       struct vring_used *used = vq->used;
> +       uint16_t i = 0;
> +
> +       if ((!vq->inflight))
> +               return RTE_VHOST_MSG_RESULT_ERR;
> +
> +       if (!vq->inflight->version) {
> +               vq->inflight->version = INFLIGHT_VERSION;
> +               return RTE_VHOST_MSG_RESULT_OK;
> +       }
> +
> +       vq->inflight_reqs = calloc(vq->size, sizeof(uint16_t));
> +       if (!vq->inflight_reqs) {
> +               RTE_LOG(ERR, VHOST_CONFIG, "Failed to allocate memory for inflight reqs.\n");
> +               return RTE_VHOST_MSG_RESULT_ERR;
> +       }
> +
> +       if (vq->inflight->used_idx != used->idx) {
> +               vq->inflight->desc[vq->inflight->last_inflight_io].inflight = 0;
> +               rte_compiler_barrier();
> +               vq->inflight->used_idx = used->idx;
> +       }
> +
> +       for (i = 0; i < vq->size; i++) {
> +               if (vq->inflight->desc[i].inflight == 1)
> +                       vq->inflight_reqs[vq->inflight_cnt++] = i;
> +       }
> +
> +       if (!vq->inflight_cnt) {
> +               free(vq->inflight_reqs);
> +               vq->inflight_reqs = NULL;
> +       }
> +
> +       vq->last_avail_idx += vq->inflight_cnt;
> +
> +       return RTE_VHOST_MSG_RESULT_OK;
> +}
> +
> +static int
>  vhost_user_set_vring_kick(struct virtio_net **pdev, struct VhostUserMsg *msg,
>                         int main_fd __rte_unused)
>  {
> @@ -1242,6 +1483,11 @@ vhost_user_set_vring_kick(struct virtio_net **pdev, struct VhostUserMsg *msg,
>                 close(vq->kickfd);
>         vq->kickfd = file.fd;
>
> +       if (vhost_check_queue_inflights(vq)) {
> +               RTE_LOG(ERR, VHOST_CONFIG, "Failed to inflights for vq: %d\n", file.index);
> +               return RTE_VHOST_MSG_RESULT_ERR;
> +       }
> +
>         return RTE_VHOST_MSG_RESULT_OK;
>  }
>
> @@ -1762,6 +2008,8 @@ static vhost_message_handler_t vhost_message_handlers[VHOST_USER_MAX] = {
>         [VHOST_USER_POSTCOPY_ADVISE] = vhost_user_set_postcopy_advise,
>         [VHOST_USER_POSTCOPY_LISTEN] = vhost_user_set_postcopy_listen,
>         [VHOST_USER_POSTCOPY_END] = vhost_user_postcopy_end,
> +       [VHOST_USER_GET_INFLIGHT_FD] = vhost_user_get_inflight_fd,
> +       [VHOST_USER_SET_INFLIGHT_FD] = vhost_user_set_inflight_fd,
>  };
>
>
> diff --git a/lib/librte_vhost/vhost_user.h b/lib/librte_vhost/vhost_user.h
> index 2a650fe4b..35f969b1b 100644
> --- a/lib/librte_vhost/vhost_user.h
> +++ b/lib/librte_vhost/vhost_user.h
> @@ -23,7 +23,8 @@
>                                          (1ULL << VHOST_USER_PROTOCOL_F_CRYPTO_SESSION) | \
>                                          (1ULL << VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD) | \
>                                          (1ULL << VHOST_USER_PROTOCOL_F_HOST_NOTIFIER) | \
> -                                        (1ULL << VHOST_USER_PROTOCOL_F_PAGEFAULT))
> +                                       (1ULL << VHOST_USER_PROTOCOL_F_PAGEFAULT) | \
> +                                       (1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD))
>
>  typedef enum VhostUserRequest {
>         VHOST_USER_NONE = 0,
> @@ -54,7 +55,9 @@ typedef enum VhostUserRequest {
>         VHOST_USER_POSTCOPY_ADVISE = 28,
>         VHOST_USER_POSTCOPY_LISTEN = 29,
>         VHOST_USER_POSTCOPY_END = 30,
> -       VHOST_USER_MAX = 31
> +       VHOST_USER_GET_INFLIGHT_FD = 31,
> +       VHOST_USER_SET_INFLIGHT_FD = 32,
> +       VHOST_USER_MAX = 33
>  } VhostUserRequest;
>
>  typedef enum VhostUserSlaveRequest {
> @@ -112,6 +115,13 @@ typedef struct VhostUserVringArea {
>         uint64_t offset;
>  } VhostUserVringArea;
>
> +typedef struct VhostUserInflight {
> +       uint64_t mmap_size;
> +       uint64_t mmap_offset;
> +       uint16_t num_queues;
> +       uint16_t queue_size;
> +} VhostUserInflight;
> +
>  typedef struct VhostUserMsg {
>         union {
>                 uint32_t master; /* a VhostUserRequest value */
> @@ -131,6 +141,7 @@ typedef struct VhostUserMsg {
>                 struct vhost_vring_addr addr;
>                 VhostUserMemory memory;
>                 VhostUserLog    log;
> +               VhostUserInflight inflight;
>                 struct vhost_iotlb_msg iotlb;
>                 VhostUserCryptoSessionParam crypto_session;
>                 VhostUserVringArea area;
> @@ -148,6 +159,7 @@ typedef struct VhostUserMsg {
>  /* vhost_user.c */
>  int vhost_user_msg_handler(int vid, int fd);
>  int vhost_user_iotlb_miss(struct virtio_net *dev, uint64_t iova, uint8_t perm);
> +void *inflight_mem_alloc(const char *name, size_t size, int *fd);
>
>  /* socket.c */
>  int read_fd_message(int sockfd, char *buf, int buflen, int *fds, int max_fds,
> --
> 2.11.0
>
This patch needs to add some functions. It will be abandoned . Later,
I will add set&clear inflight entry function and resubmit the V2
version

  reply	other threads:[~2019-04-25 10:56 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-04-25  7:56 [dpdk-dev] [PATCH] [resend] vhost: support inflight share memory protocol feature Li Lin
2019-04-25 10:56 ` lin li [this message]
2019-04-25 11:10 ` [dpdk-dev] [PATCH v2] " Li Lin
2019-04-26  9:40   ` [dpdk-dev] [PATCH v3] " Li Lin
2019-04-28 11:17     ` Tiwei Bie
2019-04-29  4:07       ` lin li
2019-04-29 10:54         ` Tiwei Bie
2019-04-30  8:37           ` lin li
2019-05-05  9:02     ` [dpdk-dev] [PATCH v4] " Li Lin
2019-05-17 15:47       ` Maxime Coquelin
2019-05-20  2:13         ` Tiwei Bie
2019-05-21  8:29           ` lin li
2019-05-21  8:46             ` Tiwei Bie
2019-05-22 10:15               ` [dpdk-dev] 答复: " Li,Lin(ACG Cloud)
2019-05-22 11:04         ` Li,Lin(ACG Cloud)
2019-06-12  8:07           ` Maxime Coquelin

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='CAF+hgq3gToAOB6+S8PxN19HgfBnAdjy=NCNPYZqGa6OmYfS4Zg@mail.gmail.com' \
    --to=chuckylinchuckylin@gmail.com \
    --cc=changpeng.liu@intel.com \
    --cc=dariusz.stojaczyk@intel.com \
    --cc=dev@dpdk.org \
    --cc=james.r.harris@intel.com \
    --cc=lilin24@baidu.com \
    --cc=maxime.coquelin@redhat.com \
    --cc=nixun@baidu.com \
    --cc=tiwei.bie@intel.com \
    --cc=zhangyu31@baidu.com \
    --cc=zhihong.wang@intel.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.