DPDK patches and discussions
 help / color / mirror / Atom feed
From: Junfeng Guo <junfeng.guo@intel.com>
To: qi.z.zhang@intel.com, jingjing.wu@intel.com, beilei.xing@intel.com
Cc: dev@dpdk.org, junfeng.guo@intel.com
Subject: [dpdk-dev] [PATCH 2/3] net/ice: enable protocol agnostic flow offloading in FDIR
Date: Fri, 24 Sep 2021 16:22:22 +0000	[thread overview]
Message-ID: <20210924162223.1543519-3-junfeng.guo@intel.com> (raw)
In-Reply-To: <20210924162223.1543519-1-junfeng.guo@intel.com>

Protocol agnostic flow offloading in Flow Director is enabled by this
patch based on the Parser Library, using existing rte_flow raw API,
without public API change.

Note that the raw flow requires:
1. byte string of raw target packet bits.
2. byte string of mask of target packet.

Here is an example:
FDIR matching ipv4 dst addr with 1.2.3.4 and redirect to queue 3:

flow create 0 ingress pattern raw \
pattern spec \
00000000000000000000000008004500001400004000401000000000000001020304 \
pattern mask \
000000000000000000000000000000000000000000000000000000000000ffffffff \
/ end actions queue index 3 / mark id 3 / end

Signed-off-by: Junfeng Guo <junfeng.guo@intel.com>
---
 drivers/net/ice/ice_ethdev.h       |   5 +
 drivers/net/ice/ice_fdir_filter.c  | 167 +++++++++++++++++++++++++++++
 drivers/net/ice/ice_generic_flow.c |   7 ++
 drivers/net/ice/ice_generic_flow.h |   3 +
 4 files changed, 182 insertions(+)

diff --git a/drivers/net/ice/ice_ethdev.h b/drivers/net/ice/ice_ethdev.h
index b4bf651c1c..8dc0c54bd7 100644
--- a/drivers/net/ice/ice_ethdev.h
+++ b/drivers/net/ice/ice_ethdev.h
@@ -304,6 +304,11 @@ struct ice_fdir_filter_conf {
 	uint64_t input_set_o; /* used for non-tunnel or tunnel outer fields */
 	uint64_t input_set_i; /* only for tunnel inner fields */
 	uint32_t mark_flag;
+
+	struct ice_parser_profile *prof;
+	const u8 *pkt_buf;
+	bool parser_ena;
+	u8 pkt_len;
 };
 
 #define ICE_MAX_FDIR_FILTER_NUM		(1024 * 16)
diff --git a/drivers/net/ice/ice_fdir_filter.c b/drivers/net/ice/ice_fdir_filter.c
index 7ba65b9b04..375308781f 100644
--- a/drivers/net/ice/ice_fdir_filter.c
+++ b/drivers/net/ice/ice_fdir_filter.c
@@ -107,6 +107,7 @@
 	ICE_INSET_NAT_T_ESP_SPI)
 
 static struct ice_pattern_match_item ice_fdir_pattern_list[] = {
+	{pattern_raw,					ICE_INSET_NONE,			ICE_INSET_NONE,			ICE_INSET_NONE},
 	{pattern_ethertype,				ICE_FDIR_INSET_ETH,		ICE_INSET_NONE,			ICE_INSET_NONE},
 	{pattern_eth_ipv4,				ICE_FDIR_INSET_ETH_IPV4,	ICE_INSET_NONE,			ICE_INSET_NONE},
 	{pattern_eth_ipv4_udp,				ICE_FDIR_INSET_ETH_IPV4_UDP,	ICE_INSET_NONE,			ICE_INSET_NONE},
@@ -1190,6 +1191,24 @@ ice_fdir_is_tunnel_profile(enum ice_fdir_tunnel_type tunnel_type)
 		return 0;
 }
 
+static int
+ice_fdir_add_del_raw(struct ice_pf *pf,
+		     struct ice_fdir_filter_conf *filter,
+		     bool add)
+{
+	struct ice_hw *hw = ICE_PF_TO_HW(pf);
+
+	unsigned char *pkt = (unsigned char *)pf->fdir.prg_pkt;
+	rte_memcpy(pkt, filter->pkt_buf, filter->pkt_len);
+
+	struct ice_fltr_desc desc;
+	memset(&desc, 0, sizeof(desc));
+	filter->input.comp_report = ICE_FXD_FLTR_QW0_COMP_REPORT_SW;
+	ice_fdir_get_prgm_desc(hw, &filter->input, &desc, add);
+
+	return ice_fdir_programming(pf, &desc);
+}
+
 static int
 ice_fdir_add_del_filter(struct ice_pf *pf,
 			struct ice_fdir_filter_conf *filter,
@@ -1306,6 +1325,45 @@ ice_fdir_create_filter(struct ice_adapter *ad,
 	bool is_tun;
 	int ret;
 
+	if (filter->parser_ena) {
+		struct ice_hw *hw = ICE_PF_TO_HW(pf);
+
+		u16 ctrl_vsi = pf->fdir.fdir_vsi->idx;
+		u16 main_vsi = pf->main_vsi->idx;
+
+		ret = ice_flow_set_hw_prof(hw, main_vsi, ctrl_vsi,
+					   filter->prof, ICE_BLK_FD);
+		if (ret)
+			return -rte_errno;
+
+		ret = ice_fdir_add_del_raw(pf, filter, true);
+		if (ret)
+			return -rte_errno;
+
+		if (filter->mark_flag == 1)
+			ice_fdir_rx_parsing_enable(ad, 1);
+
+		entry = rte_zmalloc("fdir_entry", sizeof(*entry), 0);
+		if (!entry)
+			return -rte_errno;
+
+		entry->pkt_buf = (u8 *)ice_malloc(hw, filter->pkt_len);
+		if (!entry->pkt_buf)
+			return -ENOMEM;
+
+		u8 *pkt_buf = (u8 *)ice_malloc(hw, filter->pkt_len);
+		if (!pkt_buf)
+			return -ENOMEM;
+
+		rte_memcpy(entry, filter, sizeof(*filter));
+		rte_memcpy(pkt_buf, filter->pkt_buf, filter->pkt_len);
+		entry->pkt_buf = pkt_buf;
+
+		flow->rule = entry;
+
+		return 0;
+	}
+
 	ice_fdir_extract_fltr_key(&key, filter);
 	node = ice_fdir_entry_lookup(fdir_info, &key);
 	if (node) {
@@ -1401,6 +1459,19 @@ ice_fdir_destroy_filter(struct ice_adapter *ad,
 
 	filter = (struct ice_fdir_filter_conf *)flow->rule;
 
+	if (filter->parser_ena) {
+		ret = ice_fdir_add_del_raw(pf, filter, false);
+		if (ret)
+			return -rte_errno;
+
+		filter->pkt_buf = NULL;
+		flow->rule = NULL;
+
+		rte_free(filter);
+
+		return 0;
+	}
+
 	is_tun = ice_fdir_is_tunnel_profile(filter->tunnel_type);
 
 	if (filter->counter) {
@@ -1679,6 +1750,7 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter *ad,
 	enum rte_flow_item_type l3 = RTE_FLOW_ITEM_TYPE_END;
 	enum rte_flow_item_type l4 = RTE_FLOW_ITEM_TYPE_END;
 	enum ice_fdir_tunnel_type tunnel_type = ICE_FDIR_TUNNEL_TYPE_NONE;
+	const struct rte_flow_item_raw *raw_spec, *raw_mask;
 	const struct rte_flow_item_eth *eth_spec, *eth_mask;
 	const struct rte_flow_item_ipv4 *ipv4_spec, *ipv4_last, *ipv4_mask;
 	const struct rte_flow_item_ipv6 *ipv6_spec, *ipv6_mask;
@@ -1706,6 +1778,9 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter *ad,
 	struct ice_fdir_extra *p_ext_data;
 	struct ice_fdir_v4 *p_v4 = NULL;
 	struct ice_fdir_v6 *p_v6 = NULL;
+	struct ice_parser_result rslt;
+	struct ice_parser *psr;
+	uint8_t item_num = 0;
 
 	for (item = pattern; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
 		if (item->type == RTE_FLOW_ITEM_TYPE_VXLAN)
@@ -1717,6 +1792,7 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter *ad,
 		    item->type == RTE_FLOW_ITEM_TYPE_GTP_PSC) {
 			is_outer = false;
 		}
+		item_num++;
 	}
 
 	/* This loop parse flow pattern and distinguish Non-tunnel and tunnel
@@ -1737,6 +1813,90 @@ ice_fdir_parse_pattern(__rte_unused struct ice_adapter *ad,
 			    &input_set_i : &input_set_o;
 
 		switch (item_type) {
+		case RTE_FLOW_ITEM_TYPE_RAW:
+			raw_spec = item->spec;
+			raw_mask = item->mask;
+
+			if (item_num != 1)
+				break;
+
+			/* convert raw sepc & mask from byte string to int */
+			unsigned char *tmp_spec =
+				(uint8_t *)(uintptr_t)raw_spec->pattern;
+			unsigned char *tmp_mask =
+				(uint8_t *)(uintptr_t)raw_mask->pattern;
+			uint16_t tmp_val = 0;
+			uint8_t pkt_len = 0;
+			uint8_t tmp = 0;
+			int i, j;
+
+			pkt_len = strlen((char *)(uintptr_t)raw_spec->pattern);
+			if (strlen((char *)(uintptr_t)raw_mask->pattern) !=
+				pkt_len)
+				return -rte_errno;
+
+			for (i = 0, j = 0; i < pkt_len; i += 2, j++) {
+				tmp = tmp_spec[i];
+				if (tmp >= 'a' && tmp <= 'f')
+					tmp_val = tmp - 'a' + 10;
+				if (tmp >= 'A' && tmp <= 'F')
+					tmp_val = tmp - 'A' + 10;
+				if (tmp >= '0' && tmp <= '9')
+					tmp_val = tmp - '0';
+
+				tmp_val *= 16;
+				tmp = tmp_spec[i + 1];
+				if (tmp >= 'a' && tmp <= 'f')
+					tmp_spec[j] = tmp_val + tmp - 'a' + 10;
+				if (tmp >= 'A' && tmp <= 'F')
+					tmp_spec[j] = tmp_val + tmp - 'A' + 10;
+				if (tmp >= '0' && tmp <= '9')
+					tmp_spec[j] = tmp_val + tmp - '0';
+
+				tmp = tmp_mask[i];
+				if (tmp >= 'a' && tmp <= 'f')
+					tmp_val = tmp - 'a' + 10;
+				if (tmp >= 'A' && tmp <= 'F')
+					tmp_val = tmp - 'A' + 10;
+				if (tmp >= '0' && tmp <= '9')
+					tmp_val = tmp - '0';
+
+				tmp_val *= 16;
+				tmp = tmp_mask[i + 1];
+				if (tmp >= 'a' && tmp <= 'f')
+					tmp_mask[j] = tmp_val + tmp - 'a' + 10;
+				if (tmp >= 'A' && tmp <= 'F')
+					tmp_mask[j] = tmp_val + tmp - 'A' + 10;
+				if (tmp >= '0' && tmp <= '9')
+					tmp_mask[j] = tmp_val + tmp - '0';
+			}
+
+			pkt_len /= 2;
+
+			if (ice_parser_create(&ad->hw, &psr))
+				return -rte_errno;
+			if (ice_parser_run(psr, tmp_spec, pkt_len, &rslt))
+				return -rte_errno;
+			ice_parser_destroy(psr);
+
+			if (!tmp_mask)
+				return -rte_errno;
+
+			filter->prof = (struct ice_parser_profile *)
+				ice_malloc(&ad->hw, sizeof(filter->prof));
+			if (!filter->prof)
+				return -ENOMEM;
+			if (ice_parser_profile_init(&rslt, tmp_spec, tmp_mask,
+				pkt_len, ICE_BLK_FD, true, filter->prof))
+				return -rte_errno;
+
+			filter->pkt_buf = tmp_spec;
+			filter->pkt_len = pkt_len;
+
+			filter->parser_ena = true;
+
+			break;
+
 		case RTE_FLOW_ITEM_TYPE_ETH:
 			flow_type = ICE_FLTR_PTYPE_NON_IP_L2;
 			eth_spec = item->spec;
@@ -2202,6 +2362,7 @@ ice_fdir_parse(struct ice_adapter *ad,
 	struct ice_fdir_filter_conf *filter = &pf->fdir.conf;
 	struct ice_pattern_match_item *item = NULL;
 	uint64_t input_set;
+	bool raw = false;
 	int ret;
 
 	memset(filter, 0, sizeof(*filter));
@@ -2213,7 +2374,13 @@ ice_fdir_parse(struct ice_adapter *ad,
 	ret = ice_fdir_parse_pattern(ad, pattern, error, filter);
 	if (ret)
 		goto error;
+
+	if (item->pattern_list[0] == RTE_FLOW_ITEM_TYPE_RAW)
+		raw = true;
+
 	input_set = filter->input_set_o | filter->input_set_i;
+	input_set = raw ? ~input_set : input_set;
+
 	if (!input_set || filter->input_set_o &
 	    ~(item->input_set_mask_o | ICE_INSET_ETHERTYPE) ||
 	    filter->input_set_i & ~item->input_set_mask_i) {
diff --git a/drivers/net/ice/ice_generic_flow.c b/drivers/net/ice/ice_generic_flow.c
index 9e03c2856c..c979fce080 100644
--- a/drivers/net/ice/ice_generic_flow.c
+++ b/drivers/net/ice/ice_generic_flow.c
@@ -65,6 +65,12 @@ enum rte_flow_item_type pattern_empty[] = {
 	RTE_FLOW_ITEM_TYPE_END,
 };
 
+/* raw */
+enum rte_flow_item_type pattern_raw[] = {
+	RTE_FLOW_ITEM_TYPE_RAW,
+	RTE_FLOW_ITEM_TYPE_END,
+};
+
 /* L2 */
 enum rte_flow_item_type pattern_ethertype[] = {
 	RTE_FLOW_ITEM_TYPE_ETH,
@@ -2081,6 +2087,7 @@ struct ice_ptype_match {
 };
 
 static struct ice_ptype_match ice_ptype_map[] = {
+	{pattern_raw,					ICE_PTYPE_IPV4_PAY},
 	{pattern_eth_ipv4,				ICE_PTYPE_IPV4_PAY},
 	{pattern_eth_ipv4_udp,				ICE_PTYPE_IPV4_UDP_PAY},
 	{pattern_eth_ipv4_tcp,				ICE_PTYPE_IPV4_TCP_PAY},
diff --git a/drivers/net/ice/ice_generic_flow.h b/drivers/net/ice/ice_generic_flow.h
index 8845a3e156..1b030c0466 100644
--- a/drivers/net/ice/ice_generic_flow.h
+++ b/drivers/net/ice/ice_generic_flow.h
@@ -124,6 +124,9 @@
 /* empty pattern */
 extern enum rte_flow_item_type pattern_empty[];
 
+/* raw pattern */
+extern enum rte_flow_item_type pattern_raw[];
+
 /* L2 */
 extern enum rte_flow_item_type pattern_ethertype[];
 extern enum rte_flow_item_type pattern_ethertype_vlan[];
-- 
2.25.1


  parent reply	other threads:[~2021-09-24  8:35 UTC|newest]

Thread overview: 68+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-09-24 16:22 [dpdk-dev] [PATCH 0/3] " Junfeng Guo
2021-09-24 16:22 ` [dpdk-dev] [PATCH 1/3] app/testpmd: update Max RAW pattern size to 512 Junfeng Guo
2021-09-28 10:18   ` [dpdk-dev] [PATCH v2 0/3] enable protocol agnostic flow offloading in FDIR Junfeng Guo
2021-09-28 10:18     ` [dpdk-dev] [PATCH v2 1/3] app/testpmd: update Max RAW pattern size to 512 Junfeng Guo
2021-09-28 10:18     ` [dpdk-dev] [PATCH v2 2/3] net/ice: enable protocol agnostic flow offloading in FDIR Junfeng Guo
2021-09-28 10:18     ` [dpdk-dev] [PATCH v2 3/3] doc: enable protocol agnostic flow " Junfeng Guo
2021-10-14 15:37       ` [dpdk-dev] [PATCH v3 0/5] enable protocol agnostic flow offloading " Junfeng Guo
2021-10-14 15:37         ` [dpdk-dev] [PATCH v3 1/5] net/ice/base: add method to disable FDIR SWAP option Junfeng Guo
2021-10-14 15:37         ` [dpdk-dev] [PATCH v3 2/5] net/ice/base: add function to set HW profile for raw flow Junfeng Guo
2021-10-14 15:37         ` [dpdk-dev] [PATCH v3 3/5] app/testpmd: update Max RAW pattern size to 512 Junfeng Guo
2021-10-14 15:37         ` [dpdk-dev] [PATCH v3 4/5] net/ice: enable protocol agnostic flow offloading in FDIR Junfeng Guo
2021-10-14 15:37         ` [dpdk-dev] [PATCH v3 5/5] doc: enable protocol agnostic flow " Junfeng Guo
2021-10-26 12:00           ` [dpdk-dev] [PATCH v4 0/4] enable protocol agnostic flow offloading " Junfeng Guo
2021-10-26 12:00             ` [dpdk-dev] [PATCH v4 1/4] net/ice/base: add method to disable FDIR SWAP option Junfeng Guo
2021-10-26 12:00             ` [dpdk-dev] [PATCH v4 2/4] net/ice/base: add function to set HW profile for raw flow Junfeng Guo
2021-10-27  0:58               ` Zhang, Qi Z
2021-10-27  1:58                 ` Guo, Junfeng
2021-10-27  2:17                   ` Zhang, Qi Z
2021-10-27  2:51                     ` Guo, Junfeng
2021-10-26 12:00             ` [dpdk-dev] [PATCH v4 3/4] app/testpmd: update Max RAW pattern size to 512 Junfeng Guo
2021-10-27  2:52               ` [dpdk-dev] [PATCH v5 0/4] enable protocol agnostic flow offloading in FDIR Junfeng Guo
2021-10-27  2:52                 ` [dpdk-dev] [PATCH v5 1/4] net/ice/base: add method to disable FDIR SWAP option Junfeng Guo
2021-10-27  2:52                 ` [dpdk-dev] [PATCH v5 2/4] net/ice/base: add function to set HW profile for raw flow Junfeng Guo
2021-10-27  2:52                 ` [dpdk-dev] [PATCH v5 3/4] app/testpmd: update Max RAW pattern size to 512 Junfeng Guo
2021-10-27  2:52                 ` [dpdk-dev] [PATCH v5 4/4] net/ice: enable protocol agnostic flow offloading in FDIR Junfeng Guo
2021-10-28  8:34                   ` [dpdk-dev] [PATCH v6 0/4] " Junfeng Guo
2021-10-28  8:34                     ` [dpdk-dev] [PATCH v6 1/4] net/ice/base: add method to disable FDIR SWAP option Junfeng Guo
2021-10-28  8:34                     ` [dpdk-dev] [PATCH v6 2/4] net/ice/base: add function to set HW profile for raw flow Junfeng Guo
2021-10-28  8:34                     ` [dpdk-dev] [PATCH v6 3/4] app/testpmd: update Max RAW pattern size to 512 Junfeng Guo
2021-10-28  8:34                     ` [dpdk-dev] [PATCH v6 4/4] net/ice: enable protocol agnostic flow offloading in FDIR Junfeng Guo
2021-10-28  9:13                       ` [dpdk-dev] [PATCH v7 0/4] " Junfeng Guo
2021-10-28  9:13                         ` [dpdk-dev] [PATCH v7 1/4] net/ice/base: add method to disable FDIR SWAP option Junfeng Guo
2021-10-28 11:26                           ` Zhang, Qi Z
2021-10-28 15:09                           ` Ferruh Yigit
2021-10-28  9:13                         ` [dpdk-dev] [PATCH v7 2/4] net/ice/base: add function to set HW profile for raw flow Junfeng Guo
2021-10-28 11:28                           ` Zhang, Qi Z
2021-10-28 15:13                           ` Ferruh Yigit
2021-10-28  9:13                         ` [dpdk-dev] [PATCH v7 3/4] app/testpmd: update Max RAW pattern size to 512 Junfeng Guo
2021-10-28 11:46                           ` Zhang, Qi Z
2021-10-28  9:13                         ` [dpdk-dev] [PATCH v7 4/4] net/ice: enable protocol agnostic flow offloading in FDIR Junfeng Guo
2021-10-28 11:10                           ` Zhang, Qi Z
2021-11-01  8:36                           ` [dpdk-dev] [PATCH v8 0/4] " Junfeng Guo
2021-11-01  8:36                             ` [dpdk-dev] [PATCH v8 1/4] net/ice/base: add method to disable FDIR SWAP option Junfeng Guo
2021-11-01  8:36                             ` [dpdk-dev] [PATCH v8 2/4] net/ice/base: add function to set HW profile for raw flow Junfeng Guo
2021-11-01  8:36                             ` [dpdk-dev] [PATCH v8 3/4] app/testpmd: update Max RAW pattern size to 512 Junfeng Guo
2021-11-01  8:36                             ` [dpdk-dev] [PATCH v8 4/4] net/ice: enable protocol agnostic flow offloading in FDIR Junfeng Guo
2021-11-01 23:56                               ` Zhang, Qi Z
2021-11-02  2:44                                 ` Guo, Junfeng
2021-11-02  5:39                               ` [dpdk-dev] [PATCH v9 0/4] " Junfeng Guo
2021-11-02  5:39                                 ` [dpdk-dev] [PATCH v9 1/4] net/ice/base: add method to disable FDIR SWAP option Junfeng Guo
2021-11-02  5:39                                 ` [dpdk-dev] [PATCH v9 2/4] net/ice/base: add function to set HW profile for raw flow Junfeng Guo
2021-11-02  5:39                                 ` [dpdk-dev] [PATCH v9 3/4] app/testpmd: update Max RAW pattern size to 512 Junfeng Guo
2021-11-02  5:39                                 ` [dpdk-dev] [PATCH v9 4/4] net/ice: enable protocol agnostic flow offloading in FDIR Junfeng Guo
2021-11-02 16:22                                   ` Ferruh Yigit
2021-11-03  2:26                                     ` Guo, Junfeng
2021-11-03  4:39                                   ` [dpdk-dev] [PATCH v10 0/4] " Junfeng Guo
2021-11-03  4:40                                     ` [dpdk-dev] [PATCH v10 1/4] net/ice/base: add method to disable FDIR SWAP option Junfeng Guo
2021-11-03  4:40                                     ` [dpdk-dev] [PATCH v10 2/4] net/ice/base: add function to set HW profile for raw flow Junfeng Guo
2021-11-03  4:40                                     ` [dpdk-dev] [PATCH v10 3/4] app/testpmd: update Max RAW pattern size to 512 Junfeng Guo
2021-11-03  4:40                                     ` [dpdk-dev] [PATCH v10 4/4] net/ice: enable protocol agnostic flow offloading in FDIR Junfeng Guo
2021-11-03 12:34                                     ` [dpdk-dev] [PATCH v10 0/4] " Zhang, Qi Z
2021-11-02  5:58                                 ` [dpdk-dev] [PATCH v9 " Zhang, Qi Z
2021-11-02 16:29                                 ` Ferruh Yigit
2021-11-03  3:16                                   ` Guo, Junfeng
2021-10-26 12:00             ` [dpdk-dev] [PATCH v4 4/4] net/ice: " Junfeng Guo
2021-09-24 16:22 ` Junfeng Guo [this message]
2021-09-24  8:45   ` [dpdk-dev] [PATCH 2/3] " Van Haaren, Harry
2021-09-24 16:22 ` [dpdk-dev] [PATCH 3/3] doc: enable protocol agnostic flow " Junfeng Guo

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=20210924162223.1543519-3-junfeng.guo@intel.com \
    --to=junfeng.guo@intel.com \
    --cc=beilei.xing@intel.com \
    --cc=dev@dpdk.org \
    --cc=jingjing.wu@intel.com \
    --cc=qi.z.zhang@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 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).