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: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
69ead7afdf
commit
2774c131b1
10 changed files with 50 additions and 67 deletions
|
@ -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,
|
||||||
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);
|
||||||
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 {
|
||||||
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 = {
|
||||||
.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
|
||||||
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,
|
||||||
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 = {
|
||||||
.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,
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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)
|
||||||
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 = {
|
||||||
.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 @@ error:
|
||||||
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 @@ restart:
|
||||||
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 @@ dropdst:
|
||||||
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
|
||||||
|
|
Loading…
Add table
Reference in a new issue