📄 ccid3.c
字号:
switch (step) { case 0: tstamp = entry->dccphrx_tstamp; win_count = entry->dccphrx_ccval; step = 1; break; case 1: interval = win_count - entry->dccphrx_ccval; if (interval < 0) interval += TFRC_WIN_COUNT_LIMIT; if (interval > 4) goto found; break; } } } if (unlikely(step == 0)) { LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, packet history " "contains no data packets!\n", __FUNCTION__, dccp_role(sk), sk); return ~0; } if (unlikely(interval == 0)) { LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, Could not find a " "win_count interval > 0. Defaulting to 1\n", __FUNCTION__, dccp_role(sk), sk); interval = 1; }found: rtt = timeval_delta(&tstamp, &tail->dccphrx_tstamp) * 4 / interval; ccid3_pr_debug("%s, sk=%p, approximated RTT to %uus\n", dccp_role(sk), sk, rtt); if (rtt == 0) rtt = 1; dccp_timestamp(sk, &tstamp); delta = timeval_delta(&tstamp, &hcrx->ccid3hcrx_tstamp_last_feedback); x_recv = usecs_div(hcrx->ccid3hcrx_bytes_recv, delta); tmp1 = (u64)x_recv * (u64)rtt; do_div(tmp1,10000000); tmp2 = (u32)tmp1; fval = (hcrx->ccid3hcrx_s * 100000) / tmp2; /* do not alter order above or you will get overflow on 32 bit */ p = tfrc_calc_x_reverse_lookup(fval); ccid3_pr_debug("%s, sk=%p, receive rate=%u bytes/s, implied " "loss rate=%u\n", dccp_role(sk), sk, x_recv, p); if (p == 0) return ~0; else return 1000000 / p; }static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss){ struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); if (seq_loss != DCCP_MAX_SEQNO + 1 && list_empty(&hcrx->ccid3hcrx_li_hist)) { struct dccp_li_hist_entry *li_tail; li_tail = dccp_li_hist_interval_new(ccid3_li_hist, &hcrx->ccid3hcrx_li_hist, seq_loss, win_loss); if (li_tail == NULL) return; li_tail->dccplih_interval = ccid3_hc_rx_calc_first_li(sk); } else LIMIT_NETDEBUG(KERN_WARNING "%s: FIXME: find end of " "interval\n", __FUNCTION__);}static void ccid3_hc_rx_detect_loss(struct sock *sk){ struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); u8 win_loss; const u64 seq_loss = dccp_rx_hist_detect_loss(&hcrx->ccid3hcrx_hist, &hcrx->ccid3hcrx_li_hist, &win_loss); ccid3_hc_rx_update_li(sk, seq_loss, win_loss);}static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb){ struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); const struct dccp_options_received *opt_recv; struct dccp_rx_hist_entry *packet; struct timeval now; u8 win_count; u32 p_prev, r_sample, t_elapsed; int ins; BUG_ON(hcrx == NULL || !(hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA || hcrx->ccid3hcrx_state == TFRC_RSTATE_DATA)); opt_recv = &dccp_sk(sk)->dccps_options_received; switch (DCCP_SKB_CB(skb)->dccpd_type) { case DCCP_PKT_ACK: if (hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA) return; case DCCP_PKT_DATAACK: if (opt_recv->dccpor_timestamp_echo == 0) break; p_prev = hcrx->ccid3hcrx_rtt; dccp_timestamp(sk, &now); timeval_sub_usecs(&now, opt_recv->dccpor_timestamp_echo * 10); r_sample = timeval_usecs(&now); t_elapsed = opt_recv->dccpor_elapsed_time * 10; if (unlikely(r_sample <= t_elapsed)) LIMIT_NETDEBUG(KERN_WARNING "%s: r_sample=%uus, " "t_elapsed=%uus\n", __FUNCTION__, r_sample, t_elapsed); else r_sample -= t_elapsed; if (hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA) hcrx->ccid3hcrx_rtt = r_sample; else hcrx->ccid3hcrx_rtt = (hcrx->ccid3hcrx_rtt * 9) / 10 + r_sample / 10; if (p_prev != hcrx->ccid3hcrx_rtt) ccid3_pr_debug("%s, New RTT=%luus, elapsed time=%u\n", dccp_role(sk), hcrx->ccid3hcrx_rtt, opt_recv->dccpor_elapsed_time); break; case DCCP_PKT_DATA: break; default: /* We're not interested in other packet types, move along */ return; } packet = dccp_rx_hist_entry_new(ccid3_rx_hist, sk, opt_recv->dccpor_ndp, skb, SLAB_ATOMIC); if (unlikely(packet == NULL)) { LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, Not enough mem to " "add rx packet to history, consider it lost!\n", __FUNCTION__, dccp_role(sk), sk); return; } win_count = packet->dccphrx_ccval; ins = dccp_rx_hist_add_packet(ccid3_rx_hist, &hcrx->ccid3hcrx_hist, &hcrx->ccid3hcrx_li_hist, packet); if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_ACK) return; switch (hcrx->ccid3hcrx_state) { case TFRC_RSTATE_NO_DATA: ccid3_pr_debug("%s, sk=%p(%s), skb=%p, sending initial " "feedback\n", dccp_role(sk), sk, dccp_state_name(sk->sk_state), skb); ccid3_hc_rx_send_feedback(sk); ccid3_hc_rx_set_state(sk, TFRC_RSTATE_DATA); return; case TFRC_RSTATE_DATA: hcrx->ccid3hcrx_bytes_recv += skb->len - dccp_hdr(skb)->dccph_doff * 4; if (ins != 0) break; dccp_timestamp(sk, &now); if (timeval_delta(&now, &hcrx->ccid3hcrx_tstamp_last_ack) >= hcrx->ccid3hcrx_rtt) { hcrx->ccid3hcrx_tstamp_last_ack = now; ccid3_hc_rx_send_feedback(sk); } return; default: printk(KERN_CRIT "%s: %s, sk=%p, Illegal state (%d)!\n", __FUNCTION__, dccp_role(sk), sk, hcrx->ccid3hcrx_state); dump_stack(); return; } /* Dealing with packet loss */ ccid3_pr_debug("%s, sk=%p(%s), data loss! Reacting...\n", dccp_role(sk), sk, dccp_state_name(sk->sk_state)); ccid3_hc_rx_detect_loss(sk); p_prev = hcrx->ccid3hcrx_p; /* Calculate loss event rate */ if (!list_empty(&hcrx->ccid3hcrx_li_hist)) { u32 i_mean = dccp_li_hist_calc_i_mean(&hcrx->ccid3hcrx_li_hist); /* Scaling up by 1000000 as fixed decimal */ if (i_mean != 0) hcrx->ccid3hcrx_p = 1000000 / i_mean; } if (hcrx->ccid3hcrx_p > p_prev) { ccid3_hc_rx_send_feedback(sk); return; }}static int ccid3_hc_rx_init(struct ccid *ccid, struct sock *sk){ struct dccp_sock *dp = dccp_sk(sk); struct ccid3_hc_rx_sock *hcrx = ccid_priv(ccid); ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk); if (dp->dccps_packet_size >= TFRC_MIN_PACKET_SIZE && dp->dccps_packet_size <= TFRC_MAX_PACKET_SIZE) hcrx->ccid3hcrx_s = dp->dccps_packet_size; else hcrx->ccid3hcrx_s = TFRC_STD_PACKET_SIZE; hcrx->ccid3hcrx_state = TFRC_RSTATE_NO_DATA; INIT_LIST_HEAD(&hcrx->ccid3hcrx_hist); INIT_LIST_HEAD(&hcrx->ccid3hcrx_li_hist); dccp_timestamp(sk, &hcrx->ccid3hcrx_tstamp_last_ack); hcrx->ccid3hcrx_tstamp_last_feedback = hcrx->ccid3hcrx_tstamp_last_ack; hcrx->ccid3hcrx_rtt = 5000; /* XXX 5ms for now... */ return 0;}static void ccid3_hc_rx_exit(struct sock *sk){ struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); BUG_ON(hcrx == NULL); ccid3_hc_rx_set_state(sk, TFRC_RSTATE_TERM); /* Empty packet history */ dccp_rx_hist_purge(ccid3_rx_hist, &hcrx->ccid3hcrx_hist); /* Empty loss interval history */ dccp_li_hist_purge(ccid3_li_hist, &hcrx->ccid3hcrx_li_hist);}static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info){ const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); /* Listen socks doesn't have a private CCID block */ if (sk->sk_state == DCCP_LISTEN) return; BUG_ON(hcrx == NULL); info->tcpi_ca_state = hcrx->ccid3hcrx_state; info->tcpi_options |= TCPI_OPT_TIMESTAMPS; info->tcpi_rcv_rtt = hcrx->ccid3hcrx_rtt;}static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info){ const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); /* Listen socks doesn't have a private CCID block */ if (sk->sk_state == DCCP_LISTEN) return; BUG_ON(hctx == NULL); info->tcpi_rto = hctx->ccid3hctx_t_rto; info->tcpi_rtt = hctx->ccid3hctx_rtt;}static int ccid3_hc_rx_getsockopt(struct sock *sk, const int optname, int len, u32 __user *optval, int __user *optlen){ const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); const void *val; /* Listen socks doesn't have a private CCID block */ if (sk->sk_state == DCCP_LISTEN) return -EINVAL; switch (optname) { case DCCP_SOCKOPT_CCID_RX_INFO: if (len < sizeof(hcrx->ccid3hcrx_tfrc)) return -EINVAL; len = sizeof(hcrx->ccid3hcrx_tfrc); val = &hcrx->ccid3hcrx_tfrc; break; default: return -ENOPROTOOPT; } if (put_user(len, optlen) || copy_to_user(optval, val, len)) return -EFAULT; return 0;}static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len, u32 __user *optval, int __user *optlen){ const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); const void *val; /* Listen socks doesn't have a private CCID block */ if (sk->sk_state == DCCP_LISTEN) return -EINVAL; switch (optname) { case DCCP_SOCKOPT_CCID_TX_INFO: if (len < sizeof(hctx->ccid3hctx_tfrc)) return -EINVAL; len = sizeof(hctx->ccid3hctx_tfrc); val = &hctx->ccid3hctx_tfrc; break; default: return -ENOPROTOOPT; } if (put_user(len, optlen) || copy_to_user(optval, val, len)) return -EFAULT; return 0;}static struct ccid_operations ccid3 = { .ccid_id = 3, .ccid_name = "ccid3", .ccid_owner = THIS_MODULE, .ccid_hc_tx_obj_size = sizeof(struct ccid3_hc_tx_sock), .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, .ccid_hc_tx_packet_sent = ccid3_hc_tx_packet_sent, .ccid_hc_tx_packet_recv = ccid3_hc_tx_packet_recv, .ccid_hc_tx_insert_options = ccid3_hc_tx_insert_options, .ccid_hc_tx_parse_options = ccid3_hc_tx_parse_options, .ccid_hc_rx_obj_size = sizeof(struct ccid3_hc_rx_sock), .ccid_hc_rx_init = ccid3_hc_rx_init, .ccid_hc_rx_exit = ccid3_hc_rx_exit, .ccid_hc_rx_insert_options = ccid3_hc_rx_insert_options, .ccid_hc_rx_packet_recv = ccid3_hc_rx_packet_recv, .ccid_hc_rx_get_info = ccid3_hc_rx_get_info, .ccid_hc_tx_get_info = ccid3_hc_tx_get_info, .ccid_hc_rx_getsockopt = ccid3_hc_rx_getsockopt, .ccid_hc_tx_getsockopt = ccid3_hc_tx_getsockopt,}; module_param(ccid3_debug, int, 0444);MODULE_PARM_DESC(ccid3_debug, "Enable debug messages");static __init int ccid3_module_init(void){ int rc = -ENOBUFS; ccid3_rx_hist = dccp_rx_hist_new("ccid3"); if (ccid3_rx_hist == NULL) goto out; ccid3_tx_hist = dccp_tx_hist_new("ccid3"); if (ccid3_tx_hist == NULL) goto out_free_rx; ccid3_li_hist = dccp_li_hist_new("ccid3"); if (ccid3_li_hist == NULL) goto out_free_tx; rc = ccid_register(&ccid3); if (rc != 0) goto out_free_loss_interval_history;out: return rc;out_free_loss_interval_history: dccp_li_hist_delete(ccid3_li_hist); ccid3_li_hist = NULL;out_free_tx: dccp_tx_hist_delete(ccid3_tx_hist); ccid3_tx_hist = NULL;out_free_rx: dccp_rx_hist_delete(ccid3_rx_hist); ccid3_rx_hist = NULL; goto out;}module_init(ccid3_module_init);static __exit void ccid3_module_exit(void){ ccid_unregister(&ccid3); if (ccid3_tx_hist != NULL) { dccp_tx_hist_delete(ccid3_tx_hist); ccid3_tx_hist = NULL; } if (ccid3_rx_hist != NULL) { dccp_rx_hist_delete(ccid3_rx_hist); ccid3_rx_hist = NULL; } if (ccid3_li_hist != NULL) { dccp_li_hist_delete(ccid3_li_hist); ccid3_li_hist = NULL; }}module_exit(ccid3_module_exit);MODULE_AUTHOR("Ian McDonald <iam4@cs.waikato.ac.nz>, " "Arnaldo Carvalho de Melo <acme@ghostprotocols.net>");MODULE_DESCRIPTION("DCCP TFRC CCID3 CCID");MODULE_LICENSE("GPL");MODULE_ALIAS("net-dccp-ccid-3");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -