Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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.

Since Ack Vectors provide CCID-specific information, they are now processed
by the CCID directly, separating this functionality from the main DCCP code.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>

+100 -100
+28
net/dccp/ackvec.c
··· 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 374 int __init dccp_ackvec_init(void) 347 375 { 348 376 dccp_ackvec_slab = kmem_cache_create("dccp_ackvec",
+19
net/dccp/ackvec.h
··· 114 114 { 115 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 136 #endif /* _ACKVEC_H */
+41 -93
net/dccp/ccids/ccid2.c
··· 246 246 #endif 247 247 } 248 248 249 - /* XXX Lame code duplication! 250 - * returns -1 if none was found. 251 - * else returns the next offset to use in the function call. 252 - */ 253 - static int ccid2_ackvector(struct sock *sk, struct sk_buff *skb, int offset, 254 - unsigned char **vec, unsigned char *veclen) 255 - { 256 - const struct dccp_hdr *dh = dccp_hdr(skb); 257 - unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb); 258 - unsigned char *opt_ptr; 259 - const unsigned char *opt_end = (unsigned char *)dh + 260 - (dh->dccph_doff * 4); 261 - unsigned char opt, len; 262 - unsigned char *value; 263 - 264 - BUG_ON(offset < 0); 265 - options += offset; 266 - opt_ptr = options; 267 - if (opt_ptr >= opt_end) 268 - return -1; 269 - 270 - while (opt_ptr != opt_end) { 271 - opt = *opt_ptr++; 272 - len = 0; 273 - value = NULL; 274 - 275 - /* Check if this isn't a single byte option */ 276 - if (opt > DCCPO_MAX_RESERVED) { 277 - if (opt_ptr == opt_end) 278 - goto out_invalid_option; 279 - 280 - len = *opt_ptr++; 281 - if (len < 3) 282 - goto out_invalid_option; 283 - /* 284 - * Remove the type and len fields, leaving 285 - * just the value size 286 - */ 287 - len -= 2; 288 - value = opt_ptr; 289 - opt_ptr += len; 290 - 291 - if (opt_ptr > opt_end) 292 - goto out_invalid_option; 293 - } 294 - 295 - switch (opt) { 296 - case DCCPO_ACK_VECTOR_0: 297 - case DCCPO_ACK_VECTOR_1: 298 - *vec = value; 299 - *veclen = len; 300 - return offset + (opt_ptr - options); 301 - } 302 - } 303 - 304 - return -1; 305 - 306 - out_invalid_option: 307 - DCCP_BUG("Invalid option - this should not happen (previous parsing)!"); 308 - return -1; 309 - } 310 - 311 249 /** 312 250 * ccid2_rtt_estimator - Sample RTT and compute RTO using RFC2988 algorithm 313 251 * This code is almost identical with TCP's tcp_rtt_estimator(), since ··· 370 432 ccid2_change_l_ack_ratio(sk, hc->tx_cwnd); 371 433 } 372 434 435 + static int ccid2_hc_tx_parse_options(struct sock *sk, u8 packet_type, 436 + u8 option, u8 *optval, u8 optlen) 437 + { 438 + struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk); 439 + 440 + switch (option) { 441 + case DCCPO_ACK_VECTOR_0: 442 + case DCCPO_ACK_VECTOR_1: 443 + return dccp_ackvec_parsed_add(&hc->tx_av_chunks, optval, optlen, 444 + option - DCCPO_ACK_VECTOR_0); 445 + } 446 + return 0; 447 + } 448 + 373 449 static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) 374 450 { 375 451 struct dccp_sock *dp = dccp_sk(sk); 376 452 struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk); 377 453 const bool sender_was_blocked = ccid2_cwnd_network_limited(hc); 454 + struct dccp_ackvec_parsed *avp; 378 455 u64 ackno, seqno; 379 456 struct ccid2_seq *seqp; 380 - unsigned char *vector; 381 - unsigned char veclen; 382 - int offset = 0; 383 457 int done = 0; 384 458 unsigned int maxincr = 0; 385 459 ··· 425 475 } 426 476 427 477 /* check forward path congestion */ 428 - /* still didn't send out new data packets */ 429 - if (hc->tx_seqh == hc->tx_seqt) 478 + if (dccp_packet_without_ack(skb)) 430 479 return; 431 480 432 - switch (DCCP_SKB_CB(skb)->dccpd_type) { 433 - case DCCP_PKT_ACK: 434 - case DCCP_PKT_DATAACK: 435 - break; 436 - default: 437 - return; 438 - } 481 + /* still didn't send out new data packets */ 482 + if (hc->tx_seqh == hc->tx_seqt) 483 + goto done; 439 484 440 485 ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq; 441 486 if (after48(ackno, hc->tx_high_ack)) ··· 454 509 maxincr = DIV_ROUND_UP(dp->dccps_l_ack_ratio, 2); 455 510 456 511 /* go through all ack vectors */ 457 - while ((offset = ccid2_ackvector(sk, skb, offset, 458 - &vector, &veclen)) != -1) { 512 + list_for_each_entry(avp, &hc->tx_av_chunks, node) { 459 513 /* go through this ack vector */ 460 - while (veclen--) { 461 - u64 ackno_end_rl = SUB48(ackno, dccp_ackvec_runlen(vector)); 514 + for (; avp->len--; avp->vec++) { 515 + u64 ackno_end_rl = SUB48(ackno, 516 + dccp_ackvec_runlen(avp->vec)); 462 517 463 - ccid2_pr_debug("ackvec start:%llu end:%llu\n", 518 + ccid2_pr_debug("ackvec %llu |%u,%u|\n", 464 519 (unsigned long long)ackno, 465 - (unsigned long long)ackno_end_rl); 520 + dccp_ackvec_state(avp->vec) >> 6, 521 + dccp_ackvec_runlen(avp->vec)); 466 522 /* if the seqno we are analyzing is larger than the 467 523 * current ackno, then move towards the tail of our 468 524 * seqnos. ··· 482 536 * run length 483 537 */ 484 538 while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) { 485 - const u8 state = dccp_ackvec_state(vector); 539 + const u8 state = dccp_ackvec_state(avp->vec); 486 540 487 541 /* new packet received or marked */ 488 542 if (state != DCCPAV_NOT_RECEIVED && ··· 509 563 break; 510 564 511 565 ackno = SUB48(ackno_end_rl, 1); 512 - vector++; 513 566 } 514 567 if (done) 515 568 break; ··· 576 631 sk_stop_timer(sk, &hc->tx_rtotimer); 577 632 else 578 633 sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto); 579 - 634 + done: 580 635 /* check if incoming Acks allow pending packets to be sent */ 581 636 if (sender_was_blocked && !ccid2_cwnd_network_limited(hc)) 582 637 tasklet_schedule(&dccp_sk(sk)->dccps_xmitlet); 638 + dccp_ackvec_parsed_cleanup(&hc->tx_av_chunks); 583 639 } 584 640 585 641 static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) ··· 609 663 hc->tx_last_cong = ccid2_time_stamp; 610 664 setup_timer(&hc->tx_rtotimer, ccid2_hc_tx_rto_expire, 611 665 (unsigned long)sk); 666 + INIT_LIST_HEAD(&hc->tx_av_chunks); 612 667 return 0; 613 668 } 614 669 ··· 643 696 } 644 697 645 698 struct ccid_operations ccid2_ops = { 646 - .ccid_id = DCCPC_CCID2, 647 - .ccid_name = "TCP-like", 648 - .ccid_hc_tx_obj_size = sizeof(struct ccid2_hc_tx_sock), 649 - .ccid_hc_tx_init = ccid2_hc_tx_init, 650 - .ccid_hc_tx_exit = ccid2_hc_tx_exit, 651 - .ccid_hc_tx_send_packet = ccid2_hc_tx_send_packet, 652 - .ccid_hc_tx_packet_sent = ccid2_hc_tx_packet_sent, 653 - .ccid_hc_tx_packet_recv = ccid2_hc_tx_packet_recv, 654 - .ccid_hc_rx_obj_size = sizeof(struct ccid2_hc_rx_sock), 655 - .ccid_hc_rx_packet_recv = ccid2_hc_rx_packet_recv, 699 + .ccid_id = DCCPC_CCID2, 700 + .ccid_name = "TCP-like", 701 + .ccid_hc_tx_obj_size = sizeof(struct ccid2_hc_tx_sock), 702 + .ccid_hc_tx_init = ccid2_hc_tx_init, 703 + .ccid_hc_tx_exit = ccid2_hc_tx_exit, 704 + .ccid_hc_tx_send_packet = ccid2_hc_tx_send_packet, 705 + .ccid_hc_tx_packet_sent = ccid2_hc_tx_packet_sent, 706 + .ccid_hc_tx_parse_options = ccid2_hc_tx_parse_options, 707 + .ccid_hc_tx_packet_recv = ccid2_hc_tx_packet_recv, 708 + .ccid_hc_rx_obj_size = sizeof(struct ccid2_hc_rx_sock), 709 + .ccid_hc_rx_packet_recv = ccid2_hc_rx_packet_recv, 656 710 }; 657 711 658 712 #ifdef CONFIG_IP_DCCP_CCID2_DEBUG
+2
net/dccp/ccids/ccid2.h
··· 55 55 * @tx_rtt_seq: to decay RTTVAR at most once per flight 56 56 * @tx_rpseq: last consecutive seqno 57 57 * @tx_rpdupack: dupacks since rpseq 58 + * @tx_av_chunks: list of Ack Vectors received on current skb 58 59 */ 59 60 struct ccid2_hc_tx_sock { 60 61 u32 tx_cwnd; ··· 80 79 int tx_rpdupack; 81 80 u32 tx_last_cong; 82 81 u64 tx_high_ack; 82 + struct list_head tx_av_chunks; 83 83 }; 84 84 85 85 static inline bool ccid2_cwnd_network_limited(struct ccid2_hc_tx_sock *hc)
+10 -7
net/dccp/options.c
··· 128 128 if (rc) 129 129 goto out_featneg_failed; 130 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 131 case DCCPO_TIMESTAMP: 139 132 if (len != 4) 140 133 goto out_invalid_option; ··· 217 224 pkt_type, opt, value, len)) 218 225 goto out_invalid_option; 219 226 break; 227 + case DCCPO_ACK_VECTOR_0: 228 + case DCCPO_ACK_VECTOR_1: 229 + if (dccp_packet_without_ack(skb)) /* RFC 4340, 11.4 */ 230 + break; 231 + /* 232 + * Ack vectors are processed by the TX CCID if it is 233 + * interested. The RX CCID need not parse Ack Vectors, 234 + * since it is only interested in clearing old state. 235 + * Fall through. 236 + */ 220 237 case DCCPO_MIN_TX_CCID_SPECIFIC ... DCCPO_MAX_TX_CCID_SPECIFIC: 221 238 if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk, 222 239 pkt_type, opt, value, len))