DPDK patches and discussions
 help / color / mirror / Atom feed
From: David Hunt <david.hunt@intel.com>
To: dev@dpdk.org
Cc: david.hunt@intel.com, thomas@monjalon.net
Subject: [dpdk-dev] [PATCH v4 8/9] examples/vm_power: add cli args to guest app
Date: Fri, 13 Jul 2018 15:23:01 +0100	[thread overview]
Message-ID: <20180713142302.34576-9-david.hunt@intel.com> (raw)
In-Reply-To: <20180713142302.34576-1-david.hunt@intel.com>

Add new command line arguments to the guest app to make
    testing and validation of the policy usage easier.
    These arguments are mainly around setting up the power
    management policy that is sent from the guest vm to
    to the vm_power_manager in the host

    New command line parameters:
    -n or --vm-name
       sets the name of the vm to be used by the host OS.
    -b or --busy-hours
       sets the list of hours that are predicted to be busy
    -q or --quiet-hours
       sets the list of hours that are predicted to be quiet
    -l or --vcpu-list
       sets the list of vcpus to monitor
    -p or --port-list
       sets the list of posts to monitor when using a
       workload policy.
    -o or --policy
       sets the default policy type
          TIME
          WORKLOAD
          TRAFFIC
          BRANCH_RATIO

    The format of the hours or list paramers is a comma-separated
    list of integers, which can take the form of
       a. x    e.g. --vcpu-list=1
       b. x,y  e.g. --quiet-hours=3,4
       c. x-y  e.g. --busy-hours=9-12
       d. combination of above (e.g. --busy-hours=4,5-7,9)

Signed-off-by: David Hunt <david.hunt@intel.com>
Acked-by: Radu Nicolau <radu.nicolau@intel.com>
---
 examples/vm_power_manager/guest_cli/Makefile  |   2 +-
 examples/vm_power_manager/guest_cli/main.c    | 151 +++++++++++++++++-
 examples/vm_power_manager/guest_cli/parse.c   |  82 ++++++++++
 examples/vm_power_manager/guest_cli/parse.h   |  19 +++
 .../guest_cli/vm_power_cli_guest.c            | 113 +++++++------
 .../guest_cli/vm_power_cli_guest.h            |   6 +
 6 files changed, 319 insertions(+), 54 deletions(-)
 create mode 100644 examples/vm_power_manager/guest_cli/parse.c
 create mode 100644 examples/vm_power_manager/guest_cli/parse.h

diff --git a/examples/vm_power_manager/guest_cli/Makefile b/examples/vm_power_manager/guest_cli/Makefile
index d710e22d9..8b1db861e 100644
--- a/examples/vm_power_manager/guest_cli/Makefile
+++ b/examples/vm_power_manager/guest_cli/Makefile
@@ -14,7 +14,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 APP = guest_vm_power_mgr
 
 # all source are stored in SRCS-y
-SRCS-y := main.c vm_power_cli_guest.c
+SRCS-y := main.c vm_power_cli_guest.c parse.c
 
 CFLAGS += -O3 -I$(RTE_SDK)/lib/librte_power/
 CFLAGS += $(WERROR_FLAGS)
diff --git a/examples/vm_power_manager/guest_cli/main.c b/examples/vm_power_manager/guest_cli/main.c
index b17936d6b..36365b124 100644
--- a/examples/vm_power_manager/guest_cli/main.c
+++ b/examples/vm_power_manager/guest_cli/main.c
@@ -2,23 +2,20 @@
  * Copyright(c) 2010-2014 Intel Corporation
  */
 
-/*
 #include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <sys/epoll.h>
-#include <fcntl.h>
-#include <unistd.h>
 #include <stdlib.h>
-#include <errno.h>
-*/
 #include <signal.h>
+#include <getopt.h>
+#include <string.h>
 
 #include <rte_lcore.h>
 #include <rte_power.h>
 #include <rte_debug.h>
+#include <rte_eal.h>
+#include <rte_log.h>
 
 #include "vm_power_cli_guest.h"
+#include "parse.h"
 
 static void
 sig_handler(int signo)
