aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm
diff options
context:
space:
mode:
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);