File Index
Files and directories
Sign in
FILE

psp_rxtx.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/en_accel/psp_rxtx.c C
  1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
  2/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
  3
  4#include <linux/skbuff.h>
  5#include <linux/ip.h>
  6#include <linux/udp.h>
  7#include <net/protocol.h>
  8#include <net/udp.h>
  9#include <net/ip6_checksum.h>
 10#include <net/psp/types.h>
 11
 12#include "en.h"
 13#include "psp.h"
 14#include "en_accel/psp_rxtx.h"
 15#include "en_accel/psp.h"
 16
 17enum {
 18	MLX5E_PSP_OFFLOAD_RX_SYNDROME_DECRYPTED,
 19	MLX5E_PSP_OFFLOAD_RX_SYNDROME_AUTH_FAILED,
 20	MLX5E_PSP_OFFLOAD_RX_SYNDROME_BAD_TRAILER,
 21};
 22
 23static void mlx5e_psp_set_swp(struct sk_buff *skb,
 24			      struct mlx5e_accel_tx_psp_state *psp_st,
 25			      struct mlx5_wqe_eth_seg *eseg)
 26{
 27	/* Tunnel Mode:
 28	 * SWP:      OutL3       InL3  InL4
 29	 * Pkt: MAC  IP     ESP  IP    L4
 30	 *
 31	 * Transport Mode:
 32	 * SWP:      OutL3       OutL4
 33	 * Pkt: MAC  IP     ESP  L4
 34	 *
 35	 * Tunnel(VXLAN TCP/UDP) over Transport Mode
 36	 * SWP:      OutL3                   InL3  InL4
 37	 * Pkt: MAC  IP     ESP  UDP  VXLAN  IP    L4
 38	 */
 39	u8 inner_ipproto = 0;
 40	struct ethhdr *eth;
 41
 42	/* Shared settings */
 43	eseg->swp_outer_l3_offset = skb_network_offset(skb) / 2;
 44	if (skb->protocol == htons(ETH_P_IPV6))
 45		eseg->swp_flags |= MLX5_ETH_WQE_SWP_OUTER_L3_IPV6;
 46
 47	if (skb->inner_protocol_type == ENCAP_TYPE_IPPROTO) {
 48		inner_ipproto = skb->inner_ipproto;
 49		/* Set SWP additional flags for packet of type IP|UDP|PSP|[ TCP | UDP ] */
 50		switch (inner_ipproto) {
 51		case IPPROTO_UDP:
 52			eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L4_UDP;
 53			fallthrough;
 54		case IPPROTO_TCP:
 55			eseg->swp_inner_l4_offset = skb_inner_transport_offset(skb) / 2;
 56			break;
 57		default:
 58			break;
 59		}
 60	} else {
 61		/* IP in IP tunneling like vxlan*/
 62		if (skb->inner_protocol_type != ENCAP_TYPE_ETHER)
 63			return;
 64
 65		eth = (struct ethhdr *)skb_inner_mac_header(skb);
 66		switch (ntohs(eth->h_proto)) {
 67		case ETH_P_IP:
 68			inner_ipproto = ((struct iphdr *)((char *)skb->data +
 69					 skb_inner_network_offset(skb)))->protocol;
 70			break;
 71		case ETH_P_IPV6:
 72			inner_ipproto = ((struct ipv6hdr *)((char *)skb->data +
 73					 skb_inner_network_offset(skb)))->nexthdr;
 74			break;
 75		default:
 76			break;
 77		}
 78
 79		/* Tunnel(VXLAN TCP/UDP) over Transport Mode PSP i.e. PSP payload is vxlan tunnel */
 80		switch (inner_ipproto) {
 81		case IPPROTO_UDP:
 82			eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L4_UDP;
 83			fallthrough;
 84		case IPPROTO_TCP:
 85			eseg->swp_inner_l3_offset = skb_inner_network_offset(skb) / 2;
 86			eseg->swp_inner_l4_offset =
 87				(skb->csum_start + skb->head - skb->data) / 2;
 88			if (skb->protocol == htons(ETH_P_IPV6))
 89				eseg->swp_flags |= MLX5_ETH_WQE_SWP_INNER_L3_IPV6;
 90			break;
 91		default:
 92			break;
 93		}
 94
 95		psp_st->inner_ipproto = inner_ipproto;
 96	}
 97}
 98
 99static bool mlx5e_psp_set_state(struct mlx5e_priv *priv,
100				struct sk_buff *skb,
101				struct mlx5e_accel_tx_psp_state *psp_st)
102{
103	struct psp_assoc *pas;
104	bool ret = false;
105
106	rcu_read_lock();
107	pas = psp_skb_get_assoc_rcu(skb);
108	if (!pas)
109		goto out;
110
111	ret = true;
112	psp_st->tailen = PSP_TRL_SIZE;
113	psp_st->spi = pas->tx.spi;
114	psp_st->ver = pas->version;
115	psp_st->keyid = *(u32 *)pas->drv_data;
116
117out:
118	rcu_read_unlock();
119	return ret;
120}
121
122bool mlx5e_psp_offload_handle_rx_skb(struct net_device *netdev, struct sk_buff *skb,
123				     struct mlx5_cqe64 *cqe)
124{
125	u32 psp_meta_data = be32_to_cpu(cqe->ft_metadata);
126	struct mlx5e_priv *priv = netdev_priv(netdev);
127	u16 dev_id = priv->psp->psp->id;
128	bool strip_icv = true;
129	u8 generation = 0;
130
131	/* TBD: report errors as SW counters to ethtool, any further handling ? */
132	if (MLX5_PSP_METADATA_SYNDROME(psp_meta_data) != MLX5E_PSP_OFFLOAD_RX_SYNDROME_DECRYPTED)
133		goto drop;
134
135	if (psp_dev_rcv(skb, dev_id, generation, strip_icv))
136		goto drop;
137
138	skb->decrypted = 1;
139	return false;
140
141drop:
142	kfree_skb(skb);
143	return true;
144}
145
146void mlx5e_psp_tx_build_eseg(struct mlx5e_priv *priv, struct sk_buff *skb,
147			     struct mlx5e_accel_tx_psp_state *psp_st,
148			     struct mlx5_wqe_eth_seg *eseg)
149{
150	if (!mlx5_is_psp_device(priv->mdev))
151		return;
152
153	if (unlikely(skb->protocol != htons(ETH_P_IP) &&
154		     skb->protocol != htons(ETH_P_IPV6)))
155		return;
156
157	mlx5e_psp_set_swp(skb, psp_st, eseg);
158	/* Special WA for PSP LSO in ConnectX7 */
159	eseg->swp_outer_l3_offset = 0;
160	eseg->swp_inner_l3_offset = 0;
161
162	eseg->flow_table_metadata |= cpu_to_be32(psp_st->keyid);
163	eseg->trailer |= cpu_to_be32(MLX5_ETH_WQE_INSERT_TRAILER) |
164			 cpu_to_be32(MLX5_ETH_WQE_TRAILER_HDR_OUTER_L4_ASSOC);
165}
166
167void mlx5e_psp_handle_tx_wqe(struct mlx5e_tx_wqe *wqe,
168			     struct mlx5e_accel_tx_psp_state *psp_st,
169			     struct mlx5_wqe_inline_seg *inlseg)
170{
171	inlseg->byte_count = cpu_to_be32(psp_st->tailen | MLX5_INLINE_SEG);
172}
173
174bool mlx5e_psp_handle_tx_skb(struct net_device *netdev,
175			     struct sk_buff *skb,
176			     struct mlx5e_accel_tx_psp_state *psp_st)
177{
178	struct mlx5e_priv *priv = netdev_priv(netdev);
179	struct net *net = sock_net(skb->sk);
180
181	if (!mlx5e_psp_set_state(priv, skb, psp_st))
182		return true;
183
184	/* psp_encap of the packet */
185	if (!psp_dev_encapsulate(net, skb, psp_st->spi, psp_st->ver, 0)) {
186		kfree_skb_reason(skb, SKB_DROP_REASON_PSP_OUTPUT);
187		atomic_inc(&priv->psp->tx_drop);
188		return false;
189	}
190	if (skb_is_gso(skb)) {
191		int len = skb_shinfo(skb)->gso_size + inner_tcp_hdrlen(skb);
192		struct tcphdr *th = inner_tcp_hdr(skb);
193
194		if (skb->protocol == htons(ETH_P_IP)) {
195			const struct iphdr *ip = ip_hdr(skb);
196
197			th->check = ~tcp_v4_check(len, ip->saddr, ip->daddr, 0);
198		} else {
199			const struct ipv6hdr *ip6 = ipv6_hdr(skb);
200
201			th->check = ~tcp_v6_check(len, &ip6->saddr, &ip6->daddr, 0);
202		}
203	}
204
205	return true;
206}
~/ Read-only file preview.