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); if (hctx->ccid2hctx_cwnd < hctx->ccid2hctx_ssthresh) { if (*maxincr > 0 && ++hctx->ccid2hctx_packets_acked == 2) { hctx->ccid2hctx_cwnd += 1; *maxincr -= 1; hctx->ccid2hctx_packets_acked = 0; } } else if (++hctx->ccid2hctx_packets_acked >= hctx->ccid2hctx_cwnd) { hctx->ccid2hctx_cwnd += 1; hctx->ccid2hctx_packets_acked = 0; } /* update RTO */ if (hctx->ccid2hctx_srtt == -1 || time_after(jiffies, hctx->ccid2hctx_lastrtt + hctx->ccid2hctx_srtt)) { unsigned long r = (long)jiffies - (long)seqp->ccid2s_sent; int s; /* first measurement */ if (hctx->ccid2hctx_srtt == -1) { ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n", r, jiffies, (unsigned long long)seqp->ccid2s_seq); ccid2_change_srtt(hctx, r); hctx->ccid2hctx_rttvar = r >> 1; } else {
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_hc_tx_kill_rto_timer(struct sock *sk) { 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 int ccid2_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) { struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); if (hctx->ccid2hctx_pipe < hctx->ccid2hctx_cwnd) return 0; return 1; /* XXX CCID should dequeue when ready instead of polling */ }
static void ccid2_start_rto_timer(struct sock *sk) { struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk); ccid2_pr_debug("setting RTO timeout=%ld\n", hc->tx_rto); BUG_ON(timer_pending(&hc->tx_rtotimer)); sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto); }
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_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; 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 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; } } else { /* increased cwnd enough for this single ack */ 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 {
static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val) { struct dccp_sock *dp = dccp_sk(sk); u32 max_ratio = DIV_ROUND_UP(ccid2_hc_tx_sk(sk)->ccid2hctx_cwnd, 2); /* * Ensure that Ack Ratio does not exceed ceil(cwnd/2), which is (2) from * RFC 4341, 6.1.2. We ignore the statement that Ack Ratio 2 is always * acceptable since this causes starvation/deadlock whenever cwnd < 2. * The same problem arises when Ack Ratio is 0 (ie. Ack Ratio disabled). */ if (val == 0 || val > max_ratio) { DCCP_WARN("Limiting Ack Ratio (%u) to %u\n", val, max_ratio); val = max_ratio; } if (val > DCCPF_ACK_RATIO_MAX) val = DCCPF_ACK_RATIO_MAX; if (val == dp->dccps_l_ack_ratio) return; ccid2_pr_debug("changing local ack ratio to %u\n", val); dp->dccps_l_ack_ratio = val; }
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) { const 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_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len) { struct dccp_sock *dp = dccp_sk(sk); struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk); struct ccid2_seq *next; hctx->ccid2hctx_pipe++; hctx->ccid2hctx_seqh->ccid2s_seq = dp->dccps_gss; hctx->ccid2hctx_seqh->ccid2s_acked = 0; hctx->ccid2hctx_seqh->ccid2s_sent = jiffies; next = hctx->ccid2hctx_seqh->ccid2s_next; /* check if we need to alloc more space */ if (next == hctx->ccid2hctx_seqt) { if (ccid2_hc_tx_alloc_seq(hctx)) { DCCP_CRIT("packet history - out of memory!"); /* FIXME: find a more graceful way to bail out */ return; } next = hctx->ccid2hctx_seqh->ccid2s_next; BUG_ON(next == hctx->ccid2hctx_seqt); } hctx->ccid2hctx_seqh = next; ccid2_pr_debug("cwnd=%d pipe=%d\n", hctx->ccid2hctx_cwnd, hctx->ccid2hctx_pipe); /* * FIXME: The code below is broken and the variables have been removed * from the socket struct. The `ackloss' variable was always set to 0, * and with arsent there are several problems: * (i) it doesn't just count the number of Acks, but all sent packets; * (ii) it is expressed in # of packets, not # of windows, so the * comparison below uses the wrong formula: Appendix A of RFC 4341 * comes up with the number K = cwnd / (R^2 - R) of consecutive windows * of data with no lost or marked Ack packets. If arsent were the # of * consecutive Acks received without loss, then Ack Ratio needs to be * decreased by 1 when * arsent >= K * cwnd / R = cwnd^2 / (R^3 - R^2) * where cwnd / R is the number of Acks received per window of data * (cf. RFC 4341, App. A). The problems are that * - arsent counts other packets as well; * - the comparison uses a formula different from RFC 4341; * - computing a cubic/quadratic equation each time is too complicated. * Hence a different algorithm is needed. */ #if 0 /* 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; } } else { /* No acks lost up to now... */ /* decrease ack ratio if enough packets were sent */ if (dp->dccps_l_ack_ratio > 1) { /* XXX don't calculate denominator each time */ int 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; } } else { /* we can't increase ack ratio further [1] */ hctx->ccid2hctx_arsent = 0; /* or maybe set it to cwnd*/ } } #endif /* setup RTO timer */ if (!timer_pending(&hctx->ccid2hctx_rtotimer)) ccid2_start_rto_timer(sk); #ifdef CONFIG_IP_DCCP_CCID2_DEBUG do { struct ccid2_seq *seqp = hctx->ccid2hctx_seqt; while (seqp != hctx->ccid2hctx_seqh) { ccid2_pr_debug("out seq=%llu acked=%d time=%lu\n", (unsigned long long)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 }
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; } } else { /* No acks lost up to now... */ /* decrease ack ratio if enough packets were sent */ if (dp->dccps_l_ack_ratio > 1) { /* XXX don't calculate denominator each time */ int 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; } } else { /* we can't increase ack ratio further [1] */ 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 }