static int qfSeqGapValidate(qfSeq_t *qs) { int i; char *err = NULL; for (i = 0; i < QF_SEQGAP_CT; i++) { if (qs->gaps[i].a && qs->gaps[i].b) { if (qfWrapCompare(qs->gaps[i].b, qs->gaps[i].a) < 1) { err = "invalid"; break; } if (i && (qfWrapCompare(qs->gaps[i].a, qs->gaps[i-1].b) >= 0)) { err = "inverted"; break; } } } if (!err) return 1; fprintf(stderr, "%8s gap at %u in %p (nsn %u):\n", err, i, qs, qs->nsn); for (i = 0; i < QF_SEQGAP_CT; i++) { fprintf(stderr, "\t%u-%u (%u) (%d)\n", qs->gaps[i].a, qs->gaps[i].b, qs->gaps[i].b - qs->gaps[i].a, i ? (qs->gaps[i-1].b - qs->gaps[i].a) : 0); } return 0; }
void qfAckSegment(qfAck_t *qa, uint32_t ack, uint32_t sack, uint32_t oct, uint32_t ms) { if (!qa->fan || qfWrapCompare(ack, qa->fan) > 0) { qa->fan = ack; qa->fanlms = ms; } else if (!oct) { qa->dup_ct++; } if (sack && qfWrapCompare(sack, ack) > 0) { qa->sel_ct++; } }
void qfRttSegment(qfRtt_t *rtt, uint32_t seq, uint32_t ack, uint32_t tsval, uint32_t tsecr, uint32_t ms, uint8_t tcpflags, unsigned reverse) { qfRttDir_t *fdir, *rdir; #if QOF_RTT_DEBUG char *dirname; #endif /* select which side we're looking at */ if (reverse) { fdir = &rtt->rev; rdir = &rtt->fwd; #if QOF_RTT_DEBUG dirname = "rev"; #endif } else { fdir = &rtt->fwd; rdir = &rtt->rev; #if QOF_RTT_DEBUG dirname = "fwd"; #endif } if (fdir->ackwait && (tcpflags & YF_TF_ACK) && qfWrapCompare(ack, fdir->tsack) >= 0) { /* got an ACK we were waiting for */ fdir->obs_ms = ms - fdir->lms; if (qfRttSample(rtt)) { #if QOF_RTT_DEBUG fprintf(stderr, "\ton %3s ack %u for seq %u (%u)\n", dirname, ack, fdir->tsack, ack - fdir->tsack); #endif } fdir->ackwait = 0; if (tsval) { qfRttSetEcrWait(rdir, tsval, ms); } } else if (fdir->ecrwait && qfWrapCompare(tsecr, fdir->tsack) >= 0) { /* got a TSECR we were waiting for */ if ((ms - fdir->lms) > fdir->obs_ms) { /* Minimize measured RTT on TSECR samples */ fdir->obs_ms = ms - fdir->lms; if (qfRttSample(rtt)) { #if QOF_RTT_DEBUG fprintf(stderr, "\ton %s ecr %u for val %u (%u)\n", dirname, tsecr, fdir->tsack, tsecr - fdir->tsack); #endif } } fdir->ecrwait = 0; qfRttSetAckWait(rdir, seq, ms); } else if (!rdir->ackwait && !rdir->ecrwait) { qfRttSetAckWait(rdir, seq, ms); } }
static int qfSeqGapFill(qfSeq_t *qs, uint32_t a, uint32_t b) { int i; uint32_t rtxoct = 0, nexa, nexb; /* Segment might fill multiple gaps, so iterate until we've distributed the entire segment */ while (qfWrapCompare(b, a) > 0) { /* Seek to the next applicable gap */ i = 0; while ((i < QF_SEQGAP_CT) && !qfSeqGapEmpty(qs->gaps, i) && (qfWrapCompare(a, qs->gaps[i].a)) < 0) i++; /* If we're off the edge of the gapstack, this is pure RTX. */ if (i == QF_SEQGAP_CT || qfSeqGapEmpty(qs->gaps, i)) { rtxoct += b - a; break; } /* Everything greater than the gap is also RTX */ if (qfWrapCompare(b, qs->gaps[i].b) > 0) { if (qfWrapCompare(a, qs->gaps[i].b) > 0) { rtxoct += b - a; break; } else { rtxoct += b - qs->gaps[i].b; b = qs->gaps[i].b; } } /* Check to see if we'll need to iterate */ if (qfWrapCompare(a, qs->gaps[i].a) < 0) { /* A is less than the gap; prepare to iterate */ nexa = a; nexb = b; a = qs->gaps[i].a; } else { /* A and B within or on gap edge; terminate iteration */ nexa = 0; nexb = 0; } /* Check for overlap within gap and fill */ if ((a == qs->gaps[i].a) && (b == qs->gaps[i].b)) { /* Completely fill gap */ qfSeqGapShift(qs->gaps, i); break; } else if (b == qs->gaps[i].b) { /* A within gap, B on edge; fill on the high side */ qs->gaps[i].b = a; break; } else if (a == qs->gaps[i].a) { /* B within gap, A on edge; fill on the high side */ qs->gaps[i].a = b; break; } else { /* A and B within gap; split the gap */ qs->seqlost += qfSeqGapUnshift(qs->gaps, i); qs->gaps[i].a = b; qs->gaps[i+1].b = a; } /* Modify segment and iterate */ a = nexa; b = nexb; } /* Done. Count retransmit */ if (rtxoct) { qs->rtx++; return 1; } else { return 0; } }
int qfSeqSegment(qfSeq_t *qs, qfRtt_t *rtt, uint16_t mss, uint8_t flags, uint32_t seq, uint32_t oct, uint32_t ms, uint32_t tsval, gboolean do_ts, gboolean do_iat) { uint32_t lastms = 0; /* Empty segments don't count */ if (!oct) return 0; if (qfWrapCompare(seq, qs->nsn) < 0) { /* Sequence less than NSN: fill */ if (seq - qs->nsn > qs->maxooo) { qs->maxooo = seq - qs->nsn; } if (qfSeqGapFill(qs, seq, seq + oct)) { qfCountLoss(qs, rtt, ms); } } else { /* Sequence beyond NSN: push */ if (seq != qs->nsn) { qfSeqGapPush(qs, qs->nsn, seq, mss); /* signal loss for burst tracking */ qfCountLoss(qs, rtt, ms); /* track max out of order */ if (seq - qs->nsn > qs->maxooo) { qs->maxooo = seq - qs->nsn; } } /* Detect wrap */ if (seq + oct < qs->nsn) { qs->wrapct++; } /* Determine next sequence number */ qs->nsn = seq + oct; /* track timestamp frequency */ if (do_ts && tsval) { /* increment wrap counters if necessary */ if (tsval < qs->advtsval) { qs->tsvalwrap++; } if (ms < qs->advlms) { qs->lmswrap++; } /* save current value */ qs->advtsval = tsval; } /* and advance time */ lastms = qs->advlms; qs->advlms = ms; /* calculate interarrival/interdeparture time of advancing segments */ if (do_iat) { uint32_t iat = 0, idt = 0, hz = 0; iat = ms - lastms; sstMeanAdd(&qs->seg_iat, iat); if (do_ts && tsval && (hz = qfTimestampHz(qs))) { idt = (1000 * (tsval - qs->advtsval)) / hz; sstMeanAdd(&qs->seg_variat, iat - idt); } } return 1; } /* if we're here, we didn't advance */ return 0; }