diff options
-rw-r--r-- | include/net/flow.h | 23 | ||||
-rw-r--r-- | include/net/xfrm.h | 2 | ||||
-rw-r--r-- | net/core/flow.c | 128 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 112 |
4 files changed, 163 insertions, 102 deletions
diff --git a/include/net/flow.h b/include/net/flow.h index 809970b7dfee..bb08692a20b0 100644 --- a/include/net/flow.h +++ b/include/net/flow.h | |||
@@ -86,11 +86,26 @@ struct flowi { | |||
86 | 86 | ||
87 | struct net; | 87 | struct net; |
88 | struct sock; | 88 | struct sock; |
89 | typedef int (*flow_resolve_t)(struct net *net, struct flowi *key, u16 family, | 89 | struct flow_cache_ops; |
90 | u8 dir, void **objp, atomic_t **obj_refp); | 90 | |
91 | struct flow_cache_object { | ||
92 | const struct flow_cache_ops *ops; | ||
93 | }; | ||
94 | |||
95 | struct flow_cache_ops { | ||
96 | struct flow_cache_object *(*get)(struct flow_cache_object *); | ||
97 | int (*check)(struct flow_cache_object *); | ||
98 | void (*delete)(struct flow_cache_object *); | ||
99 | }; | ||
100 | |||
101 | typedef struct flow_cache_object *(*flow_resolve_t)( | ||
102 | struct net *net, struct flowi *key, u16 family, | ||
103 | u8 dir, struct flow_cache_object *oldobj, void *ctx); | ||
104 | |||
105 | extern struct flow_cache_object *flow_cache_lookup( | ||
106 | struct net *net, struct flowi *key, u16 family, | ||
107 | u8 dir, flow_resolve_t resolver, void *ctx); | ||
91 | 108 | ||
92 | extern void *flow_cache_lookup(struct net *net, struct flowi *key, u16 family, | ||
93 | u8 dir, flow_resolve_t resolver); | ||
94 | extern void flow_cache_flush(void); | 109 | extern void flow_cache_flush(void); |
95 | extern atomic_t flow_cache_genid; | 110 | extern atomic_t flow_cache_genid; |
96 | 111 | ||
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index d74e080ba6c9..35396e2dd1dc 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <net/route.h> | 19 | #include <net/route.h> |
20 | #include <net/ipv6.h> | 20 | #include <net/ipv6.h> |
21 | #include <net/ip6_fib.h> | 21 | #include <net/ip6_fib.h> |
22 | #include <net/flow.h> | ||
22 | 23 | ||
23 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
24 | 25 | ||
@@ -481,6 +482,7 @@ struct xfrm_policy { | |||
481 | atomic_t refcnt; | 482 | atomic_t refcnt; |
482 | struct timer_list timer; | 483 | struct timer_list timer; |
483 | 484 | ||
485 | struct flow_cache_object flo; | ||
484 | u32 priority; | 486 | u32 priority; |
485 | u32 index; | 487 | u32 index; |
486 | struct xfrm_mark mark; | 488 | struct xfrm_mark mark; |
diff --git a/net/core/flow.c b/net/core/flow.c index 1d27ca6b421d..521df52a77d2 100644 --- a/net/core/flow.c +++ b/net/core/flow.c | |||
@@ -26,17 +26,16 @@ | |||
26 | #include <linux/security.h> | 26 | #include <linux/security.h> |
27 | 27 | ||
28 | struct flow_cache_entry { | 28 | struct flow_cache_entry { |
29 | struct flow_cache_entry *next; | 29 | struct flow_cache_entry *next; |
30 | u16 family; | 30 | u16 family; |
31 | u8 dir; | 31 | u8 dir; |
32 | u32 genid; | 32 | u32 genid; |
33 | struct flowi key; | 33 | struct flowi key; |
34 | void *object; | 34 | struct flow_cache_object *object; |
35 | atomic_t *object_ref; | ||
36 | }; | 35 | }; |
37 | 36 | ||
38 | struct flow_cache_percpu { | 37 | struct flow_cache_percpu { |
39 | struct flow_cache_entry ** hash_table; | 38 | struct flow_cache_entry **hash_table; |
40 | int hash_count; | 39 | int hash_count; |
41 | u32 hash_rnd; | 40 | u32 hash_rnd; |
42 | int hash_rnd_recalc; | 41 | int hash_rnd_recalc; |
@@ -44,7 +43,7 @@ struct flow_cache_percpu { | |||
44 | }; | 43 | }; |
45 | 44 | ||
46 | struct flow_flush_info { | 45 | struct flow_flush_info { |
47 | struct flow_cache * cache; | 46 | struct flow_cache *cache; |
48 | atomic_t cpuleft; | 47 | atomic_t cpuleft; |
49 | struct completion completion; | 48 | struct completion completion; |
50 | }; | 49 | }; |
@@ -52,7 +51,7 @@ struct flow_flush_info { | |||
52 | struct flow_cache { | 51 | struct flow_cache { |
53 | u32 hash_shift; | 52 | u32 hash_shift; |
54 | unsigned long order; | 53 | unsigned long order; |
55 | struct flow_cache_percpu * percpu; | 54 | struct flow_cache_percpu *percpu; |
56 | struct notifier_block hotcpu_notifier; | 55 | struct notifier_block hotcpu_notifier; |
57 | int low_watermark; | 56 | int low_watermark; |
58 | int high_watermark; | 57 | int high_watermark; |
@@ -78,12 +77,21 @@ static void flow_cache_new_hashrnd(unsigned long arg) | |||
78 | add_timer(&fc->rnd_timer); | 77 | add_timer(&fc->rnd_timer); |
79 | } | 78 | } |
80 | 79 | ||
80 | static int flow_entry_valid(struct flow_cache_entry *fle) | ||
81 | { | ||
82 | if (atomic_read(&flow_cache_genid) != fle->genid) | ||
83 | return 0; | ||
84 | if (fle->object && !fle->object->ops->check(fle->object)) | ||
85 | return 0; | ||
86 | return 1; | ||
87 | } | ||
88 | |||
81 | static void flow_entry_kill(struct flow_cache *fc, | 89 | static void flow_entry_kill(struct flow_cache *fc, |
82 | struct flow_cache_percpu *fcp, | 90 | struct flow_cache_percpu *fcp, |
83 | struct flow_cache_entry *fle) | 91 | struct flow_cache_entry *fle) |
84 | { | 92 | { |
85 | if (fle->object) | 93 | if (fle->object) |
86 | atomic_dec(fle->object_ref); | 94 | fle->object->ops->delete(fle->object); |
87 | kmem_cache_free(flow_cachep, fle); | 95 | kmem_cache_free(flow_cachep, fle); |
88 | fcp->hash_count--; | 96 | fcp->hash_count--; |
89 | } | 97 | } |
@@ -96,16 +104,18 @@ static void __flow_cache_shrink(struct flow_cache *fc, | |||
96 | int i; | 104 | int i; |
97 | 105 | ||
98 | for (i = 0; i < flow_cache_hash_size(fc); i++) { | 106 | for (i = 0; i < flow_cache_hash_size(fc); i++) { |
99 | int k = 0; | 107 | int saved = 0; |
100 | 108 | ||
101 | flp = &fcp->hash_table[i]; | 109 | flp = &fcp->hash_table[i]; |
102 | while ((fle = *flp) != NULL && k < shrink_to) { | ||
103 | k++; | ||
104 | flp = &fle->next; | ||
105 | } | ||
106 | while ((fle = *flp) != NULL) { | 110 | while ((fle = *flp) != NULL) { |
107 | *flp = fle->next; | 111 | if (saved < shrink_to && |
108 | flow_entry_kill(fc, fcp, fle); | 112 | flow_entry_valid(fle)) { |
113 | saved++; | ||
114 | flp = &fle->next; | ||
115 | } else { | ||
116 | *flp = fle->next; | ||
117 | flow_entry_kill(fc, fcp, fle); | ||
118 | } | ||
109 | } | 119 | } |
110 | } | 120 | } |
111 | } | 121 | } |
@@ -166,18 +176,21 @@ static int flow_key_compare(struct flowi *key1, struct flowi *key2) | |||
166 | return 0; | 176 | return 0; |
167 | } | 177 | } |
168 | 178 | ||
169 | void *flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir, | 179 | struct flow_cache_object * |
170 | flow_resolve_t resolver) | 180 | flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir, |
181 | flow_resolve_t resolver, void *ctx) | ||
171 | { | 182 | { |
172 | struct flow_cache *fc = &flow_cache_global; | 183 | struct flow_cache *fc = &flow_cache_global; |
173 | struct flow_cache_percpu *fcp; | 184 | struct flow_cache_percpu *fcp; |
174 | struct flow_cache_entry *fle, **head; | 185 | struct flow_cache_entry *fle, **head; |
186 | struct flow_cache_object *flo; | ||
175 | unsigned int hash; | 187 | unsigned int hash; |
176 | 188 | ||
177 | local_bh_disable(); | 189 | local_bh_disable(); |
178 | fcp = per_cpu_ptr(fc->percpu, smp_processor_id()); | 190 | fcp = per_cpu_ptr(fc->percpu, smp_processor_id()); |
179 | 191 | ||
180 | fle = NULL; | 192 | fle = NULL; |
193 | flo = NULL; | ||
181 | /* Packet really early in init? Making flow_cache_init a | 194 | /* Packet really early in init? Making flow_cache_init a |
182 | * pre-smp initcall would solve this. --RR */ | 195 | * pre-smp initcall would solve this. --RR */ |
183 | if (!fcp->hash_table) | 196 | if (!fcp->hash_table) |
@@ -185,27 +198,17 @@ void *flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir, | |||
185 | 198 | ||
186 | if (fcp->hash_rnd_recalc) | 199 | if (fcp->hash_rnd_recalc) |
187 | flow_new_hash_rnd(fc, fcp); | 200 | flow_new_hash_rnd(fc, fcp); |
188 | hash = flow_hash_code(fc, fcp, key); | ||
189 | 201 | ||
202 | hash = flow_hash_code(fc, fcp, key); | ||
190 | head = &fcp->hash_table[hash]; | 203 | head = &fcp->hash_table[hash]; |
191 | for (fle = *head; fle; fle = fle->next) { | 204 | for (fle = *head; fle; fle = fle->next) { |
192 | if (fle->family == family && | 205 | if (fle->family == family && |
193 | fle->dir == dir && | 206 | fle->dir == dir && |
194 | flow_key_compare(key, &fle->key) == 0) { | 207 | flow_key_compare(key, &fle->key) == 0) |
195 | if (fle->genid == atomic_read(&flow_cache_genid)) { | ||
196 | void *ret = fle->object; | ||
197 | |||
198 | if (ret) | ||
199 | atomic_inc(fle->object_ref); | ||
200 | local_bh_enable(); | ||
201 | |||
202 | return ret; | ||
203 | } | ||
204 | break; | 208 | break; |
205 | } | ||
206 | } | 209 | } |
207 | 210 | ||
208 | if (!fle) { | 211 | if (unlikely(!fle)) { |
209 | if (fcp->hash_count > fc->high_watermark) | 212 | if (fcp->hash_count > fc->high_watermark) |
210 | flow_cache_shrink(fc, fcp); | 213 | flow_cache_shrink(fc, fcp); |
211 | 214 | ||
@@ -219,33 +222,39 @@ void *flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir, | |||
219 | fle->object = NULL; | 222 | fle->object = NULL; |
220 | fcp->hash_count++; | 223 | fcp->hash_count++; |
221 | } | 224 | } |
225 | } else if (likely(fle->genid == atomic_read(&flow_cache_genid))) { | ||
226 | flo = fle->object; | ||
227 | if (!flo) | ||
228 | goto ret_object; | ||
229 | flo = flo->ops->get(flo); | ||
230 | if (flo) | ||
231 | goto ret_object; | ||
232 | } else if (fle->object) { | ||
233 | flo = fle->object; | ||
234 | flo->ops->delete(flo); | ||
235 | fle->object = NULL; | ||
222 | } | 236 | } |
223 | 237 | ||
224 | nocache: | 238 | nocache: |
225 | { | 239 | flo = NULL; |
226 | int err; | 240 | if (fle) { |
227 | void *obj; | 241 | flo = fle->object; |
228 | atomic_t *obj_ref; | 242 | fle->object = NULL; |
229 | 243 | } | |
230 | err = resolver(net, key, family, dir, &obj, &obj_ref); | 244 | flo = resolver(net, key, family, dir, flo, ctx); |
231 | 245 | if (fle) { | |
232 | if (fle && !err) { | 246 | fle->genid = atomic_read(&flow_cache_genid); |
233 | fle->genid = atomic_read(&flow_cache_genid); | 247 | if (!IS_ERR(flo)) |
234 | 248 | fle->object = flo; | |
235 | if (fle->object) | 249 | else |
236 | atomic_dec(fle->object_ref); | 250 | fle->genid--; |
237 | 251 | } else { | |
238 | fle->object = obj; | 252 | if (flo && !IS_ERR(flo)) |
239 | fle->object_ref = obj_ref; | 253 | flo->ops->delete(flo); |
240 | if (obj) | ||
241 | atomic_inc(fle->object_ref); | ||
242 | } | ||
243 | local_bh_enable(); | ||
244 | |||
245 | if (err) | ||
246 | obj = ERR_PTR(err); | ||
247 | return obj; | ||
248 | } | 254 | } |
255 | ret_object: | ||
256 | local_bh_enable(); | ||
257 | return flo; | ||
249 | } | 258 | } |
250 | 259 | ||
251 | static void flow_cache_flush_tasklet(unsigned long data) | 260 | static void flow_cache_flush_tasklet(unsigned long data) |
@@ -261,13 +270,12 @@ static void flow_cache_flush_tasklet(unsigned long data) | |||
261 | 270 | ||
262 | fle = fcp->hash_table[i]; | 271 | fle = fcp->hash_table[i]; |
263 | for (; fle; fle = fle->next) { | 272 | for (; fle; fle = fle->next) { |
264 | unsigned genid = atomic_read(&flow_cache_genid); | 273 | if (flow_entry_valid(fle)) |
265 | |||
266 | if (!fle->object || fle->genid == genid) | ||
267 | continue; | 274 | continue; |
268 | 275 | ||
276 | if (fle->object) | ||
277 | fle->object->ops->delete(fle->object); | ||
269 | fle->object = NULL; | 278 | fle->object = NULL; |
270 | atomic_dec(fle->object_ref); | ||
271 | } | 279 | } |
272 | } | 280 | } |
273 | 281 | ||
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 | ||
219 | static 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 | |||
231 | static 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 | |||
238 | static void xfrm_policy_flo_delete(struct flow_cache_object *flo) | ||
239 | { | ||
240 | xfrm_pol_put(container_of(flo, struct xfrm_policy, flo)); | ||
241 | } | ||
242 | |||
243 | static 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 | } |
670 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); | 695 | EXPORT_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 | } |
712 | EXPORT_SYMBOL(xfrm_policy_byid); | 735 | EXPORT_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); | ||
826 | out: | 848 | out: |
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 | ||
979 | static int xfrm_policy_lookup(struct net *net, struct flowi *fl, u16 family, | 1001 | static struct flow_cache_object * |
980 | u8 dir, void **objp, atomic_t **obj_refp) | 1002 | xfrm_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; |
1000 | end: | 1023 | |
1001 | #endif | 1024 | found: |
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 | ||
1007 | static inline int policy_to_flow_dir(int dir) | 1032 | static 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); |