From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <dev-bounces@dpdk.org>
Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124])
	by inbox.dpdk.org (Postfix) with ESMTP id 88045A0C48;
	Wed,  7 Jul 2021 08:26:46 +0200 (CEST)
Received: from [217.70.189.124] (localhost [127.0.0.1])
	by mails.dpdk.org (Postfix) with ESMTP id CBFBD41475;
	Wed,  7 Jul 2021 08:26:39 +0200 (CEST)
Received: from mga14.intel.com (mga14.intel.com [192.55.52.115])
 by mails.dpdk.org (Postfix) with ESMTP id C5AB541475
 for <dev@dpdk.org>; Wed,  7 Jul 2021 08:26:37 +0200 (CEST)
X-IronPort-AV: E=McAfee;i="6200,9189,10037"; a="209066392"
X-IronPort-AV: E=Sophos;i="5.83,331,1616482800"; d="scan'208";a="209066392"
Received: from fmsmga004.fm.intel.com ([10.253.24.48])
 by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;
 06 Jul 2021 23:26:37 -0700
X-ExtLoop1: 1
X-IronPort-AV: E=Sophos;i="5.83,331,1616482800"; d="scan'208";a="482060195"
Received: from dpdk-liulingy-1.sh.intel.com ([10.67.118.206])
 by fmsmga004.fm.intel.com with ESMTP; 06 Jul 2021 23:26:35 -0700
From: Lingyu Liu <lingyu.liu@intel.com>
To: dev@dpdk.org, qi.z.zhang@intel.com, beilei.xing@intel.com,
 jingjing.wu@intel.com
Cc: junfeng.guo@intel.com,
	Lingyu Liu <lingyu.liu@intel.com>
Date: Wed,  7 Jul 2021 12:57:52 +0000
Message-Id: <20210707125753.1494483-4-lingyu.liu@intel.com>
X-Mailer: git-send-email 2.25.1
In-Reply-To: <20210707125753.1494483-1-lingyu.liu@intel.com>
References: <20210706074258.1345934-1-lingyu.liu@intel.com>
 <20210707125753.1494483-1-lingyu.liu@intel.com>
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
Subject: [dpdk-dev] [PATCH v1 3/4] net/iavf: support AVF RSS for GTPoGRE
 packet
X-BeenThere: dev@dpdk.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: DPDK patches and discussions <dev.dpdk.org>
List-Unsubscribe: <https://mails.dpdk.org/options/dev>,
 <mailto:dev-request@dpdk.org?subject=unsubscribe>
List-Archive: <http://mails.dpdk.org/archives/dev/>
List-Post: <mailto:dev@dpdk.org>
List-Help: <mailto:dev-request@dpdk.org?subject=help>
List-Subscribe: <https://mails.dpdk.org/listinfo/dev>,
 <mailto:dev-request@dpdk.org?subject=subscribe>
Errors-To: dev-bounces@dpdk.org
Sender: "dev" <dev-bounces@dpdk.org>

Support AVF RSS for inner most header of GTPoGRE packet. It supports
RSS based on inner most IP src + dst address and TCP/UDP src + dst
port.

Signed-off-by: Lingyu Liu <lingyu.liu@intel.com>
---
 drivers/net/iavf/iavf_hash.c | 142 +++++++++++++++++++++++++++++------
 1 file changed, 118 insertions(+), 24 deletions(-)

diff --git a/drivers/net/iavf/iavf_hash.c b/drivers/net/iavf/iavf_hash.c
index f4f0bcbfef..03dae5d999 100644
--- a/drivers/net/iavf/iavf_hash.c
+++ b/drivers/net/iavf/iavf_hash.c
@@ -31,6 +31,9 @@
 #define IAVF_PHINT_OUTER_IPV4			BIT_ULL(4)
 #define IAVF_PHINT_OUTER_IPV6			BIT_ULL(5)
 #define IAVF_PHINT_GRE				BIT_ULL(6)
+/* the second IP header of GTPoGRE */
+#define IAVF_PHINT_MID_IPV4			BIT_ULL(7)
+#define IAVF_PHINT_MID_IPV6			BIT_ULL(8)
 
 #define IAVF_PHINT_GTPU_MSK	(IAVF_PHINT_GTPU	| \
 				 IAVF_PHINT_GTPU_EH	| \
@@ -233,6 +236,30 @@ struct virtchnl_proto_hdrs inner_ipv4_tcp_tmplt = {
 	TUNNEL_LEVEL_INNER, 2, {proto_hdr_ipv4_with_prot, proto_hdr_tcp}
 };
 
+struct virtchnl_proto_hdrs second_inner_ipv4_tmplt = {
+	2, 1, {proto_hdr_ipv4}
+};
+
+struct virtchnl_proto_hdrs second_inner_ipv4_udp_tmplt = {
+	2, 2, {proto_hdr_ipv4_with_prot, proto_hdr_udp}
+};
+
+struct virtchnl_proto_hdrs second_inner_ipv4_tcp_tmplt = {
+	2, 2, {proto_hdr_ipv4_with_prot, proto_hdr_tcp}
+};
+
+struct virtchnl_proto_hdrs second_inner_ipv6_tmplt = {
+	2, 1, {proto_hdr_ipv6}
+};
+
+struct virtchnl_proto_hdrs second_inner_ipv6_udp_tmplt = {
+	2, 2, {proto_hdr_ipv6_with_prot, proto_hdr_udp}
+};
+
+struct virtchnl_proto_hdrs second_inner_ipv6_tcp_tmplt = {
+	2, 2, {proto_hdr_ipv6_with_prot, proto_hdr_tcp}
+};
+
 struct virtchnl_proto_hdrs inner_ipv4_sctp_tmplt = {
 	TUNNEL_LEVEL_INNER, 2, {proto_hdr_ipv4, proto_hdr_sctp}
 };
