DCCP protocol discussions
 help / color / mirror / Atom feed
* Re: [PATCH] 1/1 dccp: transmit buffering
From: Arnaldo Carvalho de Melo @ 2006-02-15 11:57 UTC (permalink / raw)
  To: dccp
In-Reply-To: <cbec11ac0602061504y3507004dnf8b13d089d9fceba@mail.gmail.com>

Ian McDonald wrote:
> On 2/7/06, Ian McDonald <imcdnzl@gmail.com> wrote:
>>> See the comments below, I guess we don't need yet another lock :-)
>> Will look at some more about locks as time permits - we take
>> possession of our house today :-)
> 
> Still bit short of time but tested some more and found it clashed with
> feature negotiation so will need more work :-( One of the problems is
> with the code stopping the retransmit timer in feature negotiation.
> Removing that fixes it for standard test cases but it then fails with
> delay of 50 ms and 10% loss using netem where it worked without
> feature negotiation for me. Might be bottom half locking perhaps -
> haven't tested changes to that yet.

Andrea, can you take a look at this one?

>> The reason for this is to allow sending of queued packets when user
>> application says close...
>>
>>> sk_reset_timer() please, so that we make sure we have a reference count
>>> for the sock as its going to be on a timer
>> As I read the timer source code if the timer returns do I have to do a
>> sock_put (I am guessing so as I don't see how it would happen
>> elsewise).
> 
> Are you able to answer this?

Yes, you have to do a sock_put at the end of the timer routine, if
you restart the timer with sk_reset_timer it'll grab another refcount,
so the one done at first firing the timer will be dropped by the
sock_put at the end of the timer routine.

>>> sk_stop_timer please, to drop the refcount we grabbed with sk_reset_timer()
>>> elsewhere.
>>>
>> The thing with sk_stop_timer is that it doesn't check if the timer
>> routine is in use which would mean that we can have problems (I hit
>> this in testing). I presume the best way is to create a
>> sk_stop_timer_sync rather than use generic timer...
> 
> Any comments on this anyone as this is how I intend to code it...

Well, it checks, look at its usage of mod_timer to see if the timer was
pending and if not drop the lock, i.e. no refcount leakage here, if you
are worried about races that is why we use the timer routine under
bh_lock_sock()/bh_release_sock(), look at ccid3_hc_tx_no_feedback_timer.

Or is it some other worry you have? can you elaborate? If you need
mod_timer return forwarded to the sk_reset_user() user we can do it if
needed.

- Arnaldo


^ permalink raw reply

* [PATCH 1/1][DCCP]: Set the default CCID according to kernel config selection
From: Arnaldo Carvalho de Melo @ 2006-02-15 11:49 UTC (permalink / raw)
  To: dccp

[-- Attachment #1: Type: text/plain, Size: 144 bytes --]

Hi David,

   Please consider pulling from:

master.kernel.org:/pub/scm/linux/kernel/git/acme/net-2.6.17.git

Best Regards,

- Arnaldo

[-- Attachment #2: 1.patch --]
[-- Type: text/x-patch, Size: 1631 bytes --]

tree d72a8934d54b685a72b7048d6aeb52f5ee6189ab
parent 5d993b3c9996d8df5a83a2d0f7e056b8963d7ee1
author Arnaldo Carvalho de Melo <acme@mandriva.com> 1140003702 -0200
committer Arnaldo Carvalho de Melo <acme@mandriva.com> 1140003702 -0200

[DCCP]: Set the default CCID according to kernel config selection

Now CCID2 is the default, as stated in the RFC drafts, but we allow
a config where just CCID3 is built, where CCID3 becomes the default.

Signed-off-by: Ian McDonald <imcdnzl@gmail.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>

------------------------------------------------------------------------------

 dccp.h |   11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

------------------------------------------------------------------------------

diff --git a/include/linux/dccp.h b/include/linux/dccp.h
index f91c8a6..a70d1a2 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -329,9 +329,18 @@ static inline unsigned int dccp_hdr_len(
 
 /* initial values for each feature */
 #define DCCPF_INITIAL_SEQUENCE_WINDOW		100
-#define DCCPF_INITIAL_CCID			2
 #define DCCPF_INITIAL_ACK_RATIO			2
+
+#if defined(CONFIG_IP_DCCP_CCID2) || defined(CONFIG_IP_DCCP_CCID2_MODULE)
+#define DCCPF_INITIAL_CCID			2
 #define DCCPF_INITIAL_SEND_ACK_VECTOR		1
+#elif defined(CONFIG_IP_DCCP_CCID3) || defined(CONFIG_IP_DCCP_CCID3_MODULE)
+#define DCCPF_INITIAL_CCID			3
+#define DCCPF_INITIAL_SEND_ACK_VECTOR		0
+#else
+#error  "At least one CCID must be built as the default"
+#endif
+
 /* FIXME: for now we're default to 1 but it should really be 0 */
 #define DCCPF_INITIAL_SEND_NDP_COUNT		1
 

^ permalink raw reply related

* Re: [PATCH 1/1]: [CCID2]: Fix the use of the RTO timer
From: Andrea Bittau @ 2006-02-15  8:56 UTC (permalink / raw)
  To: dccp
In-Reply-To: <20060215013015.GA14878@tribal.sorbonet.org>

On Wed, Feb 15, 2006 at 02:44:53PM +1300, Ian McDonald wrote:
> This patch looks good in itself but there are further problems
> unloading than this as it occurs also with the code base prior to
> CCID2 merging....

Do you have specific examples?  I've been fighting quite a lot in trying to get
the module to unload itself cleanly =D

You probably are already aware that there is a reference count kept for timewait
sockets and for the control sock.  But that is not an issue.  

The only outstanding bug I can think of, which will not cause the module to
unload, is that connect race condition thing I've been bragging about.
Basically, if I recall correctly, the connection occurs and terminates before
sys_connect() returns, and the socket is never freed.

^ permalink raw reply

* Re: [PATCH/RFC]: Re: Problem with feature negotiation
From: Ian McDonald @ 2006-02-15  1:53 UTC (permalink / raw)
  To: dccp
In-Reply-To: <39e6f6c70602140712k5579e1bfy2445f45e9c97f966@mail.gmail.com>

> Take a look at my tree, I guess its fixed now by setting the defaults according
> to the selection of CCIDs in the kernel config, i.e. if CCID2 is built
> it is the default,
> as the spec states, but if it isn't CCID3 becomes the default and an #error is
> spit if no CCID has been selected for compilation.
>
> Please test and report results, then I'll push for Dave to get it into 2.6.17
>
Tested just fine.

Signed-off-by: Ian McDonald <imcdnzl@gmail.com>
--
Ian McDonald
http://wand.net.nz/~iam4
WAND Network Research Group
Department of Computer Science
University of Waikato
New Zealand

^ permalink raw reply

* Re: [PATCH 1/1]: [CCID2]: Fix the use of the RTO timer
From: Ian McDonald @ 2006-02-15  1:44 UTC (permalink / raw)
  To: dccp
In-Reply-To: <20060215013015.GA14878@tribal.sorbonet.org>

On 2/15/06, Andrea Bittau <a.bittau@cs.ucl.ac.uk> wrote:
> Drop sock reference count on timer expiration and reset.
>
> There was a hybrid use of standard timers and sk_timers.  This caused the
> reference count of the sock to be incorrect when resetting the RTO timer.  The
> sock reference count should now be correct, enabling its destruction, and
> allowing the DCCP module to be unloaded.
>
> Signed-off-by: Andrea Bittau <a.bittau@cs.ucl.ac.uk>
>
> ---
>
> diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c

This patch looks good in itself but there are further problems
unloading than this as it occurs also with the code base prior to
CCID2 merging....

Ian
--
Ian McDonald
http://wand.net.nz/~iam4
WAND Network Research Group
Department of Computer Science
University of Waikato
New Zealand

^ permalink raw reply

* [PATCH 1/1]: [CCID2]: Fix the use of the RTO timer
From: Andrea Bittau @ 2006-02-15  1:30 UTC (permalink / raw)
  To: dccp

Drop sock reference count on timer expiration and reset.

There was a hybrid use of standard timers and sk_timers.  This caused the
reference count of the sock to be incorrect when resetting the RTO timer.  The
sock reference count should now be correct, enabling its destruction, and
allowing the DCCP module to be unloaded.

Signed-off-by: Andrea Bittau <a.bittau@cs.ucl.ac.uk>

---

diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c
index 5495980..6d4cb43 100644
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -234,7 +234,7 @@ static void ccid2_hc_tx_rto_expire(unsig
 	ccid2_hc_tx_check_sanity(hctx);
 out:
 	bh_unlock_sock(sk);
-/*	sock_put(sk); */
+	sock_put(sk);
 }
 
 static void ccid2_start_rto_timer(struct sock *sk)
@@ -399,10 +399,12 @@ out_invalid_option:
 	return -1;
 }
 
-static void ccid2_hc_tx_kill_rto_timer(struct ccid2_hc_tx_sock *hctx)
+static void ccid2_hc_tx_kill_rto_timer(struct sock *sk)
 {
-	if (del_timer(&hctx->ccid2hctx_rtotimer))
-		ccid2_pr_debug("deleted RTO timer\n");
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+
+	sk_stop_timer(sk, &hctx->ccid2hctx_rtotimer);
+	ccid2_pr_debug("deleted RTO timer\n");
 }
 
 static inline void ccid2_new_ack(struct sock *sk, 
@@ -496,17 +498,19 @@ static inline void ccid2_new_ack(struct 
 	}
 
 	/* we got a new ack, so re-start RTO timer */
-	ccid2_hc_tx_kill_rto_timer(hctx);
+	ccid2_hc_tx_kill_rto_timer(sk);
 	ccid2_start_rto_timer(sk);
 }
 
-static void ccid2_hc_tx_dec_pipe(struct ccid2_hc_tx_sock *hctx)
+static void ccid2_hc_tx_dec_pipe(struct sock *sk)
 {
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+	
 	hctx->ccid2hctx_pipe--;
 	BUG_ON(hctx->ccid2hctx_pipe < 0);
 
 	if (hctx->ccid2hctx_pipe = 0)
-		ccid2_hc_tx_kill_rto_timer(hctx);
+		ccid2_hc_tx_kill_rto_timer(sk);
 }
 
 static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
@@ -627,7 +631,7 @@ static void ccid2_hc_tx_packet_recv(stru
 					seqp->ccid2s_acked = 1;
 					ccid2_pr_debug("Got ack for %llu\n",
 					       	       seqp->ccid2s_seq);
-					ccid2_hc_tx_dec_pipe(hctx);
+					ccid2_hc_tx_dec_pipe(sk);
 				}
 				if (seqp = hctx->ccid2hctx_seqt) {
 					done = 1;
@@ -674,7 +678,7 @@ static void ccid2_hc_tx_packet_recv(stru
 		while (1) {
 			if (!seqp->ccid2s_acked) {
 				loss = 1;
-				ccid2_hc_tx_dec_pipe(hctx);
+				ccid2_hc_tx_dec_pipe(sk);
 			}
 			if (seqp = hctx->ccid2hctx_seqt)
 				break;
@@ -760,9 +764,9 @@ static int ccid2_hc_tx_init(struct sock 
 static void ccid2_hc_tx_exit(struct sock *sk)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-        struct ccid2_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+        struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
 
-	ccid2_hc_tx_kill_rto_timer(hctx);
+	ccid2_hc_tx_kill_rto_timer(sk);
 
 	kfree(hctx->ccid2hctx_seqbuf);
 

^ permalink raw reply related

* Re: [PATCH] 1/1 dccp: transmit buffering
From: Ian McDonald @ 2006-02-15  1:18 UTC (permalink / raw)
  To: dccp
In-Reply-To: <cbec11ac0602061504y3507004dnf8b13d089d9fceba@mail.gmail.com>

On 2/7/06, Ian McDonald <imcdnzl@gmail.com> wrote:
> > See the comments below, I guess we don't need yet another lock :-)
>
> Will look at some more about locks as time permits - we take
> possession of our house today :-)

Still bit short of time but tested some more and found it clashed with
feature negotiation so will need more work :-( One of the problems is
with the code stopping the retransmit timer in feature negotiation.
Removing that fixes it for standard test cases but it then fails with
delay of 50 ms and 10% loss using netem where it worked without
feature negotiation for me. Might be bottom half locking perhaps -
haven't tested changes to that yet.
>
> The reason for this is to allow sending of queued packets when user
> application says close...
>
> > sk_reset_timer() please, so that we make sure we have a reference count
> > for the sock as its going to be on a timer
>
> As I read the timer source code if the timer returns do I have to do a
> sock_put (I am guessing so as I don't see how it would happen
> elsewise).

Are you able to answer this?
>
> > sk_stop_timer please, to drop the refcount we grabbed with sk_reset_timer()
> > elsewhere.
> >
> The thing with sk_stop_timer is that it doesn't check if the timer
> routine is in use which would mean that we can have problems (I hit
> this in testing). I presume the best way is to create a
> sk_stop_timer_sync rather than use generic timer...

Any comments on this anyone as this is how I intend to code it...

Ian
--
Ian McDonald
http://wand.net.nz/~iam4
WAND Network Research Group
Department of Computer Science
University of Waikato
New Zealand

^ permalink raw reply

* [PATCH/RFC]: Re: Problem with feature negotiation
From: Arnaldo Carvalho de Melo @ 2006-02-14 15:12 UTC (permalink / raw)
  To: dccp

On 2/14/06, Andrea Bittau <a.bittau@cs.ucl.ac.uk> wrote:
> On Tue, Feb 14, 2006 at 01:06:47PM +1300, Ian McDonald wrote:
> > If either of you too can fix that it'd be cool otherwise I'll add it
> > to my list of rainy day bugs....
>
> I'll look into it myself.  I've been caught up on other stuff, so I wasn't
> able to do much DCCP work lately.  I will very soon though [towards the end of
> the week].

Take a look at my tree, I guess its fixed now by setting the defaults according
to the selection of CCIDs in the kernel config, i.e. if CCID2 is built
it is the default,
as the spec states, but if it isn't CCID3 becomes the default and an #error is
spit if no CCID has been selected for compilation.

Please test and report results, then I'll push for Dave to get it into 2.6.17

>
> The last thing I was playing with was trying to fix the module reference
> count.
> For some reason, I think there is an invalid reference count for client
> sockets.
> This does not let you unload the module, which is painful for development.

I'll try to reproduce this here, perhaps I haven't noticed because in my tests
I use mostly qemu and when building a new kernel I just reboot the whole
virtual machine, not reloading the modules explicitely.

>
> Also, does anyone know if there is the equivalent of BSD divert sockets for
> Linux?  I was planning to use those for making a DCCP test suite.  The
> motivation is that you can intercept, inspect and drop packets.

Look at the netfilter documentation, I guess its something called ulog.

- Arnaldo

^ permalink raw reply

* Re: [BUG] Problem with feature negotiation
From: Andrea Bittau @ 2006-02-14  8:20 UTC (permalink / raw)
  To: dccp
In-Reply-To: <cbec11ac0602131606r3db89cbcp2fba640d61b92447@mail.gmail.com>

On Tue, Feb 14, 2006 at 01:06:47PM +1300, Ian McDonald wrote:
> If either of you too can fix that it'd be cool otherwise I'll add it
> to my list of rainy day bugs....

I'll look into it myself.  I've been caught up on other stuff, so I wasn't able
to do much DCCP work lately.  I will very soon though [towards the end of the
week].

The last thing I was playing with was trying to fix the module reference count.
For some reason, I think there is an invalid reference count for client sockets.
This does not let you unload the module, which is painful for development.


Also, does anyone know if there is the equivalent of BSD divert sockets for
Linux?  I was planning to use those for making a DCCP test suite.  The
motivation is that you can intercept, inspect and drop packets.

^ permalink raw reply

* [BUG] Problem with feature negotiation
From: Ian McDonald @ 2006-02-14  0:06 UTC (permalink / raw)
  To: dccp

Arnaldo/Andrea,

When I do this:
./ttcp_acme -c -l500 -r

I get a null pointer dereference in net/dccp/feat.c on line 427 which
is list_for_each_entry_safe.

Did some more testing and found it was because I had only CCID3
compiled as module and not CCID2. (i.e. bug occurs when
CONFIG_IP_DCCP_ACKVEC and CONFIG_IP_DCCP_CCID2 are not set).

If either of you too can fix that it'd be cool otherwise I'll add it
to my list of rainy day bugs....

void dccp_feat_clean(struct sock *sk)
{
	struct dccp_sock *dp = dccp_sk(sk);
	struct dccp_opt_pend *opt, *next;

	list_for_each_entry_safe(opt, next, &dp->dccps_options.dccpo_pending,
				 dccpop_node) {


Feb 14 11:12:19 localhost kernel: Unable to handle kernel NULL pointer
dereference at virtual address 00000000
Feb 14 11:12:19 localhost kernel:  printing eip:
Feb 14 11:12:19 localhost kernel: e0b9bac0
Feb 14 11:12:19 localhost kernel: *pde = 00000000
Feb 14 11:12:19 localhost kernel: Oops: 0000 [#1]
Feb 14 11:12:19 localhost kernel: PREEMPT
Feb 14 11:12:19 localhost kernel: Modules linked in: dccp lp af_packet
mousedev ide_generic usbhid snd_seq_dummy snd_seq_oss snd_seq_midi
snd_seq_midi_event snd_seq snd_mpu401 psmouse floppy parport_pc
parport pcspkr snd_via82xx snd_ac97_codec snd_ac97_bus rtc snd_pcm_oss
snd_mixer_oss 8139cp snd_pcm snd_timer snd_page_alloc snd_mpu401_uart
snd_rawmidi snd_seq_device snd soundcore i2c_viapro via_agp agpgart
i2c_core 8139too mii uhci_hcd usbcore ide_cd cdrom unix
Feb 14 11:12:19 localhost kernel: CPU:    0
Feb 14 11:12:19 localhost kernel: EIP:   
0060:[pg0+545561280/1070253056]    Not tainted VLI
Feb 14 11:12:19 localhost kernel: EFLAGS: 00010246   (2.6.16-rc2iandccp #1)
Feb 14 11:12:19 localhost kernel: EIP is at dccp_feat_clean+0xf/0xaa [dccp]
Feb 14 11:12:19 localhost kernel: eax: 00000000   ebx: 00000000   ecx:
dae16bb4   edx: 00000000
Feb 14 11:12:19 localhost kernel: esi: dae16808   edi: dae16808   ebp:
dacd3edc   esp: dacd3ed0
Feb 14 11:12:19 localhost kernel: ds: 007b   es: 007b   ss: 0068
Feb 14 11:12:19 localhost kernel: Process ttcp_acme (pid: 3726,
threadinfoÚcd2000 taskÜa94ab0)
Feb 14 11:12:19 localhost kernel: Stack: <0>dae16808 dae16808 fffffff4
dacd3efc e0b9d679 dae16808 00000000 dae16808
Feb 14 11:12:19 localhost kernel:        00000000 dae16808 dae16808
dacd3f10 c02218d0 dae16808 dae16808 dae16808
Feb 14 11:12:19 localhost kernel:        dacd3f30 c025d29e dae16808
00044544 00000001 00000002 db10f96c 00000006
Feb 14 11:12:19 localhost kernel: Call Trace:
Feb 14 11:12:19 localhost kernel:  [show_stack_log_lvl+170/181]
show_stack_log_lvl+0xaa/0xb5
Feb 14 11:12:19 localhost kernel:  [show_registers+295/397]
show_registers+0x127/0x18d
Feb 14 11:12:19 localhost kernel:  [die+321/441] die+0x141/0x1b9
Feb 14 11:12:19 localhost kernel:  [do_page_fault+915/1229]
do_page_fault+0x393/0x4cd
Feb 14 11:12:19 localhost kernel:  [error_code+79/84] error_code+0x4f/0x54
Feb 14 11:12:19 localhost kernel:  [pg0+545568377/1070253056]
dccp_v4_destroy_sock+0xe7/0xee [dccp]
Feb 14 11:12:19 localhost kernel:  [sk_common_release+21/147]
sk_common_release+0x15/0x93
Feb 14 11:12:19 localhost kernel:  [inet_create+606/641] inet_create+0x25e/0x281
Feb 14 11:12:19 localhost kernel:  [__sock_create+295/533]
__sock_create+0x127/0x215
Feb 14 11:12:19 localhost kernel:  [sys_socket+23/63] sys_socket+0x17/0x3f
Feb 14 11:12:19 localhost kernel:  [sys_socketcall+86/363]
sys_socketcall+0x56/0x16b
Feb 14 11:12:19 localhost kernel:  [syscall_call+7/11] syscall_call+0x7/0xb
Feb 14 11:12:19 localhost kernel: Code: 68 31 2e ba e0 68 95 39 ba e0
e8 69 b5 57 df 83 c4 10 8d 65 f4 31 c0 5b 5e 5f 5d c3 55 89 e5 57 8b
7d 08 56 53 8b 9f 78 03 00 00 <8b> 33 eb 46 8b 43 0c 85 c0 75 08 0f 0b
ad 01 dd 37 ba e0 50 e8


--
Ian McDonald
http://wand.net.nz/~iam4
WAND Network Research Group
Department of Computer Science
University of Waikato
New Zealand

^ permalink raw reply

* Re: [PATCH] 1/1 dccp: transmit buffering
From: Ian McDonald @ 2006-02-06 23:04 UTC (permalink / raw)
  To: dccp

> See the comments below, I guess we don't need yet another lock :-)

Will look at some more about locks as time permits - we take
possession of our house today :-)
> > @@ -191,7 +192,7 @@ static int dccp_wait_for_ccid(struct soc
> >         while (1) {
> >                 prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
> >
> > -               if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
> > +               if (sk->sk_err)
>
> Humm, have to check this one...

The reason for this is to allow sending of queued packets when user
application says close...

> sk_reset_timer() please, so that we make sure we have a reference count
> for the sock as its going to be on a timer

As I read the timer source code if the timer returns do I have to do a
sock_put (I am guessing so as I don't see how it would happen
elsewise).

> > +       dp->dccps_xmit_lock = SPIN_LOCK_UNLOCKED;
>
> Not needed

I presume you mean because that is the default state? (Provided I
don't get rid of the lock altogether)

> sk_stop_timer please, to drop the refcount we grabbed with sk_reset_timer()
> elsewhere.
>
The thing with sk_stop_timer is that it doesn't check if the timer
routine is in use which would mean that we can have problems (I hit
this in testing). I presume the best way is to create a
sk_stop_timer_sync rather than use generic timer...

Ian
--
Ian McDonald
http://wand.net.nz/~iam4
WAND Network Research Group
University of Waikato
New Zealand

^ permalink raw reply

* [PATCH 11/11][DCCP] CCID2: Initial CCID2 (TCP-Like) implementation
From: Arnaldo Carvalho de Melo @ 2006-02-04  2:39 UTC (permalink / raw)
  To: dccp

[-- Attachment #1: Type: text/plain, Size: 145 bytes --]

Hi David,

    Please consider pulling from:

master.kernel.org:/pub/scm/linux/kernel/git/acme/net-2.6.17.git

Best Regards,

- Arnaldo

[-- Attachment #2: 11.patch --]
[-- Type: text/x-patch, Size: 30162 bytes --]

tree e73f9cbf3042bd195be05fd1793431fcc3e8d077
parent 7546412b4ec28b4aee1e52140b60ade3671ff6bc
author Andrea Bittau <a.bittau@cs.ucl.ac.uk> 1138989401 -0200
committer Arnaldo Carvalho de Melo <acme@mandriva.com> 1138989401 -0200

[DCCP] CCID2: Initial CCID2 (TCP-Like) implementation

Original work by Andrea Bittau, Arnaldo Melo cleaned up and fixed several
issues on the merge process.

For now CCID2 was turned the default for all SOCK_DCCP connections, but this
will be remedied soon with the merge of the feature negotiation code.

Signed-off-by: Andrea Bittau <a.bittau@cs.ucl.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>

------------------------------------------------------------------------------

 include/linux/dccp.h    |    8 
 net/dccp/Kconfig        |    4 
 net/dccp/ccids/Kconfig  |   39 ++
 net/dccp/ccids/Makefile |    4 
 net/dccp/ccids/ccid2.c  |  838 ++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/ccids/ccid2.h  |   69 +++
 net/dccp/ipv4.c         |    1 
 7 files changed, 957 insertions(+), 6 deletions(-)

------------------------------------------------------------------------------

diff --git a/include/linux/dccp.h b/include/linux/dccp.h
index 088529f..268b457 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -314,9 +314,9 @@ static inline unsigned int dccp_hdr_len(
 
 /* initial values for each feature */
 #define DCCPF_INITIAL_SEQUENCE_WINDOW		100
-/* FIXME: for now we're using CCID 3 (TFRC) */
-#define DCCPF_INITIAL_CCID			3
-#define DCCPF_INITIAL_SEND_ACK_VECTOR		0
+/* FIXME: for now we're using CCID 2 (TCP-Like) */
+#define DCCPF_INITIAL_CCID			2
+#define DCCPF_INITIAL_SEND_ACK_VECTOR		1
 /* FIXME: for now we're default to 1 but it should really be 0 */
 #define DCCPF_INITIAL_SEND_NDP_COUNT		1
 
@@ -430,6 +430,8 @@ struct dccp_sock {
 	struct timeval			dccps_timestamp_time;
 	__u32				dccps_timestamp_echo;
 	__u32				dccps_packet_size;
+	__u16				dccps_l_ack_ratio;
+	__u16				dccps_r_ack_ratio;
 	unsigned long			dccps_ndp_count;
 	__u32				dccps_mss_cache;
 	struct dccp_options		dccps_options;
diff --git a/net/dccp/Kconfig b/net/dccp/Kconfig
index 187ac18..24a6981 100644
--- a/net/dccp/Kconfig
+++ b/net/dccp/Kconfig
@@ -24,6 +24,10 @@ config INET_DCCP_DIAG
 	def_tristate y if (IP_DCCP = y && INET_DIAG = y)
 	def_tristate m
 
+config IP_DCCP_ACKVEC
+	depends on IP_DCCP
+	def_bool N
+
 source "net/dccp/ccids/Kconfig"
 
 menu "DCCP Kernel Hacking"
diff --git a/net/dccp/ccids/Kconfig b/net/dccp/ccids/Kconfig
index 7684d83..422af19 100644
--- a/net/dccp/ccids/Kconfig
+++ b/net/dccp/ccids/Kconfig
@@ -1,6 +1,34 @@
 menu "DCCP CCIDs Configuration (EXPERIMENTAL)"
 	depends on IP_DCCP && EXPERIMENTAL
 
+config IP_DCCP_CCID2
+	tristate "CCID2 (TCP) (EXPERIMENTAL)"
+	depends on IP_DCCP
+	select IP_DCCP_ACKVEC
+	---help---
+	  CCID 2, TCP-like Congestion Control, denotes Additive Increase,
+	  Multiplicative Decrease (AIMD) congestion control with behavior
+	  modelled directly on TCP, including congestion window, slow start,
+	  timeouts, and so forth [RFC 2581].  CCID 2 achieves maximum
+	  bandwidth over the long term, consistent with the use of end-to-end
+	  congestion control, but halves its congestion window in response to
+	  each congestion event.  This leads to the abrupt rate changes
+	  typical of TCP.  Applications should use CCID 2 if they prefer
+	  maximum bandwidth utilization to steadiness of rate.  This is often
+	  the case for applications that are not playing their data directly
+	  to the user.  For example, a hypothetical application that
+	  transferred files over DCCP, using application-level retransmissions
+	  for lost packets, would prefer CCID 2 to CCID 3.  On-line games may
+	  also prefer CCID 2.
+
+	  CCID 2 is further described in:
+	  http://www.icir.org/kohler/dccp/draft-ietf-dccp-ccid2-10.txt
+
+	  This text was extracted from:
+	  http://www.icir.org/kohler/dccp/draft-ietf-dccp-spec-13.txt
+
+	  If in doubt, say M.
+
 config IP_DCCP_CCID3
 	tristate "CCID3 (TFRC) (EXPERIMENTAL)"
 	depends on IP_DCCP
@@ -15,10 +43,15 @@ config IP_DCCP_CCID3
 	  suitable than CCID 2 for applications such streaming media where a
 	  relatively smooth sending rate is of importance.
 
-	  CCID 3 is further described in [CCID 3 PROFILE]. The TFRC
-	  congestion control algorithms were initially described in RFC 3448.
+	  CCID 3 is further described in:
+
+	  http://www.icir.org/kohler/dccp/draft-ietf-dccp-ccid3-11.txt.
+
+	  The TFRC congestion control algorithms were initially described in
+	  RFC 3448.
 
-	  This text was extracted from draft-ietf-dccp-spec-11.txt.
+	  This text was extracted from:
+	  http://www.icir.org/kohler/dccp/draft-ietf-dccp-spec-13.txt
 	  
 	  If in doubt, say M.
 
diff --git a/net/dccp/ccids/Makefile b/net/dccp/ccids/Makefile
index 956f79f..438f20b 100644
--- a/net/dccp/ccids/Makefile
+++ b/net/dccp/ccids/Makefile
@@ -2,4 +2,8 @@ obj-$(CONFIG_IP_DCCP_CCID3) += dccp_ccid
 
 dccp_ccid3-y := ccid3.o
 
+obj-$(CONFIG_IP_DCCP_CCID2) += dccp_ccid2.o
+
+dccp_ccid2-y := ccid2.o
+
 obj-y += lib/
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c
new file mode 100644
index 0000000..5495980
--- /dev/null
+++ b/net/dccp/ccids/ccid2.c
@@ -0,0 +1,838 @@
+/*
+ *  net/dccp/ccids/ccid2.c
+ *
+ *  Copyright (c) 2005, 2006 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *
+ *  Changes to meet Linux coding standards, and DCCP infrastructure fixes.
+ *
+ *  Copyright (c) 2006 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This implementation should follow: draft-ietf-dccp-ccid2-10.txt
+ *
+ * BUGS:
+ * - sequence number wrapping
+ * - jiffies wrapping
+ */
+
+#include <linux/config.h>
+#include "../ccid.h"
+#include "../dccp.h"
+#include "ccid2.h"
+
+static int ccid2_debug;
+
+#if 0
+#define CCID2_DEBUG
+#endif
+
+#ifdef CCID2_DEBUG
+#define ccid2_pr_debug(format, a...) \
+        do { if (ccid2_debug) \
+                printk(KERN_DEBUG "%s: " format, __FUNCTION__, ##a); \
+        } while (0)
+#else
+#define ccid2_pr_debug(format, a...)
+#endif
+
+static const int ccid2_seq_len = 128;
+
+static inline struct ccid2_hc_tx_sock *ccid2_hc_tx_sk(const struct sock *sk)
+{
+	return dccp_sk(sk)->dccps_hc_tx_ccid_private;
+}
+
+static inline struct ccid2_hc_rx_sock *ccid2_hc_rx_sk(const struct sock *sk)
+{
+	return dccp_sk(sk)->dccps_hc_rx_ccid_private;
+}
+
+#ifdef CCID2_DEBUG
+static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hctx)
+{
+	int len = 0;
+	struct ccid2_seq *seqp;
+	int pipe = 0;
+
+	seqp = hctx->ccid2hctx_seqh;
+
+	/* there is data in the chain */
+	if (seqp != hctx->ccid2hctx_seqt) {
+		seqp = seqp->ccid2s_prev;
+		len++;
+		if (!seqp->ccid2s_acked)
+			pipe++;
+	
+		while (seqp != hctx->ccid2hctx_seqt) {
+			struct ccid2_seq *prev;
+
+			prev = seqp->ccid2s_prev;
+			len++;
+			if (!prev->ccid2s_acked)
+				pipe++;
+
+			/* packets are sent sequentially */
+			BUG_ON(seqp->ccid2s_seq <= prev->ccid2s_seq);
+			BUG_ON(seqp->ccid2s_sent < prev->ccid2s_sent);
+			BUG_ON(len > ccid2_seq_len);
+
+			seqp = prev;
+		}
+	}
+
+	BUG_ON(pipe != hctx->ccid2hctx_pipe);
+	ccid2_pr_debug("len of chain=%d\n", len);
+
+	do {
+		seqp = seqp->ccid2s_prev;
+		len++;
+		BUG_ON(len > ccid2_seq_len);
+	} while(seqp != hctx->ccid2hctx_seqh);
+
+	BUG_ON(len != ccid2_seq_len);
+	ccid2_pr_debug("total len=%d\n", len);
+}
+#else
+#define ccid2_hc_tx_check_sanity(hctx) do {} while (0)
+#endif
+
+static int ccid2_hc_tx_send_packet(struct sock *sk,
+				   struct sk_buff *skb, int len)
+{
+	struct ccid2_hc_tx_sock *hctx;
+	
+	switch (DCCP_SKB_CB(skb)->dccpd_type) {
+	case 0: /* XXX data packets from userland come through like this */
+	case DCCP_PKT_DATA:
+	case DCCP_PKT_DATAACK:
+		break;
+	/* No congestion control on other packets */
+	default:
+		return 0;
+	}
+
+        hctx = ccid2_hc_tx_sk(sk);
+
+	ccid2_pr_debug("pipe=%d cwnd=%d\n", hctx->ccid2hctx_pipe,
+		       hctx->ccid2hctx_cwnd);
+	
+	if (hctx->ccid2hctx_pipe < hctx->ccid2hctx_cwnd) {
+		/* OK we can send... make sure previous packet was sent off */
+		if (!hctx->ccid2hctx_sendwait) {
+			hctx->ccid2hctx_sendwait = 1;
+			return 0;
+		}
+	}
+
+	return 100; /* XXX */
+}
+
+static void ccid2_change_l_ack_ratio(struct sock *sk, int val)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	/*
+	 * XXX I don't really agree with val != 2.  If cwnd is 1, ack ratio
+	 * should be 1... it shouldn't be allowed to become 2.
+	 * -sorbo.
+	 */
+	if (val != 2) {
+		struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+		int max = hctx->ccid2hctx_cwnd / 2;
+
+		/* round up */
+		if (hctx->ccid2hctx_cwnd & 1)
+			max++;
+
+		if (val > max)
+			val = max;
+	}
+
+	ccid2_pr_debug("changing local ack ratio to %d\n", val);
+	WARN_ON(val <= 0);
+	dp->dccps_l_ack_ratio = val;
+}
+
+static void ccid2_change_cwnd(struct sock *sk, int val)
+{
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+
+	if (val == 0)
+		val = 1;
+
+	/* XXX do we need to change ack ratio? */
+	ccid2_pr_debug("change cwnd to %d\n", val);
+	
+	BUG_ON(val < 1);
+	hctx->ccid2hctx_cwnd = val;
+}
+
+static void ccid2_start_rto_timer(struct sock *sk);
+
+static void ccid2_hc_tx_rto_expire(unsigned long data)
+{
+	struct sock *sk = (struct sock *)data;
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+	long s;
+
+	/* XXX I don't think i'm locking correctly
+	 * -sorbo.
+	 */
+	bh_lock_sock(sk);
+	if (sock_owned_by_user(sk)) {
+		sk_reset_timer(sk, &hctx->ccid2hctx_rtotimer,
+			       jiffies + HZ / 5);
+		goto out;
+	}
+
+	ccid2_pr_debug("RTO_EXPIRE\n");
+
+	ccid2_hc_tx_check_sanity(hctx);
+
+	/* back-off timer */
+	hctx->ccid2hctx_rto <<= 1;
+
+	s = hctx->ccid2hctx_rto / HZ;
+	if (s > 60)
+		hctx->ccid2hctx_rto = 60 * HZ;
+
+	ccid2_start_rto_timer(sk);
+
+	/* adjust pipe, cwnd etc */
+	hctx->ccid2hctx_pipe = 0;
+	hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd >> 1;
+	if (hctx->ccid2hctx_ssthresh < 2)
+		hctx->ccid2hctx_ssthresh = 2;
+	ccid2_change_cwnd(sk, 1);
+
+	/* clear state about stuff we sent */
+	hctx->ccid2hctx_seqt	= hctx->ccid2hctx_seqh;
+	hctx->ccid2hctx_ssacks	= 0;
+	hctx->ccid2hctx_acks	= 0;
+	hctx->ccid2hctx_sent	= 0;
+
+	/* clear ack ratio state. */
+	hctx->ccid2hctx_arsent	 = 0;
+	hctx->ccid2hctx_ackloss  = 0;
+	hctx->ccid2hctx_rpseq	 = 0;
+	hctx->ccid2hctx_rpdupack = -1;
+	ccid2_change_l_ack_ratio(sk, 1);
+	ccid2_hc_tx_check_sanity(hctx);
+out:
+	bh_unlock_sock(sk);
+/*	sock_put(sk); */
+}
+
+static void ccid2_start_rto_timer(struct sock *sk)
+{
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+
+	ccid2_pr_debug("setting RTO timeout=%ld\n", hctx->ccid2hctx_rto);
+
+	BUG_ON(timer_pending(&hctx->ccid2hctx_rtotimer));
+	sk_reset_timer(sk, &hctx->ccid2hctx_rtotimer,
+		       jiffies + hctx->ccid2hctx_rto);
+}
+
+static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, int len)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+	u64 seq;
+
+	ccid2_hc_tx_check_sanity(hctx);
+
+	BUG_ON(!hctx->ccid2hctx_sendwait);
+	hctx->ccid2hctx_sendwait = 0;
+	hctx->ccid2hctx_pipe++;
+	BUG_ON(hctx->ccid2hctx_pipe < 0);
+
+	/* There is an issue.  What if another packet is sent between
+	 * packet_send() and packet_sent().  Then the sequence number would be
+	 * wrong.
+	 * -sorbo.
+	 */
+	seq = dp->dccps_gss;
+
+	hctx->ccid2hctx_seqh->ccid2s_seq   = seq;
+	hctx->ccid2hctx_seqh->ccid2s_acked = 0;
+	hctx->ccid2hctx_seqh->ccid2s_sent  = jiffies;
+	hctx->ccid2hctx_seqh = hctx->ccid2hctx_seqh->ccid2s_next;
+
+	ccid2_pr_debug("cwnd=%d pipe=%d\n", hctx->ccid2hctx_cwnd, 
+		       hctx->ccid2hctx_pipe);
+	
+	if (hctx->ccid2hctx_seqh == hctx->ccid2hctx_seqt) {
+		/* XXX allocate more space */
+		WARN_ON(1);
+	}
+
+	hctx->ccid2hctx_sent++;
+
+	/* Ack Ratio.  Need to maintain a concept of how many windows we sent */
+	hctx->ccid2hctx_arsent++;
+	/* We had an ack loss in this window... */
+	if (hctx->ccid2hctx_ackloss) {
+		if (hctx->ccid2hctx_arsent >= hctx->ccid2hctx_cwnd) {
+			hctx->ccid2hctx_arsent = 0;
+			hctx->ccid2hctx_ackloss = 0;
+		}
+	}
+	/* No acks lost up to now... */
+	else {
+		/* decrease ack ratio if enough packets were sent */
+		if (dp->dccps_l_ack_ratio > 1) {
+			/* XXX don't calculate denominator each time */
+			int denom;
+
+			denom = dp->dccps_l_ack_ratio * dp->dccps_l_ack_ratio - 
+				dp->dccps_l_ack_ratio;
+			denom = hctx->ccid2hctx_cwnd * hctx->ccid2hctx_cwnd / denom;
+
+			if (hctx->ccid2hctx_arsent >= denom) {
+				ccid2_change_l_ack_ratio(sk, dp->dccps_l_ack_ratio - 1);
+				hctx->ccid2hctx_arsent = 0;
+			}
+		}
+		/* we can't increase ack ratio further [1] */
+		else {
+			hctx->ccid2hctx_arsent = 0; /* or maybe set it to cwnd*/
+		}
+	}
+
+	/* setup RTO timer */
+	if (!timer_pending(&hctx->ccid2hctx_rtotimer)) {
+		ccid2_start_rto_timer(sk);
+	}
+#ifdef CCID2_DEBUG
+	ccid2_pr_debug("pipe=%d\n", hctx->ccid2hctx_pipe);
+	ccid2_pr_debug("Sent: seq=%llu\n", seq);
+	do {
+		struct ccid2_seq *seqp = hctx->ccid2hctx_seqt;
+
+		while (seqp != hctx->ccid2hctx_seqh) {
+			ccid2_pr_debug("out seq=%llu acked=%d time=%lu\n",
+			       	       seqp->ccid2s_seq, seqp->ccid2s_acked, 
+				       seqp->ccid2s_sent);
+			seqp = seqp->ccid2s_next;
+		}
+	} while(0);
+	ccid2_pr_debug("=========\n");
+	ccid2_hc_tx_check_sanity(hctx);
+#endif
+}
+
+/* XXX Lame code duplication!
+ * returns -1 if none was found.
+ * else returns the next offset to use in the function call.
+ */
+static int ccid2_ackvector(struct sock *sk, struct sk_buff *skb, int offset,
+			   unsigned char **vec, unsigned char *veclen)
+{
+        const struct dccp_hdr *dh = dccp_hdr(skb);
+        unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb);
+        unsigned char *opt_ptr;
+        const unsigned char *opt_end = (unsigned char *)dh +
+                                        (dh->dccph_doff * 4);
+        unsigned char opt, len;
+        unsigned char *value;
+
+	BUG_ON(offset < 0);
+	options += offset;
+	opt_ptr = options;
+	if (opt_ptr >= opt_end)
+		return -1;
+
+	while (opt_ptr != opt_end) {
+                opt   = *opt_ptr++;
+                len   = 0;
+                value = NULL;
+
+                /* Check if this isn't a single byte option */
+                if (opt > DCCPO_MAX_RESERVED) {
+                        if (opt_ptr == opt_end)
+                                goto out_invalid_option;
+
+                        len = *opt_ptr++;
+                        if (len < 3)
+                                goto out_invalid_option;
+                        /*
+                         * Remove the type and len fields, leaving
+                         * just the value size
+                         */
+                        len     -= 2;
+                        value   = opt_ptr;
+                        opt_ptr += len;
+
+                        if (opt_ptr > opt_end)
+                                goto out_invalid_option;
+                }
+
+		switch (opt) {
+		case DCCPO_ACK_VECTOR_0:
+		case DCCPO_ACK_VECTOR_1:
+			*vec	= value;
+			*veclen = len;
+			return offset + (opt_ptr - options);
+			break;
+		}
+	}
+
+	return -1;
+	
+out_invalid_option:
+	BUG_ON(1); /* should never happen... options were previously parsed ! */
+	return -1;
+}
+
+static void ccid2_hc_tx_kill_rto_timer(struct ccid2_hc_tx_sock *hctx)
+{
+	if (del_timer(&hctx->ccid2hctx_rtotimer))
+		ccid2_pr_debug("deleted RTO timer\n");
+}
+
+static inline void ccid2_new_ack(struct sock *sk, 
+			         struct ccid2_seq *seqp,
+				 unsigned int *maxincr)
+{
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+
+	/* slow start */
+	if (hctx->ccid2hctx_cwnd < hctx->ccid2hctx_ssthresh) {
+		hctx->ccid2hctx_acks = 0;
+
+		/* We can increase cwnd at most maxincr [ack_ratio/2] */
+		if (*maxincr) {
+			/* increase every 2 acks */
+			hctx->ccid2hctx_ssacks++;
+			if (hctx->ccid2hctx_ssacks == 2) {
+				ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd + 1);
+				hctx->ccid2hctx_ssacks = 0;
+				*maxincr = *maxincr - 1;
+			}
+		}
+		/* increased cwnd enough for this single ack */
+		else {
+			hctx->ccid2hctx_ssacks = 0;
+		}
+	}
+	else {
+		hctx->ccid2hctx_ssacks = 0;
+		hctx->ccid2hctx_acks++;
+
+		if (hctx->ccid2hctx_acks >= hctx->ccid2hctx_cwnd) {
+			ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd + 1);
+			hctx->ccid2hctx_acks = 0;
+		}
+	}
+
+	/* update RTO */
+	if (hctx->ccid2hctx_srtt == -1 ||
+	    (jiffies - hctx->ccid2hctx_lastrtt) >= hctx->ccid2hctx_srtt) {
+		unsigned long r = jiffies - seqp->ccid2s_sent;
+		int s;
+
+		/* first measurement */
+		if (hctx->ccid2hctx_srtt == -1) {
+			ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n", 
+			       	       r, jiffies, seqp->ccid2s_seq);
+			hctx->ccid2hctx_srtt = r;
+			hctx->ccid2hctx_rttvar = r >> 1;
+		}
+		else {
+			/* RTTVAR */
+			long tmp = hctx->ccid2hctx_srtt - r;
+			if (tmp < 0)
+				tmp *= -1;
+			
+			tmp >>= 2;
+			hctx->ccid2hctx_rttvar *= 3;
+			hctx->ccid2hctx_rttvar >>= 2;
+			hctx->ccid2hctx_rttvar += tmp;
+
+			/* SRTT */
+			hctx->ccid2hctx_srtt *= 7;
+			hctx->ccid2hctx_srtt >>= 3;
+			tmp = r >> 3;
+			hctx->ccid2hctx_srtt += tmp;
+		}
+		s = hctx->ccid2hctx_rttvar << 2;
+		/* clock granularity is 1 when based on jiffies */
+		if (!s)
+			s = 1;
+		hctx->ccid2hctx_rto = hctx->ccid2hctx_srtt + s;
+
+		/* must be at least a second */
+		s = hctx->ccid2hctx_rto / HZ;
+		/* DCCP doesn't require this [but I like it cuz my code sux] */
+#if 1
+		if (s < 1)
+			hctx->ccid2hctx_rto = HZ;
+#endif			
+		/* max 60 seconds */	
+		if (s > 60)
+			hctx->ccid2hctx_rto = HZ * 60;
+
+		hctx->ccid2hctx_lastrtt = jiffies;
+
+		ccid2_pr_debug("srtt: %ld rttvar: %ld rto: %ld (HZ=%d) R=%lu\n",
+		       	       hctx->ccid2hctx_srtt, hctx->ccid2hctx_rttvar,
+		       	       hctx->ccid2hctx_rto, HZ, r);
+		hctx->ccid2hctx_sent = 0;
+	}
+
+	/* we got a new ack, so re-start RTO timer */
+	ccid2_hc_tx_kill_rto_timer(hctx);
+	ccid2_start_rto_timer(sk);
+}
+
+static void ccid2_hc_tx_dec_pipe(struct ccid2_hc_tx_sock *hctx)
+{
+	hctx->ccid2hctx_pipe--;
+	BUG_ON(hctx->ccid2hctx_pipe < 0);
+
+	if (hctx->ccid2hctx_pipe == 0)
+		ccid2_hc_tx_kill_rto_timer(hctx);
+}
+
+static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+	u64 ackno, seqno;
+	struct ccid2_seq *seqp;
+	unsigned char *vector;
+	unsigned char veclen;
+	int offset = 0;
+	int done = 0;
+	int loss = 0;
+	unsigned int maxincr = 0;
+
+	ccid2_hc_tx_check_sanity(hctx);
+	/* check reverse path congestion */
+	seqno = DCCP_SKB_CB(skb)->dccpd_seq;
+
+	/* XXX this whole "algorithm" is broken.  Need to fix it to keep track
+	 * of the seqnos of the dupacks so that rpseq and rpdupack are correct
+	 * -sorbo.
+	 */
+	/* need to bootstrap */
+	if (hctx->ccid2hctx_rpdupack == -1) {
+		hctx->ccid2hctx_rpdupack = 0;
+		hctx->ccid2hctx_rpseq = seqno;
+	}
+	else {
+		/* check if packet is consecutive */
+		if ((hctx->ccid2hctx_rpseq + 1) == seqno) {
+			hctx->ccid2hctx_rpseq++;
+		}
+		/* it's a later packet */
+		else if (after48(seqno, hctx->ccid2hctx_rpseq)) {
+			hctx->ccid2hctx_rpdupack++;
+			
+			/* check if we got enough dupacks */
+			if (hctx->ccid2hctx_rpdupack >=
+			    hctx->ccid2hctx_numdupack) {
+
+				hctx->ccid2hctx_rpdupack = -1; /* XXX lame */
+				hctx->ccid2hctx_rpseq = 0;
+
+				ccid2_change_l_ack_ratio(sk, dp->dccps_l_ack_ratio << 1);
+			}
+		}
+	}
+
+	/* check forward path congestion */
+	/* still didn't send out new data packets */
+	if (hctx->ccid2hctx_seqh == hctx->ccid2hctx_seqt)
+		return;
+
+	switch (DCCP_SKB_CB(skb)->dccpd_type) {
+	case DCCP_PKT_ACK:
+	case DCCP_PKT_DATAACK:
+		break;
+	
+	default:
+		return;
+	}
+
+	ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq;
+	seqp = hctx->ccid2hctx_seqh->ccid2s_prev;
+
+	/* If in slow-start, cwnd can increase at most Ack Ratio / 2 packets for
+	 * this single ack.  I round up.
+	 * -sorbo.
+	 */
+	maxincr = dp->dccps_l_ack_ratio >> 1;
+	maxincr++;
+
+	/* go through all ack vectors */
+	while ((offset = ccid2_ackvector(sk, skb, offset, 
+					 &vector, &veclen)) != -1) {
+		/* go through this ack vector */
+		while (veclen--) {
+			const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK;
+			u64 ackno_end_rl;
+
+			dccp_set_seqno(&ackno_end_rl, ackno - rl);
+			ccid2_pr_debug("ackvec start:%llu end:%llu\n", ackno, 
+				       ackno_end_rl);
+			/* if the seqno we are analyzing is larger than the
+			 * current ackno, then move towards the tail of our
+			 * seqnos.
+			 */
+			while (after48(seqp->ccid2s_seq, ackno)) {
+				if (seqp == hctx->ccid2hctx_seqt) {
+					done = 1;
+					break;
+				}
+				seqp = seqp->ccid2s_prev;
+			}
+			if (done)
+				break;
+
+			/* check all seqnos in the range of the vector
+			 * run length 
+			 */
+			while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) {
+				const u8 state = (*vector & 
+						  DCCP_ACKVEC_STATE_MASK) >> 6;
+			
+				/* new packet received or marked */
+				if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED &&
+				    !seqp->ccid2s_acked) {
+				    	if (state == 
+					    DCCP_ACKVEC_STATE_ECN_MARKED) {
+						loss = 1;
+					}
+					else {
+						ccid2_new_ack(sk, seqp,
+							      &maxincr);
+					}
+
+					seqp->ccid2s_acked = 1;
+					ccid2_pr_debug("Got ack for %llu\n",
+					       	       seqp->ccid2s_seq);
+					ccid2_hc_tx_dec_pipe(hctx);
+				}
+				if (seqp == hctx->ccid2hctx_seqt) {
+					done = 1;
+					break;
+				}
+				seqp = seqp->ccid2s_next;
+			}
+			if (done)
+				break;
+			       
+
+			dccp_set_seqno(&ackno, ackno_end_rl - 1);
+			vector++;
+		}
+		if (done)
+			break;
+	}
+
+	/* The state about what is acked should be correct now
+	 * Check for NUMDUPACK
+	 */
+	seqp = hctx->ccid2hctx_seqh->ccid2s_prev;
+	done = 0;
+	while (1) {
+		if (seqp->ccid2s_acked) {
+			done++;
+			if (done == hctx->ccid2hctx_numdupack) {
+				break;
+			}	
+		}
+		if (seqp == hctx->ccid2hctx_seqt) {
+			break;
+		}
+		seqp = seqp->ccid2s_prev;
+	}
+
+	/* If there are at least 3 acknowledgements, anything unacknowledged
+	 * below the last sequence number is considered lost
+	 */
+	if (done == hctx->ccid2hctx_numdupack) {
+		struct ccid2_seq *last_acked = seqp;
+
+		/* check for lost packets */
+		while (1) {
+			if (!seqp->ccid2s_acked) {
+				loss = 1;
+				ccid2_hc_tx_dec_pipe(hctx);
+			}
+			if (seqp == hctx->ccid2hctx_seqt)
+				break;
+			seqp = seqp->ccid2s_prev;
+		}
+
+		hctx->ccid2hctx_seqt = last_acked;
+	}
+
+	/* trim acked packets in tail */
+	while (hctx->ccid2hctx_seqt != hctx->ccid2hctx_seqh) {
+		if (!hctx->ccid2hctx_seqt->ccid2s_acked)
+			break;
+		
+		hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqt->ccid2s_next;
+	}
+
+	if (loss) {
+		/* XXX do bit shifts guarantee a 0 as the new bit? */
+		ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd >> 1);
+		hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd;
+		if (hctx->ccid2hctx_ssthresh < 2)
+			hctx->ccid2hctx_ssthresh = 2;
+	}
+
+	ccid2_hc_tx_check_sanity(hctx);
+}
+
+static int ccid2_hc_tx_init(struct sock *sk)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+        struct ccid2_hc_tx_sock *hctx;
+	int seqcount = ccid2_seq_len;
+	int i;
+
+        dp->dccps_hc_tx_ccid_private = kzalloc(sizeof(*hctx), gfp_any());
+        if (dp->dccps_hc_tx_ccid_private == NULL)
+                return -ENOMEM;
+
+        hctx = ccid2_hc_tx_sk(sk);
+
+	/* XXX init variables with proper values */
+	hctx->ccid2hctx_cwnd	  = 1;
+	hctx->ccid2hctx_ssthresh  = 10;
+	hctx->ccid2hctx_numdupack = 3;
+
+	/* XXX init ~ to window size... */
+	hctx->ccid2hctx_seqbuf = kmalloc(sizeof(*hctx->ccid2hctx_seqbuf) *
+					 seqcount, gfp_any());
+	if (hctx->ccid2hctx_seqbuf == NULL) {
+		kfree(dp->dccps_hc_tx_ccid_private);
+		dp->dccps_hc_tx_ccid_private = NULL;
+		return -ENOMEM;
+	}
+	for (i = 0; i < (seqcount - 1); i++) {
+		hctx->ccid2hctx_seqbuf[i].ccid2s_next = 
+					&hctx->ccid2hctx_seqbuf[i + 1];
+		hctx->ccid2hctx_seqbuf[i + 1].ccid2s_prev = 
+					&hctx->ccid2hctx_seqbuf[i];
+	}
+	hctx->ccid2hctx_seqbuf[seqcount - 1].ccid2s_next =
+					hctx->ccid2hctx_seqbuf;
+	hctx->ccid2hctx_seqbuf->ccid2s_prev =
+					&hctx->ccid2hctx_seqbuf[seqcount - 1];
+
+	hctx->ccid2hctx_seqh	 = hctx->ccid2hctx_seqbuf;
+	hctx->ccid2hctx_seqt	 = hctx->ccid2hctx_seqh;
+	hctx->ccid2hctx_sent	 = 0;
+	hctx->ccid2hctx_rto	 = 3 * HZ;
+	hctx->ccid2hctx_srtt	 = -1;
+	hctx->ccid2hctx_rttvar	 = -1;
+	hctx->ccid2hctx_lastrtt  = 0;
+	hctx->ccid2hctx_rpdupack = -1;
+
+	hctx->ccid2hctx_rtotimer.function = &ccid2_hc_tx_rto_expire;
+	hctx->ccid2hctx_rtotimer.data	  = (unsigned long)sk;
+	init_timer(&hctx->ccid2hctx_rtotimer);
+
+	ccid2_hc_tx_check_sanity(hctx);
+	return 0;
+}
+
+static void ccid2_hc_tx_exit(struct sock *sk)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+        struct ccid2_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+
+	ccid2_hc_tx_kill_rto_timer(hctx);
+
+	kfree(hctx->ccid2hctx_seqbuf);
+
+	kfree(dp->dccps_hc_tx_ccid_private);
+	dp->dccps_hc_tx_ccid_private = NULL;
+}
+
+static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
+{
+	const struct dccp_sock *dp = dccp_sk(sk);
+	struct ccid2_hc_rx_sock *hcrx = ccid2_hc_rx_sk(sk);
+
+	switch (DCCP_SKB_CB(skb)->dccpd_type) {
+	case DCCP_PKT_DATA:
+	case DCCP_PKT_DATAACK:
+		hcrx->ccid2hcrx_data++;
+		if (hcrx->ccid2hcrx_data >= dp->dccps_r_ack_ratio) {
+			dccp_send_ack(sk);
+			hcrx->ccid2hcrx_data = 0;
+		}
+		break;
+	}
+}
+
+static int ccid2_hc_rx_init(struct sock *sk)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+        dp->dccps_hc_rx_ccid_private = kzalloc(sizeof(struct ccid2_hc_rx_sock),
+					       gfp_any());
+        return dp->dccps_hc_rx_ccid_private == NULL ? -ENOMEM : 0;
+}
+
+static void ccid2_hc_rx_exit(struct sock *sk)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+
+	kfree(dp->dccps_hc_rx_ccid_private);
+	dp->dccps_hc_rx_ccid_private = NULL;
+}
+
+static struct ccid ccid2 = {
+	.ccid_id		= 2,
+	.ccid_name		= "ccid2",
+	.ccid_owner		= THIS_MODULE,
+	.ccid_hc_tx_init	= ccid2_hc_tx_init,
+	.ccid_hc_tx_exit	= ccid2_hc_tx_exit,
+	.ccid_hc_tx_send_packet	= ccid2_hc_tx_send_packet,
+	.ccid_hc_tx_packet_sent	= ccid2_hc_tx_packet_sent,
+	.ccid_hc_tx_packet_recv	= ccid2_hc_tx_packet_recv,
+	.ccid_hc_rx_init	= ccid2_hc_rx_init,
+	.ccid_hc_rx_exit	= ccid2_hc_rx_exit,
+	.ccid_hc_rx_packet_recv	= ccid2_hc_rx_packet_recv,
+};
+
+module_param(ccid2_debug, int, 0444);
+MODULE_PARM_DESC(ccid2_debug, "Enable debug messages");
+ 
+static __init int ccid2_module_init(void)
+{
+	return ccid_register(&ccid2);
+}
+module_init(ccid2_module_init);
+
+static __exit void ccid2_module_exit(void)
+{
+	ccid_unregister(&ccid2);
+}
+module_exit(ccid2_module_exit);
+
+MODULE_AUTHOR("Andrea Bittau <a.bittau@cs.ucl.ac.uk>");
+MODULE_DESCRIPTION("DCCP TCP CCID2 CCID");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("net-dccp-ccid-2");
diff --git a/net/dccp/ccids/ccid2.h b/net/dccp/ccids/ccid2.h
new file mode 100644
index 0000000..0b08c90
--- /dev/null
+++ b/net/dccp/ccids/ccid2.h
@@ -0,0 +1,69 @@
+/*
+ *  net/dccp/ccids/ccid2.h
+ *
+ *  Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _DCCP_CCID2_H_
+#define _DCCP_CCID2_H_
+
+struct ccid2_seq {
+	u64			ccid2s_seq;
+	unsigned long		ccid2s_sent;
+	int			ccid2s_acked;
+	struct ccid2_seq	*ccid2s_prev;
+	struct ccid2_seq	*ccid2s_next;
+};
+
+/** struct ccid2_hc_tx_sock - CCID2 TX half connection
+ *
+ * @ccid2hctx_ssacks - ACKs recv in slow start
+ * @ccid2hctx_acks - ACKS recv in AI phase
+ * @ccid2hctx_sent - packets sent in this window
+ * @ccid2hctx_lastrtt -time RTT was last measured
+ * @ccid2hctx_arsent - packets sent [ack ratio]
+ * @ccid2hctx_ackloss - ack was lost in this win
+ * @ccid2hctx_rpseq - last consecutive seqno
+ * @ccid2hctx_rpdupack - dupacks since rpseq
+*/
+struct ccid2_hc_tx_sock {
+	int			ccid2hctx_cwnd;
+	int			ccid2hctx_ssacks;
+	int			ccid2hctx_acks;
+	int			ccid2hctx_ssthresh;
+	int			ccid2hctx_pipe;
+	int			ccid2hctx_numdupack;
+	struct ccid2_seq	*ccid2hctx_seqbuf;
+	struct ccid2_seq	*ccid2hctx_seqh;
+	struct ccid2_seq	*ccid2hctx_seqt;
+	long			ccid2hctx_rto;
+	long			ccid2hctx_srtt;
+	long			ccid2hctx_rttvar;
+	int			ccid2hctx_sent;
+	unsigned long		ccid2hctx_lastrtt;
+	struct timer_list	ccid2hctx_rtotimer;
+	unsigned long		ccid2hctx_arsent;
+	int			ccid2hctx_ackloss;
+	u64			ccid2hctx_rpseq;
+	int			ccid2hctx_rpdupack;
+	int			ccid2hctx_sendwait;
+};
+
+struct ccid2_hc_rx_sock {
+	int	ccid2hcrx_data;
+};
+
+#endif /* _DCCP_CCID2_H_ */
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index fd5a615..605e9d5 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -1080,6 +1080,7 @@ int dccp_v4_init_sock(struct sock *sk)
 	dp->dccps_mss_cache = 536;
 	dp->dccps_role = DCCP_ROLE_UNDEFINED;
 	dp->dccps_service = DCCP_SERVICE_INVALID_VALUE;
+	dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1;
 
 	return 0;
 }


^ permalink raw reply related

* [PATCH 10/11][DCCP] CCID3: Set the no_feedback_timer fields near init_timer
From: Arnaldo Carvalho de Melo @ 2006-02-04  2:38 UTC (permalink / raw)
  To: dccp

[-- Attachment #1: Type: text/plain, Size: 145 bytes --]

Hi David,

    Please consider pulling from:

master.kernel.org:/pub/scm/linux/kernel/git/acme/net-2.6.17.git

Best Regards,

- Arnaldo

[-- Attachment #2: 11.patch --]
[-- Type: text/x-patch, Size: 30162 bytes --]

tree e73f9cbf3042bd195be05fd1793431fcc3e8d077
parent 7546412b4ec28b4aee1e52140b60ade3671ff6bc
author Andrea Bittau <a.bittau@cs.ucl.ac.uk> 1138989401 -0200
committer Arnaldo Carvalho de Melo <acme@mandriva.com> 1138989401 -0200

[DCCP] CCID2: Initial CCID2 (TCP-Like) implementation

Original work by Andrea Bittau, Arnaldo Melo cleaned up and fixed several
issues on the merge process.

For now CCID2 was turned the default for all SOCK_DCCP connections, but this
will be remedied soon with the merge of the feature negotiation code.

Signed-off-by: Andrea Bittau <a.bittau@cs.ucl.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>

------------------------------------------------------------------------------

 include/linux/dccp.h    |    8 
 net/dccp/Kconfig        |    4 
 net/dccp/ccids/Kconfig  |   39 ++
 net/dccp/ccids/Makefile |    4 
 net/dccp/ccids/ccid2.c  |  838 ++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/ccids/ccid2.h  |   69 +++
 net/dccp/ipv4.c         |    1 
 7 files changed, 957 insertions(+), 6 deletions(-)

------------------------------------------------------------------------------

diff --git a/include/linux/dccp.h b/include/linux/dccp.h
index 088529f..268b457 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -314,9 +314,9 @@ static inline unsigned int dccp_hdr_len(
 
 /* initial values for each feature */
 #define DCCPF_INITIAL_SEQUENCE_WINDOW		100
-/* FIXME: for now we're using CCID 3 (TFRC) */
-#define DCCPF_INITIAL_CCID			3
-#define DCCPF_INITIAL_SEND_ACK_VECTOR		0
+/* FIXME: for now we're using CCID 2 (TCP-Like) */
+#define DCCPF_INITIAL_CCID			2
+#define DCCPF_INITIAL_SEND_ACK_VECTOR		1
 /* FIXME: for now we're default to 1 but it should really be 0 */
 #define DCCPF_INITIAL_SEND_NDP_COUNT		1
 
@@ -430,6 +430,8 @@ struct dccp_sock {
 	struct timeval			dccps_timestamp_time;
 	__u32				dccps_timestamp_echo;
 	__u32				dccps_packet_size;
+	__u16				dccps_l_ack_ratio;
+	__u16				dccps_r_ack_ratio;
 	unsigned long			dccps_ndp_count;
 	__u32				dccps_mss_cache;
 	struct dccp_options		dccps_options;
diff --git a/net/dccp/Kconfig b/net/dccp/Kconfig
index 187ac18..24a6981 100644
--- a/net/dccp/Kconfig
+++ b/net/dccp/Kconfig
@@ -24,6 +24,10 @@ config INET_DCCP_DIAG
 	def_tristate y if (IP_DCCP = y && INET_DIAG = y)
 	def_tristate m
 
+config IP_DCCP_ACKVEC
+	depends on IP_DCCP
+	def_bool N
+
 source "net/dccp/ccids/Kconfig"
 
 menu "DCCP Kernel Hacking"
diff --git a/net/dccp/ccids/Kconfig b/net/dccp/ccids/Kconfig
index 7684d83..422af19 100644
--- a/net/dccp/ccids/Kconfig
+++ b/net/dccp/ccids/Kconfig
@@ -1,6 +1,34 @@
 menu "DCCP CCIDs Configuration (EXPERIMENTAL)"
 	depends on IP_DCCP && EXPERIMENTAL
 
+config IP_DCCP_CCID2
+	tristate "CCID2 (TCP) (EXPERIMENTAL)"
+	depends on IP_DCCP
+	select IP_DCCP_ACKVEC
+	---help---
+	  CCID 2, TCP-like Congestion Control, denotes Additive Increase,
+	  Multiplicative Decrease (AIMD) congestion control with behavior
+	  modelled directly on TCP, including congestion window, slow start,
+	  timeouts, and so forth [RFC 2581].  CCID 2 achieves maximum
+	  bandwidth over the long term, consistent with the use of end-to-end
+	  congestion control, but halves its congestion window in response to
+	  each congestion event.  This leads to the abrupt rate changes
+	  typical of TCP.  Applications should use CCID 2 if they prefer
+	  maximum bandwidth utilization to steadiness of rate.  This is often
+	  the case for applications that are not playing their data directly
+	  to the user.  For example, a hypothetical application that
+	  transferred files over DCCP, using application-level retransmissions
+	  for lost packets, would prefer CCID 2 to CCID 3.  On-line games may
+	  also prefer CCID 2.
+
+	  CCID 2 is further described in:
+	  http://www.icir.org/kohler/dccp/draft-ietf-dccp-ccid2-10.txt
+
+	  This text was extracted from:
+	  http://www.icir.org/kohler/dccp/draft-ietf-dccp-spec-13.txt
+
+	  If in doubt, say M.
+
 config IP_DCCP_CCID3
 	tristate "CCID3 (TFRC) (EXPERIMENTAL)"
 	depends on IP_DCCP
@@ -15,10 +43,15 @@ config IP_DCCP_CCID3
 	  suitable than CCID 2 for applications such streaming media where a
 	  relatively smooth sending rate is of importance.
 
-	  CCID 3 is further described in [CCID 3 PROFILE]. The TFRC
-	  congestion control algorithms were initially described in RFC 3448.
+	  CCID 3 is further described in:
+
+	  http://www.icir.org/kohler/dccp/draft-ietf-dccp-ccid3-11.txt.
+
+	  The TFRC congestion control algorithms were initially described in
+	  RFC 3448.
 
-	  This text was extracted from draft-ietf-dccp-spec-11.txt.
+	  This text was extracted from:
+	  http://www.icir.org/kohler/dccp/draft-ietf-dccp-spec-13.txt
 	  
 	  If in doubt, say M.
 
diff --git a/net/dccp/ccids/Makefile b/net/dccp/ccids/Makefile
index 956f79f..438f20b 100644
--- a/net/dccp/ccids/Makefile
+++ b/net/dccp/ccids/Makefile
@@ -2,4 +2,8 @@ obj-$(CONFIG_IP_DCCP_CCID3) += dccp_ccid
 
 dccp_ccid3-y := ccid3.o
 
+obj-$(CONFIG_IP_DCCP_CCID2) += dccp_ccid2.o
+
+dccp_ccid2-y := ccid2.o
+
 obj-y += lib/
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c
new file mode 100644
index 0000000..5495980
--- /dev/null
+++ b/net/dccp/ccids/ccid2.c
@@ -0,0 +1,838 @@
+/*
+ *  net/dccp/ccids/ccid2.c
+ *
+ *  Copyright (c) 2005, 2006 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *
+ *  Changes to meet Linux coding standards, and DCCP infrastructure fixes.
+ *
+ *  Copyright (c) 2006 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This implementation should follow: draft-ietf-dccp-ccid2-10.txt
+ *
+ * BUGS:
+ * - sequence number wrapping
+ * - jiffies wrapping
+ */
+
+#include <linux/config.h>
+#include "../ccid.h"
+#include "../dccp.h"
+#include "ccid2.h"
+
+static int ccid2_debug;
+
+#if 0
+#define CCID2_DEBUG
+#endif
+
+#ifdef CCID2_DEBUG
+#define ccid2_pr_debug(format, a...) \
+        do { if (ccid2_debug) \
+                printk(KERN_DEBUG "%s: " format, __FUNCTION__, ##a); \
+        } while (0)
+#else
+#define ccid2_pr_debug(format, a...)
+#endif
+
+static const int ccid2_seq_len = 128;
+
+static inline struct ccid2_hc_tx_sock *ccid2_hc_tx_sk(const struct sock *sk)
+{
+	return dccp_sk(sk)->dccps_hc_tx_ccid_private;
+}
+
+static inline struct ccid2_hc_rx_sock *ccid2_hc_rx_sk(const struct sock *sk)
+{
+	return dccp_sk(sk)->dccps_hc_rx_ccid_private;
+}
+
+#ifdef CCID2_DEBUG
+static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hctx)
+{
+	int len = 0;
+	struct ccid2_seq *seqp;
+	int pipe = 0;
+
+	seqp = hctx->ccid2hctx_seqh;
+
+	/* there is data in the chain */
+	if (seqp != hctx->ccid2hctx_seqt) {
+		seqp = seqp->ccid2s_prev;
+		len++;
+		if (!seqp->ccid2s_acked)
+			pipe++;
+	
+		while (seqp != hctx->ccid2hctx_seqt) {
+			struct ccid2_seq *prev;
+
+			prev = seqp->ccid2s_prev;
+			len++;
+			if (!prev->ccid2s_acked)
+				pipe++;
+
+			/* packets are sent sequentially */
+			BUG_ON(seqp->ccid2s_seq <= prev->ccid2s_seq);
+			BUG_ON(seqp->ccid2s_sent < prev->ccid2s_sent);
+			BUG_ON(len > ccid2_seq_len);
+
+			seqp = prev;
+		}
+	}
+
+	BUG_ON(pipe != hctx->ccid2hctx_pipe);
+	ccid2_pr_debug("len of chain=%d\n", len);
+
+	do {
+		seqp = seqp->ccid2s_prev;
+		len++;
+		BUG_ON(len > ccid2_seq_len);
+	} while(seqp != hctx->ccid2hctx_seqh);
+
+	BUG_ON(len != ccid2_seq_len);
+	ccid2_pr_debug("total len=%d\n", len);
+}
+#else
+#define ccid2_hc_tx_check_sanity(hctx) do {} while (0)
+#endif
+
+static int ccid2_hc_tx_send_packet(struct sock *sk,
+				   struct sk_buff *skb, int len)
+{
+	struct ccid2_hc_tx_sock *hctx;
+	
+	switch (DCCP_SKB_CB(skb)->dccpd_type) {
+	case 0: /* XXX data packets from userland come through like this */
+	case DCCP_PKT_DATA:
+	case DCCP_PKT_DATAACK:
+		break;
+	/* No congestion control on other packets */
+	default:
+		return 0;
+	}
+
+        hctx = ccid2_hc_tx_sk(sk);
+
+	ccid2_pr_debug("pipe=%d cwnd=%d\n", hctx->ccid2hctx_pipe,
+		       hctx->ccid2hctx_cwnd);
+	
+	if (hctx->ccid2hctx_pipe < hctx->ccid2hctx_cwnd) {
+		/* OK we can send... make sure previous packet was sent off */
+		if (!hctx->ccid2hctx_sendwait) {
+			hctx->ccid2hctx_sendwait = 1;
+			return 0;
+		}
+	}
+
+	return 100; /* XXX */
+}
+
+static void ccid2_change_l_ack_ratio(struct sock *sk, int val)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	/*
+	 * XXX I don't really agree with val != 2.  If cwnd is 1, ack ratio
+	 * should be 1... it shouldn't be allowed to become 2.
+	 * -sorbo.
+	 */
+	if (val != 2) {
+		struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+		int max = hctx->ccid2hctx_cwnd / 2;
+
+		/* round up */
+		if (hctx->ccid2hctx_cwnd & 1)
+			max++;
+
+		if (val > max)
+			val = max;
+	}
+
+	ccid2_pr_debug("changing local ack ratio to %d\n", val);
+	WARN_ON(val <= 0);
+	dp->dccps_l_ack_ratio = val;
+}
+
+static void ccid2_change_cwnd(struct sock *sk, int val)
+{
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+
+	if (val == 0)
+		val = 1;
+
+	/* XXX do we need to change ack ratio? */
+	ccid2_pr_debug("change cwnd to %d\n", val);
+	
+	BUG_ON(val < 1);
+	hctx->ccid2hctx_cwnd = val;
+}
+
+static void ccid2_start_rto_timer(struct sock *sk);
+
+static void ccid2_hc_tx_rto_expire(unsigned long data)
+{
+	struct sock *sk = (struct sock *)data;
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+	long s;
+
+	/* XXX I don't think i'm locking correctly
+	 * -sorbo.
+	 */
+	bh_lock_sock(sk);
+	if (sock_owned_by_user(sk)) {
+		sk_reset_timer(sk, &hctx->ccid2hctx_rtotimer,
+			       jiffies + HZ / 5);
+		goto out;
+	}
+
+	ccid2_pr_debug("RTO_EXPIRE\n");
+
+	ccid2_hc_tx_check_sanity(hctx);
+
+	/* back-off timer */
+	hctx->ccid2hctx_rto <<= 1;
+
+	s = hctx->ccid2hctx_rto / HZ;
+	if (s > 60)
+		hctx->ccid2hctx_rto = 60 * HZ;
+
+	ccid2_start_rto_timer(sk);
+
+	/* adjust pipe, cwnd etc */
+	hctx->ccid2hctx_pipe = 0;
+	hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd >> 1;
+	if (hctx->ccid2hctx_ssthresh < 2)
+		hctx->ccid2hctx_ssthresh = 2;
+	ccid2_change_cwnd(sk, 1);
+
+	/* clear state about stuff we sent */
+	hctx->ccid2hctx_seqt	= hctx->ccid2hctx_seqh;
+	hctx->ccid2hctx_ssacks	= 0;
+	hctx->ccid2hctx_acks	= 0;
+	hctx->ccid2hctx_sent	= 0;
+
+	/* clear ack ratio state. */
+	hctx->ccid2hctx_arsent	 = 0;
+	hctx->ccid2hctx_ackloss  = 0;
+	hctx->ccid2hctx_rpseq	 = 0;
+	hctx->ccid2hctx_rpdupack = -1;
+	ccid2_change_l_ack_ratio(sk, 1);
+	ccid2_hc_tx_check_sanity(hctx);
+out:
+	bh_unlock_sock(sk);
+/*	sock_put(sk); */
+}
+
+static void ccid2_start_rto_timer(struct sock *sk)
+{
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+
+	ccid2_pr_debug("setting RTO timeout=%ld\n", hctx->ccid2hctx_rto);
+
+	BUG_ON(timer_pending(&hctx->ccid2hctx_rtotimer));
+	sk_reset_timer(sk, &hctx->ccid2hctx_rtotimer,
+		       jiffies + hctx->ccid2hctx_rto);
+}
+
+static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, int len)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+	u64 seq;
+
+	ccid2_hc_tx_check_sanity(hctx);
+
+	BUG_ON(!hctx->ccid2hctx_sendwait);
+	hctx->ccid2hctx_sendwait = 0;
+	hctx->ccid2hctx_pipe++;
+	BUG_ON(hctx->ccid2hctx_pipe < 0);
+
+	/* There is an issue.  What if another packet is sent between
+	 * packet_send() and packet_sent().  Then the sequence number would be
+	 * wrong.
+	 * -sorbo.
+	 */
+	seq = dp->dccps_gss;
+
+	hctx->ccid2hctx_seqh->ccid2s_seq   = seq;
+	hctx->ccid2hctx_seqh->ccid2s_acked = 0;
+	hctx->ccid2hctx_seqh->ccid2s_sent  = jiffies;
+	hctx->ccid2hctx_seqh = hctx->ccid2hctx_seqh->ccid2s_next;
+
+	ccid2_pr_debug("cwnd=%d pipe=%d\n", hctx->ccid2hctx_cwnd, 
+		       hctx->ccid2hctx_pipe);
+	
+	if (hctx->ccid2hctx_seqh == hctx->ccid2hctx_seqt) {
+		/* XXX allocate more space */
+		WARN_ON(1);
+	}
+
+	hctx->ccid2hctx_sent++;
+
+	/* Ack Ratio.  Need to maintain a concept of how many windows we sent */
+	hctx->ccid2hctx_arsent++;
+	/* We had an ack loss in this window... */
+	if (hctx->ccid2hctx_ackloss) {
+		if (hctx->ccid2hctx_arsent >= hctx->ccid2hctx_cwnd) {
+			hctx->ccid2hctx_arsent = 0;
+			hctx->ccid2hctx_ackloss = 0;
+		}
+	}
+	/* No acks lost up to now... */
+	else {
+		/* decrease ack ratio if enough packets were sent */
+		if (dp->dccps_l_ack_ratio > 1) {
+			/* XXX don't calculate denominator each time */
+			int denom;
+
+			denom = dp->dccps_l_ack_ratio * dp->dccps_l_ack_ratio - 
+				dp->dccps_l_ack_ratio;
+			denom = hctx->ccid2hctx_cwnd * hctx->ccid2hctx_cwnd / denom;
+
+			if (hctx->ccid2hctx_arsent >= denom) {
+				ccid2_change_l_ack_ratio(sk, dp->dccps_l_ack_ratio - 1);
+				hctx->ccid2hctx_arsent = 0;
+			}
+		}
+		/* we can't increase ack ratio further [1] */
+		else {
+			hctx->ccid2hctx_arsent = 0; /* or maybe set it to cwnd*/
+		}
+	}
+
+	/* setup RTO timer */
+	if (!timer_pending(&hctx->ccid2hctx_rtotimer)) {
+		ccid2_start_rto_timer(sk);
+	}
+#ifdef CCID2_DEBUG
+	ccid2_pr_debug("pipe=%d\n", hctx->ccid2hctx_pipe);
+	ccid2_pr_debug("Sent: seq=%llu\n", seq);
+	do {
+		struct ccid2_seq *seqp = hctx->ccid2hctx_seqt;
+
+		while (seqp != hctx->ccid2hctx_seqh) {
+			ccid2_pr_debug("out seq=%llu acked=%d time=%lu\n",
+			       	       seqp->ccid2s_seq, seqp->ccid2s_acked, 
+				       seqp->ccid2s_sent);
+			seqp = seqp->ccid2s_next;
+		}
+	} while(0);
+	ccid2_pr_debug("=========\n");
+	ccid2_hc_tx_check_sanity(hctx);
+#endif
+}
+
+/* XXX Lame code duplication!
+ * returns -1 if none was found.
+ * else returns the next offset to use in the function call.
+ */
+static int ccid2_ackvector(struct sock *sk, struct sk_buff *skb, int offset,
+			   unsigned char **vec, unsigned char *veclen)
+{
+        const struct dccp_hdr *dh = dccp_hdr(skb);
+        unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb);
+        unsigned char *opt_ptr;
+        const unsigned char *opt_end = (unsigned char *)dh +
+                                        (dh->dccph_doff * 4);
+        unsigned char opt, len;
+        unsigned char *value;
+
+	BUG_ON(offset < 0);
+	options += offset;
+	opt_ptr = options;
+	if (opt_ptr >= opt_end)
+		return -1;
+
+	while (opt_ptr != opt_end) {
+                opt   = *opt_ptr++;
+                len   = 0;
+                value = NULL;
+
+                /* Check if this isn't a single byte option */
+                if (opt > DCCPO_MAX_RESERVED) {
+                        if (opt_ptr == opt_end)
+                                goto out_invalid_option;
+
+                        len = *opt_ptr++;
+                        if (len < 3)
+                                goto out_invalid_option;
+                        /*
+                         * Remove the type and len fields, leaving
+                         * just the value size
+                         */
+                        len     -= 2;
+                        value   = opt_ptr;
+                        opt_ptr += len;
+
+                        if (opt_ptr > opt_end)
+                                goto out_invalid_option;
+                }
+
+		switch (opt) {
+		case DCCPO_ACK_VECTOR_0:
+		case DCCPO_ACK_VECTOR_1:
+			*vec	= value;
+			*veclen = len;
+			return offset + (opt_ptr - options);
+			break;
+		}
+	}
+
+	return -1;
+	
+out_invalid_option:
+	BUG_ON(1); /* should never happen... options were previously parsed ! */
+	return -1;
+}
+
+static void ccid2_hc_tx_kill_rto_timer(struct ccid2_hc_tx_sock *hctx)
+{
+	if (del_timer(&hctx->ccid2hctx_rtotimer))
+		ccid2_pr_debug("deleted RTO timer\n");
+}
+
+static inline void ccid2_new_ack(struct sock *sk, 
+			         struct ccid2_seq *seqp,
+				 unsigned int *maxincr)
+{
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+
+	/* slow start */
+	if (hctx->ccid2hctx_cwnd < hctx->ccid2hctx_ssthresh) {
+		hctx->ccid2hctx_acks = 0;
+
+		/* We can increase cwnd at most maxincr [ack_ratio/2] */
+		if (*maxincr) {
+			/* increase every 2 acks */
+			hctx->ccid2hctx_ssacks++;
+			if (hctx->ccid2hctx_ssacks == 2) {
+				ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd + 1);
+				hctx->ccid2hctx_ssacks = 0;
+				*maxincr = *maxincr - 1;
+			}
+		}
+		/* increased cwnd enough for this single ack */
+		else {
+			hctx->ccid2hctx_ssacks = 0;
+		}
+	}
+	else {
+		hctx->ccid2hctx_ssacks = 0;
+		hctx->ccid2hctx_acks++;
+
+		if (hctx->ccid2hctx_acks >= hctx->ccid2hctx_cwnd) {
+			ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd + 1);
+			hctx->ccid2hctx_acks = 0;
+		}
+	}
+
+	/* update RTO */
+	if (hctx->ccid2hctx_srtt == -1 ||
+	    (jiffies - hctx->ccid2hctx_lastrtt) >= hctx->ccid2hctx_srtt) {
+		unsigned long r = jiffies - seqp->ccid2s_sent;
+		int s;
+
+		/* first measurement */
+		if (hctx->ccid2hctx_srtt == -1) {
+			ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n", 
+			       	       r, jiffies, seqp->ccid2s_seq);
+			hctx->ccid2hctx_srtt = r;
+			hctx->ccid2hctx_rttvar = r >> 1;
+		}
+		else {
+			/* RTTVAR */
+			long tmp = hctx->ccid2hctx_srtt - r;
+			if (tmp < 0)
+				tmp *= -1;
+			
+			tmp >>= 2;
+			hctx->ccid2hctx_rttvar *= 3;
+			hctx->ccid2hctx_rttvar >>= 2;
+			hctx->ccid2hctx_rttvar += tmp;
+
+			/* SRTT */
+			hctx->ccid2hctx_srtt *= 7;
+			hctx->ccid2hctx_srtt >>= 3;
+			tmp = r >> 3;
+			hctx->ccid2hctx_srtt += tmp;
+		}
+		s = hctx->ccid2hctx_rttvar << 2;
+		/* clock granularity is 1 when based on jiffies */
+		if (!s)
+			s = 1;
+		hctx->ccid2hctx_rto = hctx->ccid2hctx_srtt + s;
+
+		/* must be at least a second */
+		s = hctx->ccid2hctx_rto / HZ;
+		/* DCCP doesn't require this [but I like it cuz my code sux] */
+#if 1
+		if (s < 1)
+			hctx->ccid2hctx_rto = HZ;
+#endif			
+		/* max 60 seconds */	
+		if (s > 60)
+			hctx->ccid2hctx_rto = HZ * 60;
+
+		hctx->ccid2hctx_lastrtt = jiffies;
+
+		ccid2_pr_debug("srtt: %ld rttvar: %ld rto: %ld (HZ=%d) R=%lu\n",
+		       	       hctx->ccid2hctx_srtt, hctx->ccid2hctx_rttvar,
+		       	       hctx->ccid2hctx_rto, HZ, r);
+		hctx->ccid2hctx_sent = 0;
+	}
+
+	/* we got a new ack, so re-start RTO timer */
+	ccid2_hc_tx_kill_rto_timer(hctx);
+	ccid2_start_rto_timer(sk);
+}
+
+static void ccid2_hc_tx_dec_pipe(struct ccid2_hc_tx_sock *hctx)
+{
+	hctx->ccid2hctx_pipe--;
+	BUG_ON(hctx->ccid2hctx_pipe < 0);
+
+	if (hctx->ccid2hctx_pipe == 0)
+		ccid2_hc_tx_kill_rto_timer(hctx);
+}
+
+static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+	u64 ackno, seqno;
+	struct ccid2_seq *seqp;
+	unsigned char *vector;
+	unsigned char veclen;
+	int offset = 0;
+	int done = 0;
+	int loss = 0;
+	unsigned int maxincr = 0;
+
+	ccid2_hc_tx_check_sanity(hctx);
+	/* check reverse path congestion */
+	seqno = DCCP_SKB_CB(skb)->dccpd_seq;
+
+	/* XXX this whole "algorithm" is broken.  Need to fix it to keep track
+	 * of the seqnos of the dupacks so that rpseq and rpdupack are correct
+	 * -sorbo.
+	 */
+	/* need to bootstrap */
+	if (hctx->ccid2hctx_rpdupack == -1) {
+		hctx->ccid2hctx_rpdupack = 0;
+		hctx->ccid2hctx_rpseq = seqno;
+	}
+	else {
+		/* check if packet is consecutive */
+		if ((hctx->ccid2hctx_rpseq + 1) == seqno) {
+			hctx->ccid2hctx_rpseq++;
+		}
+		/* it's a later packet */
+		else if (after48(seqno, hctx->ccid2hctx_rpseq)) {
+			hctx->ccid2hctx_rpdupack++;
+			
+			/* check if we got enough dupacks */
+			if (hctx->ccid2hctx_rpdupack >=
+			    hctx->ccid2hctx_numdupack) {
+
+				hctx->ccid2hctx_rpdupack = -1; /* XXX lame */
+				hctx->ccid2hctx_rpseq = 0;
+
+				ccid2_change_l_ack_ratio(sk, dp->dccps_l_ack_ratio << 1);
+			}
+		}
+	}
+
+	/* check forward path congestion */
+	/* still didn't send out new data packets */
+	if (hctx->ccid2hctx_seqh == hctx->ccid2hctx_seqt)
+		return;
+
+	switch (DCCP_SKB_CB(skb)->dccpd_type) {
+	case DCCP_PKT_ACK:
+	case DCCP_PKT_DATAACK:
+		break;
+	
+	default:
+		return;
+	}
+
+	ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq;
+	seqp = hctx->ccid2hctx_seqh->ccid2s_prev;
+
+	/* If in slow-start, cwnd can increase at most Ack Ratio / 2 packets for
+	 * this single ack.  I round up.
+	 * -sorbo.
+	 */
+	maxincr = dp->dccps_l_ack_ratio >> 1;
+	maxincr++;
+
+	/* go through all ack vectors */
+	while ((offset = ccid2_ackvector(sk, skb, offset, 
+					 &vector, &veclen)) != -1) {
+		/* go through this ack vector */
+		while (veclen--) {
+			const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK;
+			u64 ackno_end_rl;
+
+			dccp_set_seqno(&ackno_end_rl, ackno - rl);
+			ccid2_pr_debug("ackvec start:%llu end:%llu\n", ackno, 
+				       ackno_end_rl);
+			/* if the seqno we are analyzing is larger than the
+			 * current ackno, then move towards the tail of our
+			 * seqnos.
+			 */
+			while (after48(seqp->ccid2s_seq, ackno)) {
+				if (seqp == hctx->ccid2hctx_seqt) {
+					done = 1;
+					break;
+				}
+				seqp = seqp->ccid2s_prev;
+			}
+			if (done)
+				break;
+
+			/* check all seqnos in the range of the vector
+			 * run length 
+			 */
+			while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) {
+				const u8 state = (*vector & 
+						  DCCP_ACKVEC_STATE_MASK) >> 6;
+			
+				/* new packet received or marked */
+				if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED &&
+				    !seqp->ccid2s_acked) {
+				    	if (state == 
+					    DCCP_ACKVEC_STATE_ECN_MARKED) {
+						loss = 1;
+					}
+					else {
+						ccid2_new_ack(sk, seqp,
+							      &maxincr);
+					}
+
+					seqp->ccid2s_acked = 1;
+					ccid2_pr_debug("Got ack for %llu\n",
+					       	       seqp->ccid2s_seq);
+					ccid2_hc_tx_dec_pipe(hctx);
+				}
+				if (seqp == hctx->ccid2hctx_seqt) {
+					done = 1;
+					break;
+				}
+				seqp = seqp->ccid2s_next;
+			}
+			if (done)
+				break;
+			       
+
+			dccp_set_seqno(&ackno, ackno_end_rl - 1);
+			vector++;
+		}
+		if (done)
+			break;
+	}
+
+	/* The state about what is acked should be correct now
+	 * Check for NUMDUPACK
+	 */
+	seqp = hctx->ccid2hctx_seqh->ccid2s_prev;
+	done = 0;
+	while (1) {
+		if (seqp->ccid2s_acked) {
+			done++;
+			if (done == hctx->ccid2hctx_numdupack) {
+				break;
+			}	
+		}
+		if (seqp == hctx->ccid2hctx_seqt) {
+			break;
+		}
+		seqp = seqp->ccid2s_prev;
+	}
+
+	/* If there are at least 3 acknowledgements, anything unacknowledged
+	 * below the last sequence number is considered lost
+	 */
+	if (done == hctx->ccid2hctx_numdupack) {
+		struct ccid2_seq *last_acked = seqp;
+
+		/* check for lost packets */
+		while (1) {
+			if (!seqp->ccid2s_acked) {
+				loss = 1;
+				ccid2_hc_tx_dec_pipe(hctx);
+			}
+			if (seqp == hctx->ccid2hctx_seqt)
+				break;
+			seqp = seqp->ccid2s_prev;
+		}
+
+		hctx->ccid2hctx_seqt = last_acked;
+	}
+
+	/* trim acked packets in tail */
+	while (hctx->ccid2hctx_seqt != hctx->ccid2hctx_seqh) {
+		if (!hctx->ccid2hctx_seqt->ccid2s_acked)
+			break;
+		
+		hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqt->ccid2s_next;
+	}
+
+	if (loss) {
+		/* XXX do bit shifts guarantee a 0 as the new bit? */
+		ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd >> 1);
+		hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd;
+		if (hctx->ccid2hctx_ssthresh < 2)
+			hctx->ccid2hctx_ssthresh = 2;
+	}
+
+	ccid2_hc_tx_check_sanity(hctx);
+}
+
+static int ccid2_hc_tx_init(struct sock *sk)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+        struct ccid2_hc_tx_sock *hctx;
+	int seqcount = ccid2_seq_len;
+	int i;
+
+        dp->dccps_hc_tx_ccid_private = kzalloc(sizeof(*hctx), gfp_any());
+        if (dp->dccps_hc_tx_ccid_private == NULL)
+                return -ENOMEM;
+
+        hctx = ccid2_hc_tx_sk(sk);
+
+	/* XXX init variables with proper values */
+	hctx->ccid2hctx_cwnd	  = 1;
+	hctx->ccid2hctx_ssthresh  = 10;
+	hctx->ccid2hctx_numdupack = 3;
+
+	/* XXX init ~ to window size... */
+	hctx->ccid2hctx_seqbuf = kmalloc(sizeof(*hctx->ccid2hctx_seqbuf) *
+					 seqcount, gfp_any());
+	if (hctx->ccid2hctx_seqbuf == NULL) {
+		kfree(dp->dccps_hc_tx_ccid_private);
+		dp->dccps_hc_tx_ccid_private = NULL;
+		return -ENOMEM;
+	}
+	for (i = 0; i < (seqcount - 1); i++) {
+		hctx->ccid2hctx_seqbuf[i].ccid2s_next = 
+					&hctx->ccid2hctx_seqbuf[i + 1];
+		hctx->ccid2hctx_seqbuf[i + 1].ccid2s_prev = 
+					&hctx->ccid2hctx_seqbuf[i];
+	}
+	hctx->ccid2hctx_seqbuf[seqcount - 1].ccid2s_next =
+					hctx->ccid2hctx_seqbuf;
+	hctx->ccid2hctx_seqbuf->ccid2s_prev =
+					&hctx->ccid2hctx_seqbuf[seqcount - 1];
+
+	hctx->ccid2hctx_seqh	 = hctx->ccid2hctx_seqbuf;
+	hctx->ccid2hctx_seqt	 = hctx->ccid2hctx_seqh;
+	hctx->ccid2hctx_sent	 = 0;
+	hctx->ccid2hctx_rto	 = 3 * HZ;
+	hctx->ccid2hctx_srtt	 = -1;
+	hctx->ccid2hctx_rttvar	 = -1;
+	hctx->ccid2hctx_lastrtt  = 0;
+	hctx->ccid2hctx_rpdupack = -1;
+
+	hctx->ccid2hctx_rtotimer.function = &ccid2_hc_tx_rto_expire;
+	hctx->ccid2hctx_rtotimer.data	  = (unsigned long)sk;
+	init_timer(&hctx->ccid2hctx_rtotimer);
+
+	ccid2_hc_tx_check_sanity(hctx);
+	return 0;
+}
+
+static void ccid2_hc_tx_exit(struct sock *sk)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+        struct ccid2_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+
+	ccid2_hc_tx_kill_rto_timer(hctx);
+
+	kfree(hctx->ccid2hctx_seqbuf);
+
+	kfree(dp->dccps_hc_tx_ccid_private);
+	dp->dccps_hc_tx_ccid_private = NULL;
+}
+
+static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
+{
+	const struct dccp_sock *dp = dccp_sk(sk);
+	struct ccid2_hc_rx_sock *hcrx = ccid2_hc_rx_sk(sk);
+
+	switch (DCCP_SKB_CB(skb)->dccpd_type) {
+	case DCCP_PKT_DATA:
+	case DCCP_PKT_DATAACK:
+		hcrx->ccid2hcrx_data++;
+		if (hcrx->ccid2hcrx_data >= dp->dccps_r_ack_ratio) {
+			dccp_send_ack(sk);
+			hcrx->ccid2hcrx_data = 0;
+		}
+		break;
+	}
+}
+
+static int ccid2_hc_rx_init(struct sock *sk)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+        dp->dccps_hc_rx_ccid_private = kzalloc(sizeof(struct ccid2_hc_rx_sock),
+					       gfp_any());
+        return dp->dccps_hc_rx_ccid_private == NULL ? -ENOMEM : 0;
+}
+
+static void ccid2_hc_rx_exit(struct sock *sk)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+
+	kfree(dp->dccps_hc_rx_ccid_private);
+	dp->dccps_hc_rx_ccid_private = NULL;
+}
+
+static struct ccid ccid2 = {
+	.ccid_id		= 2,
+	.ccid_name		= "ccid2",
+	.ccid_owner		= THIS_MODULE,
+	.ccid_hc_tx_init	= ccid2_hc_tx_init,
+	.ccid_hc_tx_exit	= ccid2_hc_tx_exit,
+	.ccid_hc_tx_send_packet	= ccid2_hc_tx_send_packet,
+	.ccid_hc_tx_packet_sent	= ccid2_hc_tx_packet_sent,
+	.ccid_hc_tx_packet_recv	= ccid2_hc_tx_packet_recv,
+	.ccid_hc_rx_init	= ccid2_hc_rx_init,
+	.ccid_hc_rx_exit	= ccid2_hc_rx_exit,
+	.ccid_hc_rx_packet_recv	= ccid2_hc_rx_packet_recv,
+};
+
+module_param(ccid2_debug, int, 0444);
+MODULE_PARM_DESC(ccid2_debug, "Enable debug messages");
+ 
+static __init int ccid2_module_init(void)
+{
+	return ccid_register(&ccid2);
+}
+module_init(ccid2_module_init);
+
+static __exit void ccid2_module_exit(void)
+{
+	ccid_unregister(&ccid2);
+}
+module_exit(ccid2_module_exit);
+
+MODULE_AUTHOR("Andrea Bittau <a.bittau@cs.ucl.ac.uk>");
+MODULE_DESCRIPTION("DCCP TCP CCID2 CCID");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("net-dccp-ccid-2");
diff --git a/net/dccp/ccids/ccid2.h b/net/dccp/ccids/ccid2.h
new file mode 100644
index 0000000..0b08c90
--- /dev/null
+++ b/net/dccp/ccids/ccid2.h
@@ -0,0 +1,69 @@
+/*
+ *  net/dccp/ccids/ccid2.h
+ *
+ *  Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _DCCP_CCID2_H_
+#define _DCCP_CCID2_H_
+
+struct ccid2_seq {
+	u64			ccid2s_seq;
+	unsigned long		ccid2s_sent;
+	int			ccid2s_acked;
+	struct ccid2_seq	*ccid2s_prev;
+	struct ccid2_seq	*ccid2s_next;
+};
+
+/** struct ccid2_hc_tx_sock - CCID2 TX half connection
+ *
+ * @ccid2hctx_ssacks - ACKs recv in slow start
+ * @ccid2hctx_acks - ACKS recv in AI phase
+ * @ccid2hctx_sent - packets sent in this window
+ * @ccid2hctx_lastrtt -time RTT was last measured
+ * @ccid2hctx_arsent - packets sent [ack ratio]
+ * @ccid2hctx_ackloss - ack was lost in this win
+ * @ccid2hctx_rpseq - last consecutive seqno
+ * @ccid2hctx_rpdupack - dupacks since rpseq
+*/
+struct ccid2_hc_tx_sock {
+	int			ccid2hctx_cwnd;
+	int			ccid2hctx_ssacks;
+	int			ccid2hctx_acks;
+	int			ccid2hctx_ssthresh;
+	int			ccid2hctx_pipe;
+	int			ccid2hctx_numdupack;
+	struct ccid2_seq	*ccid2hctx_seqbuf;
+	struct ccid2_seq	*ccid2hctx_seqh;
+	struct ccid2_seq	*ccid2hctx_seqt;
+	long			ccid2hctx_rto;
+	long			ccid2hctx_srtt;
+	long			ccid2hctx_rttvar;
+	int			ccid2hctx_sent;
+	unsigned long		ccid2hctx_lastrtt;
+	struct timer_list	ccid2hctx_rtotimer;
+	unsigned long		ccid2hctx_arsent;
+	int			ccid2hctx_ackloss;
+	u64			ccid2hctx_rpseq;
+	int			ccid2hctx_rpdupack;
+	int			ccid2hctx_sendwait;
+};
+
+struct ccid2_hc_rx_sock {
+	int	ccid2hcrx_data;
+};
+
+#endif /* _DCCP_CCID2_H_ */
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index fd5a615..605e9d5 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -1080,6 +1080,7 @@ int dccp_v4_init_sock(struct sock *sk)
 	dp->dccps_mss_cache = 536;
 	dp->dccps_role = DCCP_ROLE_UNDEFINED;
 	dp->dccps_service = DCCP_SERVICE_INVALID_VALUE;
