diff options
author | Arnaldo Carvalho de Melo <acme@mandriva.com> | 2005-08-09 23:45:21 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2005-08-29 18:56:03 -0400 |
commit | 64cf1e5d8b5f88d56509260e08fa0d8314277350 (patch) | |
tree | 1b2decb48c52d8f3f3abe04ffb8e0dca80f0747a /net | |
parent | 696ab2d3bffc746fb8cf3712f066d42b9886aeed (diff) |
[DCCP]: Finish the TIMEWAIT minisock support
Using most of the infrastructure TCP uses, with a dccp_death_row,
etc. As per my current interpretation of the draft what we have with
this changeset seems to be all we need (or very close to it 8)).
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/dccp/ipv4.c | 15 | ||||
-rw-r--r-- | net/dccp/minisocks.c | 60 |
2 files changed, 60 insertions, 15 deletions
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 6bccf4dd1e70..f6da9328221e 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -97,7 +97,7 @@ static int __dccp_v4_check_established(struct sock *sk, const __u16 lport, | |||
97 | NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED); | 97 | NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED); |
98 | } else if (tw != NULL) { | 98 | } else if (tw != NULL) { |
99 | /* Silly. Should hash-dance instead... */ | 99 | /* Silly. Should hash-dance instead... */ |
100 | dccp_tw_deschedule(tw); | 100 | inet_twsk_deschedule(tw, &dccp_death_row); |
101 | NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED); | 101 | NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED); |
102 | 102 | ||
103 | inet_twsk_put(tw); | 103 | inet_twsk_put(tw); |
@@ -201,7 +201,7 @@ ok: | |||
201 | spin_unlock(&head->lock); | 201 | spin_unlock(&head->lock); |
202 | 202 | ||
203 | if (tw != NULL) { | 203 | if (tw != NULL) { |
204 | dccp_tw_deschedule(tw); | 204 | inet_twsk_deschedule(tw, &dccp_death_row); |
205 | inet_twsk_put(tw); | 205 | inet_twsk_put(tw); |
206 | } | 206 | } |
207 | 207 | ||
@@ -1131,8 +1131,9 @@ int dccp_v4_rcv(struct sk_buff *skb) | |||
1131 | */ | 1131 | */ |
1132 | 1132 | ||
1133 | if (sk->sk_state == DCCP_TIME_WAIT) { | 1133 | if (sk->sk_state == DCCP_TIME_WAIT) { |
1134 | dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: discard_and_relse\n"); | 1134 | dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: " |
1135 | goto discard_and_relse; | 1135 | "do_time_wait\n"); |
1136 | goto do_time_wait; | ||
1136 | } | 1137 | } |
1137 | 1138 | ||
1138 | if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) { | 1139 | if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) { |
@@ -1179,6 +1180,10 @@ discard_it: | |||
1179 | discard_and_relse: | 1180 | discard_and_relse: |
1180 | sock_put(sk); | 1181 | sock_put(sk); |
1181 | goto discard_it; | 1182 | goto discard_it; |
1183 | |||
1184 | do_time_wait: | ||
1185 | inet_twsk_put((struct inet_timewait_sock *)sk); | ||
1186 | goto no_dccp_socket; | ||
1182 | } | 1187 | } |
1183 | 1188 | ||
1184 | static int dccp_v4_init_sock(struct sock *sk) | 1189 | static int dccp_v4_init_sock(struct sock *sk) |
@@ -1290,5 +1295,5 @@ struct proto dccp_v4_prot = { | |||
1290 | .max_header = MAX_DCCP_HEADER, | 1295 | .max_header = MAX_DCCP_HEADER, |
1291 | .obj_size = sizeof(struct dccp_sock), | 1296 | .obj_size = sizeof(struct dccp_sock), |
1292 | .rsk_prot = &dccp_request_sock_ops, | 1297 | .rsk_prot = &dccp_request_sock_ops, |
1293 | .twsk_obj_size = sizeof(struct inet_timewait_sock), /* FIXME! create dccp_timewait_sock */ | 1298 | .twsk_obj_size = sizeof(struct inet_timewait_sock), |
1294 | }; | 1299 | }; |
diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index e498e389fccc..a6a0b270fb6c 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c | |||
@@ -22,18 +22,58 @@ | |||
22 | #include "ccid.h" | 22 | #include "ccid.h" |
23 | #include "dccp.h" | 23 | #include "dccp.h" |
24 | 24 | ||
25 | struct inet_timewait_death_row dccp_death_row = { | ||
26 | .sysctl_max_tw_buckets = NR_FILE * 2, | ||
27 | .period = DCCP_TIMEWAIT_LEN / INET_TWDR_TWKILL_SLOTS, | ||
28 | .death_lock = SPIN_LOCK_UNLOCKED, | ||
29 | .hashinfo = &dccp_hashinfo, | ||
30 | .tw_timer = TIMER_INITIALIZER(inet_twdr_hangman, 0, | ||
31 | (unsigned long)&dccp_death_row), | ||
32 | .twkill_work = __WORK_INITIALIZER(dccp_death_row.twkill_work, | ||
33 | inet_twdr_twkill_work, | ||
34 | &dccp_death_row), | ||
35 | /* Short-time timewait calendar */ | ||
36 | |||
37 | .twcal_hand = -1, | ||
38 | .twcal_timer = TIMER_INITIALIZER(inet_twdr_twcal_tick, 0, | ||
39 | (unsigned long)&dccp_death_row), | ||
40 | }; | ||
41 | |||
25 | void dccp_time_wait(struct sock *sk, int state, int timeo) | 42 | void dccp_time_wait(struct sock *sk, int state, int timeo) |
26 | { | 43 | { |
27 | /* FIXME: Implement */ | 44 | struct inet_timewait_sock *tw = NULL; |
28 | dccp_pr_debug("Want to help? Start here\n"); | ||
29 | dccp_set_state(sk, state); | ||
30 | } | ||
31 | 45 | ||
32 | /* This is for handling early-kills of TIME_WAIT sockets. */ | 46 | if (dccp_death_row.tw_count < dccp_death_row.sysctl_max_tw_buckets) |
33 | void dccp_tw_deschedule(struct inet_timewait_sock *tw) | 47 | tw = inet_twsk_alloc(sk, state); |
34 | { | 48 | |
35 | dccp_pr_debug("Want to help? Start here\n"); | 49 | if (tw != NULL) { |
36 | __inet_twsk_kill(tw, &dccp_hashinfo); | 50 | const struct inet_connection_sock *icsk = inet_csk(sk); |
51 | const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1); | ||
52 | |||
53 | /* Linkage updates. */ | ||
54 | __inet_twsk_hashdance(tw, sk, &dccp_hashinfo); | ||
55 | |||
56 | /* Get the TIME_WAIT timeout firing. */ | ||
57 | if (timeo < rto) | ||
58 | timeo = rto; | ||
59 | |||
60 | tw->tw_timeout = DCCP_TIMEWAIT_LEN; | ||
61 | if (state == DCCP_TIME_WAIT) | ||
62 | timeo = DCCP_TIMEWAIT_LEN; | ||
63 | |||
64 | inet_twsk_schedule(tw, &dccp_death_row, timeo, | ||
65 | DCCP_TIMEWAIT_LEN); | ||
66 | inet_twsk_put(tw); | ||
67 | } else { | ||
68 | /* Sorry, if we're out of memory, just CLOSE this | ||
69 | * socket up. We've got bigger problems than | ||
70 | * non-graceful socket closings. | ||
71 | */ | ||
72 | if (net_ratelimit()) | ||
73 | printk(KERN_INFO "DCCP: time wait bucket table overflow\n"); | ||
74 | } | ||
75 | |||
76 | dccp_done(sk); | ||
37 | } | 77 | } |
38 | 78 | ||
39 | struct sock *dccp_create_openreq_child(struct sock *sk, | 79 | struct sock *dccp_create_openreq_child(struct sock *sk, |
@@ -55,7 +95,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk, | |||
55 | 95 | ||
56 | newdp->dccps_hc_rx_ackpkts = NULL; | 96 | newdp->dccps_hc_rx_ackpkts = NULL; |
57 | newdp->dccps_role = DCCP_ROLE_SERVER; | 97 | newdp->dccps_role = DCCP_ROLE_SERVER; |
58 | newicsk->icsk_rto = TCP_TIMEOUT_INIT; | 98 | newicsk->icsk_rto = DCCP_TIMEOUT_INIT; |
59 | 99 | ||
60 | if (newdp->dccps_options.dccpo_send_ack_vector) { | 100 | if (newdp->dccps_options.dccpo_send_ack_vector) { |
61 | newdp->dccps_hc_rx_ackpkts = dccp_ackpkts_alloc(DCCP_MAX_ACK_VECTOR_LEN, | 101 | newdp->dccps_hc_rx_ackpkts = dccp_ackpkts_alloc(DCCP_MAX_ACK_VECTOR_LEN, |