From: YOSHIFUJI Hideaki <[EMAIL PROTECTED]>
Date: Thu, 24 Aug 2006 00:02:40 +0900

> Add Kconfig to support sub policy.
> 
> Signed-off-by: Masahide NAKAMURA <[EMAIL PROTECTED]>
> Signed-off-by: YOSHIFUJI Hideaki <[EMAIL PROTECTED]>

Applied to net-2.6.19

Note that sub-policy support is probably the area which will
need some simplifications and refactoring.

It is clear that IPSEC performance is tied strictly to the
speed at which routes can be resolved.  Sub-policies add more
overhead to this area.

We wish to push fully resolved IPSEC routes into the flow cache so
that we got not only policy but pre-lookup of bundle entry as a result
of lookup.  I attach an example patch implementing that (it is
relative to the tree before all the MIPV6 changes) to give you an
idea.

Also, if sub-policies are really the final way to address the
MIPV6+IPSEC separation issue, probably we should just kill the
kernel config option and optimize it as best we can.

diff --git a/include/net/flow.h b/include/net/flow.h
index 04d89f7..ce0e1a8 100644
--- a/include/net/flow.h
+++ b/include/net/flow.h
@@ -84,12 +84,16 @@ #define FLOW_DIR_IN 0
 #define FLOW_DIR_OUT   1
 #define FLOW_DIR_FWD   2
 
-struct sock;
 typedef void (*flow_resolve_t)(struct flowi *key, u32 sk_sid, u16 family, u8 
dir,
                               void **objp, atomic_t **obj_refp);
 
-extern void *flow_cache_lookup(struct flowi *key, u32 sk_sid, u16 family, u8 
dir,
-                              flow_resolve_t resolver);
+struct dst_entry;
+extern void *flow_cache_lookup(struct flowi *key, u32 sk_sid,
+                              u16 family, u8 dir,
+                              struct dst_entry **dstp,
+                              flow_resolve_t resolver);
+extern void flow_cache_dst_set(struct flowi *key, u32 sk_sid,
+                              u16 family, u8 dir, struct dst_entry *dst);
 extern void flow_cache_flush(void);
 extern atomic_t flow_cache_genid;
 
diff --git a/net/core/flow.c b/net/core/flow.c
index 2191af5..7949020 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -25,6 +25,7 @@ #include <net/flow.h>
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
 #include <linux/security.h>
+#include <net/dst.h>
 
 struct flow_cache_entry {
        struct flow_cache_entry *next;
@@ -35,6 +36,7 @@ struct flow_cache_entry {
        u32                     sk_sid;
        void                    *object;
        atomic_t                *object_ref;
+       struct dst_entry        *dst;
 };
 
 atomic_t flow_cache_genid = ATOMIC_INIT(0);
@@ -166,7 +168,7 @@ static int flow_key_compare(struct flowi
 }
 
 void *flow_cache_lookup(struct flowi *key, u32 sk_sid, u16 family, u8 dir,
-                       flow_resolve_t resolver)
+                       struct dst_entry **dstp, flow_resolve_t resolver)
 {
        struct flow_cache_entry *fle, **head;
        unsigned int hash;
@@ -196,6 +198,8 @@ void *flow_cache_lookup(struct flowi *ke
 
                                if (ret)
                                        atomic_inc(fle->object_ref);
+                               if (dstp)
+                                       *dstp = dst_clone(fle->dst);
                                local_bh_enable();
 
                                return ret;
@@ -217,6 +221,7 @@ void *flow_cache_lookup(struct flowi *ke
                        fle->sk_sid = sk_sid;
                        memcpy(&fle->key, key, sizeof(*key));
                        fle->object = NULL;
+                       fle->dst = NULL;
                        flow_count(cpu)++;
                }
        }
@@ -245,6 +250,34 @@ nocache:
        }
 }
 
+void flow_cache_dst_set(struct flowi *key, u32 sk_sid, u16 family, u8 dir,
+                       struct dst_entry *dst)
+{
+       struct flow_cache_entry *fle, **head;
+       unsigned int hash;
+       int cpu;
+
+       local_bh_disable();
+       cpu = smp_processor_id();
+       hash = flow_hash_code(key, cpu);
+       head = &flow_table(cpu)[hash];
+       for (fle = *head; fle; fle = fle->next) {
+               if (fle->family == family &&
+                   fle->dir == dir &&
+                   fle->sk_sid == sk_sid &&
+                   flow_key_compare(key, &fle->key) == 0) {
+                       if (fle->genid == atomic_read(&flow_cache_genid)) {
+                               struct dst_entry *orig = fle->dst;
+
+                               dst_release(orig);
+                               fle->dst = dst_clone(dst);
+                       }
+                       break;
+               }
+       }
+       local_bh_enable();
+}
+
 static void flow_cache_flush_tasklet(unsigned long data)
 {
        struct flow_flush_info *info = (void *)data;
@@ -264,6 +297,8 @@ static void flow_cache_flush_tasklet(uns
 
                        fle->object = NULL;
                        atomic_dec(fle->object_ref);
+                       dst_release(fle->dst);
+                       fle->dst = NULL;
                }
        }
 
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 554f0db..2d4cab5 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1149,7 +1149,7 @@ int xfrm_lookup(struct dst_entry **dst_p
        struct xfrm_state *xfrm[XFRM_MAX_DEPTH];
        struct dst_entry *dst, *dst_orig = *dst_p;
        int nx = 0;
-       int err;
+       int err, sock_policy;
        u32 genid;
        u16 family;
        u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT);
@@ -1157,16 +1157,21 @@ int xfrm_lookup(struct dst_entry **dst_p
 restart:
        genid = atomic_read(&flow_cache_genid);
        policy = NULL;
-       if (sk && sk->sk_policy[1])
+       sock_policy = 0;
+       if (sk && sk->sk_policy[XFRM_POLICY_OUT]) {
                policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl, sk_sid);
+               if (policy)
+                       sock_policy = 1;
+       }
 
+       dst = NULL;
        if (!policy) {
                /* To accelerate a bit...  */
                if ((dst_orig->flags & DST_NOXFRM) || 
!xfrm_policy_count[XFRM_POLICY_OUT])
                        return 0;
 
                policy = flow_cache_lookup(fl, sk_sid, dst_orig->ops->family,
-                                          dir, xfrm_policy_lookup);
+                                          dir, &dst, xfrm_policy_lookup);
        }
 
        if (!policy)
@@ -1179,6 +1184,7 @@ restart:
        case XFRM_POLICY_BLOCK:
                /* Prohibit the flow */
                err = -EPERM;
+               dst_release(dst);
                goto error;
 
        case XFRM_POLICY_ALLOW:
@@ -1188,6 +1194,14 @@ restart:
                        return 0;
                }
 
+               /* Cached dst from flow cache?  */
+               if (dst) {
+                       if (likely(!stale_bundle(dst)))
+                               break;
+                       dst_release(dst);
+                       flow_cache_dst_set(fl, sk_sid, family, dir, NULL);
+               }
+
                /* Try to find matching bundle.
                 *
                 * LATER: help from flow cache. It is optional, this
@@ -1199,8 +1213,11 @@ restart:
                        goto error;
                }
 
-               if (dst)
+               if (dst) {
+                       if (!sock_policy)
+                               flow_cache_dst_set(fl, sk_sid, family, dir, 
dst);
                        break;
+               }
 
                nx = xfrm_tmpl_resolve(policy, fl, xfrm, family);
 
@@ -1265,6 +1282,8 @@ restart:
                policy->bundles = dst;
                dst_hold(dst);
                write_unlock_bh(&policy->lock);
+               if (!sock_policy)
+                       flow_cache_dst_set(fl, sk_sid, family, dir, dst);
        }
        *dst_p = dst;
        dst_release(dst_orig);
@@ -1374,7 +1393,7 @@ int __xfrm_policy_check(struct sock *sk,
 
        if (!pol)
                pol = flow_cache_lookup(&fl, sk_sid, family, fl_dir,
-                                       xfrm_policy_lookup);
+                                       NULL, xfrm_policy_lookup);
 
        if (!pol)
                return !skb->sp || !secpath_has_tunnel(skb->sp, 0);

-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to