[2/3] examples/ipsec-secgw: add UDP encapsulation support

Message ID 20210315103616.31364-3-ktejasree@marvell.com (mailing list archive)
State Superseded, archived
Delegated to: akhil goyal
Headers
Series add lookaside IPsec UDP encapsulation and transport mode |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Tejasree Kondoj March 15, 2021, 10:36 a.m. UTC
  Adding lookaside IPsec UDP encapsulation support
for NAT traversal.
Added --udp-encap option for application to specify
if UDP encapsulation need to be enabled.
Example secgw command with UDP encapsultation enabled:
<secgw> -c 0x1 -- -P -p 0x1 --config "(0,0,0)" -f ep0.cfg --udp-encap

Signed-off-by: Tejasree Kondoj <ktejasree@marvell.com>
---
 doc/guides/rel_notes/release_21_05.rst   |  5 ++++
 doc/guides/sample_app_ug/ipsec_secgw.rst |  5 +++-
 examples/ipsec-secgw/ipsec-secgw.c       | 33 ++++++++++++++++++++++--
 examples/ipsec-secgw/ipsec-secgw.h       |  2 ++
 examples/ipsec-secgw/ipsec.c             |  1 +
 examples/ipsec-secgw/ipsec.h             |  1 +
 examples/ipsec-secgw/sad.h               |  5 +++-
 7 files changed, 48 insertions(+), 4 deletions(-)
  

Comments

Ananyev, Konstantin March 19, 2021, 4:46 p.m. UTC | #1
Hi, 
> Adding lookaside IPsec UDP encapsulation support
> for NAT traversal.
> Added --udp-encap option for application to specify
> if UDP encapsulation need to be enabled.
> Example secgw command with UDP encapsultation enabled:
> <secgw> -c 0x1 -- -P -p 0x1 --config "(0,0,0)" -f ep0.cfg --udp-encap

Can we have it not as global, but a per SA option?
Add new keyword for SA/SP into ipsec-secgw config file, etc.
Konstantin  

> 
> Signed-off-by: Tejasree Kondoj <ktejasree@marvell.com>
> ---
>  doc/guides/rel_notes/release_21_05.rst   |  5 ++++
>  doc/guides/sample_app_ug/ipsec_secgw.rst |  5 +++-
>  examples/ipsec-secgw/ipsec-secgw.c       | 33 ++++++++++++++++++++++--
>  examples/ipsec-secgw/ipsec-secgw.h       |  2 ++
>  examples/ipsec-secgw/ipsec.c             |  1 +
>  examples/ipsec-secgw/ipsec.h             |  1 +
>  examples/ipsec-secgw/sad.h               |  5 +++-
>  7 files changed, 48 insertions(+), 4 deletions(-)
> 
> diff --git a/doc/guides/rel_notes/release_21_05.rst b/doc/guides/rel_notes/release_21_05.rst
> index 66e28e21be..2e67038bfe 100644
> --- a/doc/guides/rel_notes/release_21_05.rst
> +++ b/doc/guides/rel_notes/release_21_05.rst
> @@ -75,6 +75,11 @@ New Features
>    * Added command to display Rx queue used descriptor count.
>      ``show port (port_id) rxq (queue_id) desc used count``
> 
> +* **Updated ipsec-secgw sample application.**
> +
> +  * Updated the ``ipsec-secgw`` sample application with UDP encapsulation
> +    support for NAT Traversal.
> +
> 
>  Removed Items
>  -------------
> diff --git a/doc/guides/sample_app_ug/ipsec_secgw.rst b/doc/guides/sample_app_ug/ipsec_secgw.rst
> index 176e292d3f..099f499c18 100644
> --- a/doc/guides/sample_app_ug/ipsec_secgw.rst
> +++ b/doc/guides/sample_app_ug/ipsec_secgw.rst
> @@ -139,6 +139,7 @@ The application has a number of command line options::
>                          --reassemble NUM
>                          --mtu MTU
>                          --frag-ttl FRAG_TTL_NS
> +                        --udp-encap
> 
>  Where:
> 
> @@ -234,6 +235,8 @@ Where:
>      Should be lower for low number of reassembly buckets.
>      Valid values: from 1 ns to 10 s. Default value: 10000000 (10 s).
> 
> +*   ``--udp-encap``: enables IPsec UDP Encapsulation for NAT Traversal.
> +
> 
>  The mapping of lcores to port/queues is similar to other l3fwd applications.
> 
> @@ -1023,4 +1026,4 @@ Available options:
>  *   ``-h`` Show usage.
> 
>  If <ipsec_mode> is specified, only tests for that mode will be invoked. For the
> -list of available modes please refer to run_test.sh.
> \ No newline at end of file
> +list of available modes please refer to run_test.sh.
> diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
> index 20d69ba813..57c8973e9d 100644
> --- a/examples/ipsec-secgw/ipsec-secgw.c
> +++ b/examples/ipsec-secgw/ipsec-secgw.c
> @@ -115,6 +115,7 @@ struct flow_info flow_info_tbl[RTE_MAX_ETHPORTS];
>  #define CMD_LINE_OPT_REASSEMBLE		"reassemble"
>  #define CMD_LINE_OPT_MTU		"mtu"
>  #define CMD_LINE_OPT_FRAG_TTL		"frag-ttl"
> +#define CMD_LINE_OPT_UDP_ENCAP		"udp-encap"
> 
>  #define CMD_LINE_ARG_EVENT	"event"
>  #define CMD_LINE_ARG_POLL	"poll"
> @@ -139,6 +140,7 @@ enum {
>  	CMD_LINE_OPT_REASSEMBLE_NUM,
>  	CMD_LINE_OPT_MTU_NUM,
>  	CMD_LINE_OPT_FRAG_TTL_NUM,
> +	CMD_LINE_OPT_UDP_ENCAP_NUM,
>  };
> 
>  static const struct option lgopts[] = {
> @@ -152,6 +154,7 @@ static const struct option lgopts[] = {
>  	{CMD_LINE_OPT_REASSEMBLE, 1, 0, CMD_LINE_OPT_REASSEMBLE_NUM},
>  	{CMD_LINE_OPT_MTU, 1, 0, CMD_LINE_OPT_MTU_NUM},
>  	{CMD_LINE_OPT_FRAG_TTL, 1, 0, CMD_LINE_OPT_FRAG_TTL_NUM},
> +	{CMD_LINE_OPT_UDP_ENCAP, 0, 0, CMD_LINE_OPT_UDP_ENCAP_NUM},
>  	{NULL, 0, 0, 0}
>  };
> 
> @@ -360,6 +363,9 @@ prepare_one_packet(struct rte_mbuf *pkt, struct ipsec_traffic *t)
>  	const struct rte_ether_hdr *eth;
>  	const struct rte_ipv4_hdr *iph4;
>  	const struct rte_ipv6_hdr *iph6;
> +	const struct rte_udp_hdr *udp;
> +	uint16_t nat_port;
> +	uint16_t ip4_hdr_len;
> 
>  	eth = rte_pktmbuf_mtod(pkt, const struct rte_ether_hdr *);
>  	if (eth->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
> @@ -368,9 +374,26 @@ prepare_one_packet(struct rte_mbuf *pkt, struct ipsec_traffic *t)
>  			RTE_ETHER_HDR_LEN);
>  		adjust_ipv4_pktlen(pkt, iph4, 0);
> 
> -		if (iph4->next_proto_id == IPPROTO_ESP)
> +		switch (iph4->next_proto_id) {
> +		case IPPROTO_ESP:
>  			t->ipsec.pkts[(t->ipsec.num)++] = pkt;
> -		else {
> +			break;
> +		case IPPROTO_UDP:
> +			if (app_sa_prm.udp_encap == 1) {
> +				ip4_hdr_len = ((iph4->version_ihl &
> +					RTE_IPV4_HDR_IHL_MASK) *
> +					RTE_IPV4_IHL_MULTIPLIER);
> +				udp = rte_pktmbuf_mtod_offset(pkt,
> +					struct rte_udp_hdr *, ip4_hdr_len);
> +				nat_port = rte_cpu_to_be_16(IPSEC_NAT_T_PORT);
> +				if (udp->src_port == nat_port ||
> +					udp->dst_port == nat_port){
> +					t->ipsec.pkts[(t->ipsec.num)++] = pkt;
> +					break;
> +				}
> +			}
> +		/* Fall through */
> +		default:
>  			t->ip4.data[t->ip4.num] = &iph4->next_proto_id;
>  			t->ip4.pkts[(t->ip4.num)++] = pkt;
>  		}
> @@ -1378,6 +1401,7 @@ print_usage(const char *prgname)
>  		" [--" CMD_LINE_OPT_TX_OFFLOAD " TX_OFFLOAD_MASK]"
>  		" [--" CMD_LINE_OPT_REASSEMBLE " REASSEMBLE_TABLE_SIZE]"
>  		" [--" CMD_LINE_OPT_MTU " MTU]"
> +		" [--" CMD_LINE_OPT_UDP_ENCAP "]"
>  		"\n\n"
>  		"  -p PORTMASK: Hexadecimal bitmask of ports to configure\n"
>  		"  -P : Enable promiscuous mode\n"
> @@ -1431,6 +1455,8 @@ print_usage(const char *prgname)
>  		"  --" CMD_LINE_OPT_FRAG_TTL " FRAG_TTL_NS"
>  		": fragments lifetime in nanoseconds, default\n"
>  		"    and maximum value is 10.000.000.000 ns (10 s)\n"
> +		"  --" CMD_LINE_OPT_UDP_ENCAP
> +		": enables UDP Encapsulation for NAT Traversal\n"
>  		"\n",
>  		prgname);
>  }
> @@ -1780,6 +1806,9 @@ parse_args(int32_t argc, char **argv, struct eh_conf *eh_conf)
>  			}
>  			frag_ttl_ns = ret;
>  			break;
> +		case CMD_LINE_OPT_UDP_ENCAP_NUM:
> +			app_sa_prm.udp_encap = 1;
> +			break;
>  		default:
>  			print_usage(prgname);
>  			return -1;
> diff --git a/examples/ipsec-secgw/ipsec-secgw.h b/examples/ipsec-secgw/ipsec-secgw.h
> index f2281e73cf..6887d752ab 100644
> --- a/examples/ipsec-secgw/ipsec-secgw.h
> +++ b/examples/ipsec-secgw/ipsec-secgw.h
> @@ -47,6 +47,8 @@
> 
>  #define ETHADDR(a, b, c, d, e, f) (__BYTES_TO_UINT64(a, b, c, d, e, f, 0, 0))
> 
> +#define IPSEC_NAT_T_PORT 4500
> +
>  struct traffic_type {
>  	const uint8_t *data[MAX_PKT_BURST * 2];
>  	struct rte_mbuf *pkts[MAX_PKT_BURST * 2];
> diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
> index 6baeeb342f..6e0caa198d 100644
> --- a/examples/ipsec-secgw/ipsec.c
> +++ b/examples/ipsec-secgw/ipsec.c
> @@ -52,6 +52,7 @@ set_ipsec_conf(struct ipsec_sa *sa, struct rte_security_ipsec_xform *ipsec)
>  	ipsec->esn_soft_limit = IPSEC_OFFLOAD_ESN_SOFTLIMIT;
>  	ipsec->replay_win_sz = app_sa_prm.window_size;
>  	ipsec->options.esn = app_sa_prm.enable_esn;
> +	ipsec->options.udp_encap = app_sa_prm.udp_encap;
>  }
> 
>  int
> diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
> index 7031e28c46..430afea688 100644
> --- a/examples/ipsec-secgw/ipsec.h
> +++ b/examples/ipsec-secgw/ipsec.h
> @@ -75,6 +75,7 @@ struct app_sa_prm {
>  	uint32_t window_size; /* replay window size */
>  	uint32_t enable_esn;  /* enable/disable ESN support */
>  	uint32_t cache_sz;	/* per lcore SA cache size */
> +	uint32_t udp_encap;   /* enable/disable UDP Encapsulation */
>  	uint64_t flags;       /* rte_ipsec_sa_prm.flags */
>  };
> 
> diff --git a/examples/ipsec-secgw/sad.h b/examples/ipsec-secgw/sad.h
> index 473aaa938e..89b50488ec 100644
> --- a/examples/ipsec-secgw/sad.h
> +++ b/examples/ipsec-secgw/sad.h
> @@ -77,6 +77,7 @@ sad_lookup(struct ipsec_sad *sad, struct rte_mbuf *pkts[],
>  	uint32_t spi, cache_idx;
>  	struct ipsec_sad_cache *cache;
>  	struct ipsec_sa *cached_sa;
> +	uint16_t udp_hdr_len = 0;
>  	int is_ipv4;
> 
>  	cache  = &RTE_PER_LCORE(sad_cache);
> @@ -85,8 +86,10 @@ sad_lookup(struct ipsec_sad *sad, struct rte_mbuf *pkts[],
>  	for (i = 0; i < nb_pkts; i++) {
>  		ipv4 = rte_pktmbuf_mtod(pkts[i], struct rte_ipv4_hdr *);
>  		ipv6 = rte_pktmbuf_mtod(pkts[i], struct rte_ipv6_hdr *);
> +		if (app_sa_prm.udp_encap == 1)
> +			udp_hdr_len = sizeof(struct rte_udp_hdr);
>  		esp = rte_pktmbuf_mtod_offset(pkts[i], struct rte_esp_hdr *,
> -				pkts[i]->l3_len);
> +				pkts[i]->l3_len + udp_hdr_len);
> 
>  		is_ipv4 = pkts[i]->packet_type & RTE_PTYPE_L3_IPV4;
>  		spi = rte_be_to_cpu_32(esp->spi);
> --
> 2.27.0
  
Akhil Goyal March 23, 2021, 8:02 a.m. UTC | #2
Hi Konstantin,
> Hi,
> > Adding lookaside IPsec UDP encapsulation support
> > for NAT traversal.
> > Added --udp-encap option for application to specify
> > if UDP encapsulation need to be enabled.
> > Example secgw command with UDP encapsultation enabled:
> > <secgw> -c 0x1 -- -P -p 0x1 --config "(0,0,0)" -f ep0.cfg --udp-encap
> 
> Can we have it not as global, but a per SA option?
> Add new keyword for SA/SP into ipsec-secgw config file, etc.
> Konstantin
> 

Any specific reason to make udp_encap as per SA?
UDP encapsulation is a feature which I believe should be application vide.
If it supports the feature it should be enabled for all SAs when the UDP port
is 4500 which is reserved for it. 

Regards,
Akhil
  
Ananyev, Konstantin March 23, 2021, 2:29 p.m. UTC | #3
Hi Akhil,
 
> Hi Konstantin,
> > Hi,
> > > Adding lookaside IPsec UDP encapsulation support
> > > for NAT traversal.
> > > Added --udp-encap option for application to specify
> > > if UDP encapsulation need to be enabled.
> > > Example secgw command with UDP encapsultation enabled:
> > > <secgw> -c 0x1 -- -P -p 0x1 --config "(0,0,0)" -f ep0.cfg --udp-encap
> >
> > Can we have it not as global, but a per SA option?
> > Add new keyword for SA/SP into ipsec-secgw config file, etc.
> > Konstantin
> >
> 
> Any specific reason to make udp_encap as per SA?
> UDP encapsulation is a feature which I believe should be application vide.
> If it supports the feature it should be enabled for all SAs when the UDP port
> is 4500 which is reserved for it.

Not sure why it has to be application wide?
Why it is not possible have let say SA1 in ipv4/ipv6 tunnel mode over port 0,
and SA2 with udp encap over port 1?
Note that in DPDK librte_security it is per SA option.
Konstantin
  
Akhil Goyal March 23, 2021, 3:06 p.m. UTC | #4
Hi Konstantin,
> 
> Hi Akhil,
> > > > Adding lookaside IPsec UDP encapsulation support
> > > > for NAT traversal.
> > > > Added --udp-encap option for application to specify
> > > > if UDP encapsulation need to be enabled.
> > > > Example secgw command with UDP encapsultation enabled:
> > > > <secgw> -c 0x1 -- -P -p 0x1 --config "(0,0,0)" -f ep0.cfg --udp-encap
> > >
> > > Can we have it not as global, but a per SA option?
> > > Add new keyword for SA/SP into ipsec-secgw config file, etc.
> > > Konstantin
> > >
> >
> > Any specific reason to make udp_encap as per SA?
> > UDP encapsulation is a feature which I believe should be application vide.
> > If it supports the feature it should be enabled for all SAs when the UDP port
> > is 4500 which is reserved for it.
> 
> Not sure why it has to be application wide?
> Why it is not possible have let say SA1 in ipv4/ipv6 tunnel mode over port 0,
> and SA2 with udp encap over port 1?
> Note that in DPDK librte_security it is per SA option.

UDP encapsulation can be done only if the UDP port is 4500 as per the specification.
Please correct me if I am wrong. So if UDP port is NOT 4500 and udp-encap is enabled in the
Command line, UDP encapsulation will not work.

Hence it does make sense to make it application vide. It will be tedious for the user to
Add this in every SA.

Regards,
Akhil
  
Ananyev, Konstantin March 23, 2021, 3:46 p.m. UTC | #5
> Hi Konstantin,
> >
> > Hi Akhil,
> > > > > Adding lookaside IPsec UDP encapsulation support
> > > > > for NAT traversal.
> > > > > Added --udp-encap option for application to specify
> > > > > if UDP encapsulation need to be enabled.
> > > > > Example secgw command with UDP encapsultation enabled:
> > > > > <secgw> -c 0x1 -- -P -p 0x1 --config "(0,0,0)" -f ep0.cfg --udp-encap
> > > >
> > > > Can we have it not as global, but a per SA option?
> > > > Add new keyword for SA/SP into ipsec-secgw config file, etc.
> > > > Konstantin
> > > >
> > >
> > > Any specific reason to make udp_encap as per SA?
> > > UDP encapsulation is a feature which I believe should be application vide.
> > > If it supports the feature it should be enabled for all SAs when the UDP port
> > > is 4500 which is reserved for it.
> >
> > Not sure why it has to be application wide?
> > Why it is not possible have let say SA1 in ipv4/ipv6 tunnel mode over port 0,
> > and SA2 with udp encap over port 1?
> > Note that in DPDK librte_security it is per SA option.
> 
> UDP encapsulation can be done only if the UDP port is 4500 as per the specification.
> Please correct me if I am wrong. So if UDP port is NOT 4500 and udp-encap is enabled in the
> Command line, UDP encapsulation will not work.

I am not asking you so support multiple UDP ports for IPsec encapsulation.
What I am saying: it should be possible to use SAs with UDP encapsulation
along with SAs without (plain tunnel/transport mode).
As I understand with your patch it is not possible: if user specified --udp-encap
all SAs (on all crypto-devs) will be treated as UDP encapsulated. 

> 
> Hence it does make sense to make it application vide. It will be tedious for the user to
> Add this in every SA.
> 
> Regards,
> Akhil
>
  
Akhil Goyal March 23, 2021, 5:54 p.m. UTC | #6
> 
> > Hi Konstantin,
> > >
> > > Hi Akhil,
> > > > > > Adding lookaside IPsec UDP encapsulation support
> > > > > > for NAT traversal.
> > > > > > Added --udp-encap option for application to specify
> > > > > > if UDP encapsulation need to be enabled.
> > > > > > Example secgw command with UDP encapsultation enabled:
> > > > > > <secgw> -c 0x1 -- -P -p 0x1 --config "(0,0,0)" -f ep0.cfg --udp-encap
> > > > >
> > > > > Can we have it not as global, but a per SA option?
> > > > > Add new keyword for SA/SP into ipsec-secgw config file, etc.
> > > > > Konstantin
> > > > >
> > > >
> > > > Any specific reason to make udp_encap as per SA?
> > > > UDP encapsulation is a feature which I believe should be application
> vide.
> > > > If it supports the feature it should be enabled for all SAs when the UDP
> port
> > > > is 4500 which is reserved for it.
> > >
> > > Not sure why it has to be application wide?
> > > Why it is not possible have let say SA1 in ipv4/ipv6 tunnel mode over port
> 0,
> > > and SA2 with udp encap over port 1?
> > > Note that in DPDK librte_security it is per SA option.
> >
> > UDP encapsulation can be done only if the UDP port is 4500 as per the
> specification.
> > Please correct me if I am wrong. So if UDP port is NOT 4500 and udp-encap
> is enabled in the
> > Command line, UDP encapsulation will not work.
> 
> I am not asking you so support multiple UDP ports for IPsec encapsulation.

Multiple ports are not required to be supported as per specification.
UDP encapsulation work only on one port i.e. 4500.
By specification, it says, port 4500 is reserved for NAT traversal and if a
Packet has this port, then it has to be processed accordingly.

> What I am saying: it should be possible to use SAs with UDP encapsulation
> along with SAs without (plain tunnel/transport mode).

Yes it is possible with the current patch.
If a packet has a UDP port = 4500 then it is UDP encapsulated otherwise it is not.
Hence, a packet with UDP port other than 4500 will work as it is working without
--udp-encap param.

> As I understand with your patch it is not possible: if user specified --udp-
> encap
> all SAs (on all crypto-devs) will be treated as UDP encapsulated.

Just to correct this statement.

If user specified --udp-encap all SAs (on all crypto-devs) will be treated as
UDP encapsulated if and only if the UDP port = 4500 and not otherwise.

I hope this statement clears your concern and it makes more sense to make it
application vide, just like esn and anti-replay.

Regards,
Akhil
  
Tejasree Kondoj March 24, 2021, 9:45 a.m. UTC | #7
Hi Akhil, Konstantin,

Please see inline.

Thanks
Tejasree

> -----Original Message-----
> From: Akhil Goyal <gakhil@marvell.com>
> Sent: Tuesday, March 23, 2021 11:24 PM
> To: Ananyev, Konstantin <konstantin.ananyev@intel.com>; Tejasree Kondoj
> <ktejasree@marvell.com>; Nicolau, Radu <radu.nicolau@intel.com>
> Cc: Anoob Joseph <anoobj@marvell.com>; Ankur Dwivedi
> <adwivedi@marvell.com>; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH 2/3] examples/ipsec-secgw: add UDP
> encapsulation support
> 
> >
> > > Hi Konstantin,
> > > >
> > > > Hi Akhil,
> > > > > > > Adding lookaside IPsec UDP encapsulation support for NAT
> > > > > > > traversal.
> > > > > > > Added --udp-encap option for application to specify if UDP
> > > > > > > encapsulation need to be enabled.
> > > > > > > Example secgw command with UDP encapsultation enabled:
> > > > > > > <secgw> -c 0x1 -- -P -p 0x1 --config "(0,0,0)" -f ep0.cfg
> > > > > > > --udp-encap
> > > > > >
> > > > > > Can we have it not as global, but a per SA option?
> > > > > > Add new keyword for SA/SP into ipsec-secgw config file, etc.
> > > > > > Konstantin
> > > > > >
> > > > >
> > > > > Any specific reason to make udp_encap as per SA?
> > > > > UDP encapsulation is a feature which I believe should be
> > > > > application
> > vide.
> > > > > If it supports the feature it should be enabled for all SAs when
> > > > > the UDP
> > port
> > > > > is 4500 which is reserved for it.
> > > >
> > > > Not sure why it has to be application wide?
> > > > Why it is not possible have let say SA1 in ipv4/ipv6 tunnel mode
> > > > over port
> > 0,
> > > > and SA2 with udp encap over port 1?
> > > > Note that in DPDK librte_security it is per SA option.
> > >
> > > UDP encapsulation can be done only if the UDP port is 4500 as per
> > > the
> > specification.
> > > Please correct me if I am wrong. So if UDP port is NOT 4500 and
> > > udp-encap
> > is enabled in the
> > > Command line, UDP encapsulation will not work.
> >
> > I am not asking you so support multiple UDP ports for IPsec encapsulation.
> 
> Multiple ports are not required to be supported as per specification.
> UDP encapsulation work only on one port i.e. 4500.
> By specification, it says, port 4500 is reserved for NAT traversal and if a
> Packet has this port, then it has to be processed accordingly.
> 
> > What I am saying: it should be possible to use SAs with UDP
> > encapsulation along with SAs without (plain tunnel/transport mode).
> 
> Yes it is possible with the current patch.
> If a packet has a UDP port = 4500 then it is UDP encapsulated otherwise it is
> not.
> Hence, a packet with UDP port other than 4500 will work as it is working
> without --udp-encap param.
> 
> > As I understand with your patch it is not possible: if user specified
> > --udp- encap all SAs (on all crypto-devs) will be treated as UDP
> > encapsulated.
> 
> Just to correct this statement.
> 
> If user specified --udp-encap all SAs (on all crypto-devs) will be treated as
> UDP encapsulated if and only if the UDP port = 4500 and not otherwise.
> 
> I hope this statement clears your concern and it makes more sense to make it
> application vide, just like esn and anti-replay.
> 

[Tejasree] Just realized that all SAs are treated as UDP encapsulated 
if the packet type is other than UDP. Will add per SA support.

Concern with per SA support: we cannot have "udp_encap==1" check in the prepare_one_packet()
function as SA info is not available at that time and plain UDP packets with port 4500 are
treated as IPsec and results could be unpredictable.

> Regards,
> Akhil
  
Ananyev, Konstantin March 24, 2021, 10:39 a.m. UTC | #8
Hi Tejasree,

> > > > > > > > Adding lookaside IPsec UDP encapsulation support for NAT
> > > > > > > > traversal.
> > > > > > > > Added --udp-encap option for application to specify if UDP
> > > > > > > > encapsulation need to be enabled.
> > > > > > > > Example secgw command with UDP encapsultation enabled:
> > > > > > > > <secgw> -c 0x1 -- -P -p 0x1 --config "(0,0,0)" -f ep0.cfg
> > > > > > > > --udp-encap
> > > > > > >
> > > > > > > Can we have it not as global, but a per SA option?
> > > > > > > Add new keyword for SA/SP into ipsec-secgw config file, etc.
> > > > > > > Konstantin
> > > > > > >
> > > > > >
> > > > > > Any specific reason to make udp_encap as per SA?
> > > > > > UDP encapsulation is a feature which I believe should be
> > > > > > application
> > > vide.
> > > > > > If it supports the feature it should be enabled for all SAs when
> > > > > > the UDP
> > > port
> > > > > > is 4500 which is reserved for it.
> > > > >
> > > > > Not sure why it has to be application wide?
> > > > > Why it is not possible have let say SA1 in ipv4/ipv6 tunnel mode
> > > > > over port
> > > 0,
> > > > > and SA2 with udp encap over port 1?
> > > > > Note that in DPDK librte_security it is per SA option.
> > > >
> > > > UDP encapsulation can be done only if the UDP port is 4500 as per
> > > > the
> > > specification.
> > > > Please correct me if I am wrong. So if UDP port is NOT 4500 and
> > > > udp-encap
> > > is enabled in the
> > > > Command line, UDP encapsulation will not work.
> > >
> > > I am not asking you so support multiple UDP ports for IPsec encapsulation.
> >
> > Multiple ports are not required to be supported as per specification.
> > UDP encapsulation work only on one port i.e. 4500.
> > By specification, it says, port 4500 is reserved for NAT traversal and if a
> > Packet has this port, then it has to be processed accordingly.
> >
> > > What I am saying: it should be possible to use SAs with UDP
> > > encapsulation along with SAs without (plain tunnel/transport mode).
> >
> > Yes it is possible with the current patch.
> > If a packet has a UDP port = 4500 then it is UDP encapsulated otherwise it is
> > not.
> > Hence, a packet with UDP port other than 4500 will work as it is working
> > without --udp-encap param.
> >
> > > As I understand with your patch it is not possible: if user specified
> > > --udp- encap all SAs (on all crypto-devs) will be treated as UDP
> > > encapsulated.
> >
> > Just to correct this statement.
> >
> > If user specified --udp-encap all SAs (on all crypto-devs) will be treated as
> > UDP encapsulated if and only if the UDP port = 4500 and not otherwise.
> >
> > I hope this statement clears your concern and it makes more sense to make it
> > application vide, just like esn and anti-replay.
> >
> 
> [Tejasree] Just realized that all SAs are treated as UDP encapsulated
> if the packet type is other than UDP. Will add per SA support.
>
> Concern with per SA support: we cannot have "udp_encap==1" check in the prepare_one_packet()
> function as SA info is not available at that time and plain UDP packets with port 4500 are
> treated as IPsec and results could be unpredictable.
 
If you think global udp_encap would be helpful (let say for prepare_one_packet),
I think it is possible to keep it. By default it will be 0, and can be initialized to 1,
if we have at least one session  with udp_encap enabled (after config file parsing).
My thought about it was:
-prepare_packet() - mark both ip/esp and ip/udp(sport,dport=4500) as ESP ones,
  plus set mbuf.packet_type properly (UDP/ESP) (should we set l4_len also?). 
- sad_lookup() - based on packet type (l4_len?) determine location of ESP header
  and do the lookup. Then if lookup was successful, for UDP packets check does
  SA.udp_encap==1. If no, then drop the packet.
  
Tejasree Kondoj March 25, 2021, 8:38 a.m. UTC | #9
Hi Konstantin,

Please see inline.

Thanks
Tejasree

> -----Original Message-----
> From: Ananyev, Konstantin <konstantin.ananyev@intel.com>
> Sent: Wednesday, March 24, 2021 4:10 PM
> To: Tejasree Kondoj <ktejasree@marvell.com>; Akhil Goyal
> <gakhil@marvell.com>; Nicolau, Radu <radu.nicolau@intel.com>
> Cc: Anoob Joseph <anoobj@marvell.com>; Ankur Dwivedi
> <adwivedi@marvell.com>; Jerin Jacob Kollanukkaran <jerinj@marvell.com>;
> dev@dpdk.org
> Subject: [EXT] RE: [dpdk-dev] [PATCH 2/3] examples/ipsec-secgw: add UDP
> encapsulation support
> 
> External Email
> 
> ----------------------------------------------------------------------
> Hi Tejasree,
> 
> > > > > > > > > Adding lookaside IPsec UDP encapsulation support for NAT
> > > > > > > > > traversal.
> > > > > > > > > Added --udp-encap option for application to specify if UDP
> > > > > > > > > encapsulation need to be enabled.
> > > > > > > > > Example secgw command with UDP encapsultation enabled:
> > > > > > > > > <secgw> -c 0x1 -- -P -p 0x1 --config "(0,0,0)" -f ep0.cfg
> > > > > > > > > --udp-encap
> > > > > > > >
> > > > > > > > Can we have it not as global, but a per SA option?
> > > > > > > > Add new keyword for SA/SP into ipsec-secgw config file, etc.
> > > > > > > > Konstantin
> > > > > > > >
> > > > > > >
> > > > > > > Any specific reason to make udp_encap as per SA?
> > > > > > > UDP encapsulation is a feature which I believe should be
> > > > > > > application
> > > > vide.
> > > > > > > If it supports the feature it should be enabled for all SAs when
> > > > > > > the UDP
> > > > port
> > > > > > > is 4500 which is reserved for it.
> > > > > >
> > > > > > Not sure why it has to be application wide?
> > > > > > Why it is not possible have let say SA1 in ipv4/ipv6 tunnel mode
> > > > > > over port
> > > > 0,
> > > > > > and SA2 with udp encap over port 1?
> > > > > > Note that in DPDK librte_security it is per SA option.
> > > > >
> > > > > UDP encapsulation can be done only if the UDP port is 4500 as per
> > > > > the
> > > > specification.
> > > > > Please correct me if I am wrong. So if UDP port is NOT 4500 and
> > > > > udp-encap
> > > > is enabled in the
> > > > > Command line, UDP encapsulation will not work.
> > > >
> > > > I am not asking you so support multiple UDP ports for IPsec
> encapsulation.
> > >
> > > Multiple ports are not required to be supported as per specification.
> > > UDP encapsulation work only on one port i.e. 4500.
> > > By specification, it says, port 4500 is reserved for NAT traversal and if a
> > > Packet has this port, then it has to be processed accordingly.
> > >
> > > > What I am saying: it should be possible to use SAs with UDP
> > > > encapsulation along with SAs without (plain tunnel/transport mode).
> > >
> > > Yes it is possible with the current patch.
> > > If a packet has a UDP port = 4500 then it is UDP encapsulated otherwise it
> is
> > > not.
> > > Hence, a packet with UDP port other than 4500 will work as it is working
> > > without --udp-encap param.
> > >
> > > > As I understand with your patch it is not possible: if user specified
> > > > --udp- encap all SAs (on all crypto-devs) will be treated as UDP
> > > > encapsulated.
> > >
> > > Just to correct this statement.
> > >
> > > If user specified --udp-encap all SAs (on all crypto-devs) will be treated as
> > > UDP encapsulated if and only if the UDP port = 4500 and not otherwise.
> > >
> > > I hope this statement clears your concern and it makes more sense to
> make it
> > > application vide, just like esn and anti-replay.
> > >
> >
> > [Tejasree] Just realized that all SAs are treated as UDP encapsulated
> > if the packet type is other than UDP. Will add per SA support.
> >
> > Concern with per SA support: we cannot have "udp_encap==1" check in the
> prepare_one_packet()
> > function as SA info is not available at that time and plain UDP packets with
> port 4500 are
> > treated as IPsec and results could be unpredictable.
> 
> If you think global udp_encap would be helpful (let say for
> prepare_one_packet),
> I think it is possible to keep it. By default it will be 0, and can be initialized to
> 1,
> if we have at least one session  with udp_encap enabled (after config file
> parsing).
> My thought about it was:
> -prepare_packet() - mark both ip/esp and ip/udp(sport,dport=4500) as ESP
> ones,
>   plus set mbuf.packet_type properly (UDP/ESP) (should we set l4_len also?).
> - sad_lookup() - based on packet type (l4_len?) determine location of ESP
> header
>   and do the lookup. Then if lookup was successful, for UDP packets check
> does
>   SA.udp_encap==1. If no, then drop the packet.
> 
> 
> 
> 
[Tejasree] l4_len setting is not needed. mbuf.packet_type can be used.
Will send v2 with per SA support.
  

Patch

diff --git a/doc/guides/rel_notes/release_21_05.rst b/doc/guides/rel_notes/release_21_05.rst
index 66e28e21be..2e67038bfe 100644
--- a/doc/guides/rel_notes/release_21_05.rst
+++ b/doc/guides/rel_notes/release_21_05.rst
@@ -75,6 +75,11 @@  New Features
   * Added command to display Rx queue used descriptor count.
     ``show port (port_id) rxq (queue_id) desc used count``
 
+* **Updated ipsec-secgw sample application.**
+
+  * Updated the ``ipsec-secgw`` sample application with UDP encapsulation
+    support for NAT Traversal.
+
 
 Removed Items
 -------------
diff --git a/doc/guides/sample_app_ug/ipsec_secgw.rst b/doc/guides/sample_app_ug/ipsec_secgw.rst
index 176e292d3f..099f499c18 100644
--- a/doc/guides/sample_app_ug/ipsec_secgw.rst
+++ b/doc/guides/sample_app_ug/ipsec_secgw.rst
@@ -139,6 +139,7 @@  The application has a number of command line options::
                         --reassemble NUM
                         --mtu MTU
                         --frag-ttl FRAG_TTL_NS
+                        --udp-encap
 
 Where:
 
@@ -234,6 +235,8 @@  Where:
     Should be lower for low number of reassembly buckets.
     Valid values: from 1 ns to 10 s. Default value: 10000000 (10 s).
 
+*   ``--udp-encap``: enables IPsec UDP Encapsulation for NAT Traversal.
+
 
 The mapping of lcores to port/queues is similar to other l3fwd applications.
 
@@ -1023,4 +1026,4 @@  Available options:
 *   ``-h`` Show usage.
 
 If <ipsec_mode> is specified, only tests for that mode will be invoked. For the
-list of available modes please refer to run_test.sh.
\ No newline at end of file
+list of available modes please refer to run_test.sh.
diff --git a/examples/ipsec-secgw/ipsec-secgw.c b/examples/ipsec-secgw/ipsec-secgw.c
index 20d69ba813..57c8973e9d 100644
--- a/examples/ipsec-secgw/ipsec-secgw.c
+++ b/examples/ipsec-secgw/ipsec-secgw.c
@@ -115,6 +115,7 @@  struct flow_info flow_info_tbl[RTE_MAX_ETHPORTS];
 #define CMD_LINE_OPT_REASSEMBLE		"reassemble"
 #define CMD_LINE_OPT_MTU		"mtu"
 #define CMD_LINE_OPT_FRAG_TTL		"frag-ttl"
+#define CMD_LINE_OPT_UDP_ENCAP		"udp-encap"
 
 #define CMD_LINE_ARG_EVENT	"event"
 #define CMD_LINE_ARG_POLL	"poll"
@@ -139,6 +140,7 @@  enum {
 	CMD_LINE_OPT_REASSEMBLE_NUM,
 	CMD_LINE_OPT_MTU_NUM,
 	CMD_LINE_OPT_FRAG_TTL_NUM,
+	CMD_LINE_OPT_UDP_ENCAP_NUM,
 };
 
 static const struct option lgopts[] = {
@@ -152,6 +154,7 @@  static const struct option lgopts[] = {
 	{CMD_LINE_OPT_REASSEMBLE, 1, 0, CMD_LINE_OPT_REASSEMBLE_NUM},
 	{CMD_LINE_OPT_MTU, 1, 0, CMD_LINE_OPT_MTU_NUM},
 	{CMD_LINE_OPT_FRAG_TTL, 1, 0, CMD_LINE_OPT_FRAG_TTL_NUM},
+	{CMD_LINE_OPT_UDP_ENCAP, 0, 0, CMD_LINE_OPT_UDP_ENCAP_NUM},
 	{NULL, 0, 0, 0}
 };
 
@@ -360,6 +363,9 @@  prepare_one_packet(struct rte_mbuf *pkt, struct ipsec_traffic *t)
 	const struct rte_ether_hdr *eth;
 	const struct rte_ipv4_hdr *iph4;
 	const struct rte_ipv6_hdr *iph6;
+	const struct rte_udp_hdr *udp;
+	uint16_t nat_port;
+	uint16_t ip4_hdr_len;
 
 	eth = rte_pktmbuf_mtod(pkt, const struct rte_ether_hdr *);
 	if (eth->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
@@ -368,9 +374,26 @@  prepare_one_packet(struct rte_mbuf *pkt, struct ipsec_traffic *t)
 			RTE_ETHER_HDR_LEN);
 		adjust_ipv4_pktlen(pkt, iph4, 0);
 
-		if (iph4->next_proto_id == IPPROTO_ESP)
+		switch (iph4->next_proto_id) {
+		case IPPROTO_ESP:
 			t->ipsec.pkts[(t->ipsec.num)++] = pkt;
-		else {
+			break;
+		case IPPROTO_UDP:
+			if (app_sa_prm.udp_encap == 1) {
+				ip4_hdr_len = ((iph4->version_ihl &
+					RTE_IPV4_HDR_IHL_MASK) *
+					RTE_IPV4_IHL_MULTIPLIER);
+				udp = rte_pktmbuf_mtod_offset(pkt,
+					struct rte_udp_hdr *, ip4_hdr_len);
+				nat_port = rte_cpu_to_be_16(IPSEC_NAT_T_PORT);
+				if (udp->src_port == nat_port ||
+					udp->dst_port == nat_port){
+					t->ipsec.pkts[(t->ipsec.num)++] = pkt;
+					break;
+				}
+			}
+		/* Fall through */
+		default:
 			t->ip4.data[t->ip4.num] = &iph4->next_proto_id;
 			t->ip4.pkts[(t->ip4.num)++] = pkt;
 		}
@@ -1378,6 +1401,7 @@  print_usage(const char *prgname)
 		" [--" CMD_LINE_OPT_TX_OFFLOAD " TX_OFFLOAD_MASK]"
 		" [--" CMD_LINE_OPT_REASSEMBLE " REASSEMBLE_TABLE_SIZE]"
 		" [--" CMD_LINE_OPT_MTU " MTU]"
+		" [--" CMD_LINE_OPT_UDP_ENCAP "]"
 		"\n\n"
 		"  -p PORTMASK: Hexadecimal bitmask of ports to configure\n"
 		"  -P : Enable promiscuous mode\n"
@@ -1431,6 +1455,8 @@  print_usage(const char *prgname)
 		"  --" CMD_LINE_OPT_FRAG_TTL " FRAG_TTL_NS"
 		": fragments lifetime in nanoseconds, default\n"
 		"    and maximum value is 10.000.000.000 ns (10 s)\n"
+		"  --" CMD_LINE_OPT_UDP_ENCAP
+		": enables UDP Encapsulation for NAT Traversal\n"
 		"\n",
 		prgname);
 }
@@ -1780,6 +1806,9 @@  parse_args(int32_t argc, char **argv, struct eh_conf *eh_conf)
 			}
 			frag_ttl_ns = ret;
 			break;
