aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2005-06-19 01:43:22 -0400
committerDavid S. Miller <davem@davemloft.net>2005-06-19 01:43:22 -0400
commit4666faab095230ec8aa62da6c33391287f281154 (patch)
tree36d61925bb02dd7de537ff65d35190eeebbf47fa
parent26b15dad9f1c19d6d4f7b999b07eaa6d98e4b375 (diff)
[IPSEC] Kill spurious hard expire messages
This patch ensures that the hard state/policy expire notifications are only sent when the state/policy is successfully removed from their respective tables. As it is, it's possible for a state/policy to both expire through reaching a hard limit, as well as being deleted by the user. Note that this behaviour isn't actually forbidden by RFC 2367. However, it is a quality of implementation issue. As an added bonus, the restructuring in this patch will help eventually in moving the expire notifications from softirq context into process context, thus improving their reliability. One important side-effect from this change is that SAs reaching their hard byte/packet limits are now deleted immediately, just like SAs that have reached their hard time limits. Previously they were announced immediately but only deleted after 30 seconds. This is bad because it prevents the system from issuing an ACQUIRE command until the existing state was deleted by the user or expires after the time is up. In the scenario where the expire notification was lost this introduces a 30 second delay into the system for no good reason. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--include/net/xfrm.h2
-rw-r--r--net/xfrm/xfrm_policy.c8
-rw-r--r--net/xfrm/xfrm_state.c16
3 files changed, 13 insertions, 13 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index a159655ebede..aaa0f5f330e2 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -679,7 +679,7 @@ static inline int xfrm_sk_clone_policy(struct sock *sk)
679 return 0; 679 return 0;
680} 680}
681 681
682extern void xfrm_policy_delete(struct xfrm_policy *pol, int dir); 682extern int xfrm_policy_delete(struct xfrm_policy *pol, int dir);
683 683
684static inline void xfrm_sk_free_policy(struct sock *sk) 684static inline void xfrm_sk_free_policy(struct sock *sk)
685{ 685{
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index d07f5ce31824..0a4260719a12 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -216,8 +216,8 @@ out:
216 216
217expired: 217expired:
218 read_unlock(&xp->lock); 218 read_unlock(&xp->lock);
219 km_policy_expired(xp, dir, 1); 219 if (!xfrm_policy_delete(xp, dir))
220 xfrm_policy_delete(xp, dir); 220 km_policy_expired(xp, dir, 1);
221 xfrm_pol_put(xp); 221 xfrm_pol_put(xp);
222} 222}
223 223
@@ -555,7 +555,7 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
555 return NULL; 555 return NULL;
556} 556}
557 557
558void xfrm_policy_delete(struct xfrm_policy *pol, int dir) 558int xfrm_policy_delete(struct xfrm_policy *pol, int dir)
559{ 559{
560 write_lock_bh(&xfrm_policy_lock); 560 write_lock_bh(&xfrm_policy_lock);
561 pol = __xfrm_policy_unlink(pol, dir); 561 pol = __xfrm_policy_unlink(pol, dir);
@@ -564,7 +564,9 @@ void xfrm_policy_delete(struct xfrm_policy *pol, int dir)
564 if (dir < XFRM_POLICY_MAX) 564 if (dir < XFRM_POLICY_MAX)
565 atomic_inc(&flow_cache_genid); 565 atomic_inc(&flow_cache_genid);
566 xfrm_policy_kill(pol); 566 xfrm_policy_kill(pol);
567 return 0;
567 } 568 }
569 return -ENOENT;
568} 570}
569 571
570int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) 572int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 918a94c552a5..94f7416a4ab0 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -154,6 +154,7 @@ static void xfrm_timer_handler(unsigned long data)
154 next = tmo; 154 next = tmo;
155 } 155 }
156 156
157 x->km.dying = warn;
157 if (warn) 158 if (warn)
158 km_state_expired(x, 0); 159 km_state_expired(x, 0);
159resched: 160resched:
@@ -169,9 +170,8 @@ expired:
169 next = 2; 170 next = 2;
170 goto resched; 171 goto resched;
171 } 172 }
172 if (x->id.spi != 0) 173 if (!__xfrm_state_delete(x) && x->id.spi)
173 km_state_expired(x, 1); 174 km_state_expired(x, 1);
174 __xfrm_state_delete(x);
175 175
176out: 176out:
177 spin_unlock(&x->lock); 177 spin_unlock(&x->lock);
@@ -566,16 +566,18 @@ int xfrm_state_check_expire(struct xfrm_state *x)
566 566
567 if (x->curlft.bytes >= x->lft.hard_byte_limit || 567 if (x->curlft.bytes >= x->lft.hard_byte_limit ||
568 x->curlft.packets >= x->lft.hard_packet_limit) { 568 x->curlft.packets >= x->lft.hard_packet_limit) {
569 km_state_expired(x, 1); 569 x->km.state = XFRM_STATE_EXPIRED;
570 if (!mod_timer(&x->timer, jiffies + XFRM_ACQ_EXPIRES*HZ)) 570 if (!mod_timer(&x->timer, jiffies))
571 xfrm_state_hold(x); 571 xfrm_state_hold(x);
572 return -EINVAL; 572 return -EINVAL;
573 } 573 }
574 574
575 if (!x->km.dying && 575 if (!x->km.dying &&
576 (x->curlft.bytes >= x->lft.soft_byte_limit || 576 (x->curlft.bytes >= x->lft.soft_byte_limit ||
577 x->curlft.packets >= x->lft.soft_packet_limit)) 577 x->curlft.packets >= x->lft.soft_packet_limit)) {
578 x->km.dying = 1;
578 km_state_expired(x, 0); 579 km_state_expired(x, 0);
580 }
579 return 0; 581 return 0;
580} 582}
581EXPORT_SYMBOL(xfrm_state_check_expire); 583EXPORT_SYMBOL(xfrm_state_check_expire);
@@ -833,10 +835,6 @@ static void km_state_expired(struct xfrm_state *x, int hard)
833{ 835{
834 struct km_event c; 836 struct km_event c;
835 837
836 if (hard)
837 x->km.state = XFRM_STATE_EXPIRED;
838 else
839 x->km.dying = 1;
840 c.data = hard; 838 c.data = hard;
841 c.event = XFRM_SAP_EXPIRED; 839 c.event = XFRM_SAP_EXPIRED;
842 km_state_notify(x, &c); 840 km_state_notify(x, &c);