diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2008-09-04 01:30:19 -0400 |
---|---|---|
committer | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2008-09-04 01:45:37 -0400 |
commit | c8bf462bc567c3dcb083ff95cc13060dd06f138c (patch) | |
tree | c612129b23db7bb8613fff4c6e2d51301bc77f65 /net/dccp | |
parent | 5a577b488f687f339dea62e7bb4f4c5793ad523f (diff) |
dccp ccid-2: Separate option parsing from CCID processing
This patch replaces an almost identical replication of code: large parts
of dccp_parse_options() re-appeared as ccid2_ackvector() in ccid2.c.
Apart from the duplication, this caused two more problems:
1. CCIDs should not need to be concerned with parsing header options;
2. one can not assume that Ack Vectors appear as a contiguous area within an
skb, it is legal to insert other options and/or padding in between. The
current code would throw an error and stop reading in such a case.
The patch provides a new data structure and associated list housekeeping.
Only small changes were necessary to integrate with CCID-2: data structure
initialisation, adapt list traversal routine, and add call to the provided
cleanup routine.
The latter also lead to fixing the following BUG: CCID-2 so far ignored
Ack Vectors on all packets other than Ack/DataAck, which is incorrect,
since Ack Vectors can be present on any packet that has an Ack field.
Details:
--------
* received Ack Vectors are parsed by dccp_parse_options() alone, which passes
the result on to the CCID-specific routine ccid_hc_tx_parse_options();
* CCIDs interested in using/decoding Ack Vector information will add code
to fetch parsed Ack Vectors via this interface;
* a data structure, `struct dccp_ackvec_parsed' is provided as interface;
* this structure arranges Ack Vectors of the same skb into a FIFO order;
* a doubly-linked list is used to keep the required FIFO code small.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Diffstat (limited to 'net/dccp')
-rw-r--r-- | net/dccp/ackvec.c | 28 | ||||
-rw-r--r-- | net/dccp/ackvec.h | 19 | ||||
-rw-r--r-- | net/dccp/ccids/ccid2.c | 135 | ||||
-rw-r--r-- | net/dccp/ccids/ccid2.h | 2 | ||||
-rw-r--r-- | net/dccp/options.c | 17 |
5 files changed, 101 insertions, 100 deletions
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c index 66b8a51300c0..41819848bdda 100644 --- a/net/dccp/ackvec.c +++ b/net/dccp/ackvec.c | |||
@@ -343,6 +343,34 @@ free_records: | |||
343 | } | 343 | } |
344 | } | 344 | } |
345 | 345 | ||
346 | /* | ||
347 | * Routines to keep track of Ack Vectors received in an skb | ||
348 | */ | ||
349 | int dccp_ackvec_parsed_add(struct list_head *head, u8 *vec, u8 len, u8 nonce) | ||
350 | { | ||
351 | struct dccp_ackvec_parsed *new = kmalloc(sizeof(*new), GFP_ATOMIC); | ||
352 | |||
353 | if (new == NULL) | ||
354 | return -ENOBUFS; | ||
355 | new->vec = vec; | ||
356 | new->len = len; | ||
357 | new->nonce = nonce; | ||
358 | |||
359 | list_add_tail(&new->node, head); | ||
360 | return 0; | ||
361 | } | ||
362 | EXPORT_SYMBOL_GPL(dccp_ackvec_parsed_add); | ||
363 | |||
364 | void dccp_ackvec_parsed_cleanup(struct list_head *parsed_chunks) | ||
365 | { | ||
366 | struct dccp_ackvec_parsed *cur, *next; | ||
367 | |||
368 | list_for_each_entry_safe(cur, next, parsed_chunks, node) | ||
369 | kfree(cur); | ||
370 | INIT_LIST_HEAD(parsed_chunks); | ||
371 | } | ||
372 | EXPORT_SYMBOL_GPL(dccp_ackvec_parsed_cleanup); | ||
373 | |||
346 | int __init dccp_ackvec_init(void) | 374 | int __init dccp_ackvec_init(void) |
347 | { | 375 | { |
348 | dccp_ackvec_slab = kmem_cache_create("dccp_ackvec", | 376 | dccp_ackvec_slab = kmem_cache_create("dccp_ackvec", |
diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h index db447503b636..6cdca79a99f7 100644 --- a/net/dccp/ackvec.h +++ b/net/dccp/ackvec.h | |||
@@ -114,4 +114,23 @@ static inline bool dccp_ackvec_is_empty(const struct dccp_ackvec *av) | |||
114 | { | 114 | { |
115 | return av->av_overflow == 0 && av->av_buf_head == av->av_buf_tail; | 115 | return av->av_overflow == 0 && av->av_buf_head == av->av_buf_tail; |
116 | } | 116 | } |
117 | |||
118 | /** | ||
119 | * struct dccp_ackvec_parsed - Record offsets of Ack Vectors in skb | ||
120 | * @vec: start of vector (offset into skb) | ||
121 | * @len: length of @vec | ||
122 | * @nonce: whether @vec had an ECN nonce of 0 or 1 | ||
123 | * @node: FIFO - arranged in descending order of ack_ackno | ||
124 | * This structure is used by CCIDs to access Ack Vectors in a received skb. | ||
125 | */ | ||
126 | struct dccp_ackvec_parsed { | ||
127 | u8 *vec, | ||
128 | len, | ||
129 | nonce:1; | ||
130 | struct list_head node; | ||
131 | }; | ||
132 | |||
133 | extern int dccp_ackvec_parsed_add(struct list_head *head, | ||
134 | u8 *vec, u8 len, u8 nonce); | ||
135 | extern void dccp_ackvec_parsed_cleanup(struct list_head *parsed_chunks); | ||
117 | #endif /* _ACKVEC_H */ | 136 | #endif /* _ACKVEC_H */ |
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index 813d5cd40e8b..bbf16b35734d 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c | |||
@@ -317,68 +317,6 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, unsigned int len) | |||
317 | #endif | 317 | #endif |
318 | } | 318 | } |
319 | 319 | ||
320 | /* XXX Lame code duplication! | ||
321 | * returns -1 if none was found. | ||
322 | * else returns the next offset to use in the function call. | ||
323 | */ | ||
324 | static int ccid2_ackvector(struct sock *sk, struct sk_buff *skb, int offset, | ||
325 | unsigned char **vec, unsigned char *veclen) | ||
326 | { | ||
327 | const struct dccp_hdr *dh = dccp_hdr(skb); | ||
328 | unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb); | ||
329 | unsigned char *opt_ptr; | ||
330 | const unsigned char *opt_end = (unsigned char *)dh + | ||
331 | (dh->dccph_doff * 4); | ||
332 | unsigned char opt, len; | ||
333 | unsigned char *value; | ||
334 | |||
335 | BUG_ON(offset < 0); | ||
336 | options += offset; | ||
337 | opt_ptr = options; | ||
338 | if (opt_ptr >= opt_end) | ||
339 | return -1; | ||
340 | |||
341 | while (opt_ptr != opt_end) { | ||
342 | opt = *opt_ptr++; | ||
343 | len = 0; | ||
344 | value = NULL; | ||
345 | |||
346 | /* Check if this isn't a single byte option */ | ||
347 | if (opt > DCCPO_MAX_RESERVED) { | ||
348 | if (opt_ptr == opt_end) | ||
349 | goto out_invalid_option; | ||
350 | |||
351 | len = *opt_ptr++; | ||
352 | if (len < 3) | ||
353 | goto out_invalid_option; | ||
354 | /* | ||
355 | * Remove the type and len fields, leaving | ||
356 | * just the value size | ||
357 | */ | ||
358 | len -= 2; | ||
359 | value = opt_ptr; | ||
360 | opt_ptr += len; | ||
361 | |||
362 | if (opt_ptr > opt_end) | ||
363 | goto out_invalid_option; | ||
364 | } | ||
365 | |||
366 | switch (opt) { | ||
367 | case DCCPO_ACK_VECTOR_0: | ||
368 | case DCCPO_ACK_VECTOR_1: | ||
369 | *vec = value; | ||
370 | *veclen = len; | ||
371 | return offset + (opt_ptr - options); | ||
372 | } | ||
373 | } | ||
374 | |||
375 | return -1; | ||
376 | |||
377 | out_invalid_option: | ||
378 | DCCP_BUG("Invalid option - this should not happen (previous parsing)!"); | ||
379 | return -1; | ||
380 | } | ||
381 | |||
382 | static void ccid2_hc_tx_kill_rto_timer(struct sock *sk) | 320 | static void ccid2_hc_tx_kill_rto_timer(struct sock *sk) |
383 | { | 321 | { |
384 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); | 322 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); |
@@ -499,15 +437,27 @@ static void ccid2_congestion_event(struct sock *sk, struct ccid2_seq *seqp) | |||
499 | ccid2_change_l_ack_ratio(sk, hctx->cwnd); | 437 | ccid2_change_l_ack_ratio(sk, hctx->cwnd); |
500 | } | 438 | } |
501 | 439 | ||
440 | static int ccid2_hc_tx_parse_options(struct sock *sk, u8 packet_type, | ||
441 | u8 option, u8 *optval, u8 optlen) | ||
442 | { | ||
443 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); | ||
444 | |||
445 | switch (option) { | ||
446 | case DCCPO_ACK_VECTOR_0: | ||
447 | case DCCPO_ACK_VECTOR_1: | ||
448 | return dccp_ackvec_parsed_add(&hctx->av_chunks, optval, optlen, | ||
449 | option - DCCPO_ACK_VECTOR_0); | ||
450 | } | ||
451 | return 0; | ||
452 | } | ||
453 | |||
502 | static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | 454 | static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) |
503 | { | 455 | { |
504 | struct dccp_sock *dp = dccp_sk(sk); | 456 | struct dccp_sock *dp = dccp_sk(sk); |
505 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); | 457 | struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); |
458 | struct dccp_ackvec_parsed *avp; | ||
506 | u64 ackno, seqno; | 459 | u64 ackno, seqno; |
507 | struct ccid2_seq *seqp; | 460 | struct ccid2_seq *seqp; |
508 | unsigned char *vector; | ||
509 | unsigned char veclen; | ||
510 | int offset = 0; | ||
511 | int done = 0; | 461 | int done = 0; |
512 | unsigned int maxincr = 0; | 462 | unsigned int maxincr = 0; |
513 | 463 | ||
@@ -542,17 +492,12 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
542 | } | 492 | } |
543 | 493 | ||
544 | /* check forward path congestion */ | 494 | /* check forward path congestion */ |
545 | /* still didn't send out new data packets */ | 495 | if (dccp_packet_without_ack(skb)) |
546 | if (hctx->seqh == hctx->seqt) | ||
547 | return; | 496 | return; |
548 | 497 | ||
549 | switch (DCCP_SKB_CB(skb)->dccpd_type) { | 498 | /* still didn't send out new data packets */ |
550 | case DCCP_PKT_ACK: | 499 | if (hctx->seqh == hctx->seqt) |
551 | case DCCP_PKT_DATAACK: | 500 | goto done; |
552 | break; | ||
553 | default: | ||
554 | return; | ||
555 | } | ||
556 | 501 | ||
557 | ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq; | 502 | ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq; |
558 | if (after48(ackno, hctx->high_ack)) | 503 | if (after48(ackno, hctx->high_ack)) |
@@ -576,15 +521,16 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
576 | maxincr = DIV_ROUND_UP(dp->dccps_l_ack_ratio, 2); | 521 | maxincr = DIV_ROUND_UP(dp->dccps_l_ack_ratio, 2); |
577 | 522 | ||
578 | /* go through all ack vectors */ | 523 | /* go through all ack vectors */ |
579 | while ((offset = ccid2_ackvector(sk, skb, offset, | 524 | list_for_each_entry(avp, &hctx->av_chunks, node) { |
580 | &vector, &veclen)) != -1) { | ||
581 | /* go through this ack vector */ | 525 | /* go through this ack vector */ |
582 | while (veclen--) { | 526 | for (; avp->len--; avp->vec++) { |
583 | u64 ackno_end_rl = SUB48(ackno, dccp_ackvec_runlen(vector)); | 527 | u64 ackno_end_rl = SUB48(ackno, |
528 | dccp_ackvec_runlen(avp->vec)); | ||
584 | 529 | ||
585 | ccid2_pr_debug("ackvec start:%llu end:%llu\n", | 530 | ccid2_pr_debug("ackvec %llu |%u,%u|\n", |
586 | (unsigned long long)ackno, | 531 | (unsigned long long)ackno, |
587 | (unsigned long long)ackno_end_rl); | 532 | dccp_ackvec_state(avp->vec) >> 6, |
533 | dccp_ackvec_runlen(avp->vec)); | ||
588 | /* if the seqno we are analyzing is larger than the | 534 | /* if the seqno we are analyzing is larger than the |
589 | * current ackno, then move towards the tail of our | 535 | * current ackno, then move towards the tail of our |
590 | * seqnos. | 536 | * seqnos. |
@@ -603,7 +549,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
603 | * run length | 549 | * run length |
604 | */ | 550 | */ |
605 | while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) { | 551 | while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) { |
606 | const u8 state = dccp_ackvec_state(vector); | 552 | const u8 state = dccp_ackvec_state(avp->vec); |
607 | 553 | ||
608 | /* new packet received or marked */ | 554 | /* new packet received or marked */ |
609 | if (state != DCCPAV_NOT_RECEIVED && | 555 | if (state != DCCPAV_NOT_RECEIVED && |
@@ -630,7 +576,6 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
630 | break; | 576 | break; |
631 | 577 | ||
632 | ackno = SUB48(ackno_end_rl, 1); | 578 | ackno = SUB48(ackno_end_rl, 1); |
633 | vector++; | ||
634 | } | 579 | } |
635 | if (done) | 580 | if (done) |
636 | break; | 581 | break; |
@@ -694,6 +639,8 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
694 | } | 639 | } |
695 | 640 | ||
696 | ccid2_hc_tx_check_sanity(hctx); | 641 | ccid2_hc_tx_check_sanity(hctx); |
642 | done: | ||
643 | dccp_ackvec_parsed_cleanup(&hctx->av_chunks); | ||
697 | } | 644 | } |
698 | 645 | ||
699 | static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) | 646 | static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) |
@@ -727,6 +674,7 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) | |||
727 | hctx->rpdupack = -1; | 674 | hctx->rpdupack = -1; |
728 | hctx->last_cong = jiffies; | 675 | hctx->last_cong = jiffies; |
729 | setup_timer(&hctx->rtotimer, ccid2_hc_tx_rto_expire, (unsigned long)sk); | 676 | setup_timer(&hctx->rtotimer, ccid2_hc_tx_rto_expire, (unsigned long)sk); |
677 | INIT_LIST_HEAD(&hctx->av_chunks); | ||
730 | 678 | ||
731 | ccid2_hc_tx_check_sanity(hctx); | 679 | ccid2_hc_tx_check_sanity(hctx); |
732 | return 0; | 680 | return 0; |
@@ -762,17 +710,18 @@ static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
762 | } | 710 | } |
763 | 711 | ||
764 | static struct ccid_operations ccid2 = { | 712 | static struct ccid_operations ccid2 = { |
765 | .ccid_id = DCCPC_CCID2, | 713 | .ccid_id = DCCPC_CCID2, |
766 | .ccid_name = "TCP-like", | 714 | .ccid_name = "TCP-like", |
767 | .ccid_owner = THIS_MODULE, | 715 | .ccid_owner = THIS_MODULE, |
768 | .ccid_hc_tx_obj_size = sizeof(struct ccid2_hc_tx_sock), | 716 | .ccid_hc_tx_obj_size = sizeof(struct ccid2_hc_tx_sock), |
769 | .ccid_hc_tx_init = ccid2_hc_tx_init, | 717 | .ccid_hc_tx_init = ccid2_hc_tx_init, |
770 | .ccid_hc_tx_exit = ccid2_hc_tx_exit, | 718 | .ccid_hc_tx_exit = ccid2_hc_tx_exit, |
771 | .ccid_hc_tx_send_packet = ccid2_hc_tx_send_packet, | 719 | .ccid_hc_tx_send_packet = ccid2_hc_tx_send_packet, |
772 | .ccid_hc_tx_packet_sent = ccid2_hc_tx_packet_sent, | 720 | .ccid_hc_tx_packet_sent = ccid2_hc_tx_packet_sent, |
773 | .ccid_hc_tx_packet_recv = ccid2_hc_tx_packet_recv, | 721 | .ccid_hc_tx_parse_options = ccid2_hc_tx_parse_options, |
774 | .ccid_hc_rx_obj_size = sizeof(struct ccid2_hc_rx_sock), | 722 | .ccid_hc_tx_packet_recv = ccid2_hc_tx_packet_recv, |
775 | .ccid_hc_rx_packet_recv = ccid2_hc_rx_packet_recv, | 723 | .ccid_hc_rx_obj_size = sizeof(struct ccid2_hc_rx_sock), |
724 | .ccid_hc_rx_packet_recv = ccid2_hc_rx_packet_recv, | ||
776 | }; | 725 | }; |
777 | 726 | ||
778 | #ifdef CONFIG_IP_DCCP_CCID2_DEBUG | 727 | #ifdef CONFIG_IP_DCCP_CCID2_DEBUG |
diff --git a/net/dccp/ccids/ccid2.h b/net/dccp/ccids/ccid2.h index d7815804bceb..907deed255b4 100644 --- a/net/dccp/ccids/ccid2.h +++ b/net/dccp/ccids/ccid2.h | |||
@@ -47,6 +47,7 @@ struct ccid2_seq { | |||
47 | * @lastrtt: time RTT was last measured | 47 | * @lastrtt: time RTT was last measured |
48 | * @rpseq: last consecutive seqno | 48 | * @rpseq: last consecutive seqno |
49 | * @rpdupack: dupacks since rpseq | 49 | * @rpdupack: dupacks since rpseq |
50 | * @av_chunks: list of Ack Vectors received on current skb | ||
50 | */ | 51 | */ |
51 | struct ccid2_hc_tx_sock { | 52 | struct ccid2_hc_tx_sock { |
52 | u32 cwnd; | 53 | u32 cwnd; |
@@ -66,6 +67,7 @@ struct ccid2_hc_tx_sock { | |||
66 | int rpdupack; | 67 | int rpdupack; |
67 | unsigned long last_cong; | 68 | unsigned long last_cong; |
68 | u64 high_ack; | 69 | u64 high_ack; |
70 | struct list_head av_chunks; | ||
69 | }; | 71 | }; |
70 | 72 | ||
71 | struct ccid2_hc_rx_sock { | 73 | struct ccid2_hc_rx_sock { |
diff --git a/net/dccp/options.c b/net/dccp/options.c index 791e07853a79..e5a32979d7d7 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c | |||
@@ -128,13 +128,6 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, | |||
128 | if (rc) | 128 | if (rc) |
129 | goto out_featneg_failed; | 129 | goto out_featneg_failed; |
130 | break; | 130 | break; |
131 | case DCCPO_ACK_VECTOR_0: | ||
132 | case DCCPO_ACK_VECTOR_1: | ||
133 | if (dccp_packet_without_ack(skb)) /* RFC 4340, 11.4 */ | ||
134 | break; | ||
135 | dccp_pr_debug("%s Ack Vector (len=%u)\n", dccp_role(sk), | ||
136 | len); | ||
137 | break; | ||
138 | case DCCPO_TIMESTAMP: | 131 | case DCCPO_TIMESTAMP: |
139 | if (len != 4) | 132 | if (len != 4) |
140 | goto out_invalid_option; | 133 | goto out_invalid_option; |
@@ -224,6 +217,16 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, | |||
224 | pkt_type, opt, value, len)) | 217 | pkt_type, opt, value, len)) |
225 | goto out_invalid_option; | 218 | goto out_invalid_option; |
226 | break; | 219 | break; |
220 | case DCCPO_ACK_VECTOR_0: | ||
221 | case DCCPO_ACK_VECTOR_1: | ||
222 | if (dccp_packet_without_ack(skb)) /* RFC 4340, 11.4 */ | ||
223 | break; | ||
224 | /* | ||
225 | * Ack vectors are processed by the TX CCID if it is | ||
226 | * interested. The RX CCID need not parse Ack Vectors, | ||
227 | * since it is only interested in clearing old state. | ||
228 | * Fall through. | ||
229 | */ | ||
227 | case DCCPO_MIN_TX_CCID_SPECIFIC ... DCCPO_MAX_TX_CCID_SPECIFIC: | 230 | case DCCPO_MIN_TX_CCID_SPECIFIC ... DCCPO_MAX_TX_CCID_SPECIFIC: |
228 | if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk, | 231 | if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk, |
229 | pkt_type, opt, value, len)) | 232 | pkt_type, opt, value, len)) |