+		case CMD_LINE_OPT_UDP_ENCAP_NUM:
+			app_sa_prm.udp_encap = 1;
+			break;
 		default:
 			print_usage(prgname);
 			return -1;
diff --git a/examples/ipsec-secgw/ipsec-secgw.h b/examples/ipsec-secgw/ipsec-secgw.h
index f2281e73cf..6887d752ab 100644
--- a/examples/ipsec-secgw/ipsec-secgw.h
+++ b/examples/ipsec-secgw/ipsec-secgw.h
@@ -47,6 +47,8 @@ 
 
 #define ETHADDR(a, b, c, d, e, f) (__BYTES_TO_UINT64(a, b, c, d, e, f, 0, 0))
 
+#define IPSEC_NAT_T_PORT 4500
+
 struct traffic_type {
 	const uint8_t *data[MAX_PKT_BURST * 2];
 	struct rte_mbuf *pkts[MAX_PKT_BURST * 2];
diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index 6baeeb342f..6e0caa198d 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -52,6 +52,7 @@  set_ipsec_conf(struct ipsec_sa *sa, struct rte_security_ipsec_xform *ipsec)
 	ipsec->esn_soft_limit = IPSEC_OFFLOAD_ESN_SOFTLIMIT;
 	ipsec->replay_win_sz = app_sa_prm.window_size;
 	ipsec->options.esn = app_sa_prm.enable_esn;
+	ipsec->options.udp_encap = app_sa_prm.udp_encap;
 }
 
 int
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 7031e28c46..430afea688 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -75,6 +75,7 @@  struct app_sa_prm {
 	uint32_t window_size; /* replay window size */
 	uint32_t enable_esn;  /* enable/disable ESN support */
 	uint32_t cache_sz;	/* per lcore SA cache size */
+	uint32_t udp_encap;   /* enable/disable UDP Encapsulation */
 	uint64_t flags;       /* rte_ipsec_sa_prm.flags */
 };
 
