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: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
45b018bedd
commit
b6ca8bd5a9
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -121,7 +121,7 @@ bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x)
|
|||
return false;
|
||||
|
||||
if ((x->xso.offload_handle && (dev == dst->path->dev)) &&
|
||||
!dst->child->xfrm && x->type->get_mtu) {
|
||||
!xdst->child->xfrm && x->type->get_mtu) {
|
||||
mtu = x->type->get_mtu(x, xdst->child_mtu_cached);
|
||||
|
||||
if (skb->len <= mtu)
|
||||
|
|
Loading…
Reference in a new issue