Soft Patch Panel
 help / color / mirror / Atom feed
From: ogawa.yasufumi@lab.ntt.co.jp
To: ferruh.yigit@intel.com, spp@dpdk.org, ogawa.yasufumi@lab.ntt.co.jp
Subject: [spp] [PATCH 3/6] spp_nfv: refactor common for spp_nfv
Date: Tue, 15 Jan 2019 12:27:58 +0900	[thread overview]
Message-ID: <1547522881-10105-4-git-send-email-ogawa.yasufumi@lab.ntt.co.jp> (raw)
In-Reply-To: <1547522881-10105-1-git-send-email-ogawa.yasufumi@lab.ntt.co.jp>

From: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>

Move specific variables and functions for spp_nfv from
`shared/common.*` to `nfv/*`.

Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/nfv/Makefile        |  3 +-
 src/nfv/command_utils.h | 46 ++++++++++++++++------------
 src/nfv/commands.h      | 68 ++++++++++++++++++++++-------------------
 src/nfv/main.c          | 22 +++++++------
 src/nfv/nfv.h           |  8 ++---
 src/nfv/params.h        |  9 +++---
 6 files changed, 86 insertions(+), 70 deletions(-)

diff --git a/src/nfv/Makefile b/src/nfv/Makefile
index d6884c5..cee1236 100644
--- a/src/nfv/Makefile
+++ b/src/nfv/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2015-2016 Intel Corporation
+# Copyright(c) 2019 Nippon Telegraph and Telephone Corporation
 
 ifeq ($(RTE_SDK),)
 $(error "Please define RTE_SDK environment variable")
@@ -12,7 +13,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 APP = spp_nfv
 
 # all source are stored in SRCS-y
-SRCS-y := main.c ../shared/common.c
+SRCS-y := main.c ../shared/common.c ../shared/secondary.c
 
 CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += $(WERROR_FLAGS) -O3 -MMD
diff --git a/src/nfv/command_utils.h b/src/nfv/command_utils.h
index e3c7db1..f026732 100644
--- a/src/nfv/command_utils.h
+++ b/src/nfv/command_utils.h
@@ -1,16 +1,22 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2018  Nippon Telegraph and Telephone Corporation.
+ * Copyright(c) 2015-2016 Intel Corporation
+ * Copyright(c) 2019 Nippon Telegraph and Telephone Corporation
  */
 
-#ifndef NFV_COMMAND_UTILS_H
-#define NFV_COMMAND_UTILS_H
+#ifndef _NFV_COMMAND_UTILS_H_
+#define _NFV_COMMAND_UTILS_H_
 
 #include "common.h"
-#include "nfv.h"
+#include "secondary.h"
+
+#define RTE_LOGTYPE_SPP_NFV RTE_LOGTYPE_USER1
 
 // The number of receive descriptors to allocate for the receive ring.
 #define NR_DESCS 128
 
