📄 ccid3.c
字号:
/* * net/dccp/ccids/ccid3.c * * Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand. * Copyright (c) 2005-6 Ian McDonald <imcdnzl@gmail.com> * * An implementation of the DCCP protocol * * This code has been developed by the University of Waikato WAND * research group. For further information please see http://www.wand.net.nz/ * * This code also uses code from Lulea University, rereleased as GPL by its * authors: * Copyright (c) 2003 Nils-Erik Mattsson, Joacim Haggmark, Magnus Erixzon * * Changes to meet Linux coding standards, to make it meet latest ccid3 draft * and to make it work as a loadable module in the DCCP stack written by * Arnaldo Carvalho de Melo <acme@conectiva.com.br>. * * Copyright (c) 2005 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. */#include <linux/config.h>#include "../ccid.h"#include "../dccp.h"#include "lib/packet_history.h"#include "lib/loss_interval.h"#include "lib/tfrc.h"#include "ccid3.h"/* * Reason for maths here is to avoid 32 bit overflow when a is big. * With this we get close to the limit. */static inline u32 usecs_div(const u32 a, const u32 b){ const u32 div = a < (UINT_MAX / (USEC_PER_SEC / 10)) ? 10 : a < (UINT_MAX / (USEC_PER_SEC / 50)) ? 50 : a < (UINT_MAX / (USEC_PER_SEC / 100)) ? 100 : a < (UINT_MAX / (USEC_PER_SEC / 500)) ? 500 : a < (UINT_MAX / (USEC_PER_SEC / 1000)) ? 1000 : a < (UINT_MAX / (USEC_PER_SEC / 5000)) ? 5000 : a < (UINT_MAX / (USEC_PER_SEC / 10000)) ? 10000 : a < (UINT_MAX / (USEC_PER_SEC / 50000)) ? 50000 : 100000; const u32 tmp = a * (USEC_PER_SEC / div); return (b >= 2 * div) ? tmp / (b / div) : tmp;}static int ccid3_debug;#ifdef CCID3_DEBUG#define ccid3_pr_debug(format, a...) \ do { if (ccid3_debug) \ printk(KERN_DEBUG "%s: " format, __FUNCTION__, ##a); \ } while (0)#else#define ccid3_pr_debug(format, a...)#endifstatic struct dccp_tx_hist *ccid3_tx_hist;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, TFRC_SSTATE_NO_FBACK, TFRC_SSTATE_FBACK, TFRC_SSTATE_TERM,};#ifdef CCID3_DEBUGstatic const char *ccid3_tx_state_name(enum ccid3_hc_tx_states state){ static char *ccid3_state_names[] = { [TFRC_SSTATE_NO_SENT] = "NO_SENT", [TFRC_SSTATE_NO_FBACK] = "NO_FBACK", [TFRC_SSTATE_FBACK] = "FBACK", [TFRC_SSTATE_TERM] = "TERM", }; return ccid3_state_names[state];}#endifstatic inline void ccid3_hc_tx_set_state(struct sock *sk, enum ccid3_hc_tx_states state){ struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); enum ccid3_hc_tx_states oldstate = hctx->ccid3hctx_state; ccid3_pr_debug("%s(%p) %-8.8s -> %s\n", dccp_role(sk), sk, ccid3_tx_state_name(oldstate), ccid3_tx_state_name(state)); WARN_ON(state == oldstate); hctx->ccid3hctx_state = state;}/* Calculate new t_ipi (inter packet interval) by t_ipi = s / X_inst */static inline void ccid3_calc_new_t_ipi(struct ccid3_hc_tx_sock *hctx){ /* * If no feedback spec says t_ipi is 1 second (set elsewhere and then * doubles after every no feedback timer (separate function) */ if (hctx->ccid3hctx_state != TFRC_SSTATE_NO_FBACK) hctx->ccid3hctx_t_ipi = usecs_div(hctx->ccid3hctx_s, hctx->ccid3hctx_x);}/* Calculate new delta by delta = min(t_ipi / 2, t_gran / 2) */static inline void ccid3_calc_new_delta(struct ccid3_hc_tx_sock *hctx){ hctx->ccid3hctx_delta = min_t(u32, hctx->ccid3hctx_t_ipi / 2, TFRC_OPSYS_HALF_TIME_GRAN);}/* * Update X by * If (p > 0) * x_calc = calcX(s, R, p); * X = max(min(X_calc, 2 * X_recv), s / t_mbi); * Else * If (now - tld >= R) * X = max(min(2 * X, 2 * X_recv), s / R); * tld = now; */ static void ccid3_hc_tx_update_x(struct sock *sk){ struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); /* To avoid large error in calcX */ if (hctx->ccid3hctx_p >= TFRC_SMALLEST_P) { hctx->ccid3hctx_x_calc = tfrc_calc_x(hctx->ccid3hctx_s, hctx->ccid3hctx_rtt, hctx->ccid3hctx_p); hctx->ccid3hctx_x = max_t(u32, min_t(u32, hctx->ccid3hctx_x_calc, 2 * hctx->ccid3hctx_x_recv), (hctx->ccid3hctx_s / TFRC_MAX_BACK_OFF_TIME)); } else { struct timeval now; dccp_timestamp(sk, &now); if (timeval_delta(&now, &hctx->ccid3hctx_t_ld) >= hctx->ccid3hctx_rtt) { hctx->ccid3hctx_x = max_t(u32, min_t(u32, hctx->ccid3hctx_x_recv, hctx->ccid3hctx_x) * 2, usecs_div(hctx->ccid3hctx_s, hctx->ccid3hctx_rtt)); hctx->ccid3hctx_t_ld = now; } }}static void ccid3_hc_tx_no_feedback_timer(unsigned long data){ struct sock *sk = (struct sock *)data; unsigned long next_tmout = 0; struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); bh_lock_sock(sk); if (sock_owned_by_user(sk)) { /* Try again later. */ /* XXX: set some sensible MIB */ sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer, jiffies + HZ / 5); goto out; } ccid3_pr_debug("%s, sk=%p, state=%s\n", dccp_role(sk), sk, ccid3_tx_state_name(hctx->ccid3hctx_state)); switch (hctx->ccid3hctx_state) { case TFRC_SSTATE_TERM: goto out; case TFRC_SSTATE_NO_FBACK: /* Halve send rate */ hctx->ccid3hctx_x /= 2; if (hctx->ccid3hctx_x < (hctx->ccid3hctx_s / TFRC_MAX_BACK_OFF_TIME)) hctx->ccid3hctx_x = (hctx->ccid3hctx_s / TFRC_MAX_BACK_OFF_TIME); ccid3_pr_debug("%s, sk=%p, state=%s, updated tx rate to %d " "bytes/s\n", dccp_role(sk), sk, ccid3_tx_state_name(hctx->ccid3hctx_state), hctx->ccid3hctx_x); next_tmout = max_t(u32, 2 * usecs_div(hctx->ccid3hctx_s, hctx->ccid3hctx_x), TFRC_INITIAL_TIMEOUT); /* * FIXME - not sure above calculation is correct. See section * 5 of CCID3 11 should adjust tx_t_ipi and double that to * achieve it really */ break; case TFRC_SSTATE_FBACK: /* * Check if IDLE since last timeout and recv rate is less than * 4 packets per RTT */ if (!hctx->ccid3hctx_idle || (hctx->ccid3hctx_x_recv >= 4 * usecs_div(hctx->ccid3hctx_s, hctx->ccid3hctx_rtt))) { ccid3_pr_debug("%s, sk=%p, state=%s, not idle\n", dccp_role(sk), sk, ccid3_tx_state_name(hctx->ccid3hctx_state)); /* Halve sending rate */ /* If (X_calc > 2 * X_recv) * X_recv = max(X_recv / 2, s / (2 * t_mbi)); * Else * X_recv = X_calc / 4; */ BUG_ON(hctx->ccid3hctx_p >= TFRC_SMALLEST_P && hctx->ccid3hctx_x_calc == 0); /* check also if p is zero -> x_calc is infinity? */ if (hctx->ccid3hctx_p < TFRC_SMALLEST_P || hctx->ccid3hctx_x_calc > 2 * hctx->ccid3hctx_x_recv) hctx->ccid3hctx_x_recv = max_t(u32, hctx->ccid3hctx_x_recv / 2, hctx->ccid3hctx_s / (2 * TFRC_MAX_BACK_OFF_TIME)); else hctx->ccid3hctx_x_recv = hctx->ccid3hctx_x_calc / 4; /* Update sending rate */ ccid3_hc_tx_update_x(sk); } /* * Schedule no feedback timer to expire in * max(4 * R, 2 * s / X) */ next_tmout = max_t(u32, hctx->ccid3hctx_t_rto, 2 * usecs_div(hctx->ccid3hctx_s, hctx->ccid3hctx_x)); break; default: printk(KERN_CRIT "%s: %s, sk=%p, Illegal state (%d)!\n", __FUNCTION__, dccp_role(sk), sk, hctx->ccid3hctx_state); dump_stack(); goto out; } sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer, jiffies + max_t(u32, 1, usecs_to_jiffies(next_tmout))); hctx->ccid3hctx_idle = 1;out: bh_unlock_sock(sk); sock_put(sk);}static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb, int len){ struct dccp_sock *dp = dccp_sk(sk); struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); struct dccp_tx_hist_entry *new_packet; struct timeval now; long delay; int rc = -ENOTCONN; BUG_ON(hctx == NULL || hctx->ccid3hctx_state == TFRC_SSTATE_TERM); /* Check if pure ACK or Terminating*/ /* * XXX: We only call this function for DATA and DATAACK, on, these * packets can have zero length, but why the comment about "pure ACK"? */ if (unlikely(len == 0)) goto out; /* See if last packet allocated was not sent */ new_packet = dccp_tx_hist_head(&hctx->ccid3hctx_hist); if (new_packet == NULL || new_packet->dccphtx_sent) { new_packet = dccp_tx_hist_entry_new(ccid3_tx_hist, SLAB_ATOMIC); rc = -ENOBUFS; if (unlikely(new_packet == NULL)) { LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, not enough " "mem to add to history, send refused\n", __FUNCTION__, dccp_role(sk), sk); goto out; } dccp_tx_hist_add_entry(&hctx->ccid3hctx_hist, new_packet); } dccp_timestamp(sk, &now); switch (hctx->ccid3hctx_state) { case TFRC_SSTATE_NO_SENT: hctx->ccid3hctx_no_feedback_timer.function = ccid3_hc_tx_no_feedback_timer; hctx->ccid3hctx_no_feedback_timer.data = (unsigned long)sk; sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer, jiffies + usecs_to_jiffies(TFRC_INITIAL_TIMEOUT)); hctx->ccid3hctx_last_win_count = 0; hctx->ccid3hctx_t_last_win_count = now; ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK); hctx->ccid3hctx_t_ipi = TFRC_INITIAL_IPI; /* Set nominal send time for initial packet */ hctx->ccid3hctx_t_nom = now; timeval_add_usecs(&hctx->ccid3hctx_t_nom, hctx->ccid3hctx_t_ipi); ccid3_calc_new_delta(hctx); rc = 0; break; case TFRC_SSTATE_NO_FBACK: case TFRC_SSTATE_FBACK: delay = (timeval_delta(&now, &hctx->ccid3hctx_t_nom) - hctx->ccid3hctx_delta); delay /= -1000; /* divide by -1000 is to convert to ms and get sign right */ rc = delay > 0 ? delay : 0; break; default: printk(KERN_CRIT "%s: %s, sk=%p, Illegal state (%d)!\n", __FUNCTION__, dccp_role(sk), sk, hctx->ccid3hctx_state); dump_stack(); rc = -EINVAL; break; } /* Can we send? if so add options and add to packet history */ if (rc == 0) { dp->dccps_hc_tx_insert_options = 1; new_packet->dccphtx_ccval = DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count; }out: return rc;}static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, int len){ const struct dccp_sock *dp = dccp_sk(sk); struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); struct timeval now; BUG_ON(hctx == NULL || hctx->ccid3hctx_state == TFRC_SSTATE_TERM); dccp_timestamp(sk, &now); /* check if we have sent a data packet */ if (len > 0) { unsigned long quarter_rtt; struct dccp_tx_hist_entry *packet; packet = dccp_tx_hist_head(&hctx->ccid3hctx_hist); if (unlikely(packet == NULL)) { LIMIT_NETDEBUG(KERN_WARNING "%s: packet doesn't " "exists in history!\n", __FUNCTION__); return; } if (unlikely(packet->dccphtx_sent)) { LIMIT_NETDEBUG(KERN_WARNING "%s: no unsent packet in " "history!\n", __FUNCTION__); return; } packet->dccphtx_tstamp = now; packet->dccphtx_seqno = dp->dccps_gss; /* * Check if win_count have changed * Algorithm in "8.1. Window Counter Valuer" in * draft-ietf-dccp-ccid3-11.txt */ quarter_rtt = timeval_delta(&now, &hctx->ccid3hctx_t_last_win_count); if (likely(hctx->ccid3hctx_rtt > 8)) quarter_rtt /= hctx->ccid3hctx_rtt / 4; if (quarter_rtt > 0) { hctx->ccid3hctx_t_last_win_count = now; hctx->ccid3hctx_last_win_count = (hctx->ccid3hctx_last_win_count + min_t(unsigned long, quarter_rtt, 5)) % 16; ccid3_pr_debug("%s, sk=%p, window changed from " "%u to %u!\n", dccp_role(sk), sk, packet->dccphtx_ccval, hctx->ccid3hctx_last_win_count); } hctx->ccid3hctx_idle = 0; packet->dccphtx_rtt = hctx->ccid3hctx_rtt; packet->dccphtx_sent = 1; } else ccid3_pr_debug("%s, sk=%p, seqno=%llu NOT inserted!\n", dccp_role(sk), sk, dp->dccps_gss); switch (hctx->ccid3hctx_state) { case TFRC_SSTATE_NO_SENT: /* if first wasn't pure ack */ if (len != 0) printk(KERN_CRIT "%s: %s, First packet sent is noted " "as a data packet\n", __FUNCTION__, dccp_role(sk)); return; case TFRC_SSTATE_NO_FBACK:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -