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

Commit b6ca8bd5 authored by David Miller's avatar David Miller Committed by David S. Miller
Browse files

xfrm: Move child route linkage into xfrm_dst.



XFRM bundle child chains look like this:

	xdst1 --> xdst2 --> xdst3 --> path_dst

All of xdstN are xfrm_dst objects and xdst->u.dst.xfrm is non-NULL.
The final child pointer in the chain, here called 'path_dst', is some
other kind of route such as an ipv4 or ipv6 one.

The xfrm output path pops routes, one at a time, via the child
pointer, until we hit one which has a dst->xfrm pointer which
is NULL.

We can easily preserve the above mechanisms with child sitting
only in the xfrm_dst structure.  All children in the chain
before we break out of the xfrm_output() loop have dst->xfrm
non-NULL and are therefore xfrm_dst objects.

Since we break out of the loop when we find dst->xfrm NULL, we
will not try to dereference 'dst' as if it were an xfrm_dst.

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 45b018be
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -35,7 +35,6 @@ struct sk_buff;
struct dst_entry {
	struct net_device       *dev;
	struct rcu_head		rcu_head;
	struct dst_entry	*child;
	struct  dst_ops	        *ops;
	unsigned long		_metrics;
	unsigned long           expires;
@@ -89,7 +88,7 @@ struct dst_entry {
	 * Align __refcnt to a 64 bytes alignment
	 * (L1_CACHE_SIZE would be too much)
	 */
	long			__pad_to_align_refcnt[2];
	long			__pad_to_align_refcnt[3];
#endif
	/*
	 * __refcnt wants to be on a different cache line from
+10 −5
Original line number Diff line number Diff line
@@ -968,7 +968,7 @@ static inline bool xfrm_sec_ctx_match(struct xfrm_sec_ctx *s1, struct xfrm_sec_c

/* A struct encoding bundle of transformations to apply to some set of flow.
 *
 * dst->child points to the next element of bundle.
 * xdst->child points to the next element of bundle.
 * dst->xfrm  points to an instanse of transformer.
 *
 * Due to unfortunate limitations of current routing cache, which we
@@ -984,6 +984,7 @@ struct xfrm_dst {
		struct rt6_info		rt6;
	} u;
	struct dst_entry *route;
	struct dst_entry *child;
	struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
	int num_pols, num_xfrms;
	u32 xfrm_genid;
@@ -997,8 +998,10 @@ struct xfrm_dst {
static inline struct dst_entry *xfrm_dst_child(const struct dst_entry *dst)
{
#ifdef CONFIG_XFRM
	if (dst->xfrm)
		return dst->child;
	if (dst->xfrm) {
		struct xfrm_dst *xdst = (struct xfrm_dst *) dst;
		return xdst->child;
	}
#endif
	return NULL;
}
@@ -1006,7 +1009,7 @@ static inline struct dst_entry *xfrm_dst_child(const struct dst_entry *dst)
#ifdef CONFIG_XFRM
static inline void xfrm_dst_set_child(struct xfrm_dst *xdst, struct dst_entry *child)
{
	xdst->u.dst.child = child;
	xdst->child = child;
}

static inline void xfrm_dst_destroy(struct xfrm_dst *xdst)
@@ -1880,12 +1883,14 @@ bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x);
static inline bool xfrm_dst_offload_ok(struct dst_entry *dst)
{
	struct xfrm_state *x = dst->xfrm;
	struct xfrm_dst *xdst;

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

	xdst = (struct xfrm_dst *) dst;
	if (x->xso.offload_handle && (x->xso.dev == dst->path->dev) &&
	    !dst->child->xfrm)
	    !xdst->child->xfrm)
		return true;

	return false;
+6 −3
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <linux/sched.h>
#include <linux/prefetch.h>
#include <net/lwtunnel.h>
#include <net/xfrm.h>

#include <net/dst.h>
#include <net/dst_metadata.h>
@@ -62,7 +63,6 @@ void dst_init(struct dst_entry *dst, struct dst_ops *ops,
	      struct net_device *dev, int initial_ref, int initial_obsolete,
	      unsigned short flags)
{
	dst->child = NULL;
	dst->dev = dev;
	if (dev)
		dev_hold(dev);
@@ -121,8 +121,11 @@ struct dst_entry *dst_destroy(struct dst_entry * dst)
	smp_rmb();

#ifdef CONFIG_XFRM
	if (dst->xfrm)
		child = dst->child;
	if (dst->xfrm) {
		struct xfrm_dst *xdst = (struct xfrm_dst *) dst;

		child = xdst->child;
	}
#endif
	if (!(dst->flags & DST_NOCOUNT))
		dst_entries_add(dst->ops, -1);
+6 −6
Original line number Diff line number Diff line
@@ -399,7 +399,7 @@ struct pktgen_dev {
	__u8	ipsmode;		/* IPSEC mode (config) */
	__u8	ipsproto;		/* IPSEC type (config) */
	__u32	spi;
	struct dst_entry dst;
	struct xfrm_dst xdst;
	struct dst_ops dstops;
#endif
	char result[512];
@@ -2609,7 +2609,7 @@ static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev)
	 * supports both transport/tunnel mode + ESP/AH type.
	 */
	if ((x->props.mode == XFRM_MODE_TUNNEL) && (pkt_dev->spi != 0))
		skb->_skb_refdst = (unsigned long)&pkt_dev->dst | SKB_DST_NOREF;
		skb->_skb_refdst = (unsigned long)&pkt_dev->xdst.u.dst | SKB_DST_NOREF;

	rcu_read_lock_bh();
	err = x->outer_mode->output(x, skb);
@@ -3742,10 +3742,10 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
	 * performance under such circumstance.
	 */
	pkt_dev->dstops.family = AF_INET;
	pkt_dev->dst.dev = pkt_dev->odev;
	dst_init_metrics(&pkt_dev->dst, pktgen_dst_metrics, false);
	pkt_dev->dst.child = &pkt_dev->dst;
	pkt_dev->dst.ops = &pkt_dev->dstops;
	pkt_dev->xdst.u.dst.dev = pkt_dev->odev;
	dst_init_metrics(&pkt_dev->xdst.u.dst, pktgen_dst_metrics, false);
	pkt_dev->xdst.child = &pkt_dev->xdst.u.dst;
	pkt_dev->xdst.u.dst.ops = &pkt_dev->dstops;
#endif

	return add_dev_to_thread(t, pkt_dev);
+2 −1
Original line number Diff line number Diff line
@@ -93,7 +93,8 @@ match_policy_out(const struct sk_buff *skb, const struct xt_policy_info *info,
	if (dst->xfrm == NULL)
		return -1;

	for (i = 0; dst && dst->xfrm; dst = dst->child, i++) {
	for (i = 0; dst && dst->xfrm;
	     dst = ((struct xfrm_dst *)dst)->child, i++) {
		pos = strict ? i : 0;
		if (pos >= info->len)
			return 0;
Loading