Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d77e38e6 authored by Steffen Klassert's avatar Steffen Klassert
Browse files

xfrm: Add an IPsec hardware offloading API



This patch adds all the bits that are needed to do
IPsec hardware offload for IPsec states and ESP packets.
We add xfrmdev_ops to the net_device. xfrmdev_ops has
function pointers that are needed to manage the xfrm
states in the hardware and to do a per packet
offloading decision.

Joint work with:
Ilan Tayari <ilant@mellanox.com>
Guy Shapiro <guysh@mellanox.com>
Yossi Kuperman <yossiku@mellanox.com>

Signed-off-by: default avatarGuy Shapiro <guysh@mellanox.com>
Signed-off-by: default avatarIlan Tayari <ilant@mellanox.com>
Signed-off-by: default avatarYossi Kuperman <yossiku@mellanox.com>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent c35fe410
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -824,6 +824,16 @@ struct netdev_xdp {
	};
};

#ifdef CONFIG_XFRM_OFFLOAD
struct xfrmdev_ops {
	int	(*xdo_dev_state_add) (struct xfrm_state *x);
	void	(*xdo_dev_state_delete) (struct xfrm_state *x);
	void	(*xdo_dev_state_free) (struct xfrm_state *x);
	bool	(*xdo_dev_offload_ok) (struct sk_buff *skb,
				       struct xfrm_state *x);
};
#endif

/*
 * This structure defines the management hooks for network devices.
 * The following hooks can be defined; unless noted otherwise, they are
@@ -1697,6 +1707,10 @@ struct net_device {
	const struct ndisc_ops *ndisc_ops;
#endif

#ifdef CONFIG_XFRM
	const struct xfrmdev_ops *xfrmdev_ops;
#endif

	const struct header_ops *header_ops;

	unsigned int		flags;
+64 −1
Original line number Diff line number Diff line
@@ -120,6 +120,13 @@ struct xfrm_state_walk {
	struct xfrm_address_filter *filter;
};

struct xfrm_state_offload {
	struct net_device	*dev;
	unsigned long		offload_handle;
	unsigned int		num_exthdrs;
	u8			flags;
};

/* Full description of state of transformer. */
struct xfrm_state {
	possible_net_t		xs_net;
@@ -207,6 +214,8 @@ struct xfrm_state {
	struct xfrm_lifetime_cur curlft;
	struct tasklet_hrtimer	mtimer;

	struct xfrm_state_offload xso;

	/* used to fix curlft->add_time when changing date */
	long		saved_tmo;

@@ -1453,7 +1462,6 @@ struct xfrm6_tunnel {
void xfrm_init(void);
void xfrm4_init(void);
int xfrm_state_init(struct net *net);
void xfrm_dev_init(void);
void xfrm_state_fini(struct net *net);
void xfrm4_state_init(void);
void xfrm4_protocol_init(void);
@@ -1559,6 +1567,7 @@ struct xfrmk_spdinfo {
struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq);
int xfrm_state_delete(struct xfrm_state *x);
int xfrm_state_flush(struct net *net, u8 proto, bool task_valid);
int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_valid);
void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si);
void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si);
u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq);
@@ -1641,6 +1650,11 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
}
#endif

struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, int oif,
				    const xfrm_address_t *saddr,
				    const xfrm_address_t *daddr,
				    int family);

struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp);

void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type);
@@ -1846,6 +1860,55 @@ static inline struct xfrm_offload *xfrm_offload(struct sk_buff *skb)
}
#endif

#ifdef CONFIG_XFRM_OFFLOAD
void __net_init xfrm_dev_init(void);
int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
		       struct xfrm_user_offload *xuo);
bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x);

static inline void xfrm_dev_state_delete(struct xfrm_state *x)
{
	struct xfrm_state_offload *xso = &x->xso;

	if (xso->dev)
		xso->dev->xfrmdev_ops->xdo_dev_state_delete(x);
}

static inline void xfrm_dev_state_free(struct xfrm_state *x)
{
	struct xfrm_state_offload *xso = &x->xso;
	 struct net_device *dev = xso->dev;

	if (dev && dev->xfrmdev_ops) {
		dev->xfrmdev_ops->xdo_dev_state_free(x);
		xso->dev = NULL;
		dev_put(dev);
	}
}
#else
static inline void __net_init xfrm_dev_init(void)
{
}

static inline int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, struct xfrm_user_offload *xuo)
{
	return 0;
}

static inline void xfrm_dev_state_delete(struct xfrm_state *x)
{
}

static inline void xfrm_dev_state_free(struct xfrm_state *x)
{
}

static inline bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x)
{
	return false;
}
#endif

static inline int xfrm_mark_get(struct nlattr **attrs, struct xfrm_mark *m)
{
	if (attrs[XFRMA_MARK])
+8 −0
Original line number Diff line number Diff line
@@ -303,6 +303,7 @@ enum xfrm_attr_type_t {
	XFRMA_PROTO,		/* __u8 */
	XFRMA_ADDRESS_FILTER,	/* struct xfrm_address_filter */
	XFRMA_PAD,
	XFRMA_OFFLOAD_DEV,	/* struct xfrm_state_offload */
	__XFRMA_MAX

#define XFRMA_MAX (__XFRMA_MAX - 1)
@@ -494,6 +495,13 @@ struct xfrm_address_filter {
	__u8				dplen;
};

struct xfrm_user_offload {
	int				ifindex;
	__u8				flags;
};
#define XFRM_OFFLOAD_IPV6	1
#define XFRM_OFFLOAD_INBOUND	2

#ifndef __KERNEL__
/* backwards compatibility for userspace */
#define XFRMGRP_ACQUIRE		1
+3 −4
Original line number Diff line number Diff line
@@ -435,9 +435,6 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
	aead_request_set_crypt(req, sg, dsg, ivlen + clen, iv);
	aead_request_set_ad(req, assoclen);

	seqno = cpu_to_be64(XFRM_SKB_CB(skb)->seq.output.low +
			    ((u64)XFRM_SKB_CB(skb)->seq.output.hi << 32));

	memset(iv, 0, ivlen);
	memcpy(iv + ivlen - min(ivlen, 8), (u8 *)&seqno + 8 - min(ivlen, 8),
	       min(ivlen, 8));
@@ -470,6 +467,7 @@ static int esp_input_done2(struct sk_buff *skb, int err)
{
	const struct iphdr *iph;
	struct xfrm_state *x = xfrm_input_state(skb);
	struct xfrm_offload *xo = xfrm_offload(skb);
	struct crypto_aead *aead = x->data;
	int alen = crypto_aead_authsize(aead);
	int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
@@ -478,6 +476,7 @@ static int esp_input_done2(struct sk_buff *skb, int err)
	u8 nexthdr[2];
	int padlen;

	if (!xo || (xo && !(xo->flags & CRYPTO_DONE)))
		kfree(ESP_SKB_CB(skb)->tmp);

	if (unlikely(err))
+2 −1
Original line number Diff line number Diff line
@@ -29,7 +29,8 @@ static int xfrm4_tunnel_check_size(struct sk_buff *skb)
		goto out;

	mtu = dst_mtu(skb_dst(skb));
	if (skb->len > mtu) {
	if ((!skb_is_gso(skb) && skb->len > mtu) ||
	    (skb_is_gso(skb) && skb_gso_network_seglen(skb) > ip_skb_dst_mtu(skb->sk, skb))) {
		skb->protocol = htons(ETH_P_IP);

		if (skb->sk)
Loading