+#define PCAP_IFACE_RX "/tmp/spp-rx%d.pcap"
+#define PCAP_IFACE_TX "/tmp/spp-tx%d.pcap"
+
 static void
 forward_array_init_one(unsigned int i)
 {
@@ -105,11 +111,11 @@ add_patch(uint16_t in_port, uint16_t out_port)
 	ports_fwd_array[out_port].rx_func = &rte_eth_rx_burst;
 	ports_fwd_array[out_port].tx_func = &rte_eth_tx_burst;
 
-	RTE_LOG(DEBUG, APP, "STATUS: in port %d in_port_id %d\n", in_port,
+	RTE_LOG(DEBUG, SPP_NFV, "STATUS: in port %d in_port_id %d\n", in_port,
 		ports_fwd_array[in_port].in_port_id);
-	RTE_LOG(DEBUG, APP, "STATUS: in port %d patch out port id %d\n",
+	RTE_LOG(DEBUG, SPP_NFV, "STATUS: in port %d patch out port id %d\n",
 		in_port, ports_fwd_array[in_port].out_port_id);
-	RTE_LOG(DEBUG, APP, "STATUS: outport %d in_port_id %d\n", out_port,
+	RTE_LOG(DEBUG, SPP_NFV, "STATUS: outport %d in_port_id %d\n", out_port,
 		ports_fwd_array[out_port].in_port_id);
 
 	return 0;
@@ -135,7 +141,7 @@ create_pcap_rx(char *rx_fpath)
 	if (tmp_fp == NULL) {
 		(tmp_fp = fopen(template, "w"));
 		if (tmp_fp == NULL) {
-			RTE_LOG(ERR, APP, "Failed to open %s\n", template);
+			RTE_LOG(ERR, SPP_NFV, "Failed to open %s\n", template);
 			return -1;
 		}
 	}
@@ -143,12 +149,12 @@ create_pcap_rx(char *rx_fpath)
 	sprintf(cmd_str, "text2pcap %s %s", template, rx_fpath);
 	res = system(cmd_str);
 	if (res != 0) {
-		RTE_LOG(ERR, APP,
+		RTE_LOG(ERR, SPP_NFV,
 				"Failed to create pcap device %s\n",
 				rx_fpath);
 		return -1;
 	}
-	RTE_LOG(INFO, APP, "PCAP device created\n");
+	RTE_LOG(INFO, SPP_NFV, "PCAP device created\n");
 	fclose(tmp_fp);
 	return 0;
 }
@@ -169,21 +175,21 @@ add_ring_pmd(int ring_id)
 	/* Look up ring with provided ring_id */
 	ring = rte_ring_lookup(rx_queue_name);
 	if (ring == NULL) {
-		RTE_LOG(ERR, APP,
+		RTE_LOG(ERR, SPP_NFV,
 			"Failed to get RX ring %s - is primary running?\n",
 			rx_queue_name);
 		return -1;
 	}
-	RTE_LOG(INFO, APP, "Looked up ring '%s'\n", rx_queue_name);
+	RTE_LOG(INFO, SPP_NFV, "Looked up ring '%s'\n", rx_queue_name);
 
 	/* create ring pmd*/
 	res = rte_eth_from_ring(ring);
 	if (res < 0) {
-		RTE_LOG(ERR, APP,
+		RTE_LOG(ERR, SPP_NFV,
 			"Cannot create eth dev with rte_eth_from_ring()\n");
 		return -1;
 	}
-	RTE_LOG(INFO, APP, "Created ring PMD: %d\n", res);
+	RTE_LOG(INFO, SPP_NFV, "Created ring PMD: %d\n", res);
 
 	return res;
 }
@@ -242,7 +248,7 @@ add_vhost_pmd(int index)
 	if (ret < 0)
 		return ret;
 
-	RTE_LOG(DEBUG, APP, "vhost port id %d\n", vhost_port_id);
+	RTE_LOG(DEBUG, SPP_NFV, "vhost port id %d\n", vhost_port_id);
 
 	return vhost_port_id;
 }
@@ -329,7 +335,7 @@ add_pcap_pmd(int index)
 	if (ret < 0)
 		return ret;
 
-	RTE_LOG(DEBUG, APP, "pcap port id %d\n", pcap_pmd_port_id);
+	RTE_LOG(DEBUG, SPP_NFV, "pcap port id %d\n", pcap_pmd_port_id);
 
 	return pcap_pmd_port_id;
 }
@@ -391,7 +397,7 @@ add_null_pmd(int index)
 	if (ret < 0)
 		return ret;
 
-	RTE_LOG(DEBUG, APP, "null port id %d\n", null_pmd_port_id);
+	RTE_LOG(DEBUG, SPP_NFV, "null port id %d\n", null_pmd_port_id);
 
 	return null_pmd_port_id;
 }
@@ -416,8 +422,8 @@ forward_array_reset(void)
 	for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
 		if (ports_fwd_array[i].in_port_id != PORT_RESET) {
 			ports_fwd_array[i].out_port_id = PORT_RESET;
-			RTE_LOG(INFO, APP, "Port ID %d\n", i);
-			RTE_LOG(INFO, APP, "out_port_id %d\n",
+			RTE_LOG(INFO, SPP_NFV, "Port ID %d\n", i);
+			RTE_LOG(INFO, SPP_NFV, "out_port_id %d\n",
 				ports_fwd_array[i].out_port_id);
 		}
 	}
@@ -434,4 +440,4 @@ static enum port_type get_port_type(char *portname)
 	return UNDEF;
 }
 
-#endif
+#endif // _NFV_COMMAND_UTILS_H_
diff --git a/src/nfv/commands.h b/src/nfv/commands.h
index b33625f..35340f9 100644
--- a/src/nfv/commands.h
+++ b/src/nfv/commands.h
@@ -1,14 +1,17 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2018  Nippon Telegraph and Telephone Corporation.
+ * Copyright(c) 2015-2016 Intel Corporation
+ * Copyright(c) 2019 Nippon Telegraph and Telephone Corporation
  */
 
-#ifndef NFV_COMMANDS_H
-#define NFV_COMMANDS_H
+#ifndef _NFV_COMMANDS_H_
+#define _NFV_COMMANDS_H_
 
 #include "common.h"
 #include "nfv.h"
 #include "command_utils.h"
 
+#define RTE_LOGTYPE_SPP_NFV RTE_LOGTYPE_USER1
+
 static int
 do_del(char *res_uid)
 {
@@ -19,7 +22,7 @@ do_del(char *res_uid)
 
 	res = parse_resource_uid(res_uid, &p_type, &p_id);
 	if (res < 0) {
-		RTE_LOG(ERR, APP,
+		RTE_LOG(ERR, SPP_NFV,
 			"Failed to parse resource UID\n");
 		return -1;
 	}
@@ -30,7 +33,7 @@ do_del(char *res_uid)
 			return -1;
 
 	} else if (!strcmp(p_type, "ring")) {
-		RTE_LOG(DEBUG, APP, "Del ring id %d\n", p_id);
+		RTE_LOG(DEBUG, SPP_NFV, "Del ring id %d\n", p_id);
 		port_id = find_port_id(p_id, RING);
 		if (port_id == PORT_RESET)
 			return -1;
@@ -115,7 +118,7 @@ do_connection(int *connected, int *sock)
 
 	if (*connected == 0) {
 		if (*sock < 0) {
-			RTE_LOG(INFO, APP, "Creating socket...\n");
+			RTE_LOG(INFO, SPP_NFV, "Creating socket...\n");
 			*sock = socket(AF_INET, SOCK_STREAM, 0);
 			if (*sock < 0)
 				rte_exit(EXIT_FAILURE, "socket error\n");
@@ -127,15 +130,16 @@ do_connection(int *connected, int *sock)
 			servaddr.sin_port = htons(server_port);
 		}
 
-		RTE_LOG(INFO, APP, "Trying to connect ... socket %d\n", *sock);
+		RTE_LOG(INFO,
+			SPP_NFV, "Trying to connect ... socket %d\n", *sock);
 		ret = connect(*sock, (struct sockaddr *) &servaddr,
 				sizeof(servaddr));
 		if (ret < 0) {
-			RTE_LOG(ERR, APP, "Connection Error");
+			RTE_LOG(ERR, SPP_NFV, "Connection Error");
 			return ret;
 		}
 
-		RTE_LOG(INFO, APP, "Connected\n");
+		RTE_LOG(INFO, SPP_NFV, "Connected\n");
 		*connected = 1;
 	}
 
@@ -156,7 +160,7 @@ parse_command(char *str)
 	/* tokenize user command from controller */
 	token_list[max_token] = strtok(str, " ");
 	while (token_list[max_token] != NULL) {
-		RTE_LOG(DEBUG, APP, "token %d = %s\n", max_token,
+		RTE_LOG(DEBUG, SPP_NFV, "token %d = %s\n", max_token,
 			token_list[max_token]);
 		max_token++;
 		token_list[max_token] = strtok(NULL, " ");
@@ -166,7 +170,7 @@ parse_command(char *str)
 		return 0;
 
 	if (!strcmp(token_list[0], "status")) {
-		RTE_LOG(DEBUG, APP, "status\n");
+		RTE_LOG(DEBUG, SPP_NFV, "status\n");
 		memset(str, '\0', MSG_SIZE);
 		if (cmd == FORWARD)
 			get_sec_stats_json(str, client_id, "running",
@@ -186,26 +190,26 @@ parse_command(char *str)
 			client_id = id;
 
 	} else if (!strcmp(token_list[0], "exit")) {
-		RTE_LOG(DEBUG, APP, "exit\n");
-		RTE_LOG(DEBUG, APP, "stop\n");
+		RTE_LOG(DEBUG, SPP_NFV, "exit\n");
+		RTE_LOG(DEBUG, SPP_NFV, "stop\n");
 		cmd = STOP;
 		ret = -1;
 
 	} else if (!strcmp(token_list[0], "stop")) {
-		RTE_LOG(DEBUG, APP, "stop\n");
+		RTE_LOG(DEBUG, SPP_NFV, "stop\n");
 		cmd = STOP;
 
 	} else if (!strcmp(token_list[0], "forward")) {
-		RTE_LOG(DEBUG, APP, "forward\n");
+		RTE_LOG(DEBUG, SPP_NFV, "forward\n");
 		cmd = FORWARD;
 
 	} else if (!strcmp(token_list[0], "add")) {
-		RTE_LOG(DEBUG, APP, "Received add command\n");
+		RTE_LOG(DEBUG, SPP_NFV, "Received add command\n");
 		if (do_add(token_list[1]) < 0)
-			RTE_LOG(ERR, APP, "Failed to do_add()\n");
+			RTE_LOG(ERR, SPP_NFV, "Failed to do_add()\n");
 
 	} else if (!strcmp(token_list[0], "patch")) {
-		RTE_LOG(DEBUG, APP, "patch\n");
+		RTE_LOG(DEBUG, SPP_NFV, "patch\n");
 
 		if (max_token <= 1)
 			return 0;
@@ -241,41 +245,41 @@ parse_command(char *str)
 					"Patch not found, both of",
 					in_p_type, in_p_id,
 					out_p_type, out_p_id);
-				RTE_LOG(ERR, APP, "%s\n", err_msg);
+				RTE_LOG(ERR, SPP_NFV, "%s\n", err_msg);
 			} else if (in_port == PORT_RESET) {
 				char err_msg[128];
 				memset(err_msg, '\0', sizeof(err_msg));
 				sprintf(err_msg, "%s '%s:%d'",
 					"Patch not found, in_port",
 					in_p_type, in_p_id);
-				RTE_LOG(ERR, APP, "%s\n", err_msg);
+				RTE_LOG(ERR, SPP_NFV, "%s\n", err_msg);
 			} else if (out_port == PORT_RESET) {
 				char err_msg[128];
 				memset(err_msg, '\0', sizeof(err_msg));
 				sprintf(err_msg, "%s '%s:%d'",
 					"Patch not found, out_port",
 					out_p_type, out_p_id);
-				RTE_LOG(ERR, APP, "%s\n", err_msg);
+				RTE_LOG(ERR, SPP_NFV, "%s\n", err_msg);
 			}
 
 			if (add_patch(in_port, out_port) == 0)
-				RTE_LOG(INFO, APP,
+				RTE_LOG(INFO, SPP_NFV,
 					"Patched '%s:%d' and '%s:%d'\n",
 					in_p_type, in_p_id,
 					out_p_type, out_p_id);
 
 			else
-				RTE_LOG(ERR, APP, "Failed to patch\n");
+				RTE_LOG(ERR, SPP_NFV, "Failed to patch\n");
 			ret = 0;
 		}
 
 	} else if (!strcmp(token_list[0], "del")) {
-		RTE_LOG(DEBUG, APP, "Received del command\n");
+		RTE_LOG(DEBUG, SPP_NFV, "Received del command\n");
 
 		cmd = STOP;
 
 		if (do_del(token_list[1]) < 0)
-			RTE_LOG(ERR, APP, "Failed to do_del()\n");
+			RTE_LOG(ERR, SPP_NFV, "Failed to do_del()\n");
 	}
 
 	return ret;
@@ -290,13 +294,13 @@ do_receive(int *connected, int *sock, char *str)
 
 	ret = recv(*sock, str, MSG_SIZE, 0);
 	if (ret <= 0) {
-		RTE_LOG(DEBUG, APP, "Receive count: %d\n", ret);
+		RTE_LOG(DEBUG, SPP_NFV, "Receive count: %d\n", ret);
 		if (ret < 0)
-			RTE_LOG(ERR, APP, "Receive Fail");
+			RTE_LOG(ERR, SPP_NFV, "Receive Fail");
 		else
-			RTE_LOG(INFO, APP, "Receive 0\n");
+			RTE_LOG(INFO, SPP_NFV, "Receive 0\n");
 
-		RTE_LOG(INFO, APP, "Assume Server closed connection\n");
+		RTE_LOG(INFO, SPP_NFV, "Assume Server closed connection\n");
 		close(*sock);
 		*sock = SOCK_RESET;
 		*connected = 0;
@@ -313,14 +317,14 @@ do_send(int *connected, int *sock, char *str)
 
 	ret = send(*sock, str, MSG_SIZE, 0);
 	if (ret == -1) {
-		RTE_LOG(ERR, APP, "send failed");
+		RTE_LOG(ERR, SPP_NFV, "send failed");
 		*connected = 0;
 		return -1;
 	}
 
-	RTE_LOG(INFO, APP, "To Server: %s\n", str);
+	RTE_LOG(INFO, SPP_NFV, "To Server: %s\n", str);
 
 	return 0;
 }
 
-#endif
+#endif // _NFV_COMMANDS_H_
diff --git a/src/nfv/main.c b/src/nfv/main.c
index f1555af..6e9e844 100644
--- a/src/nfv/main.c
+++ b/src/nfv/main.c
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2018  Nippon Telegraph and Telephone Corporation.
+ * Copyright(c) 2015-2016 Intel Corporation
+ * Copyright(c) 2019 Nippon Telegraph and Telephone Corporation
  */
 
 #include <arpa/inet.h>
@@ -8,9 +9,12 @@
 #include <rte_eth_ring.h>
 #include <rte_eth_vhost.h>
 #include <rte_memzone.h>
+#include <rte_log.h>
 
 #include "nfv.h"
 
+#define RTE_LOGTYPE_SPP_NFV RTE_LOGTYPE_USER1
+
 static sig_atomic_t on = 1;
 
 /*
@@ -19,7 +23,7 @@ static sig_atomic_t on = 1;
 static void
 usage(const char *progname)
 {
-	RTE_LOG(INFO, APP,
+	RTE_LOG(INFO, SPP_NFV,
 		"Usage: %s [EAL args] -- -n <client_id>\n\n", progname);
 }
 
@@ -114,12 +118,12 @@ nfv_loop(void)
 {
 	unsigned int lcore_id = rte_lcore_id();
 
-	RTE_LOG(INFO, APP, "entering main loop on lcore %u\n", lcore_id);
+	RTE_LOG(INFO, SPP_NFV, "entering main loop on lcore %u\n", lcore_id);
 
 	while (1) {
 		if (unlikely(cmd == STOP)) {
 			sleep(1);
-			/*RTE_LOG(INFO, APP, "Idling\n");*/
+			/*RTE_LOG(INFO, SPP_NFV, "Idling\n");*/
 			continue;
 		} else if (cmd == FORWARD) {
 			forward();
@@ -190,7 +194,7 @@ main(int argc, char *argv[])
 
 	set_user_log_debug(1);
 
-	RTE_LOG(INFO, APP, "Number of Ports: %d\n", nb_ports);
+	RTE_LOG(INFO, SPP_NFV, "Number of Ports: %d\n", nb_ports);
 
 	cmd = STOP;
 
@@ -211,8 +215,8 @@ main(int argc, char *argv[])
 		rte_eal_remote_launch(main_loop, NULL, lcore_id);
 	}
 
-	RTE_LOG(INFO, APP, "My ID %d start handling message\n", client_id);
-	RTE_LOG(INFO, APP, "[Press Ctrl-C to quit ...]\n");
+	RTE_LOG(INFO, SPP_NFV, "My ID %d start handling message\n", client_id);
+	RTE_LOG(INFO, SPP_NFV, "[Press Ctrl-C to quit ...]\n");
 
 	/* send and receive msg loop */
 	while (on) {
@@ -226,7 +230,7 @@ main(int argc, char *argv[])
 		if (ret < 0)
 			continue;
 
-		RTE_LOG(DEBUG, APP, "Received string: %s\n", str);
+		RTE_LOG(DEBUG, SPP_NFV, "Received string: %s\n", str);
 
 		flg_exit = parse_command(str);
 
@@ -242,6 +246,6 @@ main(int argc, char *argv[])
 	/* exit */
 	close(sock);
 	sock = SOCK_RESET;
-	RTE_LOG(INFO, APP, "spp_nfv exit.\n");
+	RTE_LOG(INFO, SPP_NFV, "spp_nfv exit.\n");
 	return 0;
 }
diff --git a/src/nfv/nfv.h b/src/nfv/nfv.h
index a8e037d..d9e5adf 100644
--- a/src/nfv/nfv.h
+++ b/src/nfv/nfv.h
@@ -1,13 +1,13 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2018  Nippon Telegraph and Telephone Corporation.
+ * Copyright(c) 2019 Nippon Telegraph and Telephone Corporation
  */
 
-#ifndef NFV_H
-#define NFV_H
+#ifndef _NFV_H_
+#define _NFV_H_
 
 #include "common.h"
 #include "params.h"
 #include "command_utils.h"
 #include "commands.h"
 
-#endif
+#endif // _NFV_H_
diff --git a/src/nfv/params.h b/src/nfv/params.h
index f7525ae..aa9c720 100644
--- a/src/nfv/params.h
+++ b/src/nfv/params.h
@@ -1,9 +1,10 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2018  Nippon Telegraph and Telephone Corporation.
+ * Copyright(c) 2015-2016 Intel Corporation
+ * Copyright(c) 2019 Nippon Telegraph and Telephone Corporation
  */
 
-#ifndef NFV_PARAMS_H
-#define NFV_PARAMS_H
+#ifndef _NFV_PARAMS_H_
+#define _NFV_PARAMS_H_
 
 /* It is used to convert port name from string type to enum */
 struct porttype_map {
@@ -38,4 +39,4 @@ static enum cmd_type cmd;
 
 static struct port_map port_map[RTE_MAX_ETHPORTS];
 
-#endif
+#endif // _NFV_PARAMS_H_
-- 
2.17.1

  parent reply	other threads:[~2019-01-15  3:30 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-01-15  3:27 [spp] [PATCH 0/6] Refactor common libs ogawa.yasufumi
2019-01-15  3:27 ` [spp] [PATCH 1/6] spp_primary: refactor common for primary ogawa.yasufumi
2019-01-15  3:27 ` [spp] [PATCH 2/6] shared: refactor common for SPP secondaries ogawa.yasufumi
2019-01-15  3:27 ` ogawa.yasufumi [this message]
2019-01-15  3:27 ` [spp] [PATCH 4/6] shared: refactor common functions ogawa.yasufumi
2019-01-15  3:28 ` [spp] [PATCH 5/6] shared: refactor libs of SPP secondary ogawa.yasufumi
2019-01-15  3:28 ` [spp] [PATCH 6/6] spp_nfv: refactor file structure ogawa.yasufumi

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=1547522881-10105-4-git-send-email-ogawa.yasufumi@lab.ntt.co.jp \
    --to=ogawa.yasufumi@lab.ntt.co.jp \
    --cc=ferruh.yigit@intel.com \
    --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).