aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2010-04-06 20:30:04 -0400
committerDavid S. Miller <davem@davemloft.net>2010-04-07 06:43:18 -0400
commitfe1a5f031e76bd8761a7803d75b95ee96e84a574 (patch)
treec74392cef02c1529b00df6c5d0b8f4239fe091c3 /net/xfrm
parent8020eb82d4c37d21dade0abeb8feed265a01819e (diff)
flow: virtualize flow cache entry methods
This allows to validate the cached object before returning it. It also allows to destruct object properly, if the last reference was held in flow cache. This is also a prepartion for caching bundles in the flow cache. In return for virtualizing the methods, we save on: - not having to regenerate the whole flow cache on policy removal: each flow matching a killed policy gets refreshed as the getter function notices it smartly. - we do not have to call flow_cache_flush from policy gc, since the flow cache now properly deletes the object if it had any references Signed-off-by: Timo Teras <timo.teras@iki.fi> Acked-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/xfrm')
-rw-r--r--net/xfrm/xfrm_policy.c112
1 files changed, 74 insertions, 38 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 82789cf1c632..7722baeb140d 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -216,6 +216,35 @@ expired:
216 xfrm_pol_put(xp); 216 xfrm_pol_put(xp);
217} 217}
218 218
219static struct flow_cache_object *xfrm_policy_flo_get(struct flow_cache_object *flo)
220{
221 struct xfrm_policy *pol = container_of(flo, struct xfrm_policy, flo);
222
223 if (unlikely(pol->walk.dead))
224 flo = NULL;
225 else
226 xfrm_pol_hold(pol);
227
228 return flo;
229}
230
231static int xfrm_policy_flo_check(struct flow_cache_object *flo)
232{
233 struct xfrm_policy *pol = container_of(flo, struct xfrm_policy, flo);
234
235 return !pol->walk.dead;
236}
237
238static void xfrm_policy_flo_delete(struct flow_cache_object *flo)
239{
240 xfrm_pol_put(container_of(flo, struct xfrm_policy, flo));
241}
242
243static const struct flow_cache_ops xfrm_policy_fc_ops = {
244 .get = xfrm_policy_flo_get,
245 .check = xfrm_policy_flo_check,
246 .delete = xfrm_policy_flo_delete,
247};
219 248
220/* Allocate xfrm_policy. Not used here, it is supposed to be used by pfkeyv2 249/* Allocate xfrm_policy. Not used here, it is supposed to be used by pfkeyv2
221 * SPD calls. 250 * SPD calls.
@@ -236,6 +265,7 @@ struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp)
236 atomic_set(&policy->refcnt, 1); 265 atomic_set(&policy->refcnt, 1);
237 setup_timer(&policy->timer, xfrm_policy_timer, 266 setup_timer(&policy->timer, xfrm_policy_timer,
238 (unsigned long)policy); 267 (unsigned long)policy);
268 policy->flo.ops = &xfrm_policy_fc_ops;
239 } 269 }
240 return policy; 270 return policy;
241} 271}
@@ -269,9 +299,6 @@ static void xfrm_policy_gc_kill(struct xfrm_policy *policy)
269 if (del_timer(&policy->timer)) 299 if (del_timer(&policy->timer))
270 atomic_dec(&policy->refcnt); 300 atomic_dec(&policy->refcnt);
271 301
272 if (atomic_read(&policy->refcnt) > 1)
273 flow_cache_flush();
274
275 xfrm_pol_put(policy); 302 xfrm_pol_put(policy);
276} 303}
277 304
@@ -661,10 +688,8 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
661 } 688 }
662 write_unlock_bh(&xfrm_policy_lock); 689 write_unlock_bh(&xfrm_policy_lock);
663 690
664 if (ret && delete) { 691 if (ret && delete)
665 atomic_inc(&flow_cache_genid);
666 xfrm_policy_kill(ret); 692 xfrm_policy_kill(ret);
667 }
668 return ret; 693 return ret;
669} 694}
670EXPORT_SYMBOL(xfrm_policy_bysel_ctx); 695EXPORT_SYMBOL(xfrm_policy_bysel_ctx);
@@ -703,10 +728,8 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
703 } 728 }
704 write_unlock_bh(&xfrm_policy_lock); 729 write_unlock_bh(&xfrm_policy_lock);
705 730
706 if (ret && delete) { 731 if (ret && delete)
707 atomic_inc(&flow_cache_genid);
708 xfrm_policy_kill(ret); 732 xfrm_policy_kill(ret);
709 }
710 return ret; 733 return ret;
711} 734}
712EXPORT_SYMBOL(xfrm_policy_byid); 735EXPORT_SYMBOL(xfrm_policy_byid);
@@ -822,7 +845,6 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
822 } 845 }
823 if (!cnt) 846 if (!cnt)
824 err = -ESRCH; 847 err = -ESRCH;
825 atomic_inc(&flow_cache_genid);
826out: 848out:
827 write_unlock_bh(&xfrm_policy_lock); 849 write_unlock_bh(&xfrm_policy_lock);
828 return err; 850 return err;
@@ -976,32 +998,35 @@ fail:
976 return ret; 998 return ret;
977} 999}
978 1000
979static int xfrm_policy_lookup(struct net *net, struct flowi *fl, u16 family, 1001static struct flow_cache_object *
980 u8 dir, void **objp, atomic_t **obj_refp) 1002xfrm_policy_lookup(struct net *net, struct flowi *fl, u16 family,
1003 u8 dir, struct flow_cache_object *old_obj, void *ctx)
981{ 1004{
982 struct xfrm_policy *pol; 1005 struct xfrm_policy *pol;
983 int err = 0; 1006
1007 if (old_obj)
1008 xfrm_pol_put(container_of(old_obj, struct xfrm_policy, flo));
984 1009
985#ifdef CONFIG_XFRM_SUB_POLICY 1010#ifdef CONFIG_XFRM_SUB_POLICY
986 pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_SUB, fl, family, dir); 1011 pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_SUB, fl, family, dir);
987 if (IS_ERR(pol)) { 1012 if (IS_ERR(pol))
988 err = PTR_ERR(pol); 1013 return ERR_CAST(pol);
989 pol = NULL; 1014 if (pol)
990 } 1015 goto found;
991 if (pol || err)
992 goto end;
993#endif 1016#endif
994 pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family, dir); 1017 pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family, dir);
995 if (IS_ERR(pol)) { 1018 if (IS_ERR(pol))
996 err = PTR_ERR(pol); 1019 return ERR_CAST(pol);
997 pol = NULL; 1020 if (pol)
998 } 1021 goto found;
999#ifdef CONFIG_XFRM_SUB_POLICY 1022 return NULL;
1000end: 1023
1001#endif 1024found:
1002 if ((*objp = (void *) pol) != NULL) 1025 /* Resolver returns two references:
1003 *obj_refp = &pol->refcnt; 1026 * one for cache and one for caller of flow_cache_lookup() */
1004 return err; 1027 xfrm_pol_hold(pol);
1028
1029 return &pol->flo;
1005} 1030}
1006 1031
1007static inline int policy_to_flow_dir(int dir) 1032static inline int policy_to_flow_dir(int dir)
@@ -1091,8 +1116,6 @@ int xfrm_policy_delete(struct xfrm_policy *pol, int dir)
1091 pol = __xfrm_policy_unlink(pol, dir); 1116 pol = __xfrm_policy_unlink(pol, dir);
1092 write_unlock_bh(&xfrm_policy_lock); 1117 write_unlock_bh(&xfrm_policy_lock);
1093 if (pol) { 1118 if (pol) {
1094 if (dir < XFRM_POLICY_MAX)
1095 atomic_inc(&flow_cache_genid);
1096 xfrm_policy_kill(pol); 1119 xfrm_policy_kill(pol);
1097 return 0; 1120 return 0;
1098 } 1121 }
@@ -1578,18 +1601,24 @@ restart:
1578 } 1601 }
1579 1602
1580 if (!policy) { 1603 if (!policy) {
1604 struct flow_cache_object *flo;
1605
1581 /* To accelerate a bit... */ 1606 /* To accelerate a bit... */
1582 if ((dst_orig->flags & DST_NOXFRM) || 1607 if ((dst_orig->flags & DST_NOXFRM) ||
1583 !net->xfrm.policy_count[XFRM_POLICY_OUT]) 1608 !net->xfrm.policy_count[XFRM_POLICY_OUT])
1584 goto nopol; 1609 goto nopol;
1585 1610
1586 policy = flow_cache_lookup(net, fl, dst_orig->ops->family, 1611 flo = flow_cache_lookup(net, fl, dst_orig->ops->family,
1587 dir, xfrm_policy_lookup); 1612 dir, xfrm_policy_lookup, NULL);
1588 err = PTR_ERR(policy); 1613 err = PTR_ERR(flo);
1589 if (IS_ERR(policy)) { 1614 if (IS_ERR(flo)) {
1590 XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR); 1615 XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
1591 goto dropdst; 1616 goto dropdst;
1592 } 1617 }
1618 if (flo)
1619 policy = container_of(flo, struct xfrm_policy, flo);
1620 else
1621 policy = NULL;
1593 } 1622 }
1594 1623
1595 if (!policy) 1624 if (!policy)
@@ -1939,9 +1968,16 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
1939 } 1968 }
1940 } 1969 }
1941 1970
1942 if (!pol) 1971 if (!pol) {
1943 pol = flow_cache_lookup(net, &fl, family, fl_dir, 1972 struct flow_cache_object *flo;
1944 xfrm_policy_lookup); 1973
1974 flo = flow_cache_lookup(net, &fl, family, fl_dir,
1975 xfrm_policy_lookup, NULL);
1976 if (IS_ERR_OR_NULL(flo))
1977 pol = ERR_CAST(flo);
1978 else
1979 pol = container_of(flo, struct xfrm_policy, flo);
1980 }
1945 1981
1946 if (IS_ERR(pol)) { 1982 if (IS_ERR(pol)) {
1947 XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR); 1983 XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);