@@ -421,6 +448,30 @@ static struct iavf_pattern_match_item iavf_hash_pattern_list[] = {
 	{iavf_pattern_eth_ipv6_gtpu_eh_ipv4,		IAVF_RSS_TYPE_GTPU_IPV4,	&inner_ipv4_tmplt},
 	{iavf_pattern_eth_ipv6_gtpu_eh_ipv4_udp,	IAVF_RSS_TYPE_GTPU_IPV4_UDP,	&inner_ipv4_udp_tmplt},
 	{iavf_pattern_eth_ipv6_gtpu_eh_ipv4_tcp,	IAVF_RSS_TYPE_GTPU_IPV4_TCP,	&inner_ipv4_tcp_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv4_gtpu_ipv4,		IAVF_RSS_TYPE_GTPU_IPV4,	&second_inner_ipv4_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv4_gtpu_ipv4_udp,		IAVF_RSS_TYPE_GTPU_IPV4_UDP,	&second_inner_ipv4_udp_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv4_gtpu_ipv4_tcp,		IAVF_RSS_TYPE_GTPU_IPV4_TCP,	&second_inner_ipv4_tcp_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv6_gtpu_ipv4,		IAVF_RSS_TYPE_GTPU_IPV4,	&second_inner_ipv4_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv6_gtpu_ipv4_udp,		IAVF_RSS_TYPE_GTPU_IPV4_UDP,	&second_inner_ipv4_udp_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv6_gtpu_ipv4_tcp,		IAVF_RSS_TYPE_GTPU_IPV4_TCP,	&second_inner_ipv4_tcp_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv4_gtpu_ipv4,		IAVF_RSS_TYPE_GTPU_IPV4,	&second_inner_ipv4_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv4_gtpu_ipv4_udp,		IAVF_RSS_TYPE_GTPU_IPV4_UDP,	&second_inner_ipv4_udp_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv4_gtpu_ipv4_tcp,		IAVF_RSS_TYPE_GTPU_IPV4_TCP,	&second_inner_ipv4_tcp_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv6_gtpu_ipv4,		IAVF_RSS_TYPE_GTPU_IPV4,	&second_inner_ipv4_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv6_gtpu_ipv4_udp,		IAVF_RSS_TYPE_GTPU_IPV4_UDP,	&second_inner_ipv4_udp_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv6_gtpu_ipv4_tcp,		IAVF_RSS_TYPE_GTPU_IPV4_TCP,	&second_inner_ipv4_tcp_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv4_gtpu_eh_ipv4,		IAVF_RSS_TYPE_GTPU_IPV4,	&second_inner_ipv4_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv4_gtpu_eh_ipv4_udp,	IAVF_RSS_TYPE_GTPU_IPV4_UDP,	&second_inner_ipv4_udp_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv4_gtpu_eh_ipv4_tcp,	IAVF_RSS_TYPE_GTPU_IPV4_TCP,	&second_inner_ipv4_tcp_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv6_gtpu_eh_ipv4,		IAVF_RSS_TYPE_GTPU_IPV4,	&second_inner_ipv4_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv6_gtpu_eh_ipv4_udp,	IAVF_RSS_TYPE_GTPU_IPV4_UDP,	&second_inner_ipv4_udp_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv6_gtpu_eh_ipv4_tcp,	IAVF_RSS_TYPE_GTPU_IPV4_TCP,	&second_inner_ipv4_tcp_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv4_gtpu_eh_ipv4,		IAVF_RSS_TYPE_GTPU_IPV4,	&second_inner_ipv4_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv4_gtpu_eh_ipv4_udp,	IAVF_RSS_TYPE_GTPU_IPV4_UDP,	&second_inner_ipv4_udp_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv4_gtpu_eh_ipv4_tcp,	IAVF_RSS_TYPE_GTPU_IPV4_TCP,	&second_inner_ipv4_tcp_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv6_gtpu_eh_ipv4,		IAVF_RSS_TYPE_GTPU_IPV4,	&second_inner_ipv4_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv6_gtpu_eh_ipv4_udp,	IAVF_RSS_TYPE_GTPU_IPV4_UDP,	&second_inner_ipv4_udp_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv6_gtpu_eh_ipv4_tcp,	IAVF_RSS_TYPE_GTPU_IPV4_TCP,	&second_inner_ipv4_tcp_tmplt},
 	{iavf_pattern_eth_ipv4_esp,			IAVF_RSS_TYPE_IPV4_ESP,		&ipv4_esp_tmplt},
 	{iavf_pattern_eth_ipv4_udp_esp,			IAVF_RSS_TYPE_IPV4_ESP,		&ipv4_udp_esp_tmplt},
 	{iavf_pattern_eth_ipv4_ah,			IAVF_RSS_TYPE_IPV4_AH,		&ipv4_ah_tmplt},
@@ -459,6 +510,30 @@ static struct iavf_pattern_match_item iavf_hash_pattern_list[] = {
 	{iavf_pattern_eth_ipv6_gtpu_eh_ipv6,		IAVF_RSS_TYPE_GTPU_IPV6,	&inner_ipv6_tmplt},
 	{iavf_pattern_eth_ipv6_gtpu_eh_ipv6_udp,	IAVF_RSS_TYPE_GTPU_IPV6_UDP,	&inner_ipv6_udp_tmplt},
 	{iavf_pattern_eth_ipv6_gtpu_eh_ipv6_tcp,	IAVF_RSS_TYPE_GTPU_IPV6_TCP,	&inner_ipv6_tcp_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv4_gtpu_ipv6,		IAVF_RSS_TYPE_GTPU_IPV6,	&second_inner_ipv6_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv4_gtpu_ipv6_udp,		IAVF_RSS_TYPE_GTPU_IPV6_UDP,	&second_inner_ipv6_udp_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv4_gtpu_ipv6_tcp,		IAVF_RSS_TYPE_GTPU_IPV6_TCP,	&second_inner_ipv6_tcp_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv6_gtpu_ipv6,		IAVF_RSS_TYPE_GTPU_IPV6,	&second_inner_ipv6_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv6_gtpu_ipv6_udp,		IAVF_RSS_TYPE_GTPU_IPV6_UDP,	&second_inner_ipv6_udp_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv6_gtpu_ipv6_tcp,		IAVF_RSS_TYPE_GTPU_IPV6_TCP,	&second_inner_ipv6_tcp_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv4_gtpu_ipv6,		IAVF_RSS_TYPE_GTPU_IPV6,	&second_inner_ipv6_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv4_gtpu_ipv6_udp,		IAVF_RSS_TYPE_GTPU_IPV6_UDP,	&second_inner_ipv6_udp_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv4_gtpu_ipv6_tcp,		IAVF_RSS_TYPE_GTPU_IPV6_TCP,	&second_inner_ipv6_tcp_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv6_gtpu_ipv6,		IAVF_RSS_TYPE_GTPU_IPV6,	&second_inner_ipv6_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv6_gtpu_ipv6_udp,		IAVF_RSS_TYPE_GTPU_IPV6_UDP,	&second_inner_ipv6_udp_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv6_gtpu_ipv6_tcp,		IAVF_RSS_TYPE_GTPU_IPV6_TCP,	&second_inner_ipv6_tcp_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv4_gtpu_eh_ipv6,		IAVF_RSS_TYPE_GTPU_IPV6,	&second_inner_ipv6_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv4_gtpu_eh_ipv6_udp,	IAVF_RSS_TYPE_GTPU_IPV6_UDP,	&second_inner_ipv6_udp_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv4_gtpu_eh_ipv6_tcp,	IAVF_RSS_TYPE_GTPU_IPV6_TCP,	&second_inner_ipv6_tcp_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv6_gtpu_eh_ipv6,		IAVF_RSS_TYPE_GTPU_IPV6,	&second_inner_ipv6_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv6_gtpu_eh_ipv6_udp,	IAVF_RSS_TYPE_GTPU_IPV6_UDP,	&second_inner_ipv6_udp_tmplt},
+	{iavf_pattern_eth_ipv4_gre_ipv6_gtpu_eh_ipv6_tcp,	IAVF_RSS_TYPE_GTPU_IPV6_TCP,	&second_inner_ipv6_tcp_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv4_gtpu_eh_ipv6,		IAVF_RSS_TYPE_GTPU_IPV6,	&second_inner_ipv6_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv4_gtpu_eh_ipv6_udp,	IAVF_RSS_TYPE_GTPU_IPV6_UDP,	&second_inner_ipv6_udp_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv4_gtpu_eh_ipv6_tcp,	IAVF_RSS_TYPE_GTPU_IPV6_TCP,	&second_inner_ipv6_tcp_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv6_gtpu_eh_ipv6,		IAVF_RSS_TYPE_GTPU_IPV6,	&second_inner_ipv6_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv6_gtpu_eh_ipv6_udp,	IAVF_RSS_TYPE_GTPU_IPV6_UDP,	&second_inner_ipv6_udp_tmplt},
+	{iavf_pattern_eth_ipv6_gre_ipv6_gtpu_eh_ipv6_tcp,	IAVF_RSS_TYPE_GTPU_IPV6_TCP,	&second_inner_ipv6_tcp_tmplt},
 	{iavf_pattern_eth_ipv6_esp,			IAVF_RSS_TYPE_IPV6_ESP,		&ipv6_esp_tmplt},
 	{iavf_pattern_eth_ipv6_udp_esp,			IAVF_RSS_TYPE_IPV6_ESP,		&ipv6_udp_esp_tmplt},
 	{iavf_pattern_eth_ipv6_ah,			IAVF_RSS_TYPE_IPV6_AH,		&ipv6_ah_tmplt},
@@ -607,10 +682,14 @@ iavf_hash_parse_pattern(const struct rte_flow_item pattern[], uint64_t *phint,
 		case RTE_FLOW_ITEM_TYPE_IPV4:
 			if (!(*phint & IAVF_PHINT_GTPU_MSK) && !(*phint & IAVF_PHINT_GRE))
 				*phint |= IAVF_PHINT_OUTER_IPV4;
+			if ((*phint & IAVF_PHINT_GRE) && !(*phint & IAVF_PHINT_GTPU_MSK))
+				*phint |= IAVF_PHINT_MID_IPV4;
 			break;
 		case RTE_FLOW_ITEM_TYPE_IPV6:
 			if (!(*phint & IAVF_PHINT_GTPU_MSK) && !(*phint & IAVF_PHINT_GRE))
 				*phint |= IAVF_PHINT_OUTER_IPV6;
+			if ((*phint & IAVF_PHINT_GRE) && !(*phint & IAVF_PHINT_GTPU_MSK))
+				*phint |= IAVF_PHINT_MID_IPV6;
 			break;
 		case RTE_FLOW_ITEM_TYPE_GTPU:
 			*phint |= IAVF_PHINT_GTPU;
@@ -881,14 +960,15 @@ iavf_refine_proto_hdrs_by_pattern(struct virtchnl_proto_hdrs *proto_hdrs,
 	struct virtchnl_proto_hdr *hdr1;
 	struct virtchnl_proto_hdr *hdr2;
 	int i, shift_count = 1;
+	int tun_lvl = proto_hdrs->tunnel_level;
 
 	if (!(phint & IAVF_PHINT_GTPU_MSK) && !(phint & IAVF_PHINT_GRE))
 		return;
 
-	if (phint & IAVF_PHINT_LAYERS_MSK)
-		shift_count++;
+	while (tun_lvl) {
+		if (phint & IAVF_PHINT_LAYERS_MSK)
+			shift_count = 2;
 
-	if (proto_hdrs->tunnel_level == TUNNEL_LEVEL_INNER) {
 		/* shift headers layer */
 		for (i = proto_hdrs->count - 1 + shift_count;
 		     i > shift_count - 1; i--) {
@@ -906,30 +986,44 @@ iavf_refine_proto_hdrs_by_pattern(struct virtchnl_proto_hdrs *proto_hdrs,
 			hdr2 = &proto_hdrs->proto_hdr[0];
 			hdr2->field_selector = 0;
 			proto_hdrs->count++;
-			proto_hdrs->tunnel_level = TUNNEL_LEVEL_OUTER;
+			tun_lvl--;
+
+			if (tun_lvl == TUNNEL_LEVEL_OUTER) {
+				if (phint & IAVF_PHINT_OUTER_IPV4)
+					VIRTCHNL_SET_PROTO_HDR_TYPE(hdr2, IPV4);
+				else if (phint & IAVF_PHINT_OUTER_IPV6)
+					VIRTCHNL_SET_PROTO_HDR_TYPE(hdr2, IPV6);
+			} else if (tun_lvl == TUNNEL_LEVEL_INNER) {
+				if (phint & IAVF_PHINT_MID_IPV4)
+					VIRTCHNL_SET_PROTO_HDR_TYPE(hdr2, IPV4);
+				else if (phint & IAVF_PHINT_MID_IPV6)
+					VIRTCHNL_SET_PROTO_HDR_TYPE(hdr2, IPV6);
+			}
+		}
 
-			if (phint & IAVF_PHINT_OUTER_IPV4)
-				VIRTCHNL_SET_PROTO_HDR_TYPE(hdr2, IPV4);
-			else if (phint & IAVF_PHINT_OUTER_IPV6)
-				VIRTCHNL_SET_PROTO_HDR_TYPE(hdr2, IPV6);
+		hdr1->field_selector = 0;
+		proto_hdrs->count++;
+
+		if (phint & IAVF_PHINT_GTPU_EH_DWN)
+			VIRTCHNL_SET_PROTO_HDR_TYPE(hdr1, GTPU_EH_PDU_DWN);
+		else if (phint & IAVF_PHINT_GTPU_EH_UP)
+			VIRTCHNL_SET_PROTO_HDR_TYPE(hdr1, GTPU_EH_PDU_UP);
+		else if (phint & IAVF_PHINT_GTPU_EH)
+			VIRTCHNL_SET_PROTO_HDR_TYPE(hdr1, GTPU_EH);
+		else if (phint & IAVF_PHINT_GTPU)
+			VIRTCHNL_SET_PROTO_HDR_TYPE(hdr1, GTPU_IP);
+
+		if (phint & IAVF_PHINT_GRE) {
+			if (phint & IAVF_PHINT_GTPU) {
+				/* if GTPoGRE, add GRE header at the outer tunnel  */
+				if (tun_lvl == TUNNEL_LEVEL_OUTER)
+					VIRTCHNL_SET_PROTO_HDR_TYPE(hdr1, GRE);
+			} else {
+					VIRTCHNL_SET_PROTO_HDR_TYPE(hdr1, GRE);
+			}
 		}
-	} else {
-		hdr1 = &proto_hdrs->proto_hdr[proto_hdrs->count];
 	}
-
-	hdr1->field_selector = 0;
-	proto_hdrs->count++;
-
-	if (phint & IAVF_PHINT_GTPU_EH_DWN)
-		VIRTCHNL_SET_PROTO_HDR_TYPE(hdr1, GTPU_EH_PDU_DWN);
-	else if (phint & IAVF_PHINT_GTPU_EH_UP)
-		VIRTCHNL_SET_PROTO_HDR_TYPE(hdr1, GTPU_EH_PDU_UP);
-	else if (phint & IAVF_PHINT_GTPU_EH)
-		VIRTCHNL_SET_PROTO_HDR_TYPE(hdr1, GTPU_EH);
-	else if (phint & IAVF_PHINT_GTPU)
-		VIRTCHNL_SET_PROTO_HDR_TYPE(hdr1, GTPU_IP);
-	else if (phint & IAVF_PHINT_GRE)
-		VIRTCHNL_SET_PROTO_HDR_TYPE(hdr1, GRE);
+	proto_hdrs->tunnel_level = tun_lvl;
 }
 
 static void iavf_refine_proto_hdrs(struct virtchnl_proto_hdrs *proto_hdrs,
-- 
2.25.1