+	dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1;
 
 	return 0;
 }


^ permalink raw reply related

* [PATCH 9/11][DCCP]: Don't alloc ack vector for the control sock
From: Arnaldo Carvalho de Melo @ 2006-02-04  2:38 UTC (permalink / raw)
  To: dccp

[-- Attachment #1: Type: text/plain, Size: 145 bytes --]

Hi David,

    Please consider pulling from:

master.kernel.org:/pub/scm/linux/kernel/git/acme/net-2.6.17.git

Best Regards,

- Arnaldo

[-- Attachment #2: 9.patch --]
[-- Type: text/x-patch, Size: 1652 bytes --]

tree 53906d2a70f6c94436b548e25548c10cea620498
parent c312bf30df32e63f17614eb9c7e127e85f40e354
author Arnaldo Carvalho de Melo <acme@mandriva.com> 1138987845 -0200
committer Arnaldo Carvalho de Melo <acme@mandriva.com> 1138987845 -0200

[DCCP]: Don't alloc ack vector for the control sock

Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>

------------------------------------------------------------------------------

 ipv4.c |   11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

------------------------------------------------------------------------------

diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 9fedeca..fd5a615 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -1040,12 +1040,6 @@ int dccp_v4_init_sock(struct sock *sk)
 	dccp_options_init(&dp->dccps_options);
 	do_gettimeofday(&dp->dccps_epoch);
 
-	if (dp->dccps_options.dccpo_send_ack_vector) {
-		dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(GFP_KERNEL);
-		if (dp->dccps_hc_rx_ackvec == NULL)
-			return -ENOMEM;
-	}
-
 	/*
 	 * FIXME: We're hardcoding the CCID, and doing this at this point makes
 	 * the listening (master) sock get CCID control blocks, which is not
@@ -1054,6 +1048,11 @@ int dccp_v4_init_sock(struct sock *sk)
 	 * setsockopt(CCIDs-I-want/accept). -acme
 	 */
 	if (likely(!dccp_ctl_socket_init)) {
+		if (dp->dccps_options.dccpo_send_ack_vector) {
+			dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(GFP_KERNEL);
+			if (dp->dccps_hc_rx_ackvec == NULL)
+				return -ENOMEM;
+		}
 		dp->dccps_hc_rx_ccid = ccid_init(dp->dccps_options.dccpo_rx_ccid,
 						 sk);
 		dp->dccps_hc_tx_ccid = ccid_init(dp->dccps_options.dccpo_tx_ccid,


^ permalink raw reply related

* [PATCH 8/11][DCCP] ackvec: Delete all the ack vector records in dccp_ackvec_free
From: Arnaldo Carvalho de Melo @ 2006-02-04  2:38 UTC (permalink / raw)
  To: dccp

[-- Attachment #1: Type: text/plain, Size: 145 bytes --]

Hi David,

    Please consider pulling from:

master.kernel.org:/pub/scm/linux/kernel/git/acme/net-2.6.17.git

Best Regards,

- Arnaldo

[-- Attachment #2: 8.patch --]
[-- Type: text/x-patch, Size: 1189 bytes --]

tree 39d2dec525df09a590e0d9ad162d734f3344e26d
parent 90753caf01c1a27cf3fd18f0e71c77db268856d3
author Arnaldo Carvalho de Melo <acme@mandriva.com> 1138987721 -0200
committer Arnaldo Carvalho de Melo <acme@mandriva.com> 1138987721 -0200

[DCCP] ackvec: Delete all the ack vector records in dccp_ackvec_free

Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>

------------------------------------------------------------------------------

 ackvec.c |   12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

------------------------------------------------------------------------------

diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c
index 2a82acc..08b1b08 100644
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -159,7 +159,17 @@ void dccp_ackvec_free(struct dccp_ackvec
 {
 	if (unlikely(av == NULL))
 		return;
-	WARN_ON(!list_empty(&av->dccpav_records));
+
+	if (!list_empty(&av->dccpav_records)) {
+		struct dccp_ackvec_record *avr, *next;
+
+		list_for_each_entry_safe(avr, next, &av->dccpav_records,
+					 dccpavr_node) {
+			list_del_init(&avr->dccpavr_node);
+			dccp_ackvec_record_delete(avr);
+		}
+	}
+
 	kmem_cache_free(dccp_ackvec_slab, av);
 }
 


^ permalink raw reply related

* [PATCH 7/11][DCCP] CCID: Allow ccid_{init,exit} to be NULL
From: Arnaldo Carvalho de Melo @ 2006-02-04  2:38 UTC (permalink / raw)
  To: dccp

[-- Attachment #1: Type: text/plain, Size: 145 bytes --]

Hi David,

    Please consider pulling from:

master.kernel.org:/pub/scm/linux/kernel/git/acme/net-2.6.17.git

Best Regards,

- Arnaldo

[-- Attachment #2: 7.patch --]
[-- Type: text/x-patch, Size: 2102 bytes --]

tree 819a12569a02512dbbb427d857fbe22756bc4772
parent 90e6088d8191c44c120ede18b19e09ad0da28121
author Arnaldo Carvalho de Melo <acme@mandriva.com> 1138987435 -0200
committer Arnaldo Carvalho de Melo <acme@mandriva.com> 1138987435 -0200

[DCCP] CCID: Allow ccid_{init,exit} to be NULL

Testing if the ccid being instantiated has these methods in
ccid_init().

Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>

------------------------------------------------------------------------------

 ccid.c        |    5 +----
 ccids/ccid3.c |   11 -----------
 2 files changed, 1 insertion(+), 15 deletions(-)

------------------------------------------------------------------------------

diff --git a/net/dccp/ccid.c b/net/dccp/ccid.c
index 9d8fc0e..06b191a 100644
--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -59,9 +59,6 @@ int ccid_register(struct ccid *ccid)
 {
 	int err;
 
-	if (ccid->ccid_init == NULL)
-		return -1;
-
 	ccids_write_lock();
 	err = -EEXIST;
 	if (ccids[ccid->ccid_id] == NULL) {
@@ -106,7 +103,7 @@ struct ccid *ccid_init(unsigned char id,
 	if (!try_module_get(ccid->ccid_owner))
 		goto out_err;
 
-	if (ccid->ccid_init(sk) != 0)
+	if (ccid->ccid_init != NULL && ccid->ccid_init(sk) != 0)
 		goto out_module_put;
 out:
 	ccids_read_unlock();
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
index aa68e0a..c539c33 100644
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -76,15 +76,6 @@ static struct dccp_tx_hist *ccid3_tx_his
 static struct dccp_rx_hist *ccid3_rx_hist;
 static struct dccp_li_hist *ccid3_li_hist;
 
-static int ccid3_init(struct sock *sk)
-{
-	return 0;
-}
-
-static void ccid3_exit(struct sock *sk)
-{
-}
-
 /* TFRC sender states */
 enum ccid3_hc_tx_states {
        	TFRC_SSTATE_NO_SENT = 1,
@@ -1178,8 +1169,6 @@ static struct ccid ccid3 = {
 	.ccid_id		   = 3,
 	.ccid_name		   = "ccid3",
 	.ccid_owner		   = THIS_MODULE,
-	.ccid_init		   = ccid3_init,
-	.ccid_exit		   = ccid3_exit,
 	.ccid_hc_tx_init	   = ccid3_hc_tx_init,
 	.ccid_hc_tx_exit	   = ccid3_hc_tx_exit,
 	.ccid_hc_tx_send_packet	   = ccid3_hc_tx_send_packet,

^ permalink raw reply related

* [PATCH 6/11][DCCP] ackvec: Introduce ack vector records
From: Arnaldo Carvalho de Melo @ 2006-02-04  2:38 UTC (permalink / raw)
  To: dccp

[-- Attachment #1: Type: text/plain, Size: 145 bytes --]

Hi David,

    Please consider pulling from:

master.kernel.org:/pub/scm/linux/kernel/git/acme/net-2.6.17.git

Best Regards,

- Arnaldo

[-- Attachment #2: 6.patch --]
[-- Type: text/x-patch, Size: 14469 bytes --]

tree eb7f8a8d6cd052db0733fe81197fa99897c7f338
parent afdb503062867b41594a55474660105ad386dfc4
author Arnaldo Carvalho de Melo <acme@mandriva.com> 1138971876 -0200
committer Arnaldo Carvalho de Melo <acme@mandriva.com> 1138971876 -0200

[DCCP] ackvec: Introduce ack vector records

Based on a patch by Andrea Bittau.

Signed-off-by: Andrea Bittau <a.bittau@cs.ucl.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>

------------------------------------------------------------------------------

 ackvec.c |  240 ++++++++++++++++++++++++++++++++++++++-------------------------
 ackvec.h |   31 ++++++--
 2 files changed, 173 insertions(+), 98 deletions(-)

------------------------------------------------------------------------------

diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c
index 6440825..2a82acc 100644
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -22,6 +22,47 @@
 #include <net/sock.h>
 
 static kmem_cache_t *dccp_ackvec_slab;
+static kmem_cache_t *dccp_ackvec_record_slab;
+
+static struct dccp_ackvec_record *dccp_ackvec_record_new(void)
+{
+	struct dccp_ackvec_record *avr =
+			kmem_cache_alloc(dccp_ackvec_record_slab, GFP_ATOMIC);
+
+	if (avr != NULL)
+		INIT_LIST_HEAD(&avr->dccpavr_node);
+
+	return avr;
+}
+
+static void dccp_ackvec_record_delete(struct dccp_ackvec_record *avr)
+{
+	if (unlikely(avr == NULL))
+		return;
+	/* Check if deleting a linked record */
+	WARN_ON(!list_empty(&avr->dccpavr_node));
+	kmem_cache_free(dccp_ackvec_record_slab, avr);
+}
+ 
+static void dccp_ackvec_insert_avr(struct dccp_ackvec *av, 
+				   struct dccp_ackvec_record *avr)
+{
+	/*
+	 * AVRs are sorted by seqno. Since we are sending them in order, we
+	 * just add the AVR at the head of the list.
+	 * -sorbo.
+	 */
+	if (!list_empty(&av->dccpav_records)) {
+		const struct dccp_ackvec_record *head =
+					list_entry(av->dccpav_records.next,
+						   struct dccp_ackvec_record,
+						   dccpavr_node);
+		BUG_ON(before48(avr->dccpavr_ack_seqno,
+				head->dccpavr_ack_seqno));
+	}
+
+	list_add(&avr->dccpavr_node, &av->dccpav_records);
+}
 
 int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
 {
@@ -35,6 +76,14 @@ int dccp_insert_option_ackvec(struct soc
 	struct timeval now;
 	u32 elapsed_time;
 	unsigned char *to, *from;
+	struct dccp_ackvec_record *avr;
+
+	if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
+		return -1;
+
+	avr = dccp_ackvec_record_new();
+	if (avr == NULL)
+		return -1;
 
 	dccp_timestamp(sk, &now);
 	elapsed_time = timeval_delta(&now, &av->dccpav_time) / 10;
@@ -42,19 +91,6 @@ int dccp_insert_option_ackvec(struct soc
 	if (elapsed_time != 0)
 		dccp_insert_option_elapsed_time(sk, skb, elapsed_time);
 
-	if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
-		return -1;
-
-	/*
-	 * XXX: now we have just one ack vector sent record, so
-	 * we have to wait for it to be cleared.
-	 *
-	 * Of course this is not acceptable, but this is just for
-	 * basic testing now.
-	 */
-	if (av->dccpav_ack_seqno != DCCP_MAX_SEQNO + 1)
-		return -1;
-
 	DCCP_SKB_CB(skb)->dccpd_opt_len += len;
 
 	to    = skb_push(skb, len);
@@ -65,8 +101,8 @@ int dccp_insert_option_ackvec(struct soc
 	from = av->dccpav_buf + av->dccpav_buf_head;
 
 	/* Check if buf_head wraps */
-	if ((int)av->dccpav_buf_head + len > av->dccpav_vec_len) {
-		const u32 tailsize = av->dccpav_vec_len - av->dccpav_buf_head;
+	if ((int)av->dccpav_buf_head + len > DCCP_MAX_ACKVEC_LEN) {
+		const u32 tailsize = DCCP_MAX_ACKVEC_LEN - av->dccpav_buf_head;
 
 		memcpy(to, from, tailsize);
 		to   += tailsize;
@@ -83,21 +119,21 @@ int dccp_insert_option_ackvec(struct soc
 	 *	sequence number it used for the ack packet; ack_ptr will equal
 	 *	buf_head; ack_ackno will equal buf_ackno; and ack_nonce will
 	 *	equal buf_nonce.
-	 *
-	 * This implemention uses just one ack record for now.
 	 */
-	av->dccpav_ack_seqno = DCCP_SKB_CB(skb)->dccpd_seq;
-	av->dccpav_ack_ptr   = av->dccpav_buf_head;
-	av->dccpav_ack_ackno = av->dccpav_buf_ackno;
-	av->dccpav_ack_nonce = av->dccpav_buf_nonce;
-	av->dccpav_sent_len  = av->dccpav_vec_len;
+	avr->dccpavr_ack_seqno = DCCP_SKB_CB(skb)->dccpd_seq;
+	avr->dccpavr_ack_ptr   = av->dccpav_buf_head;
+	avr->dccpavr_ack_ackno = av->dccpav_buf_ackno;
+	avr->dccpavr_ack_nonce = av->dccpav_buf_nonce;
+	avr->dccpavr_sent_len  = av->dccpav_vec_len;
+
+	dccp_ackvec_insert_avr(av, avr);
 
 	dccp_pr_debug("%sACK Vector 0, len=%d, ack_seqno=%llu, "
 		      "ack_ackno=%llu\n",
-		      debug_prefix, av->dccpav_sent_len,
-		      (unsigned long long)av->dccpav_ack_seqno,
-		      (unsigned long long)av->dccpav_ack_ackno);
-	return -1;
+		      debug_prefix, avr->dccpavr_sent_len,
+		      (unsigned long long)avr->dccpavr_ack_seqno,
+		      (unsigned long long)avr->dccpavr_ack_ackno);
+	return 0;
 }
 
 struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority)
@@ -107,13 +143,13 @@ struct dccp_ackvec *dccp_ackvec_alloc(co
 	if (av != NULL) {
 		av->dccpav_buf_head	=
 			av->dccpav_buf_tail = DCCP_MAX_ACKVEC_LEN - 1;
-		av->dccpav_buf_ackno	=
-			av->dccpav_ack_ackno = av->dccpav_ack_seqno = ~0LLU;
+		av->dccpav_buf_ackno	= DCCP_MAX_SEQNO + 1;
 		av->dccpav_buf_nonce = av->dccpav_buf_nonce = 0;
 		av->dccpav_ack_ptr	= 0;
 		av->dccpav_time.tv_sec	= 0;
 		av->dccpav_time.tv_usec	= 0;
 		av->dccpav_sent_len	= av->dccpav_vec_len = 0;
+		INIT_LIST_HEAD(&av->dccpav_records);
 	}
 
 	return av;
@@ -121,6 +157,9 @@ struct dccp_ackvec *dccp_ackvec_alloc(co
 
 void dccp_ackvec_free(struct dccp_ackvec *av)
 {
+	if (unlikely(av == NULL))
+		return;
+	WARN_ON(!list_empty(&av->dccpav_records));
 	kmem_cache_free(dccp_ackvec_slab, av);
 }
 
@@ -299,44 +338,50 @@ void dccp_ackvec_print(const struct dccp
 }
 #endif
 
-static void dccp_ackvec_throw_away_ack_record(struct dccp_ackvec *av)
+static void dccp_ackvec_throw_record(struct dccp_ackvec *av,
+				     struct dccp_ackvec_record *avr)
 {
-	/*
-	 * As we're keeping track of the ack vector size (dccpav_vec_len) and
-	 * the sent ack vector size (dccpav_sent_len) we don't need
-	 * dccpav_buf_tail at all, but keep this code here as in the future
-	 * we'll implement a vector of ack records, as suggested in
-	 * draft-ietf-dccp-spec-11.txt Appendix A. -acme
-	 */
-#if 0
-	u32 new_buf_tail = av->dccpav_ack_ptr + 1;
-	if (new_buf_tail >= av->dccpav_vec_len)
-		new_buf_tail -= av->dccpav_vec_len;
-	av->dccpav_buf_tail = new_buf_tail;
-#endif
-	av->dccpav_vec_len -= av->dccpav_sent_len;
+	struct dccp_ackvec_record *next;
+
+	av->dccpav_buf_tail = avr->dccpavr_ack_ptr - 1;
+	if (av->dccpav_buf_tail == 0)
+		av->dccpav_buf_tail = DCCP_MAX_ACKVEC_LEN - 1;
+
+	av->dccpav_vec_len -= avr->dccpavr_sent_len;
+
+	/* free records */
+	list_for_each_entry_safe_from(avr, next, &av->dccpav_records,
+				      dccpavr_node) {
+		list_del_init(&avr->dccpavr_node);
+		dccp_ackvec_record_delete(avr);
+	}
 }
 
 void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av, struct sock *sk,
 				 const u64 ackno)
 {
-	/* Check if we actually sent an ACK vector */
-	if (av->dccpav_ack_seqno == DCCP_MAX_SEQNO + 1)
-		return;
+	struct dccp_ackvec_record *avr;
 
-	if (ackno == av->dccpav_ack_seqno) {
+	/*
+	 * If we traverse backwards, it should be faster when we have large
+	 * windows. We will be receiving ACKs for stuff we sent a while back
+	 * -sorbo.
+	 */
+	list_for_each_entry_reverse(avr, &av->dccpav_records, dccpavr_node) {
+		if (ackno == avr->dccpavr_ack_seqno) {
 #ifdef CONFIG_IP_DCCP_DEBUG
-		struct dccp_sock *dp = dccp_sk(sk);
-		const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
-					"CLIENT rx ack: " : "server rx ack: ";
+			struct dccp_sock *dp = dccp_sk(sk);
+			const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
+						"CLIENT rx ack: " : "server rx ack: ";
 #endif
-		dccp_pr_debug("%sACK packet 0, len=%d, ack_seqno=%llu, "
-			      "ack_ackno=%llu, ACKED!\n",
-			      debug_prefix, 1,
-			      (unsigned long long)av->dccpav_ack_seqno,
-			      (unsigned long long)av->dccpav_ack_ackno);
-		dccp_ackvec_throw_away_ack_record(av);
-		av->dccpav_ack_seqno = DCCP_MAX_SEQNO + 1;
+			dccp_pr_debug("%sACK packet 0, len=%d, ack_seqno=%llu, "
+				      "ack_ackno=%llu, ACKED!\n",
+				      debug_prefix, 1,
+				      (unsigned long long)avr->dccpavr_ack_seqno,
+				      (unsigned long long)avr->dccpavr_ack_ackno);
+			dccp_ackvec_throw_record(av, avr);
+			break;
+		}
 	}
 }
 
@@ -346,28 +391,20 @@ static void dccp_ackvec_check_rcv_ackvec
 					    const unsigned char *vector)
 {
 	unsigned char i;
+	struct dccp_ackvec_record *avr;
 
 	/* Check if we actually sent an ACK vector */
-	if (av->dccpav_ack_seqno == DCCP_MAX_SEQNO + 1)
+	if (list_empty(&av->dccpav_records))
 		return;
-	/*
-	 * We're in the receiver half connection, so if the received an ACK
-	 * vector ackno (e.g. 50) before dccpav_ack_seqno (e.g. 52), we're
-	 * not interested.
-	 *
-	 * Extra explanation with example:
-	 * 
-	 * if we received an ACK vector with ackno 50, it can only be acking
-	 * 50, 49, 48, etc, not 52 (the seqno for the ACK vector we sent).
-	 */
-	/* dccp_pr_debug("is %llu < %llu? ", ackno, av->dccpav_ack_seqno); */
-	if (before48(ackno, av->dccpav_ack_seqno)) {
-		/* dccp_pr_debug_cat("yes\n"); */
-		return;
-	}
-	/* dccp_pr_debug_cat("no\n"); */
 
 	i = len;
+	/*
+	 * XXX
+	 * I think it might be more efficient to work backwards. See comment on
+	 * rcv_ackno. -sorbo.
+	 */
+	avr = list_entry(av->dccpav_records.next, struct dccp_ackvec_record,
+			 dccpavr_node);
 	while (i--) {
 		const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK;
 		u64 ackno_end_rl;
@@ -375,14 +412,20 @@ static void dccp_ackvec_check_rcv_ackvec
 		dccp_set_seqno(&ackno_end_rl, ackno - rl);
 
 		/*
-		 * dccp_pr_debug("is %llu <= %llu <= %llu? ", ackno_end_rl,
-		 * av->dccpav_ack_seqno, ackno);
+		 * If our AVR sequence number is greater than the ack, go
+		 * forward in the AVR list until it is not so.
 		 */
-		if (between48(av->dccpav_ack_seqno, ackno_end_rl, ackno)) {
+		list_for_each_entry_from(avr, &av->dccpav_records,
+					 dccpavr_node) {
+			if (!after48(avr->dccpavr_ack_seqno, ackno))
+				goto found;
+		}
+		/* End of the dccpav_records list, not found, exit */
+		break;
+found:
+		if (between48(avr->dccpavr_ack_seqno, ackno_end_rl, ackno)) {
 			const u8 state = (*vector &
 					  DCCP_ACKVEC_STATE_MASK) >> 6;
-			/* dccp_pr_debug_cat("yes\n"); */
-
 			if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED) {
 #ifdef CONFIG_IP_DCCP_DEBUG
 				struct dccp_sock *dp = dccp_sk(sk);
@@ -395,19 +438,16 @@ static void dccp_ackvec_check_rcv_ackvec
 					      "ACKED!\n",
 					      debug_prefix, len,
 					      (unsigned long long)
-					      av->dccpav_ack_seqno,
+					      avr->dccpavr_ack_seqno,
 					      (unsigned long long)
-					      av->dccpav_ack_ackno);
-				dccp_ackvec_throw_away_ack_record(av);
+					      avr->dccpavr_ack_ackno);
+				dccp_ackvec_throw_record(av, avr);
 			}
 			/*
-			 * If dccpav_ack_seqno was not received, no problem
-			 * we'll send another ACK vector.
+			 * If it wasn't received, continue scanning... we might
+			 * find another one.
 			 */
-			av->dccpav_ack_seqno = DCCP_MAX_SEQNO + 1;
-			break;
 		}
-		/* dccp_pr_debug_cat("no\n"); */
 
 		dccp_set_seqno(&ackno, ackno_end_rl - 1);
 		++vector;
@@ -428,19 +468,31 @@ int dccp_ackvec_parse(struct sock *sk, c
 }
 
 static char dccp_ackvec_slab_msg[] __initdata =
-	KERN_CRIT "DCCP: Unable to create ack vectors slab cache\n";
+	KERN_CRIT "DCCP: Unable to create ack vectors slab caches\n";
 
 int __init dccp_ackvec_init(void)
 {
 	dccp_ackvec_slab = kmem_cache_create("dccp_ackvec",
 					     sizeof(struct dccp_ackvec), 0,
 					     SLAB_HWCACHE_ALIGN, NULL, NULL);
-	if (dccp_ackvec_slab == NULL) {
-		printk(dccp_ackvec_slab_msg);
-		return -ENOBUFS;
-	}
+	if (dccp_ackvec_slab == NULL)
+		goto out_err;
+
+	dccp_ackvec_record_slab =
+			kmem_cache_create("dccp_ackvec_record",
+					  sizeof(struct dccp_ackvec_record),
+					  0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (dccp_ackvec_record_slab == NULL)
+		goto out_destroy_slab;
 
 	return 0;
+
+out_destroy_slab:
+	kmem_cache_destroy(dccp_ackvec_slab);
+	dccp_ackvec_slab = NULL;
+out_err:
+	printk(dccp_ackvec_slab_msg);
+	return -ENOBUFS;
 }
 
 void dccp_ackvec_exit(void)
@@ -449,4 +501,8 @@ void dccp_ackvec_exit(void)
 		kmem_cache_destroy(dccp_ackvec_slab);
 		dccp_ackvec_slab = NULL;
 	}
+	if (dccp_ackvec_record_slab != NULL) {
+		kmem_cache_destroy(dccp_ackvec_record_slab);
+		dccp_ackvec_record_slab = NULL;
+	}
 }
diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h
index 470bae8..1d9ec4a 100644
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -13,6 +13,7 @@
 
 #include <linux/config.h>
 #include <linux/compiler.h>
+#include <linux/list.h>
 #include <linux/time.h>
 #include <linux/types.h>
 
@@ -42,11 +43,8 @@
  * Ack Vectors it has recently sent. For each packet sent carrying an
  * Ack Vector, it remembers four variables:
  *
- * @dccpav_ack_seqno - the Sequence Number used for the packet
- * 		       (HC-Receiver seqno)
  * @dccpav_ack_ptr - the value of buf_head at the time of acknowledgement.
- * @dccpav_ack_ackno - the Acknowledgement Number used for the packet
- * 		       (HC-Sender seqno)
+ * @dccpav_records - list of dccp_ackvec_record
  * @dccpav_ack_nonce - the one-bit sum of the ECN Nonces for all State 0.
  *
  * @dccpav_time		- the time in usecs
@@ -54,8 +52,7 @@
  */
 struct dccp_ackvec {
 	u64		dccpav_buf_ackno;
-	u64		dccpav_ack_seqno;
-	u64		dccpav_ack_ackno;
+	struct list_head dccpav_records;
 	struct timeval	dccpav_time;
 	u8		dccpav_buf_head;
 	u8		dccpav_buf_tail;
@@ -67,6 +64,28 @@ struct dccp_ackvec {
 	u8		dccpav_buf[DCCP_MAX_ACKVEC_LEN];
 };
 
+/** struct dccp_ackvec_record - ack vector record
+ *
+ * ACK vector record as defined in Appendix A of spec. 
+ *
+ * The list is sorted by dccpavr_ack_seqno
+ *
+ * @dccpavr_node - node in dccpav_records
+ * @dccpavr_ack_seqno - sequence number of the packet this record was sent on
+ * @dccpavr_ack_ackno - sequence number being acknowledged
+ * @dccpavr_ack_ptr - pointer into dccpav_buf where this record starts
+ * @dccpavr_ack_nonce - dccpav_ack_nonce at the time this record was sent
+ * @dccpavr_sent_len - lenght of the record in dccpav_buf
+ */
+struct dccp_ackvec_record {
+	struct list_head dccpavr_node;
+	u64		 dccpavr_ack_seqno;
+	u64		 dccpavr_ack_ackno;
+	u8		 dccpavr_ack_ptr;
+	u8		 dccpavr_ack_nonce;
+	u8		 dccpavr_sent_len;
+};
+
 struct sock;
 struct sk_buff;
 

^ permalink raw reply related

* [PATCH 5/11][LIST]: Introduce list_for_each_entry_from
From: Arnaldo Carvalho de Melo @ 2006-02-04  2:38 UTC (permalink / raw)
  To: dccp

[-- Attachment #1: Type: text/plain, Size: 145 bytes --]

Hi David,

    Please consider pulling from:

master.kernel.org:/pub/scm/linux/kernel/git/acme/net-2.6.17.git

Best Regards,

- Arnaldo

[-- Attachment #2: 5.patch --]
[-- Type: text/x-patch, Size: 1546 bytes --]

tree dd63ed037c6999ea5382a19b95bddd530d10a49f
parent f46cb510ee1e527b0d6b8a8c13a757c8355d08fd
author Arnaldo Carvalho de Melo <acme@mandriva.com> 1138971659 -0200
committer Arnaldo Carvalho de Melo <acme@mandriva.com> 1138971659 -0200

[LIST]: Introduce list_for_each_entry_from

For iterating over list of given type continuing from existing point.

Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>

------------------------------------------------------------------------------

 list.h |   11 +++++++++++
 1 file changed, 11 insertions(+)

------------------------------------------------------------------------------

diff --git a/include/linux/list.h b/include/linux/list.h
index dffc0fe..5bb5aab 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -409,6 +409,17 @@ static inline void list_splice_init(stru
 	     pos = list_entry(pos->member.next, typeof(*pos), member))
 
 /**
+ * list_for_each_entry_from -	iterate over list of given type
+ *			continuing from existing point
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_from(pos, head, member) 			\
+	for (; prefetch(pos->member.next), &pos->member != (head);	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
  * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
  * @pos:	the type * to use as a loop counter.
  * @n:		another type * to use as temporary storage

^ permalink raw reply related

* [PATCH 4/11][LIST]: Introduce list_for_each_entry_safe_from
From: Arnaldo Carvalho de Melo @ 2006-02-04  2:38 UTC (permalink / raw)
  To: dccp

[-- Attachment #1: Type: text/plain, Size: 145 bytes --]

Hi David,

    Please consider pulling from:

master.kernel.org:/pub/scm/linux/kernel/git/acme/net-2.6.17.git

Best Regards,

- Arnaldo

[-- Attachment #2: 4.patch --]
[-- Type: text/x-patch, Size: 1690 bytes --]

tree 90c345002f9b2c485b64c2b53582fb848eabbc4d
parent ec01d0836f8e4405ef0281590c296180a08f21c3
author Arnaldo Carvalho de Melo <acme@mandriva.com> 1138911314 -0200
committer Arnaldo Carvalho de Melo <acme@mandriva.com> 1138911314 -0200

[LIST]: Introduce list_for_each_entry_safe_from

For iterate over list of given type from existing point safe against removal of
list entry.

Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>

------------------------------------------------------------------------------

 list.h |   13 +++++++++++++
 1 file changed, 13 insertions(+)

------------------------------------------------------------------------------

diff --git a/include/linux/list.h b/include/linux/list.h
index 945daa1..dffc0fe 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -436,6 +436,19 @@ static inline void list_splice_init(stru
 	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
 
 /**
+ * list_for_each_entry_safe_from - iterate over list of given type
+ *			from existing point safe against removal of list entry
+ * @pos:	the type * to use as a loop counter.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member) 			\
+	for (n = list_entry(pos->member.next, typeof(*pos), member);		\
+	     &pos->member != (head);						\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
  * list_for_each_entry_safe_reverse - iterate backwards over list of given type safe against
  *				      removal of list entry
  * @pos:	the type * to use as a loop counter.

^ permalink raw reply related

* [PATCH 3/11][DCCP] ackvec: Introduce dccp_ackvec_slab
From: Arnaldo Carvalho de Melo @ 2006-02-04  2:38 UTC (permalink / raw)
  To: dccp

[-- Attachment #1: Type: text/plain, Size: 145 bytes --]

Hi David,

    Please consider pulling from:

master.kernel.org:/pub/scm/linux/kernel/git/acme/net-2.6.17.git

Best Regards,

- Arnaldo

[-- Attachment #2: 3.patch --]
[-- Type: text/x-patch, Size: 3935 bytes --]

tree 5f23c5d6dc4e941fea9013d0b94c8bfdcc20cd96
parent 0559c9a7ed5e7ff25c931656a6d837b23b68507e
author Arnaldo Carvalho de Melo <acme@mandriva.com> 1138893615 -0200
committer Arnaldo Carvalho de Melo <acme@mandriva.com> 1138893615 -0200

[DCCP] ackvec: Introduce dccp_ackvec_slab

Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>

------------------------------------------------------------------------------

 ackvec.c |   34 ++++++++++++++++++++++++++++++++--
 ackvec.h |   12 ++++++++++++
 proto.c  |    9 ++++++++-
 3 files changed, 52 insertions(+), 3 deletions(-)

------------------------------------------------------------------------------

diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c
index 3483740..6440825 100644
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -13,10 +13,16 @@
 #include "dccp.h"
 
 #include <linux/dccp.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
 #include <linux/skbuff.h>
+#include <linux/slab.h>
 
 #include <net/sock.h>
 
+static kmem_cache_t *dccp_ackvec_slab;
+
 int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
@@ -96,7 +102,7 @@ int dccp_insert_option_ackvec(struct soc
 
 struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority)
 {
-	struct dccp_ackvec *av = kmalloc(sizeof(*av), priority);
+	struct dccp_ackvec *av = kmem_cache_alloc(dccp_ackvec_slab, priority);
 
 	if (av != NULL) {
 		av->dccpav_buf_head	=
@@ -115,7 +121,7 @@ struct dccp_ackvec *dccp_ackvec_alloc(co
 
 void dccp_ackvec_free(struct dccp_ackvec *av)
 {
-	kfree(av);
+	kmem_cache_free(dccp_ackvec_slab, av);
 }
 
 static inline u8 dccp_ackvec_state(const struct dccp_ackvec *av,
@@ -420,3 +426,27 @@ int dccp_ackvec_parse(struct sock *sk, c
 				        len, value);
 	return 0;
 }
+
+static char dccp_ackvec_slab_msg[] __initdata =
+	KERN_CRIT "DCCP: Unable to create ack vectors slab cache\n";
+
+int __init dccp_ackvec_init(void)
+{
+	dccp_ackvec_slab = kmem_cache_create("dccp_ackvec",
+					     sizeof(struct dccp_ackvec), 0,
+					     SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (dccp_ackvec_slab == NULL) {
+		printk(dccp_ackvec_slab_msg);
+		return -ENOBUFS;
+	}
+
+	return 0;
+}
+
+void dccp_ackvec_exit(void)
+{
+	if (dccp_ackvec_slab != NULL) {
+		kmem_cache_destroy(dccp_ackvec_slab);
+		dccp_ackvec_slab = NULL;
+	}
+}
diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h
index f083daf..470bae8 100644
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -71,6 +71,9 @@ struct sock;
 struct sk_buff;
 
 #ifdef CONFIG_IP_DCCP_ACKVEC
+extern int dccp_ackvec_init(void);
+extern void dccp_ackvec_exit(void);
+
 extern struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority);
 extern void dccp_ackvec_free(struct dccp_ackvec *av);
 
@@ -89,6 +92,15 @@ static inline int dccp_ackvec_pending(co
 	return av->dccpav_sent_len != av->dccpav_vec_len;
 }
 #else /* CONFIG_IP_DCCP_ACKVEC */
+static inline int dccp_ackvec_init(void)
+{
+	return 0;
+}
+
+static inline void dccp_ackvec_exit(void)
+{
+}
+
 static inline struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority)
 {
 	return NULL;
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 568d266..81ad249 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -877,11 +877,17 @@ static int __init dccp_init(void)
 
 	inet_register_protosw(&dccp_v4_protosw);
 
-	rc = dccp_ctl_sock_init();
+	rc = dccp_ackvec_init();
 	if (rc)
 		goto out_unregister_protosw;
+
+	rc = dccp_ctl_sock_init();
+	if (rc)
+		goto out_ackvec_exit;
 out:
 	return rc;
+out_ackvec_exit:
+	dccp_ackvec_exit();
 out_unregister_protosw:
 	inet_unregister_protosw(&dccp_v4_protosw);
 	inet_del_protocol(&dccp_protocol, IPPROTO_DCCP);
@@ -923,6 +929,7 @@ static void __exit dccp_fini(void)
 			     sizeof(struct inet_ehash_bucket)));
 	kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
 	proto_unregister(&dccp_prot);
+	dccp_ackvec_exit();
 }
 
 module_init(dccp_init);

^ permalink raw reply related

* [PATCH 2/11][DCCP]: Fix error handling in dccp_init
From: Arnaldo Carvalho de Melo @ 2006-02-04  2:38 UTC (permalink / raw)
  To: dccp

[-- Attachment #1: Type: text/plain, Size: 145 bytes --]

Hi David,

    Please consider pulling from:

master.kernel.org:/pub/scm/linux/kernel/git/acme/net-2.6.17.git

Best Regards,

- Arnaldo

[-- Attachment #2: 2.patch --]
[-- Type: text/x-patch, Size: 1134 bytes --]

tree 84d7122001b844a79051505ecce03e2d246d6944
parent c3be0c39c8df0a3354df713028088ac1f5b0a780
author Arnaldo Carvalho de Melo <acme@mandriva.com> 1138888350 -0200
committer Arnaldo Carvalho de Melo <acme@mandriva.com> 1138888350 -0200

[DCCP]: Fix error handling in dccp_init

Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>

------------------------------------------------------------------------------

 proto.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

------------------------------------------------------------------------------

diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 65b11ea..568d266 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -799,6 +799,7 @@ static int __init dccp_init(void)
 	if (rc)
 		goto out;
 
+	rc = -ENOBUFS;
 	dccp_hashinfo.bind_bucket_cachep =
 		kmem_cache_create("dccp_bind_bucket",
 				  sizeof(struct inet_bind_bucket), 0,
@@ -866,7 +867,8 @@ static int __init dccp_init(void)
 		INIT_HLIST_HEAD(&dccp_hashinfo.bhash[i].chain);
 	}
 
-	if (init_dccp_v4_mibs())
+	rc = init_dccp_v4_mibs();
+	if (rc)
 		goto out_free_dccp_bhash;
 
 	rc = -EAGAIN;


^ permalink raw reply related

* [PATCH 1/11][DCCP] ackvec: Ditch dccpav_buf_len
From: Arnaldo Carvalho de Melo @ 2006-02-04  2:37 UTC (permalink / raw)
  To: dccp

[-- Attachment #1: Type: text/plain, Size: 145 bytes --]

Hi David,

    Please consider pulling from:

master.kernel.org:/pub/scm/linux/kernel/git/acme/net-2.6.17.git

Best Regards,

- Arnaldo

[-- Attachment #2: 1.patch --]
[-- Type: text/x-patch, Size: 5061 bytes --]

tree 10a90ca17347915aa5643ed1795a1312c750a440
parent 2799e0977dcf6010c469332e5639fcea179bcd9f
author Arnaldo Carvalho de Melo <acme@mandriva.com> 1138881941 -0200
committer Arnaldo Carvalho de Melo <acme@mandriva.com> 1138881941 -0200

[DCCP] ackvec: Ditch dccpav_buf_len

Simplifying the code a bit as we're always using DCCP_MAX_ACKVEC_LEN.

Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>

------------------------------------------------------------------------------

 ackvec.c    |   24 ++++++++++--------------
 ackvec.h    |   10 +++-------
 ipv4.c      |    3 +--
 minisocks.c |    3 +--
 4 files changed, 15 insertions(+), 25 deletions(-)

------------------------------------------------------------------------------

diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c
index 2c77daf..3483740 100644
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -20,6 +20,10 @@
 int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
+#ifdef CONFIG_IP_DCCP_DEBUG
+	const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
+				"CLIENT tx: " : "server tx: ";
+#endif
 	struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec;
 	int len = av->dccpav_vec_len + 2;
 	struct timeval now;
@@ -90,21 +94,13 @@ int dccp_insert_option_ackvec(struct soc
 	return -1;
 }
 
-struct dccp_ackvec *dccp_ackvec_alloc(const unsigned int len,
-				      const gfp_t priority)
+struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority)
 {
-	struct dccp_ackvec *av;
-
-	BUG_ON(len == 0);
-
-	if (len > DCCP_MAX_ACKVEC_LEN)
-		return NULL;
+	struct dccp_ackvec *av = kmalloc(sizeof(*av), priority);
 
-	av = kmalloc(sizeof(*av) + len, priority);
 	if (av != NULL) {
-		av->dccpav_buf_len	= len;
 		av->dccpav_buf_head	=
-			av->dccpav_buf_tail = av->dccpav_buf_len - 1;
+			av->dccpav_buf_tail = DCCP_MAX_ACKVEC_LEN - 1;
 		av->dccpav_buf_ackno	=
 			av->dccpav_ack_ackno = av->dccpav_ack_seqno = ~0LLU;
 		av->dccpav_buf_nonce = av->dccpav_buf_nonce = 0;
@@ -146,7 +142,7 @@ static inline int dccp_ackvec_set_buf_he
 	unsigned int gap;
 	long new_head;
 
-	if (av->dccpav_vec_len + packets > av->dccpav_buf_len)
+	if (av->dccpav_vec_len + packets > DCCP_MAX_ACKVEC_LEN)
 		return -ENOBUFS;
 
 	gap	 = packets - 1;
@@ -158,7 +154,7 @@ static inline int dccp_ackvec_set_buf_he
 			       gap + new_head + 1);
 			gap = -new_head;
 		}
-		new_head += av->dccpav_buf_len;
+		new_head += DCCP_MAX_ACKVEC_LEN;
 	} 
 
 	av->dccpav_buf_head = new_head;
@@ -251,7 +247,7 @@ int dccp_ackvec_add(struct dccp_ackvec *
 				goto out_duplicate;
 
 			delta -= len + 1;
-			if (++index == av->dccpav_buf_len)
+			if (++index == DCCP_MAX_ACKVEC_LEN)
 				index = 0;
 		}
 	}
diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h
index f7dfb5f..f083daf 100644
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -49,7 +49,6 @@
  * 		       (HC-Sender seqno)
  * @dccpav_ack_nonce - the one-bit sum of the ECN Nonces for all State 0.
  *
- * @dccpav_buf_len	- circular buffer length
  * @dccpav_time		- the time in usecs
  * @dccpav_buf - circular buffer of acknowledgeable packets
  */
@@ -63,18 +62,16 @@ struct dccp_ackvec {
 	u8		dccpav_ack_ptr;
 	u8		dccpav_sent_len;
 	u8		dccpav_vec_len;
-	u8		dccpav_buf_len;
 	u8		dccpav_buf_nonce;
 	u8		dccpav_ack_nonce;
-	u8		dccpav_buf[0];
+	u8		dccpav_buf[DCCP_MAX_ACKVEC_LEN];
 };
 
 struct sock;
 struct sk_buff;
 
 #ifdef CONFIG_IP_DCCP_ACKVEC
-extern struct dccp_ackvec *dccp_ackvec_alloc(unsigned int len,
-					  const gfp_t priority);
+extern struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority);
 extern void dccp_ackvec_free(struct dccp_ackvec *av);
 
 extern int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
@@ -92,8 +89,7 @@ static inline int dccp_ackvec_pending(co
 	return av->dccpav_sent_len != av->dccpav_vec_len;
 }
 #else /* CONFIG_IP_DCCP_ACKVEC */
-static inline struct dccp_ackvec *dccp_ackvec_alloc(unsigned int len,
-					   const gfp_t priority)
+static inline struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority)
 {
 	return NULL;
 }
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 00f9832..9fedeca 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -1041,8 +1041,7 @@ int dccp_v4_init_sock(struct sock *sk)
 	do_gettimeofday(&dp->dccps_epoch);
 
 	if (dp->dccps_options.dccpo_send_ack_vector) {
-		dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(DCCP_MAX_ACKVEC_LEN,
-							   GFP_KERNEL);
+		dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(GFP_KERNEL);
 		if (dp->dccps_hc_rx_ackvec == NULL)
 			return -ENOMEM;
 	}
diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c
index 29261fc..a60a3e9 100644
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -116,8 +116,7 @@ struct sock *dccp_create_openreq_child(s
 
 		if (newdp->dccps_options.dccpo_send_ack_vector) {
 			newdp->dccps_hc_rx_ackvec =
-				dccp_ackvec_alloc(DCCP_MAX_ACKVEC_LEN,
-						  GFP_ATOMIC);
+						dccp_ackvec_alloc(GFP_ATOMIC);
 			/*
 			 * XXX: We're using the same CCIDs set on the parent,
 			 * i.e. sk_clone copied the master sock and left the


^ permalink raw reply related

* Comments on the feature negotiation patch
From: Arnaldo Carvalho de Melo @ 2006-02-03 19:02 UTC (permalink / raw)
  To: dccp

Hi Andrea,

    Now that I have merged the ackvec record and ccid2 patches could
you please address
my initial concerns with the feature negotiation patch?

Patch reviewed:  http://128.16.66.93/acme-dccp-feat.diff

+struct dccp_opt_pend {
+	struct list_head	dccpop_list;

Please name this as "dccpop_node", "_list" implies that this member
contains a list, and not
that it is part of a list (dccpo_pending)

+	u8			dccpop_type;
+	u8			dccpop_feat;

+	__u8			dccpo_send_ndp_count;

Try to be consistent with types, using __u8 instead of u8 and unsigned
char when the struct is
to be visible only in the kernel build process.

+int dccp_feat_change(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len,
+		     gfp_t gfp)
+{
+	struct dccp_opt_pend *opt;
+	struct dccp_sock *dp;
+	
+	dccp_pr_debug("feat change type=%d feat=%d\n", type, feature);
+
+	/* check if that feature is already being negotiated */
+	dp = dccp_sk(sk);

In these cases it saves some lines and thus is the preferred form to have dp
assigned at its declaration place, like:

          struct dccp_sock *dp = dccp_sk(sk);

+	/* negotiation for a new feature */
+	opt = kmalloc(sizeof(*opt), gfp);
+	if (!opt)
+		return -ENOMEM;
+
+	memset(opt, 0, sizeof(*opt));

Use kzalloc, replacing kmalloc + memset(0)

+	/* check if we are the black sheep */
+	if (dp->dccps_role = DCCP_ROLE_CLIENT) {
+		spref = rpref;
+		slen = rlen;
+		rpref = opt->dccpop_val;
+		rlen = opt->dccpop_len;
+	}
+	else {

Please use:

           } else {

+		default:
+			BUG(); /* XXX implement res */
+		}

This is a bit extreme, WARN_ON(1) please.

+	/* put it in the "confirm queue" */
+	if (!opt->dccpop_sc) {
+		opt->dccpop_sc = kmalloc(sizeof(*opt->dccpop_sc), GFP_ATOMIC);

Sure that dccp_feat_reconcile can't be called from process context (GFP_KERNEL)?
I haven't checked.

+		spref = rpref;
+		slen = rlen;
+		rpref = opt->dccpop_val;
+		rlen = opt->dccpop_len;

This one is cosmetic, but some folks like these assignments aligned at
the =, like:

     spref = rpref;
     slen   = rlen;

+int dccp_feat_init(struct sock *sk)
+{
+	struct dccp_sock *dp;
+	int rc;
+	gfp_t gfp = GFP_KERNEL; /* XXX is this correct ? */

well, you could have dccp_feat_init() receiving this gfp_t and look at
the callsites to
see wheter GFP_KERNEL or GFP_ATOMIC should be used, if its just of one type... I
haven't looked at where dccp_feat_init commences, but I guess that we can have
this as just GFP_KERNEL.

+	/* confirm any options [NN opts] */
+	list_for_each_entry_safe(opt, next, &dp->dccps_options.dccpo_conf,
+				 dccpop_list) {
+		dccp_insert_feat_opt(skb, opt->dccpop_type,
+				     opt->dccpop_feat, opt->dccpop_val,
+				     opt->dccpop_len);
+		
+		/* fear empty confirms */
+		if (opt->dccpop_val)
+			kfree(opt->dccpop_val);
+		kfree(opt);

Humm, kfree without removing opt from dccps_options.dccpo_conf?

+	}
+	INIT_LIST_HEAD(&dp->dccps_options.dccpo_conf);

Ah, ok, saving some cycles, should be safe :-)


+	list_for_each_entry(opt, &dp->dccps_options.dccpo_pending, dccpop_list){

spaces between ) and { please


       Please look at this patch again taking those aspects into
consideration and I'll be
glad to merge it so that we can get back at testing all these new features.

        Ah, thanks a lot for following the general naming of structs,
functions, etc, its very
nice to have consistent coding guidelines!

- Arnaldo

^ permalink raw reply

* Re: [RFC] TCP MTU probing
From: John Heffner @ 2006-02-01 21:40 UTC (permalink / raw)
  To: dccp

On Monday 30 January 2006 20:21, Ian McDonald wrote:
> On 1/31/06, David S. Miller <davem@davemloft.net> wrote:
> > From: John Heffner <jheffner@psc.edu>
> > Date: Tue, 06 Dec 2005 14:42:53 -0500
> >
> > > I'd like to get a few people at least to look this over, and maybe give
> > > it a try.  One remaining item to consider is how best to cache the
> > > state between connections.  Are there any major concerns or
> > > reservations about this approach, or the patch itself?
>
> Just having a read of this now (missed first time round) and I see
> that PMTUD as per this RFC is also allowed by DCCP in it's spec
> (Section 14.1).
>
> > and then I'll happily at this in for net-2.6.17
>
> At some future stage we should merge this into the DCCP tree too.
> Looking at the code there are quite a few places where it has TCP in
> there where maybe it would be better to have IP in there to save
> further changes when DCCP starts to use the code....

That would be good.  I think SCTP should do this as well.  I moved struct mtup 
from struct tcp_sock to struct inet_connection_sock.  I think most of the 
actual code really ends up being pretty protocol-specific though.

  -John

^ permalink raw reply

* Re: feature negotiation patch for linux
From: Arnaldo Carvalho de Melo @ 2006-02-01 14:18 UTC (permalink / raw)
  To: dccp

On 1/31/06, Andrea Bittau <a.bittau@cs.ucl.ac.uk> wrote:
> http://128.16.66.93/acme-dccp-feat.diff
>
> [no domain name because it's expiring today =( ]
>
> It's my initial "mega-patch, rough" implementation of feature negotiation for
> linux, based on acme's tree.
>
> It supports CHANGE_L, CHANGE_R via setsockopt from userland.
> It will change / confirm.
> It supports mandatory options.  [no support from userland yet though].
> It supports re-transmission of change options.
>
> TODO:
> * getsockopt to poll for option status.
> * setsockopt with a flag for mandatory options.
> * actually change the option in the protocol itself.  Until now they are only
>   negotiation and an empty function is called =D
>
>
> Any comments are welcome.  I'll try to contact acme now, and hopefully stuff
> will start getting merged.


Excellent news! First round of comments:

+	list_for_each(cur, &dp->dccps_options.dccpo_pending) {
+		opt = list_entry(cur, struct dccp_opt_pend, dccpop_list);

Please use list_for_each_entry()

dccp_feat_change should receive a gfp_t for use in kmalloc,
as it is called from setsockopt and there we should just use GFP_KERNEL.

ACK_RATIO in dccp_feat_init()? CCID2 specific stuff?

- Arnaldo

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox