From: Valentine Fatiev <valentinef@nvidia.com>
Subject: [PATCH] BACKPORT:
 drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c

Change-Id: Id6bf326e3e4156181a86d2ac69c8cb2c937cde5c
---
 .../mellanox/mlx5/core/en_accel/ipsec_rxtx.c  | 114 +++++++++++++++++-
 1 file changed, 110 insertions(+), 4 deletions(-)

--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_rxtx.c
@@ -74,6 +74,9 @@ static int mlx5e_ipsec_remove_trailer(st
 
 static void mlx5e_ipsec_set_swp(struct sk_buff *skb,
 				struct mlx5_wqe_eth_seg *eseg, u8 mode,
+#ifndef HAVE_XFRM_OFFLOAD_INNER_IPPROTO
+				struct mlx5e_accel_tx_ipsec_state *ipsec_st,
+#endif
 				struct xfrm_offload *xo)
 {
 	/* Tunnel Mode:
@@ -88,7 +91,11 @@ static void mlx5e_ipsec_set_swp(struct s
 	 * SWP:      OutL3                   InL3  InL4
 	 * Pkt: MAC  IP     ESP  UDP  VXLAN  IP    L4
 	 */
-
+#ifndef HAVE_XFRM_OFFLOAD_INNER_IPPROTO
+	struct ethhdr *eth;
+#endif
+	u8 inner_ipproto = 0;
+	struct xfrm_state *x;
 	/* Shared settings */
 	eseg->swp_outer_l3_offset = skb_network_offset(skb) / 2;
 	if (skb->protocol == htons(ETH_P_IPV6))
@@ -96,11 +103,36 @@ static void mlx5e_ipsec_set_swp(struct s
 
 	/* Tunnel mode */
 	if (mode == XFRM_MODE_TUNNEL) {
+#ifdef HAVE_XFRM_OFFLOAD_INNER_IPPROTO
+		inner_ipproto = xo->inner_ipproto;
+#endif
+		/* Backport code to support kernels that don't have IPsec Tunnel mode Fix:
+		 * 45a98ef4922d net/xfrm: IPsec tunnel mode fix inner_ipproto setting in sec_path
+		 */
+		if (!inner_ipproto) {
+			x = xfrm_input_state(skb);
+			switch (x->props.family) {
+			case AF_INET:
+				inner_ipproto = ((struct iphdr *)(skb->data + skb_inner_network_offset(skb)))->protocol;
+				break;
+			case AF_INET6:
+				inner_ipproto = ((struct ipv6hdr *)(skb->data + skb_inner_network_offset(skb)))->nexthdr;
+				break;
+			default:
+				break;
+			}
+		}
+
+#ifdef HAVE_XFRM_OFFLOAD_INNER_IPPROTO
+		xo->inner_ipproto = inner_ipproto;
+#else
+		ipsec_st->inner_ipproto = inner_ipproto;
+#endif
 		eseg->swp_inner_l3_offset = skb_inner_network_offset(skb) / 2;
 		if (xo->proto == IPPROTO_IPV6)
 			eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L3_IPV6;
 
-		switch (xo->inner_ipproto) {
+		switch (inner_ipproto) {
 		case IPPROTO_UDP:
 			eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L4_UDP;
 			fallthrough;
@@ -118,7 +150,32 @@ static void mlx5e_ipsec_set_swp(struct s
 	if (mode != XFRM_MODE_TRANSPORT)
 		return;
 
-	if (!xo->inner_ipproto) {
+#ifdef HAVE_XFRM_OFFLOAD_INNER_IPPROTO
+	inner_ipproto = xo->inner_ipproto;
+#else
+	if (skb->inner_protocol_type != ENCAP_TYPE_ETHER){
+		return;
+	}
+
+	if (skb->inner_protocol_type == ENCAP_TYPE_IPPROTO) {
+		inner_ipproto = skb->inner_ipproto;
+	} else {
+		eth = (struct ethhdr *)skb_inner_mac_header(skb);
+		switch (ntohs(eth->h_proto)) {
+		case ETH_P_IP:
+			inner_ipproto = ((struct iphdr *)(skb->data + skb_inner_network_offset(skb)))->protocol;;
+			break;
+		case ETH_P_IPV6:
+			inner_ipproto = ((struct ipv6hdr *)(skb->data + skb_inner_network_offset(skb)))->nexthdr;
+			break;
+		default:
+			break;
+		}
+	}
+	ipsec_st->inner_ipproto = inner_ipproto;
+#endif
+
+	if (!inner_ipproto) {
 		switch (xo->proto) {
 		case IPPROTO_UDP:
 			eseg->swp_flags |= MLX5_ETH_WQE_SWP_OUTER_L4_UDP;
@@ -132,7 +189,7 @@ static void mlx5e_ipsec_set_swp(struct s
 		}
 	} else {
 		/* Tunnel(VXLAN TCP/UDP) over Transport Mode */
-		switch (xo->inner_ipproto) {
+		switch (inner_ipproto) {
 		case IPPROTO_UDP:
 			eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L4_UDP;
 			fallthrough;
@@ -184,6 +241,26 @@ void mlx5e_ipsec_set_iv(struct sk_buff *
 	skb_store_bits(skb, iv_offset, &seqno, 8);
 }
 
+/* Copy from upstream net/ipv4/esp4.c */
+#ifndef HAVE_ESP_OUTPUT_FILL_TRAILER
+	static
+void esp_output_fill_trailer(u8 *tail, int tfclen, int plen, __u8 proto)
+{ 
+	/* Fill padding... */
+	if (tfclen) {
+		memset(tail, 0, tfclen);
+		tail += tfclen;
+	}
+	do {
+		int i;
+		for (i = 0; i < plen - 2; i++)
+			tail[i] = i + 1;
+	} while (0);
+	tail[plen - 2] = plen - 2;
+	tail[plen - 1] = proto;
+}
+#endif
+
 void mlx5e_ipsec_handle_tx_wqe(struct mlx5e_tx_wqe *wqe,
 			       struct mlx5e_accel_tx_ipsec_state *ipsec_st,
 			       struct mlx5_wqe_inline_seg *inlseg)
@@ -217,17 +294,24 @@ static int mlx5e_ipsec_set_state(struct
 }
 
 void mlx5e_ipsec_tx_build_eseg(struct mlx5e_priv *priv, struct sk_buff *skb,
+#ifndef HAVE_XFRM_OFFLOAD_INNER_IPPROTO
+			       struct mlx5e_accel_tx_ipsec_state *ipsec_st,
+#endif
 			       struct mlx5_wqe_eth_seg *eseg)
 {
 	struct xfrm_offload *xo = xfrm_offload(skb);
 	struct xfrm_encap_tmpl  *encap;
 	struct xfrm_state *x;
+#ifdef HAVE_SECPATH_SET_RETURN_POINTER
 	struct sec_path *sp;
+#endif
 	u8 l3_proto;
 
+#ifdef HAVE_SECPATH_SET_RETURN_POINTER
 	sp = skb_sec_path(skb);
 	if (unlikely(sp->len != 1))
 		return;
+#endif
 
 	x = xfrm_input_state(skb);
 	if (unlikely(!x))
@@ -238,7 +322,11 @@ void mlx5e_ipsec_tx_build_eseg(struct ml
 		      skb->protocol != htons(ETH_P_IPV6))))
 		return;
 
+#ifdef HAVE_XFRM_OFFLOAD_INNER_IPPROTO
 	mlx5e_ipsec_set_swp(skb, eseg, x->props.mode, xo);
+#else
+	mlx5e_ipsec_set_swp(skb, eseg, x->props.mode, ipsec_st, xo);
+#endif
 
 	l3_proto = (x->props.family == AF_INET) ?
 		   ((struct iphdr *)skb_network_header(skb))->protocol :
@@ -266,10 +354,16 @@ bool mlx5e_ipsec_handle_tx_skb(struct ne
 	struct xfrm_offload *xo = xfrm_offload(skb);
 	struct mlx5e_ipsec_sa_entry *sa_entry;
 	struct xfrm_state *x;
+#ifdef HAVE_SECPATH_SET_RETURN_POINTER
 	struct sec_path *sp;
+#endif
 
+#ifdef HAVE_SECPATH_SET_RETURN_POINTER
 	sp = skb_sec_path(skb);
 	if (unlikely(sp->len != 1)) {
+#else
+	if (unlikely(skb->sp->len != 1)) {
+#endif
 		atomic64_inc(&priv->ipsec->sw_stats.ipsec_tx_drop_bundle);
 		goto drop;
 	}
@@ -312,15 +406,22 @@ void mlx5e_ipsec_offload_handle_rx_skb(s
 	struct mlx5e_ipsec *ipsec = priv->ipsec;
 	struct mlx5e_ipsec_sa_entry *sa_entry;
 	struct xfrm_offload *xo;
+#ifdef HAVE_SECPATH_SET_RETURN_POINTER
 	struct sec_path *sp;
+#endif
 	u32  sa_handle;
 
 	if (!ipsec)
 		return;
 
 	sa_handle = MLX5_IPSEC_METADATA_HANDLE(ipsec_meta_data);
+#ifdef HAVE_SECPATH_SET_RETURN_POINTER
 	sp = secpath_set(skb);
 	if (unlikely(!sp)) {
+#else
+	skb->sp = secpath_dup(skb->sp);
+	if (unlikely(!skb->sp)) {
+#endif
 		atomic64_inc(&ipsec->sw_stats.ipsec_rx_drop_sp_alloc);
 		return;
 	}
@@ -335,8 +436,13 @@ void mlx5e_ipsec_offload_handle_rx_skb(s
 	xfrm_state_hold(sa_entry->x);
 	rcu_read_unlock();
 
+#ifdef HAVE_SECPATH_SET_RETURN_POINTER
 	sp->xvec[sp->len++] = sa_entry->x;
 	sp->olen++;
+#else
+	skb->sp->xvec[skb->sp->len++] = sa_entry->x;
+	skb->sp->olen++;
+#endif
 
 	xo = xfrm_offload(skb);
 	xo->flags = CRYPTO_DONE;
