|
@@ -39,6 +39,11 @@
|
|
|
#define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ))
|
|
|
#define XFRM_MAX_QUEUE_LEN 100
|
|
|
|
|
|
+struct xfrm_flo {
|
|
|
+ struct dst_entry *dst_orig;
|
|
|
+ u8 flags;
|
|
|
+};
|
|
|
+
|
|
|
static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock);
|
|
|
static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO]
|
|
|
__read_mostly;
|
|
@@ -1877,13 +1882,14 @@ static int xdst_queue_output(struct sock *sk, struct sk_buff *skb)
|
|
|
}
|
|
|
|
|
|
static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net,
|
|
|
- struct dst_entry *dst,
|
|
|
+ struct xfrm_flo *xflo,
|
|
|
const struct flowi *fl,
|
|
|
int num_xfrms,
|
|
|
u16 family)
|
|
|
{
|
|
|
int err;
|
|
|
struct net_device *dev;
|
|
|
+ struct dst_entry *dst;
|
|
|
struct dst_entry *dst1;
|
|
|
struct xfrm_dst *xdst;
|
|
|
|
|
@@ -1891,9 +1897,12 @@ static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net,
|
|
|
if (IS_ERR(xdst))
|
|
|
return xdst;
|
|
|
|
|
|
- if (net->xfrm.sysctl_larval_drop || num_xfrms <= 0)
|
|
|
+ if (!(xflo->flags & XFRM_LOOKUP_QUEUE) ||
|
|
|
+ net->xfrm.sysctl_larval_drop ||
|
|
|
+ num_xfrms <= 0)
|
|
|
return xdst;
|
|
|
|
|
|
+ dst = xflo->dst_orig;
|
|
|
dst1 = &xdst->u.dst;
|
|
|
dst_hold(dst);
|
|
|
xdst->route = dst;
|
|
@@ -1935,7 +1944,7 @@ static struct flow_cache_object *
|
|
|
xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir,
|
|
|
struct flow_cache_object *oldflo, void *ctx)
|
|
|
{
|
|
|
- struct dst_entry *dst_orig = (struct dst_entry *)ctx;
|
|
|
+ struct xfrm_flo *xflo = (struct xfrm_flo *)ctx;
|
|
|
struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
|
|
|
struct xfrm_dst *xdst, *new_xdst;
|
|
|
int num_pols = 0, num_xfrms = 0, i, err, pol_dead;
|
|
@@ -1976,7 +1985,8 @@ xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir,
|
|
|
goto make_dummy_bundle;
|
|
|
}
|
|
|
|
|
|
- new_xdst = xfrm_resolve_and_create_bundle(pols, num_pols, fl, family, dst_orig);
|
|
|
+ new_xdst = xfrm_resolve_and_create_bundle(pols, num_pols, fl, family,
|
|
|
+ xflo->dst_orig);
|
|
|
if (IS_ERR(new_xdst)) {
|
|
|
err = PTR_ERR(new_xdst);
|
|
|
if (err != -EAGAIN)
|
|
@@ -2010,7 +2020,7 @@ make_dummy_bundle:
|
|
|
/* We found policies, but there's no bundles to instantiate:
|
|
|
* either because the policy blocks, has no transformations or
|
|
|
* we could not build template (no xfrm_states).*/
|
|
|
- xdst = xfrm_create_dummy_bundle(net, dst_orig, fl, num_xfrms, family);
|
|
|
+ xdst = xfrm_create_dummy_bundle(net, xflo, fl, num_xfrms, family);
|
|
|
if (IS_ERR(xdst)) {
|
|
|
xfrm_pols_put(pols, num_pols);
|
|
|
return ERR_CAST(xdst);
|
|
@@ -2104,13 +2114,18 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
|
|
|
}
|
|
|
|
|
|
if (xdst == NULL) {
|
|
|
+ struct xfrm_flo xflo;
|
|
|
+
|
|
|
+ xflo.dst_orig = dst_orig;
|
|
|
+ xflo.flags = flags;
|
|
|
+
|
|
|
/* To accelerate a bit... */
|
|
|
if ((dst_orig->flags & DST_NOXFRM) ||
|
|
|
!net->xfrm.policy_count[XFRM_POLICY_OUT])
|
|
|
goto nopol;
|
|
|
|
|
|
flo = flow_cache_lookup(net, fl, family, dir,
|
|
|
- xfrm_bundle_lookup, dst_orig);
|
|
|
+ xfrm_bundle_lookup, &xflo);
|
|
|
if (flo == NULL)
|
|
|
goto nopol;
|
|
|
if (IS_ERR(flo)) {
|
|
@@ -2202,7 +2217,8 @@ struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig,
|
|
|
const struct flowi *fl,
|
|
|
struct sock *sk, int flags)
|
|
|
{
|
|
|
- struct dst_entry *dst = xfrm_lookup(net, dst_orig, fl, sk, flags);
|
|
|
+ struct dst_entry *dst = xfrm_lookup(net, dst_orig, fl, sk,
|
|
|
+ flags | XFRM_LOOKUP_QUEUE);
|
|
|
|
|
|
if (IS_ERR(dst) && PTR_ERR(dst) == -EREMOTE)
|
|
|
return make_blackhole(net, dst_orig->ops->family, dst_orig);
|
|
@@ -2476,7 +2492,7 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
|
|
|
|
|
|
skb_dst_force(skb);
|
|
|
|
|
|
- dst = xfrm_lookup(net, skb_dst(skb), &fl, NULL, 0);
|
|
|
+ dst = xfrm_lookup(net, skb_dst(skb), &fl, NULL, XFRM_LOOKUP_QUEUE);
|
|
|
if (IS_ERR(dst)) {
|
|
|
res = 0;
|
|
|
dst = NULL;
|