Skip to content

Commit

Permalink
xfrm: Move dst->path into struct xfrm_dst
Browse files Browse the repository at this point in the history
The first member of an IPSEC route bundle chain sets it's dst->path to
the underlying ipv4/ipv6 route that carries the bundle.

Stated another way, if one were to follow the xfrm_dst->child chain of
the bundle, the final non-NULL pointer would be the path and point to
either an ipv4 or an ipv6 route.

This is largely used to make sure that PMTU events propagate down to
the correct ipv4 or ipv6 route.

When we don't have the top of an IPSEC bundle 'dst->path == dst'.

Move it down into xfrm_dst and key off of dst->xfrm.

Signed-off-by: David S. Miller <[email protected]>
Reviewed-by: Eric Dumazet <[email protected]>
  • Loading branch information
davem330 committed Nov 30, 2017
1 parent 3a2232e commit 0f6c480
Show file tree
Hide file tree
Showing 9 changed files with 33 additions and 29 deletions.
3 changes: 1 addition & 2 deletions include/net/dst.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ struct dst_entry {
struct dst_ops *ops;
unsigned long _metrics;
unsigned long expires;
struct dst_entry *path;
#ifdef CONFIG_XFRM
struct xfrm_state *xfrm;
#else
Expand Down Expand Up @@ -87,7 +86,7 @@ struct dst_entry {
* Align __refcnt to a 64 bytes alignment
* (L1_CACHE_SIZE would be too much)
*/
long __pad_to_align_refcnt[4];
long __pad_to_align_refcnt[5];
#endif
/*
* __refcnt wants to be on a different cache line from
Expand Down
15 changes: 14 additions & 1 deletion include/net/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,7 @@ struct xfrm_dst {
} u;
struct dst_entry *route;
struct dst_entry *child;
struct dst_entry *path;
struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
int num_pols, num_xfrms;
u32 xfrm_genid;
Expand All @@ -995,6 +996,18 @@ struct xfrm_dst {
u32 path_cookie;
};

static inline struct dst_entry *xfrm_dst_path(const struct dst_entry *dst)
{
#ifdef CONFIG_XFRM
if (dst->xfrm) {
const struct xfrm_dst *xdst = (const struct xfrm_dst *) dst;

return xdst->path;
}
#endif
return (struct dst_entry *) dst;
}

static inline struct dst_entry *xfrm_dst_child(const struct dst_entry *dst)
{
#ifdef CONFIG_XFRM
Expand Down Expand Up @@ -1889,7 +1902,7 @@ static inline bool xfrm_dst_offload_ok(struct dst_entry *dst)
return false;

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

Expand Down
1 change: 0 additions & 1 deletion net/bridge/br_nf_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ void br_netfilter_rtable_init(struct net_bridge *br)

atomic_set(&rt->dst.__refcnt, 1);
rt->dst.dev = br->dev;
rt->dst.path = &rt->dst;
dst_init_metrics(&rt->dst, br_dst_default_metrics, true);
rt->dst.flags = DST_NOXFRM | DST_FAKE_RTABLE;
rt->dst.ops = &fake_dst_ops;
Expand Down
1 change: 0 additions & 1 deletion net/core/dst.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ void dst_init(struct dst_entry *dst, struct dst_ops *ops,
dst->ops = ops;
dst_init_metrics(dst, dst_default_metrics.metrics, true);
dst->expires = 0UL;
dst->path = dst;
#ifdef CONFIG_XFRM
dst->xfrm = NULL;
#endif
Expand Down
2 changes: 1 addition & 1 deletion net/ipv4/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -1106,7 +1106,7 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
new = true;
}

__ip_rt_update_pmtu((struct rtable *) rt->dst.path, &fl4, mtu);
__ip_rt_update_pmtu((struct rtable *) xfrm_dst_path(&rt->dst), &fl4, mtu);

if (!dst_check(&rt->dst, 0)) {
if (new)
Expand Down
4 changes: 2 additions & 2 deletions net/ipv6/ip6_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -1201,13 +1201,13 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
rt->dst.dev->mtu : dst_mtu(&rt->dst);
else
mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
rt->dst.dev->mtu : dst_mtu(rt->dst.path);
rt->dst.dev->mtu : dst_mtu(xfrm_dst_path(&rt->dst));
if (np->frag_size < mtu) {
if (np->frag_size)
mtu = np->frag_size;
}
cork->base.fragsize = mtu;
if (dst_allfrag(rt->dst.path))
if (dst_allfrag(xfrm_dst_path(&rt->dst)))
cork->base.flags |= IPCORK_ALLFRAG;
cork->base.length = 0;

Expand Down
6 changes: 0 additions & 6 deletions net/ipv6/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -4596,8 +4596,6 @@ static int __net_init ip6_route_net_init(struct net *net)
GFP_KERNEL);
if (!net->ipv6.ip6_null_entry)
goto out_ip6_dst_entries;
net->ipv6.ip6_null_entry->dst.path =
(struct dst_entry *)net->ipv6.ip6_null_entry;
net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
dst_init_metrics(&net->ipv6.ip6_null_entry->dst,
ip6_template_metrics, true);
Expand All @@ -4609,8 +4607,6 @@ static int __net_init ip6_route_net_init(struct net *net)
GFP_KERNEL);
if (!net->ipv6.ip6_prohibit_entry)
goto out_ip6_null_entry;
net->ipv6.ip6_prohibit_entry->dst.path =
(struct dst_entry *)net->ipv6.ip6_prohibit_entry;
net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst,
ip6_template_metrics, true);
Expand All @@ -4620,8 +4616,6 @@ static int __net_init ip6_route_net_init(struct net *net)
GFP_KERNEL);
if (!net->ipv6.ip6_blk_hole_entry)
goto out_ip6_prohibit_entry;
net->ipv6.ip6_blk_hole_entry->dst.path =
(struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
ip6_template_metrics, true);
Expand Down
2 changes: 1 addition & 1 deletion net/xfrm/xfrm_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x)
if (!x->type_offload || x->encap)
return false;

if ((x->xso.offload_handle && (dev == dst->path->dev)) &&
if ((x->xso.offload_handle && (dev == xfrm_dst_path(dst)->dev)) &&
!xdst->child->xfrm && x->type->get_mtu) {
mtu = x->type->get_mtu(x, xdst->child_mtu_cached);

Expand Down
28 changes: 14 additions & 14 deletions net/xfrm/xfrm_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -1626,7 +1626,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
}

xfrm_dst_set_child(xdst_prev, dst);
xdst0->u.dst.path = dst;
xdst0->path = dst;

err = -ENODEV;
dev = dst->dev;
Expand Down Expand Up @@ -1879,8 +1879,8 @@ static void xfrm_policy_queue_process(struct timer_list *t)
xfrm_decode_session(skb, &fl, dst->ops->family);
spin_unlock(&pq->hold_queue.lock);

dst_hold(dst->path);
dst = xfrm_lookup(net, dst->path, &fl, sk, 0);
dst_hold(xfrm_dst_path(dst));
dst = xfrm_lookup(net, xfrm_dst_path(dst), &fl, sk, 0);
if (IS_ERR(dst))
goto purge_queue;

Expand Down Expand Up @@ -1909,8 +1909,8 @@ static void xfrm_policy_queue_process(struct timer_list *t)
skb = __skb_dequeue(&list);

xfrm_decode_session(skb, &fl, skb_dst(skb)->ops->family);
dst_hold(skb_dst(skb)->path);
dst = xfrm_lookup(net, skb_dst(skb)->path, &fl, skb->sk, 0);
dst_hold(xfrm_dst_path(skb_dst(skb)));
dst = xfrm_lookup(net, xfrm_dst_path(skb_dst(skb)), &fl, skb->sk, 0);
if (IS_ERR(dst)) {
kfree_skb(skb);
continue;
Expand Down Expand Up @@ -2012,7 +2012,7 @@ static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net,

dst_hold(dst);
xfrm_dst_set_child(xdst, dst);
dst1->path = dst;
xdst->path = dst;

xfrm_init_path((struct xfrm_dst *)dst1, dst, 0);

Expand Down Expand Up @@ -2630,7 +2630,7 @@ static int xfrm_bundle_ok(struct xfrm_dst *first)
struct xfrm_dst *last;
u32 mtu;

if (!dst_check(dst->path, ((struct xfrm_dst *)dst)->path_cookie) ||
if (!dst_check(xfrm_dst_path(dst), ((struct xfrm_dst *)dst)->path_cookie) ||
(dst->dev && !netif_running(dst->dev)))
return 0;

Expand Down Expand Up @@ -2691,22 +2691,20 @@ static int xfrm_bundle_ok(struct xfrm_dst *first)

static unsigned int xfrm_default_advmss(const struct dst_entry *dst)
{
return dst_metric_advmss(dst->path);
return dst_metric_advmss(xfrm_dst_path(dst));
}

static unsigned int xfrm_mtu(const struct dst_entry *dst)
{
unsigned int mtu = dst_metric_raw(dst, RTAX_MTU);

return mtu ? : dst_mtu(dst->path);
return mtu ? : dst_mtu(xfrm_dst_path(dst));
}

static const void *xfrm_get_dst_nexthop(const struct dst_entry *dst,
const void *daddr)
{
const struct dst_entry *path = dst->path;

for (; dst != path; dst = xfrm_dst_child(dst)) {
while (dst->xfrm) {
const struct xfrm_state *xfrm = dst->xfrm;

if (xfrm->props.mode == XFRM_MODE_TRANSPORT)
Expand All @@ -2715,6 +2713,8 @@ static const void *xfrm_get_dst_nexthop(const struct dst_entry *dst,
daddr = xfrm->coaddr;
else if (!(xfrm->type->flags & XFRM_TYPE_LOCAL_COADDR))
daddr = &xfrm->id.daddr;

dst = xfrm_dst_child(dst);
}
return daddr;
}
Expand All @@ -2723,7 +2723,7 @@ static struct neighbour *xfrm_neigh_lookup(const struct dst_entry *dst,
struct sk_buff *skb,
const void *daddr)
{
const struct dst_entry *path = dst->path;
const struct dst_entry *path = xfrm_dst_path(dst);

if (!skb)
daddr = xfrm_get_dst_nexthop(dst, daddr);
Expand All @@ -2732,7 +2732,7 @@ static struct neighbour *xfrm_neigh_lookup(const struct dst_entry *dst,

static void xfrm_confirm_neigh(const struct dst_entry *dst, const void *daddr)
{
const struct dst_entry *path = dst->path;
const struct dst_entry *path = xfrm_dst_path(dst);

daddr = xfrm_get_dst_nexthop(dst, daddr);
path->ops->confirm_neigh(path, daddr);
Expand Down

0 comments on commit 0f6c480

Please sign in to comment.