Commit 2774c131 authored by David S. Miller's avatar David S. Miller

xfrm: Handle blackhole route creation via afinfo.

That way we don't have to potentially do this in every xfrm_lookup()
caller.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 69ead7af
...@@ -432,17 +432,9 @@ static inline int xfrm_lookup(struct net *net, struct dst_entry **dst_p, ...@@ -432,17 +432,9 @@ static inline int xfrm_lookup(struct net *net, struct dst_entry **dst_p,
{ {
return 0; return 0;
} }
static inline int __xfrm_lookup(struct net *net, struct dst_entry **dst_p,
const struct flowi *fl, struct sock *sk,
int flags)
{
return 0;
}
#else #else
extern int xfrm_lookup(struct net *net, struct dst_entry **dst_p, extern int xfrm_lookup(struct net *net, struct dst_entry **dst_p,
const struct flowi *fl, struct sock *sk, int flags); const struct flowi *fl, struct sock *sk, int flags);
extern int __xfrm_lookup(struct net *net, struct dst_entry **dst_p,
const struct flowi *fl, struct sock *sk, int flags);
#endif #endif
#endif #endif
......
...@@ -520,8 +520,8 @@ extern struct dst_entry * ip6_sk_dst_lookup_flow(struct sock *sk, ...@@ -520,8 +520,8 @@ extern struct dst_entry * ip6_sk_dst_lookup_flow(struct sock *sk,
struct flowi *fl, struct flowi *fl,
const struct in6_addr *final_dst, const struct in6_addr *final_dst,
bool can_sleep); bool can_sleep);
extern struct dst_entry * ip6_dst_blackhole(struct net *net, extern struct dst_entry * ip6_blackhole_route(struct net *net,
struct dst_entry *orig_dst); struct dst_entry *orig_dst);
/* /*
* skb processing functions * skb processing functions
......
...@@ -121,6 +121,7 @@ extern void rt_cache_flush_batch(struct net *net); ...@@ -121,6 +121,7 @@ extern void rt_cache_flush_batch(struct net *net);
extern int __ip_route_output_key(struct net *, struct rtable **, const struct flowi *flp); extern int __ip_route_output_key(struct net *, struct rtable **, const struct flowi *flp);
extern int ip_route_output_key(struct net *, struct rtable **, struct flowi *flp); extern int ip_route_output_key(struct net *, struct rtable **, struct flowi *flp);
extern int ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk); extern int ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk);
extern struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_orig);
extern int ip_route_input_common(struct sk_buff *skb, __be32 dst, __be32 src, extern int ip_route_input_common(struct sk_buff *skb, __be32 dst, __be32 src,
u8 tos, struct net_device *devin, bool noref); u8 tos, struct net_device *devin, bool noref);
......
...@@ -280,6 +280,7 @@ struct xfrm_policy_afinfo { ...@@ -280,6 +280,7 @@ struct xfrm_policy_afinfo {
int (*fill_dst)(struct xfrm_dst *xdst, int (*fill_dst)(struct xfrm_dst *xdst,
struct net_device *dev, struct net_device *dev,
const struct flowi *fl); const struct flowi *fl);
struct dst_entry *(*blackhole_route)(struct net *net, struct dst_entry *orig);
}; };
extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo); extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo);
......
...@@ -2675,12 +2675,10 @@ static struct dst_ops ipv4_dst_blackhole_ops = { ...@@ -2675,12 +2675,10 @@ static struct dst_ops ipv4_dst_blackhole_ops = {
.update_pmtu = ipv4_rt_blackhole_update_pmtu, .update_pmtu = ipv4_rt_blackhole_update_pmtu,
}; };
struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_orig)
static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi *flp)
{ {
struct rtable *ort = *rp; struct rtable *rt = dst_alloc(&ipv4_dst_blackhole_ops, 1);
struct rtable *rt = (struct rtable *) struct rtable *ort = (struct rtable *) dst_orig;
dst_alloc(&ipv4_dst_blackhole_ops, 1);
if (rt) { if (rt) {
struct dst_entry *new = &rt->dst; struct dst_entry *new = &rt->dst;
...@@ -2714,9 +2712,9 @@ static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi ...@@ -2714,9 +2712,9 @@ static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi
dst_free(new); dst_free(new);
} }
dst_release(&(*rp)->dst); dst_release(dst_orig);
*rp = rt;
return rt ? 0 : -ENOMEM; return rt ? &rt->dst : ERR_PTR(-ENOMEM);
} }
int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp, int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp,
...@@ -2732,11 +2730,7 @@ int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp, ...@@ -2732,11 +2730,7 @@ int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp,
flp->fl4_src = (*rp)->rt_src; flp->fl4_src = (*rp)->rt_src;
if (!flp->fl4_dst) if (!flp->fl4_dst)
flp->fl4_dst = (*rp)->rt_dst; flp->fl4_dst = (*rp)->rt_dst;
err = __xfrm_lookup(net, (struct dst_entry **)rp, flp, sk, 0); return xfrm_lookup(net, (struct dst_entry **)rp, flp, sk, 0);
if (err == -EREMOTE)
err = ipv4_dst_blackhole(net, rp, flp);
return err;
} }
return 0; return 0;
......
...@@ -234,6 +234,7 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = { ...@@ -234,6 +234,7 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
.get_tos = xfrm4_get_tos, .get_tos = xfrm4_get_tos,
.init_path = xfrm4_init_path, .init_path = xfrm4_init_path,
.fill_dst = xfrm4_fill_dst, .fill_dst = xfrm4_fill_dst,
.blackhole_route = ipv4_blackhole_route,
}; };
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
......
...@@ -1025,18 +1025,12 @@ struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi *fl, ...@@ -1025,18 +1025,12 @@ struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi *fl,
return ERR_PTR(err); return ERR_PTR(err);
if (final_dst) if (final_dst)
ipv6_addr_copy(&fl->fl6_dst, final_dst); ipv6_addr_copy(&fl->fl6_dst, final_dst);
if (can_sleep) { if (can_sleep)
fl->flags |= FLOWI_FLAG_CAN_SLEEP; fl->flags |= FLOWI_FLAG_CAN_SLEEP;
err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
if (err == -EREMOTE) err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
return ip6_dst_blackhole(sock_net(sk), dst); if (err)
if (err) return ERR_PTR(err);
return ERR_PTR(err);
} else {
err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
if (err)
return ERR_PTR(err);
}
return dst; return dst;
} }
EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow); EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow);
...@@ -1070,18 +1064,12 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi *fl, ...@@ -1070,18 +1064,12 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi *fl,
return ERR_PTR(err); return ERR_PTR(err);
if (final_dst) if (final_dst)
ipv6_addr_copy(&fl->fl6_dst, final_dst); ipv6_addr_copy(&fl->fl6_dst, final_dst);
if (can_sleep) { if (can_sleep)
fl->flags |= FLOWI_FLAG_CAN_SLEEP; fl->flags |= FLOWI_FLAG_CAN_SLEEP;
err = __xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
if (err == -EREMOTE) err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
return ip6_dst_blackhole(sock_net(sk), dst); if (err)
if (err) return ERR_PTR(err);
return ERR_PTR(err);
} else {
err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0);
if (err)
return ERR_PTR(err);
}
return dst; return dst;
} }
EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow);
......
...@@ -870,7 +870,7 @@ struct dst_entry * ip6_route_output(struct net *net, struct sock *sk, ...@@ -870,7 +870,7 @@ struct dst_entry * ip6_route_output(struct net *net, struct sock *sk,
EXPORT_SYMBOL(ip6_route_output); EXPORT_SYMBOL(ip6_route_output);
struct dst_entry *ip6_dst_blackhole(struct net *net, struct dst_entry *dst_orig) struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig)
{ {
struct rt6_info *rt = dst_alloc(&ip6_dst_blackhole_ops, 1); struct rt6_info *rt = dst_alloc(&ip6_dst_blackhole_ops, 1);
struct rt6_info *ort = (struct rt6_info *) dst_orig; struct rt6_info *ort = (struct rt6_info *) dst_orig;
...@@ -907,7 +907,6 @@ struct dst_entry *ip6_dst_blackhole(struct net *net, struct dst_entry *dst_orig) ...@@ -907,7 +907,6 @@ struct dst_entry *ip6_dst_blackhole(struct net *net, struct dst_entry *dst_orig)
dst_release(dst_orig); dst_release(dst_orig);
return new ? new : ERR_PTR(-ENOMEM); return new ? new : ERR_PTR(-ENOMEM);
} }
EXPORT_SYMBOL_GPL(ip6_dst_blackhole);
/* /*
* Destination cache support functions * Destination cache support functions
......
...@@ -274,6 +274,7 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { ...@@ -274,6 +274,7 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
.get_tos = xfrm6_get_tos, .get_tos = xfrm6_get_tos,
.init_path = xfrm6_init_path, .init_path = xfrm6_init_path,
.fill_dst = xfrm6_fill_dst, .fill_dst = xfrm6_fill_dst,
.blackhole_route = ip6_blackhole_route,
}; };
static int __init xfrm6_policy_init(void) static int __init xfrm6_policy_init(void)
......
...@@ -1735,14 +1735,31 @@ xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir, ...@@ -1735,14 +1735,31 @@ xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir,
return ERR_PTR(err); return ERR_PTR(err);
} }
static struct dst_entry *make_blackhole(struct net *net, u16 family,
struct dst_entry *dst_orig)
{
struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
struct dst_entry *ret;
if (!afinfo) {
dst_release(dst_orig);
ret = ERR_PTR(-EINVAL);
} else {
ret = afinfo->blackhole_route(net, dst_orig);
}
xfrm_policy_put_afinfo(afinfo);
return ret;
}
/* Main function: finds/creates a bundle for given flow. /* Main function: finds/creates a bundle for given flow.
* *
* At the moment we eat a raw IP route. Mostly to speed up lookups * At the moment we eat a raw IP route. Mostly to speed up lookups
* on interfaces with disabled IPsec. * on interfaces with disabled IPsec.
*/ */
int __xfrm_lookup(struct net *net, struct dst_entry **dst_p, int xfrm_lookup(struct net *net, struct dst_entry **dst_p,
const struct flowi *fl, const struct flowi *fl,
struct sock *sk, int flags) struct sock *sk, int flags)
{ {
struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
struct flow_cache_object *flo; struct flow_cache_object *flo;
...@@ -1829,7 +1846,12 @@ int __xfrm_lookup(struct net *net, struct dst_entry **dst_p, ...@@ -1829,7 +1846,12 @@ int __xfrm_lookup(struct net *net, struct dst_entry **dst_p,
dst_release(dst); dst_release(dst);
xfrm_pols_put(pols, drop_pols); xfrm_pols_put(pols, drop_pols);
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
return -EREMOTE;
dst = make_blackhole(net, family, dst_orig);
if (IS_ERR(dst))
return PTR_ERR(dst);
*dst_p = dst;
return 0;
} }
if (fl->flags & FLOWI_FLAG_CAN_SLEEP) { if (fl->flags & FLOWI_FLAG_CAN_SLEEP) {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
...@@ -1895,22 +1917,6 @@ int __xfrm_lookup(struct net *net, struct dst_entry **dst_p, ...@@ -1895,22 +1917,6 @@ int __xfrm_lookup(struct net *net, struct dst_entry **dst_p,
xfrm_pols_put(pols, drop_pols); xfrm_pols_put(pols, drop_pols);
return err; return err;
} }
EXPORT_SYMBOL(__xfrm_lookup);
int xfrm_lookup(struct net *net, struct dst_entry **dst_p,
const struct flowi *fl,
struct sock *sk, int flags)
{
int err = __xfrm_lookup(net, dst_p, fl, sk, flags);
if (err == -EREMOTE) {
dst_release(*dst_p);
*dst_p = NULL;
err = -EAGAIN;
}
return err;
}
EXPORT_SYMBOL(xfrm_lookup); EXPORT_SYMBOL(xfrm_lookup);
static inline int static inline int
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment