xfrm_device.c 8.7 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-or-later
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * xfrm_device.c - IPsec device offloading code.
 *
 * Copyright (c) 2015 secunet Security Networks AG
 *
 * Author:
 * Steffen Klassert <steffen.klassert@secunet.com>
 */

#include <linux/errno.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <net/dst.h>
#include <net/xfrm.h>
#include <linux/notifier.h>

21
#ifdef CONFIG_XFRM_OFFLOAD
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
static void __xfrm_transport_prep(struct xfrm_state *x, struct sk_buff *skb,
				  unsigned int hsize)
{
	struct xfrm_offload *xo = xfrm_offload(skb);

	skb_reset_mac_len(skb);
	pskb_pull(skb, skb->mac_len + hsize + x->props.header_len);

	if (xo->flags & XFRM_GSO_SEGMENT) {
		skb_reset_transport_header(skb);
		skb->transport_header -= x->props.header_len;
	}
}

static void __xfrm_mode_tunnel_prep(struct xfrm_state *x, struct sk_buff *skb,
				    unsigned int hsize)

{
	struct xfrm_offload *xo = xfrm_offload(skb);

	if (xo->flags & XFRM_GSO_SEGMENT)
		skb->transport_header = skb->network_header + hsize;

	skb_reset_mac_len(skb);
	pskb_pull(skb, skb->mac_len + x->props.header_len);
}

/* Adjust pointers into the packet when IPsec is done at layer2 */
static void xfrm_outer_mode_prep(struct xfrm_state *x, struct sk_buff *skb)
{
52
	switch (x->outer_mode.encap) {
53
	case XFRM_MODE_TUNNEL:
54
		if (x->outer_mode.family == AF_INET)
55 56
			return __xfrm_mode_tunnel_prep(x, skb,
						       sizeof(struct iphdr));
57
		if (x->outer_mode.family == AF_INET6)
58 59 60 61
			return __xfrm_mode_tunnel_prep(x, skb,
						       sizeof(struct ipv6hdr));
		break;
	case XFRM_MODE_TRANSPORT:
62
		if (x->outer_mode.family == AF_INET)
63 64
			return __xfrm_transport_prep(x, skb,
						     sizeof(struct iphdr));
65
		if (x->outer_mode.family == AF_INET6)
66 67 68 69 70 71 72 73 74 75
			return __xfrm_transport_prep(x, skb,
						     sizeof(struct ipv6hdr));
		break;
	case XFRM_MODE_ROUTEOPTIMIZATION:
	case XFRM_MODE_IN_TRIGGER:
	case XFRM_MODE_BEET:
		break;
	}
}

76
struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features, bool *again)
77 78
{
	int err;
79
	unsigned long flags;
80
	struct xfrm_state *x;
81
	struct sk_buff *skb2, *nskb;
82
	struct softnet_data *sd;
83
	netdev_features_t esp_features = features;
84
	struct xfrm_offload *xo = xfrm_offload(skb);
85
	struct sec_path *sp;
86

87 88
	if (!xo)
		return skb;
89

90 91
	if (!(features & NETIF_F_HW_ESP))
		esp_features = features & ~(NETIF_F_SG | NETIF_F_CSUM_MASK);
92

93 94
	sp = skb_sec_path(skb);
	x = sp->xvec[sp->len - 1];
95 96 97
	if (xo->flags & XFRM_GRO || x->xso.flags & XFRM_OFFLOAD_INBOUND)
		return skb;

98 99 100 101 102 103 104 105 106 107
	local_irq_save(flags);
	sd = this_cpu_ptr(&softnet_data);
	err = !skb_queue_empty(&sd->xfrm_backlog);
	local_irq_restore(flags);

	if (err) {
		*again = true;
		return skb;
	}

108 109 110
	if (skb_is_gso(skb)) {
		struct net_device *dev = skb->dev;

111
		if (unlikely(x->xso.dev != dev)) {
112 113 114 115 116 117 118 119 120
			struct sk_buff *segs;

			/* Packet got rerouted, fixup features and segment it. */
			esp_features = esp_features & ~(NETIF_F_HW_ESP
							| NETIF_F_GSO_ESP);

			segs = skb_gso_segment(skb, esp_features);
			if (IS_ERR(segs)) {
				kfree_skb(skb);
121
				atomic_long_inc(&dev->tx_dropped);
122 123 124 125 126 127 128 129 130
				return NULL;
			} else {
				consume_skb(skb);
				skb = segs;
			}
		}
	}

	if (!skb->next) {
131
		esp_features |= skb->dev->gso_partial_features;
132
		xfrm_outer_mode_prep(x, skb);
133

134 135
		xo->flags |= XFRM_DEV_RESUME;

136
		err = x->type_offload->xmit(x, skb, esp_features);
137
		if (err) {
138 139 140
			if (err == -EINPROGRESS)
				return NULL;

141
			XFRM_INC_STATS(xs_net(x), LINUX_MIB_XFRMOUTSTATEPROTOERROR);
142 143
			kfree_skb(skb);
			return NULL;
144 145 146
		}

		skb_push(skb, skb->data - skb_mac_header(skb));
147 148

		return skb;
149 150
	}

151
	skb_list_walk_safe(skb, skb2, nskb) {
152
		esp_features |= skb->dev->gso_partial_features;
153
		skb_mark_not_on_list(skb2);
154 155

		xo = xfrm_offload(skb2);
156
		xo->flags |= XFRM_DEV_RESUME;
157

158
		xfrm_outer_mode_prep(x, skb2);
159 160

		err = x->type_offload->xmit(x, skb2, esp_features);
161 162 163
		if (!err) {
			skb2->next = nskb;
		} else if (err != -EINPROGRESS) {
164 165 166 167
			XFRM_INC_STATS(xs_net(x), LINUX_MIB_XFRMOUTSTATEPROTOERROR);
			skb2->next = nskb;
			kfree_skb_list(skb2);
			return NULL;
168 169 170 171 172 173
		} else {
			if (skb == skb2)
				skb = nskb;

			if (!skb)
				return NULL;
174

175
			continue;
176
		}
177 178

		skb_push(skb2, skb2->data - skb_mac_header(skb2));
179
	}
180 181

	return skb;
182 183 184
}
EXPORT_SYMBOL_GPL(validate_xmit_xfrm);

185 186 187 188 189 190 191 192 193 194 195
int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
		       struct xfrm_user_offload *xuo)
{
	int err;
	struct dst_entry *dst;
	struct net_device *dev;
	struct xfrm_state_offload *xso = &x->xso;
	xfrm_address_t *saddr;
	xfrm_address_t *daddr;

	if (!x->type_offload)
196
		return -EINVAL;
197

198 199
	/* We don't yet support UDP encapsulation and TFC padding. */
	if (x->encap || x->tfcpad)
200
		return -EINVAL;
201 202 203 204 205 206 207 208 209 210 211

	dev = dev_get_by_index(net, xuo->ifindex);
	if (!dev) {
		if (!(xuo->flags & XFRM_OFFLOAD_INBOUND)) {
			saddr = &x->props.saddr;
			daddr = &x->id.daddr;
		} else {
			saddr = &x->id.daddr;
			daddr = &x->props.saddr;
		}

212
		dst = __xfrm_dst_lookup(net, 0, 0, saddr, daddr,
213 214
					x->props.family,
					xfrm_smark_get(0, x));
215 216 217 218 219 220 221 222 223 224
		if (IS_ERR(dst))
			return 0;

		dev = dst->dev;

		dev_hold(dev);
		dst_release(dst);
	}

	if (!dev->xfrmdev_ops || !dev->xfrmdev_ops->xdo_dev_state_add) {
225
		xso->dev = NULL;
226 227 228 229
		dev_put(dev);
		return 0;
	}

230 231 232 233 234 235 236
	if (x->props.flags & XFRM_STATE_ESN &&
	    !dev->xfrmdev_ops->xdo_dev_state_advance_esn) {
		xso->dev = NULL;
		dev_put(dev);
		return -EINVAL;
	}

237 238 239 240 241 242
	xso->dev = dev;
	xso->num_exthdrs = 1;
	xso->flags = xuo->flags;

	err = dev->xfrmdev_ops->xdo_dev_state_add(x);
	if (err) {
243 244
		xso->num_exthdrs = 0;
		xso->flags = 0;
245
		xso->dev = NULL;
246
		dev_put(dev);
247 248 249

		if (err != -EOPNOTSUPP)
			return err;
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
	}

	return 0;
}
EXPORT_SYMBOL_GPL(xfrm_dev_state_add);

bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x)
{
	int mtu;
	struct dst_entry *dst = skb_dst(skb);
	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
	struct net_device *dev = x->xso.dev;

	if (!x->type_offload || x->encap)
		return false;

266
	if ((!dev || (dev == xfrm_dst_path(dst)->dev)) &&
267 268
	    (!xdst->child->xfrm)) {
		mtu = xfrm_state_mtu(x, xdst->child_mtu_cached);
269 270 271
		if (skb->len <= mtu)
			goto ok;

272
		if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu))
273 274 275 276 277 278 279 280 281 282 283 284
			goto ok;
	}

	return false;

ok:
	if (dev && dev->xfrmdev_ops && dev->xfrmdev_ops->xdo_dev_offload_ok)
		return x->xso.dev->xfrmdev_ops->xdo_dev_offload_ok(skb, x);

	return true;
}
EXPORT_SYMBOL_GPL(xfrm_dev_offload_ok);
285 286 287 288 289 290 291 292 293 294

void xfrm_dev_resume(struct sk_buff *skb)
{
	struct net_device *dev = skb->dev;
	int ret = NETDEV_TX_BUSY;
	struct netdev_queue *txq;
	struct softnet_data *sd;
	unsigned long flags;

	rcu_read_lock();
295
	txq = netdev_core_pick_tx(dev, skb, NULL);
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333

	HARD_TX_LOCK(dev, txq, smp_processor_id());
	if (!netif_xmit_frozen_or_stopped(txq))
		skb = dev_hard_start_xmit(skb, dev, txq, &ret);
	HARD_TX_UNLOCK(dev, txq);

	if (!dev_xmit_complete(ret)) {
		local_irq_save(flags);
		sd = this_cpu_ptr(&softnet_data);
		skb_queue_tail(&sd->xfrm_backlog, skb);
		raise_softirq_irqoff(NET_TX_SOFTIRQ);
		local_irq_restore(flags);
	}
	rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(xfrm_dev_resume);

void xfrm_dev_backlog(struct softnet_data *sd)
{
	struct sk_buff_head *xfrm_backlog = &sd->xfrm_backlog;
	struct sk_buff_head list;
	struct sk_buff *skb;

	if (skb_queue_empty(xfrm_backlog))
		return;

	__skb_queue_head_init(&list);

	spin_lock(&xfrm_backlog->lock);
	skb_queue_splice_init(xfrm_backlog, &list);
	spin_unlock(&xfrm_backlog->lock);

	while (!skb_queue_empty(&list)) {
		skb = __skb_dequeue(&list);
		xfrm_dev_resume(skb);
	}

}
334
#endif
335

336
static int xfrm_api_check(struct net_device *dev)
337
{
338
#ifdef CONFIG_XFRM_OFFLOAD
339 340 341 342
	if ((dev->features & NETIF_F_HW_ESP_TX_CSUM) &&
	    !(dev->features & NETIF_F_HW_ESP))
		return NOTIFY_BAD;

343 344 345 346 347 348 349 350 351 352
	if ((dev->features & NETIF_F_HW_ESP) &&
	    (!(dev->xfrmdev_ops &&
	       dev->xfrmdev_ops->xdo_dev_state_add &&
	       dev->xfrmdev_ops->xdo_dev_state_delete)))
		return NOTIFY_BAD;
#else
	if (dev->features & (NETIF_F_HW_ESP | NETIF_F_HW_ESP_TX_CSUM))
		return NOTIFY_BAD;
#endif

353 354 355
	return NOTIFY_DONE;
}

356 357 358 359 360
static int xfrm_dev_register(struct net_device *dev)
{
	return xfrm_api_check(dev);
}

361 362
static int xfrm_dev_feat_change(struct net_device *dev)
{
363
	return xfrm_api_check(dev);
364 365 366 367
}

static int xfrm_dev_down(struct net_device *dev)
{
368
	if (dev->features & NETIF_F_HW_ESP)
369 370 371 372 373
		xfrm_dev_state_flush(dev_net(dev), dev, true);

	return NOTIFY_DONE;
}

374 375 376 377 378
static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
{
	struct net_device *dev = netdev_notifier_info_to_dev(ptr);

	switch (event) {
379 380 381 382 383 384
	case NETDEV_REGISTER:
		return xfrm_dev_register(dev);

	case NETDEV_FEAT_CHANGE:
		return xfrm_dev_feat_change(dev);

385
	case NETDEV_DOWN:
386
		return xfrm_dev_down(dev);
387 388 389 390 391 392 393 394
	}
	return NOTIFY_DONE;
}

static struct notifier_block xfrm_dev_notifier = {
	.notifier_call	= xfrm_dev_event,
};

395
void __init xfrm_dev_init(void)
396 397 398
{
	register_netdevice_notifier(&xfrm_dev_notifier);
}