diff --git a/examples/ipsec-secgw/sad.h b/examples/ipsec-secgw/sad.h
index 473aaa938e..89b50488ec 100644
--- a/examples/ipsec-secgw/sad.h
+++ b/examples/ipsec-secgw/sad.h
@@ -77,6 +77,7 @@  sad_lookup(struct ipsec_sad *sad, struct rte_mbuf *pkts[],
 	uint32_t spi, cache_idx;
 	struct ipsec_sad_cache *cache;
 	struct ipsec_sa *cached_sa;
+	uint16_t udp_hdr_len = 0;
 	int is_ipv4;
 
 	cache  = &RTE_PER_LCORE(sad_cache);
@@ -85,8 +86,10 @@  sad_lookup(struct ipsec_sad *sad, struct rte_mbuf *pkts[],
 	for (i = 0; i < nb_pkts; i++) {
 		ipv4 = rte_pktmbuf_mtod(pkts[i], struct rte_ipv4_hdr *);
 		ipv6 = rte_pktmbuf_mtod(pkts[i], struct rte_ipv6_hdr *);
+		if (app_sa_prm.udp_encap == 1)
+			udp_hdr_len = sizeof(struct rte_udp_hdr);
 		esp = rte_pktmbuf_mtod_offset(pkts[i], struct rte_esp_hdr *,
-				pkts[i]->l3_len);
+				pkts[i]->l3_len + udp_hdr_len);
 
 		is_ipv4 = pkts[i]->packet_type & RTE_PTYPE_L3_IPV4;
 		spi = rte_be_to_cpu_32(esp->spi);