@@ -32,6 +29,136 @@ sig_handler(int signo)
 
 }
 
+#define MAX_HOURS 24
+
+/* Parse the argument given in the command line of the application */
+static int
+parse_args(int argc, char **argv)
+{
+	int opt, ret;
+	char **argvopt;
+	int option_index;
+	char *prgname = argv[0];
+	const struct option lgopts[] = {
+		{ "vm-name", required_argument, 0, 'n'},
+		{ "busy-hours", required_argument, 0, 'b'},
+		{ "quiet-hours", required_argument, 0, 'q'},
+		{ "port-list", required_argument, 0, 'p'},
+		{ "vcpu-list", required_argument, 0, 'l'},
+		{ "policy", required_argument, 0, 'o'},
+		{NULL, 0, 0, 0}
+	};
+	struct channel_packet *policy;
+	unsigned short int hours[MAX_HOURS];
+	unsigned short int cores[MAX_VCPU_PER_VM];
+	unsigned short int ports[MAX_VCPU_PER_VM];
+	int i, cnt, idx;
+
+	policy = get_policy();
+	set_policy_defaults(policy);
+
+	argvopt = argv;
+
+	while ((opt = getopt_long(argc, argvopt, "n:b:q:p:",
+				  lgopts, &option_index)) != EOF) {
+
+		switch (opt) {
+		/* portmask */
+		case 'n':
+			strcpy(policy->vm_name, optarg);
+			printf("Setting VM Name to [%s]\n", policy->vm_name);
+			break;
+		case 'b':
+		case 'q':
+			//printf("***Processing set using [%s]\n", optarg);
+			cnt = parse_set(optarg, hours, MAX_HOURS);
+			if (cnt < 0) {
+				printf("Invalid value passed to quiet/busy hours - [%s]\n",
+						optarg);
+				break;
+			}
+			idx = 0;
+			for (i = 0; i < MAX_HOURS; i++) {
+				if (hours[i]) {
+					if (opt == 'b') {
+						printf("***Busy Hour %d\n", i);
+						policy->timer_policy.busy_hours
+							[idx++] = i;
+					} else {
+						printf("***Quiet Hour %d\n", i);
+						policy->timer_policy.quiet_hours
+							[idx++] = i;
+					}
+				}
+			}
+			break;
+		case 'l':
+			cnt = parse_set(optarg, cores, MAX_VCPU_PER_VM);
+			if (cnt < 0) {
+				printf("Invalid value passed to vcpu-list - [%s]\n",
+						optarg);
+				break;
+			}
+			idx = 0;
+			for (i = 0; i < MAX_VCPU_PER_VM; i++) {
+				if (cores[i]) {
+					printf("***Using core %d\n", i);
+					policy->vcpu_to_control[idx++] = i;
+				}
+			}
+			policy->num_vcpu = idx;
+			printf("Total cores: %d\n", idx);
+			break;
+		case 'p':
+			cnt = parse_set(optarg, ports, MAX_VCPU_PER_VM);
+			if (cnt < 0) {
+				printf("Invalid value passed to port-list - [%s]\n",
+						optarg);
+				break;
+			}
+			idx = 0;
+			for (i = 0; i < MAX_VCPU_PER_VM; i++) {
+				if (ports[i]) {
+					printf("***Using port %d\n", i);
+					set_policy_mac(i, idx++);
+				}
+			}
+			policy->nb_mac_to_monitor = idx;
+			printf("Total Ports: %d\n", idx);
+			break;
+		case 'o':
+			if (!strcmp(optarg, "TRAFFIC"))
+				policy->policy_to_use = TRAFFIC;
+			else if (!strcmp(optarg, "TIME"))
+				policy->policy_to_use = TIME;
+			else if (!strcmp(optarg, "WORKLOAD"))
+				policy->policy_to_use = WORKLOAD;
+			else if (!strcmp(optarg, "BRANCH_RATIO"))
+				policy->policy_to_use = BRANCH_RATIO;
+			else {
+				printf("Invalid policy specified: %s\n",
+						optarg);
+				return -1;
+			}
+			break;
+		/* long options */
+
+		case 0:
+			break;
+
+		default:
+			return -1;
+		}
+	}
+
+	if (optind >= 0)
+		argv[optind-1] = prgname;
+
+	ret = optind-1;
+	optind = 0; /* reset getopt lib */
+	return ret;
+}
+
 int
 main(int argc, char **argv)
 {
@@ -45,6 +172,14 @@ main(int argc, char **argv)
 	signal(SIGINT, sig_handler);
 	signal(SIGTERM, sig_handler);
 
+	argc -= ret;
+	argv += ret;
+
+	/* parse application arguments (after the EAL ones) */
+	ret = parse_args(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Invalid arguments\n");
+
 	rte_power_set_env(PM_ENV_KVM_VM);
 	RTE_LCORE_FOREACH(lcore_id) {
 		rte_power_init(lcore_id);
diff --git a/examples/vm_power_manager/guest_cli/parse.c b/examples/vm_power_manager/guest_cli/parse.c
new file mode 100644
index 000000000..528df6d6f
--- /dev/null
+++ b/examples/vm_power_manager/guest_cli/parse.c
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation.
+ * Copyright(c) 2014 6WIND S.A.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <rte_log.h>
+#include "parse.h"
+
+/*
+ * Parse elem, the elem could be single number/range or group
+ * 1) A single number elem, it's just a simple digit. e.g. 9
+ * 2) A single range elem, two digits with a '-' between. e.g. 2-6
+ * 3) A group elem, combines multiple 1) or 2) e.g 0,2-4,6
+ *    Within group, '-' used for a range separator;
+ *                       ',' used for a single number.
+ */
+int
+parse_set(const char *input, uint16_t set[], unsigned int num)
+{
+	unsigned int idx;
+	const char *str = input;
+	char *end = NULL;
+	unsigned int min, max;
+
+	memset(set, 0, num * sizeof(uint16_t));
+
+	while (isblank(*str))
+		str++;
+
+	/* only digit or left bracket is qualify for start point */
+	if (!isdigit(*str) || *str == '\0')
+		return -1;
+
+	while (isblank(*str))
+		str++;
+	if (*str == '\0')
+		return -1;
+
+	min = num;
+	do {
+
+		/* go ahead to the first digit */
+		while (isblank(*str))
+			str++;
+		if (!isdigit(*str))
+			return -1;
+
+		/* get the digit value */
+		errno = 0;
+		idx = strtoul(str, &end, 10);
+		if (errno || end == NULL || idx >= num)
+			return -1;
+
+		/* go ahead to separator '-' and ',' */
+		while (isblank(*end))
+			end++;
+		if (*end == '-') {
+			if (min == num)
+				min = idx;
+			else /* avoid continuous '-' */
+				return -1;
+		} else if ((*end == ',') || (*end == '\0')) {
+			max = idx;
+
+			if (min == num)
+				min = idx;
+
+			for (idx = RTE_MIN(min, max);
+					idx <= RTE_MAX(min, max); idx++) {
+				set[idx] = 1;
+			}
+			min = num;
+		} else
+			return -1;
+
+		str = end + 1;
+	} while (*end != '\0');
+
+	return str - input;
+}
diff --git a/examples/vm_power_manager/guest_cli/parse.h b/examples/vm_power_manager/guest_cli/parse.h
new file mode 100644
index 000000000..c8aa0ea50
--- /dev/null
+++ b/examples/vm_power_manager/guest_cli/parse.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef PARSE_H_
+#define PARSE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int
+parse_set(const char *, uint16_t [], unsigned int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PARSE_H_ */
diff --git a/examples/vm_power_manager/guest_cli/vm_power_cli_guest.c b/examples/vm_power_manager/guest_cli/vm_power_cli_guest.c
index 43bdeacef..0db1b804f 100644
--- a/examples/vm_power_manager/guest_cli/vm_power_cli_guest.c
+++ b/examples/vm_power_manager/guest_cli/vm_power_cli_guest.c
@@ -33,6 +33,71 @@ struct cmd_quit_result {
 	cmdline_fixed_string_t quit;
 };
 
+union PFID {
+	struct ether_addr addr;
+	uint64_t pfid;
+};
+
+static struct channel_packet policy;
+
+struct channel_packet *
+get_policy(void)
+{
+	return &policy;
+}
+
+int
+set_policy_mac(int port, int idx)
+{
+	struct channel_packet *policy;
+	union PFID pfid;
+
+	/* Use port MAC address as the vfid */
+	rte_eth_macaddr_get(port, &pfid.addr);
+
+	printf("Port %u MAC: %02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":"
+			"%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 "\n",
+			port,
+			pfid.addr.addr_bytes[0], pfid.addr.addr_bytes[1],
+			pfid.addr.addr_bytes[2], pfid.addr.addr_bytes[3],
+			pfid.addr.addr_bytes[4], pfid.addr.addr_bytes[5]);
+	policy = get_policy();
+	policy->vfid[idx] = pfid.pfid;
+	return 0;
+}
+
+void
+set_policy_defaults(struct channel_packet *pkt)
+{
+	set_policy_mac(0, 0);
+	pkt->nb_mac_to_monitor = 1;
+
+	pkt->t_boost_status.tbEnabled = false;
+
+	pkt->vcpu_to_control[0] = 0;
+	pkt->vcpu_to_control[1] = 1;
+	pkt->num_vcpu = 2;
+	/* Dummy Population. */
+	pkt->traffic_policy.min_packet_thresh = 96000;
+	pkt->traffic_policy.avg_max_packet_thresh = 1800000;
+	pkt->traffic_policy.max_max_packet_thresh = 2000000;
+
+	pkt->timer_policy.busy_hours[0] = 3;
+	pkt->timer_policy.busy_hours[1] = 4;
+	pkt->timer_policy.busy_hours[2] = 5;
+	pkt->timer_policy.quiet_hours[0] = 11;
+	pkt->timer_policy.quiet_hours[1] = 12;
+	pkt->timer_policy.quiet_hours[2] = 13;
+
+	pkt->timer_policy.hours_to_use_traffic_profile[0] = 8;
+	pkt->timer_policy.hours_to_use_traffic_profile[1] = 10;
+
+	pkt->workload = LOW;
+	pkt->policy_to_use = TIME;
+	pkt->command = PKT_POLICY;
+	strcpy(pkt->vm_name, "ubuntu2");
+}
+
 static void cmd_quit_parsed(__attribute__((unused)) void *parsed_result,
 				__attribute__((unused)) struct cmdline *cl,
 			    __attribute__((unused)) void *data)
@@ -118,54 +183,12 @@ struct cmd_send_policy_result {
 	cmdline_fixed_string_t cmd;
 };
 
-union PFID {
-	struct ether_addr addr;
-	uint64_t pfid;
-};
-
 static inline int
-send_policy(void)
+send_policy(struct channel_packet *pkt)
 {
-	struct channel_packet pkt;
 	int ret;
 
-	union PFID pfid;
-	/* Use port MAC address as the vfid */
-	rte_eth_macaddr_get(0, &pfid.addr);
-	printf("Port %u MAC: %02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":"
-			"%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 "\n",
-			1,
-			pfid.addr.addr_bytes[0], pfid.addr.addr_bytes[1],
-			pfid.addr.addr_bytes[2], pfid.addr.addr_bytes[3],
-			pfid.addr.addr_bytes[4], pfid.addr.addr_bytes[5]);
-	pkt.vfid[0] = pfid.pfid;
-
-	pkt.nb_mac_to_monitor = 1;
-	pkt.t_boost_status.tbEnabled = false;
-
-	pkt.vcpu_to_control[0] = 0;
-	pkt.vcpu_to_control[1] = 1;
-	pkt.num_vcpu = 2;
-	/* Dummy Population. */
-	pkt.traffic_policy.min_packet_thresh = 96000;
-	pkt.traffic_policy.avg_max_packet_thresh = 1800000;
-	pkt.traffic_policy.max_max_packet_thresh = 2000000;
-
-	pkt.timer_policy.busy_hours[0] = 3;
-	pkt.timer_policy.busy_hours[1] = 4;
-	pkt.timer_policy.busy_hours[2] = 5;
-	pkt.timer_policy.quiet_hours[0] = 11;
-	pkt.timer_policy.quiet_hours[1] = 12;
-	pkt.timer_policy.quiet_hours[2] = 13;
-
-	pkt.timer_policy.hours_to_use_traffic_profile[0] = 8;
-	pkt.timer_policy.hours_to_use_traffic_profile[1] = 10;
-
-	pkt.workload = LOW;
-	pkt.policy_to_use = TIME;
-	pkt.command = PKT_POLICY;
-	strcpy(pkt.vm_name, "ubuntu2");
-	ret = rte_power_guest_channel_send_msg(&pkt, 1);
+	ret = rte_power_guest_channel_send_msg(pkt, 1);
 	if (ret == 0)
 		return 1;
 	RTE_LOG(DEBUG, POWER, "Error sending message: %s\n",
@@ -182,7 +205,7 @@ cmd_send_policy_parsed(void *parsed_result, struct cmdline *cl,
 
 	if (!strcmp(res->cmd, "now")) {
 		printf("Sending Policy down now!\n");
-		ret = send_policy();
+		ret = send_policy(&policy);
 	}
 	if (ret != 1)
 		cmdline_printf(cl, "Error sending message: %s\n",
diff --git a/examples/vm_power_manager/guest_cli/vm_power_cli_guest.h b/examples/vm_power_manager/guest_cli/vm_power_cli_guest.h
index 75a262967..fd77f6a69 100644
--- a/examples/vm_power_manager/guest_cli/vm_power_cli_guest.h
+++ b/examples/vm_power_manager/guest_cli/vm_power_cli_guest.h
@@ -11,6 +11,12 @@ extern "C" {
 
 #include "channel_commands.h"
 
+struct channel_packet *get_policy(void);
+
+int set_policy_mac(int port, int idx);
+
+void set_policy_defaults(struct channel_packet *pkt);
+
 void run_cli(__attribute__((unused)) void *arg);
 
 #ifdef __cplusplus
-- 
2.17.1

  parent reply	other threads:[~2018-07-13 14:23 UTC|newest]

Thread overview: 46+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-06-07  7:36 [dpdk-dev] [PATCH v1 0/6] examples/vm_power: 100% Busy Polling David Hunt
2018-06-07  7:37 ` [dpdk-dev] [PATCH v1 1/6] examples/vm_power: add check for port count David Hunt
2018-06-21 13:24   ` [dpdk-dev] [PATCH v2 0/8] examples/vm_power: 100% Busy Polling David Hunt
2018-06-21 13:24     ` [dpdk-dev] [PATCH v2 1/8] examples/vm_power: add check for port count David Hunt
2018-06-26  9:23       ` [dpdk-dev] [0/9] examples/vm_power: 100% Busy Polling David Hunt
2018-06-26  9:23         ` [dpdk-dev] [PATCH v3 1/9] examples/vm_power: add check for port count David Hunt
2018-07-13 14:22           ` [dpdk-dev] [PATCH v4 0/9] examples/vm_power: 100% Busy Polling David Hunt
2018-07-13 14:22             ` [dpdk-dev] [PATCH v4 1/9] examples/vm_power: add check for port count David Hunt
2018-07-13 14:22             ` [dpdk-dev] [PATCH v4 2/9] examples/vm_power: add core list parameter David Hunt
2018-07-13 14:22             ` [dpdk-dev] [PATCH v4 3/9] examples/vm_power: add oob monitoring functions David Hunt
2018-07-13 14:22             ` [dpdk-dev] [PATCH v4 4/9] examples/vm_power: allow greater than 64 cores David Hunt
2018-07-13 14:22             ` [dpdk-dev] [PATCH v4 5/9] examples/vm_power: add thread for oob core monitor David Hunt
2018-07-13 14:22             ` [dpdk-dev] [PATCH v4 6/9] examples/vm_power: add port-list to command line David Hunt
2018-07-13 14:23             ` [dpdk-dev] [PATCH v4 7/9] examples/vm_power: add branch ratio policy type David Hunt
2018-07-13 14:23             ` David Hunt [this message]
2018-07-13 14:23             ` [dpdk-dev] [PATCH v4 9/9] examples/vm_power: make branch ratio configurable David Hunt
2018-07-20 22:06             ` [dpdk-dev] [PATCH v4 0/9] examples/vm_power: 100% Busy Polling Thomas Monjalon
2018-06-26  9:23         ` [dpdk-dev] [PATCH v3 2/9] examples/vm_power: add core list parameter David Hunt
2018-06-26  9:23         ` [dpdk-dev] [PATCH v3 3/9] examples/vm_power: add oob monitoring functions David Hunt
2018-07-12 19:13           ` Thomas Monjalon
2018-07-12 22:18             ` Stephen Hemminger
2018-07-13  8:24             ` Hunt, David
2018-06-26  9:23         ` [dpdk-dev] [PATCH v3 4/9] examples/vm_power: allow greater than 64 cores David Hunt
2018-06-26  9:23         ` [dpdk-dev] [PATCH v3 5/9] examples/vm_power: add thread for oob core monitor David Hunt
2018-06-26  9:23         ` [dpdk-dev] [PATCH v3 6/9] examples/vm_power: add port-list to command line David Hunt
2018-06-26  9:23         ` [dpdk-dev] [PATCH v3 7/9] examples/vm_power: add branch ratio policy type David Hunt
2018-06-26  9:23         ` [dpdk-dev] [PATCH v3 8/9] examples/vm_power: add cli args to guest app David Hunt
2018-06-26  9:23         ` [dpdk-dev] [PATCH v3 9/9] examples/vm_power: make branch ratio configurable David Hunt
2018-07-12 19:09         ` [dpdk-dev] [0/9] examples/vm_power: 100% Busy Polling Thomas Monjalon
2018-07-13  8:31           ` Hunt, David
2018-07-13  8:33             ` Thomas Monjalon
2018-07-13  8:43               ` Hunt, David
2018-07-18 15:23                 ` Thomas Monjalon
2018-06-21 13:24     ` [dpdk-dev] [PATCH v2 2/8] examples/vm_power: add core list parameter David Hunt
2018-06-21 13:24     ` [dpdk-dev] [PATCH v2 3/8] examples/vm_power: add oob monitoring functions David Hunt
2018-06-21 13:24     ` [dpdk-dev] [PATCH v2 4/8] examples/vm_power: allow greater than 64 cores David Hunt
2018-06-21 13:24     ` [dpdk-dev] [PATCH v2 5/8] examples/vm_power: add thread for oob core monitor David Hunt
2018-06-21 13:24     ` [dpdk-dev] [PATCH v2 6/8] examples/vm_power: add port-list to command line David Hunt
2018-06-21 13:24     ` [dpdk-dev] [PATCH v2 7/8] examples/vm_power: add branch ratio policy type David Hunt
2018-06-21 13:24     ` [dpdk-dev] [PATCH v2 8/8] examples/vm_power: add cli args to guest app David Hunt
2018-06-21 14:28     ` [dpdk-dev] [PATCH v2 0/8] examples/vm_power: 100% Busy Polling Radu Nicolau
2018-06-07  7:37 ` [dpdk-dev] [PATCH v1 2/6] examples/vm_power: add core list parameter David Hunt
2018-06-07  7:37 ` [dpdk-dev] [PATCH v1 3/6] examples/vm_power: add oob monitoring functions David Hunt
2018-06-07  7:37 ` [dpdk-dev] [PATCH v1 4/6] examples/vm_power: allow greater than 64 cores David Hunt
2018-06-07  7:37 ` [dpdk-dev] [PATCH v1 5/6] examples/vm_power: add thread for oob core monitor David Hunt
2018-06-07  7:37 ` [dpdk-dev] [PATCH v1 6/6] examples/vm_power: add port-list to command line David Hunt

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=20180713142302.34576-9-david.hunt@intel.com \
    --to=david.hunt@intel.com \
    --cc=dev@dpdk.org \
    --cc=thomas@monjalon.net \
    /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).