Qt: introduce sampling options for the RTT graph
This commit is contained in:
parent
f215bd6a8c
commit
ec09e1bbc7
@ -853,7 +853,18 @@ Throughput:: Average throughput and goodput.
|
|||||||
|
|
||||||
Round Trip Time:: Round trip time vs time or sequence number. RTT is
|
Round Trip Time:: Round trip time vs time or sequence number. RTT is
|
||||||
based on the acknowledgment timestamp corresponding to a particular
|
based on the acknowledgment timestamp corresponding to a particular
|
||||||
segment.
|
segment. The sampling method selects which segments are taken into
|
||||||
|
account and how the RTT is computed:
|
||||||
|
|
||||||
|
* `All Data Packets`, all segments carrying data are computed, and when
|
||||||
|
present, SACK is ignored.
|
||||||
|
* `All Data Packets w/ SACK`, all segments carrying data are computed,
|
||||||
|
the RTT value is based on SACK if present.
|
||||||
|
* `Data Packets matching RTT`, only segments with a corresponding RTT
|
||||||
|
value in the packet list are computed.
|
||||||
|
* `Data Packets matching Karn RTT`, only segments with a corresponding RTT
|
||||||
|
value in the packet list are computed, ambiguous ACKs following Karn's
|
||||||
|
definition are excluded.
|
||||||
|
|
||||||
Window Scaling:: Window size and outstanding bytes.
|
Window Scaling:: Window size and outstanding bytes.
|
||||||
|
|
||||||
|
@ -158,6 +158,14 @@ TCPStreamDialog::TCPStreamDialog(QWidget *parent, capture_file *cf, tcp_graph_ty
|
|||||||
if (graph_type == GRAPH_WSCALE) graph_idx = gtcb->count() - 1;
|
if (graph_type == GRAPH_WSCALE) graph_idx = gtcb->count() - 1;
|
||||||
gtcb->setUpdatesEnabled(true);
|
gtcb->setUpdatesEnabled(true);
|
||||||
|
|
||||||
|
QComboBox *smcb = ui->samplingMethodComboBox;
|
||||||
|
smcb->setUpdatesEnabled(false);
|
||||||
|
smcb->addItem(ui->actionSamplingAllPackets->text(), SAMPLING_ALL);
|
||||||
|
smcb->addItem(ui->actionSamplingAllPacketsSACK->text(), SAMPLING_ALL_SACK);
|
||||||
|
smcb->addItem(ui->actionSamplingRTT->text(), SAMPLING_RTT);
|
||||||
|
smcb->addItem(ui->actionSamplingKarn->text(), SAMPLING_KARN);
|
||||||
|
smcb->setUpdatesEnabled(true);
|
||||||
|
|
||||||
ui->dragRadioButton->setChecked(mouse_drags_);
|
ui->dragRadioButton->setChecked(mouse_drags_);
|
||||||
|
|
||||||
ctx_menu_.addAction(ui->actionZoomIn);
|
ctx_menu_.addAction(ui->actionZoomIn);
|
||||||
@ -709,8 +717,12 @@ void TCPStreamDialog::showWidgetsForGraphType()
|
|||||||
{
|
{
|
||||||
if (graph_.type == GRAPH_RTT) {
|
if (graph_.type == GRAPH_RTT) {
|
||||||
ui->bySeqNumberCheckBox->setVisible(true);
|
ui->bySeqNumberCheckBox->setVisible(true);
|
||||||
|
ui->samplingMethodComboBox->setVisible(true);
|
||||||
|
ui->samplingLabel->setVisible(true);
|
||||||
} else {
|
} else {
|
||||||
ui->bySeqNumberCheckBox->setVisible(false);
|
ui->bySeqNumberCheckBox->setVisible(false);
|
||||||
|
ui->samplingMethodComboBox->setVisible(false);
|
||||||
|
ui->samplingLabel->setVisible(false);
|
||||||
}
|
}
|
||||||
if (graph_.type == GRAPH_THROUGHPUT) {
|
if (graph_.type == GRAPH_THROUGHPUT) {
|
||||||
#ifdef MA_1_SECOND
|
#ifdef MA_1_SECOND
|
||||||
@ -1448,7 +1460,7 @@ rtt_selectively_ack_range(QVector<double>& x_vals, bool bySeqNumber,
|
|||||||
} else {
|
} else {
|
||||||
x_vals.append(cur->time);
|
x_vals.append(cur->time);
|
||||||
}
|
}
|
||||||
rtt.append((rt_val - cur->time) * 1000.0);
|
rtt.append(rt_val - cur->time);
|
||||||
// in this case, we will delete current unack
|
// in this case, we will delete current unack
|
||||||
// [ update "begin" if necessary - we will return it to the
|
// [ update "begin" if necessary - we will return it to the
|
||||||
// caller to let them know we deleted it ]
|
// caller to let them know we deleted it ]
|
||||||
@ -1466,7 +1478,7 @@ rtt_selectively_ack_range(QVector<double>& x_vals, bool bySeqNumber,
|
|||||||
} else {
|
} else {
|
||||||
x_vals.append(cur->time);
|
x_vals.append(cur->time);
|
||||||
}
|
}
|
||||||
rtt.append((rt_val - cur->time) * 1000.0);
|
rtt.append(rt_val - cur->time);
|
||||||
// in this case, "right" marks the start of remaining bytes
|
// in this case, "right" marks the start of remaining bytes
|
||||||
cur->seqno = right;
|
cur->seqno = right;
|
||||||
continue;
|
continue;
|
||||||
@ -1480,7 +1492,7 @@ rtt_selectively_ack_range(QVector<double>& x_vals, bool bySeqNumber,
|
|||||||
} else {
|
} else {
|
||||||
x_vals.append(cur->time);
|
x_vals.append(cur->time);
|
||||||
}
|
}
|
||||||
rtt.append((rt_val - cur->time) * 1000.0);
|
rtt.append(rt_val - cur->time);
|
||||||
// in this case, "left" is just beyond the remaining bytes
|
// in this case, "left" is just beyond the remaining bytes
|
||||||
cur->end_seqno = left;
|
cur->end_seqno = left;
|
||||||
continue;
|
continue;
|
||||||
@ -1496,7 +1508,7 @@ rtt_selectively_ack_range(QVector<double>& x_vals, bool bySeqNumber,
|
|||||||
} else {
|
} else {
|
||||||
x_vals.append(cur->time);
|
x_vals.append(cur->time);
|
||||||
}
|
}
|
||||||
rtt.append((rt_val - cur->time) * 1000.0);
|
rtt.append(rt_val - cur->time);
|
||||||
// then split cur into two unacked segments
|
// then split cur into two unacked segments
|
||||||
// (linking the right-hand unack after the left)
|
// (linking the right-hand unack after the left)
|
||||||
cur->next = rtt_get_new_unack(cur->time, right, cur->end_seqno - right);
|
cur->next = rtt_get_new_unack(cur->time, right, cur->end_seqno - right);
|
||||||
@ -1551,6 +1563,7 @@ void TCPStreamDialog::fillRoundTripTime()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (struct segment *seg = graph_.segments; seg != NULL; seg = seg->next) {
|
for (struct segment *seg = graph_.segments; seg != NULL; seg = seg->next) {
|
||||||
|
/* sender traffic analysis */
|
||||||
if (compareHeaders(seg)) {
|
if (compareHeaders(seg)) {
|
||||||
uint32_t seqno = seg->th_seq - seq_base;
|
uint32_t seqno = seg->th_seq - seq_base;
|
||||||
if (seg->th_seglen && !rtt_is_retrans(unack_list, seqno)) {
|
if (seg->th_seglen && !rtt_is_retrans(unack_list, seqno)) {
|
||||||
@ -1564,15 +1577,23 @@ void TCPStreamDialog::fillRoundTripTime()
|
|||||||
}
|
}
|
||||||
rtt_put_unack_on_list(&unack_list, u);
|
rtt_put_unack_on_list(&unack_list, u);
|
||||||
}
|
}
|
||||||
} else {
|
/* else: ignore redundant sequences (Keep-Alives, Spurious,..) */
|
||||||
|
}
|
||||||
|
/* receiver traffic analysis */
|
||||||
|
else {
|
||||||
uint32_t ack_no = seg->th_ack - seq_base;
|
uint32_t ack_no = seg->th_ack - seq_base;
|
||||||
double rt_val = seg->rel_secs + seg->rel_usecs / 1000000.0;
|
double rt_val = seg->rel_secs + seg->rel_usecs / 1000000.0;
|
||||||
rt_val -= ts_offset_;
|
rt_val -= ts_offset_;
|
||||||
struct rtt_unack *v;
|
struct rtt_unack *v;
|
||||||
|
|
||||||
for (u = unack_list; u; u = v) {
|
for (u = unack_list; u; u = v) {
|
||||||
if (tcp_seq_after(ack_no, u->seqno)) {
|
|
||||||
// full or partial ack of seg by ack_no
|
// full or partial ack of seg by ack_no
|
||||||
|
if (tcp_seq_after(ack_no, u->seqno)) {
|
||||||
|
// fully acked segment, but we're also acking a newer one on the next round
|
||||||
|
if (tcp_seq_after(ack_no, u->end_seqno)) {
|
||||||
|
/* breach RFC, take more RTT samples */
|
||||||
|
if( graph_.rtt_sampling & RTT_ALL) {
|
||||||
|
|
||||||
if (bySeqNumber) {
|
if (bySeqNumber) {
|
||||||
x_vals.append(u->seqno);
|
x_vals.append(u->seqno);
|
||||||
sequence_num_map_.insert(u->seqno, seg);
|
sequence_num_map_.insert(u->seqno, seg);
|
||||||
@ -1580,23 +1601,56 @@ void TCPStreamDialog::fillRoundTripTime()
|
|||||||
x_vals.append(u->time);
|
x_vals.append(u->time);
|
||||||
}
|
}
|
||||||
rtt.append(rt_val - u->time);
|
rtt.append(rt_val - u->time);
|
||||||
if (tcp_seq_eq_or_after(ack_no, u->end_seqno)) {
|
}
|
||||||
// fully acked segment - nothing more to see here
|
|
||||||
v = u->next;
|
v = u->next;
|
||||||
rtt_delete_unack_from_list(&unack_list, u);
|
rtt_delete_unack_from_list(&unack_list, u);
|
||||||
// no need to compare SACK blocks for fully ACKed seg
|
// no need to compare SACK blocks for fully ACKed seg
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fully acked segment, currently the one being acked now
|
||||||
|
else if (tcp_seq_eq(ack_no, u->end_seqno)) {
|
||||||
|
if(!(graph_.rtt_sampling & RTT_KRN && (seg->ack_karn)) ) {
|
||||||
|
if (bySeqNumber) {
|
||||||
|
x_vals.append(u->seqno);
|
||||||
|
sequence_num_map_.insert(u->seqno, seg);
|
||||||
} else {
|
} else {
|
||||||
|
x_vals.append(u->time);
|
||||||
|
}
|
||||||
|
rtt.append(rt_val - u->time);
|
||||||
|
}
|
||||||
|
/* else: ignore Karn ambiguous ACKs */
|
||||||
|
|
||||||
|
v = u->next;
|
||||||
|
rtt_delete_unack_from_list(&unack_list, u);
|
||||||
|
// no need to compare SACK blocks for fully ACKed seg
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// partial ack of seg by ack_no
|
||||||
|
else {
|
||||||
|
if(!(graph_.rtt_sampling & RTT_KRN && (seg->ack_karn)) ) {
|
||||||
|
if (bySeqNumber) {
|
||||||
|
x_vals.append(u->seqno);
|
||||||
|
sequence_num_map_.insert(u->seqno, seg);
|
||||||
|
} else {
|
||||||
|
x_vals.append(u->time);
|
||||||
|
}
|
||||||
|
rtt.append(rt_val - u->time);
|
||||||
// partial ack of GSO seg
|
// partial ack of GSO seg
|
||||||
u->seqno = ack_no;
|
u->seqno = ack_no;
|
||||||
// (keep going - still need to compare SACK blocks...)
|
// (keep going - still need to compare SACK blocks...)
|
||||||
}
|
}
|
||||||
|
/* else: ignore Karn ambiguous ACKs */
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
v = u->next;
|
v = u->next;
|
||||||
// selectively acking u more than once
|
// selectively acking u more than once
|
||||||
// can shatter it into multiple intervals.
|
// can shatter it into multiple intervals.
|
||||||
// If we link those back into the list between u and v,
|
// If we link those back into the list between u and v,
|
||||||
// then each subsequent SACK selectively ACKs that range.
|
// then each subsequent SACK selectively ACKs that range.
|
||||||
|
if( graph_.rtt_sampling & RTT_SAK ) {
|
||||||
for (int i = 0; i < seg->num_sack_ranges; ++i) {
|
for (int i = 0; i < seg->num_sack_ranges; ++i) {
|
||||||
uint32_t left = seg->sack_left_edge[i] - seq_base;
|
uint32_t left = seg->sack_left_edge[i] - seq_base;
|
||||||
uint32_t right = seg->sack_right_edge[i] - seq_base;
|
uint32_t right = seg->sack_right_edge[i] - seq_base;
|
||||||
@ -1610,6 +1664,7 @@ void TCPStreamDialog::fillRoundTripTime()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// it's possible there's still unacked segs - so be sure to free list!
|
// it's possible there's still unacked segs - so be sure to free list!
|
||||||
rtt_destroy_unack_list(&unack_list);
|
rtt_destroy_unack_list(&unack_list);
|
||||||
base_graph_->setData(x_vals, rtt);
|
base_graph_->setData(x_vals, rtt);
|
||||||
@ -2092,6 +2147,33 @@ void TCPStreamDialog::on_zoomRadioButton_toggled(bool checked)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TCPStreamDialog::on_samplingMethodComboBox_currentIndexChanged(int index)
|
||||||
|
{
|
||||||
|
if (index < 0) return;
|
||||||
|
|
||||||
|
// reset flags
|
||||||
|
graph_.rtt_sampling = 0;
|
||||||
|
|
||||||
|
switch (index) {
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
graph_.rtt_sampling |= RTT_ALL;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
graph_.rtt_sampling |= RTT_ALL;
|
||||||
|
graph_.rtt_sampling |= RTT_SAK;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
graph_.rtt_sampling |= RTT_RTT;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
graph_.rtt_sampling |= RTT_KRN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fillGraph(/*reset_axes=*/true, /*set_focus=*/false);
|
||||||
|
}
|
||||||
|
|
||||||
void TCPStreamDialog::on_bySeqNumberCheckBox_stateChanged(int /* state */)
|
void TCPStreamDialog::on_bySeqNumberCheckBox_stateChanged(int /* state */)
|
||||||
{
|
{
|
||||||
fillGraph(/*reset_axes=*/true, /*set_focus=*/false);
|
fillGraph(/*reset_axes=*/true, /*set_focus=*/false);
|
||||||
@ -2348,3 +2430,4 @@ void TCPStreamDialog::on_buttonBox_helpRequested()
|
|||||||
{
|
{
|
||||||
mainApp->helpTopicAction(HELP_STATS_TCP_STREAM_GRAPHS_DIALOG);
|
mainApp->helpTopicAction(HELP_STATS_TCP_STREAM_GRAPHS_DIALOG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,6 +157,7 @@ private slots:
|
|||||||
void on_dragRadioButton_toggled(bool checked);
|
void on_dragRadioButton_toggled(bool checked);
|
||||||
void on_zoomRadioButton_toggled(bool checked);
|
void on_zoomRadioButton_toggled(bool checked);
|
||||||
void on_bySeqNumberCheckBox_stateChanged(int state);
|
void on_bySeqNumberCheckBox_stateChanged(int state);
|
||||||
|
void on_samplingMethodComboBox_currentIndexChanged(int index);
|
||||||
void on_showSegLengthCheckBox_stateChanged(int state);
|
void on_showSegLengthCheckBox_stateChanged(int state);
|
||||||
void on_showThroughputCheckBox_stateChanged(int state);
|
void on_showThroughputCheckBox_stateChanged(int state);
|
||||||
void on_showGoodputCheckBox_stateChanged(int state);
|
void on_showGoodputCheckBox_stateChanged(int state);
|
||||||
@ -193,3 +194,4 @@ private slots:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif // TCP_STREAM_DIALOG_H
|
#endif // TCP_STREAM_DIALOG_H
|
||||||
|
|
||||||
|
@ -229,6 +229,26 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="samplingLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Sampling Method</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="samplingMethodComboBox">
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::TabFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frame">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Select which packets and how the RTT sampling is done</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="bySeqNumberCheckBox">
|
<widget class="QCheckBox" name="bySeqNumberCheckBox">
|
||||||
<property name="focusPolicy">
|
<property name="focusPolicy">
|
||||||
@ -607,6 +627,50 @@
|
|||||||
<string>4</string>
|
<string>4</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionSamplingAllPackets">
|
||||||
|
<property name="text">
|
||||||
|
<string>All Data Packets</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Sampling from all data packets</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>1</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSamplingAllPacketsSACK">
|
||||||
|
<property name="text">
|
||||||
|
<string>All Data Packets w/ SACK</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Sampling from all data packets w/ SACK</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>2</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSamplingRTT">
|
||||||
|
<property name="text">
|
||||||
|
<string>Data Packets matching RTT</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Sampling from RTT packets</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>3</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSamplingKarn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Data Packets matching Karn RTT</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Sampling from Karn RTT packets</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>4</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
<action name="actionZoomInX">
|
<action name="actionZoomInX">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Zoom In X Axis</string>
|
<string>Zoom In X Axis</string>
|
||||||
|
@ -114,6 +114,8 @@ tapall_tcpip_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, cons
|
|||||||
copy_address(&segment->ip_src, &tcphdr->ip_src);
|
copy_address(&segment->ip_src, &tcphdr->ip_src);
|
||||||
copy_address(&segment->ip_dst, &tcphdr->ip_dst);
|
copy_address(&segment->ip_dst, &tcphdr->ip_dst);
|
||||||
|
|
||||||
|
segment->ack_karn=tcphdr->flagkarn;
|
||||||
|
|
||||||
segment->num_sack_ranges = MIN(MAX_TCP_SACK_RANGES, tcphdr->num_sack_ranges);
|
segment->num_sack_ranges = MIN(MAX_TCP_SACK_RANGES, tcphdr->num_sack_ranges);
|
||||||
if (segment->num_sack_ranges > 0) {
|
if (segment->num_sack_ranges > 0) {
|
||||||
/* Copy entries in the order they happen */
|
/* Copy entries in the order they happen */
|
||||||
@ -359,7 +361,7 @@ select_tcpip_session(capture_file *cf)
|
|||||||
return th_stream;
|
return th_stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtt_is_retrans(struct rtt_unack *list, unsigned int seqno)
|
bool rtt_is_retrans(struct rtt_unack *list, unsigned int seqno)
|
||||||
{
|
{
|
||||||
struct rtt_unack *u;
|
struct rtt_unack *u;
|
||||||
|
|
||||||
|
@ -27,6 +27,19 @@ typedef enum tcp_graph_type_ {
|
|||||||
GRAPH_UNDEFINED
|
GRAPH_UNDEFINED
|
||||||
} tcp_graph_type;
|
} tcp_graph_type;
|
||||||
|
|
||||||
|
#define RTT_ALL 0x0001
|
||||||
|
#define RTT_SAK 0x0002
|
||||||
|
#define RTT_RTT 0x0004
|
||||||
|
#define RTT_KRN 0x0008
|
||||||
|
|
||||||
|
typedef enum rtt_sampling_method_ {
|
||||||
|
SAMPLING_ALL,
|
||||||
|
SAMPLING_ALL_SACK,
|
||||||
|
SAMPLING_RTT,
|
||||||
|
SAMPLING_KARN,
|
||||||
|
SAMPLING_UNDEFINED
|
||||||
|
} rtt_sampling_method;
|
||||||
|
|
||||||
struct segment {
|
struct segment {
|
||||||
struct segment *next;
|
struct segment *next;
|
||||||
uint32_t num;
|
uint32_t num;
|
||||||
@ -49,6 +62,8 @@ struct segment {
|
|||||||
address ip_src;
|
address ip_src;
|
||||||
address ip_dst;
|
address ip_dst;
|
||||||
|
|
||||||
|
bool ack_karn; /* true when ambiguous according to Karn's algo */
|
||||||
|
|
||||||
uint8_t num_sack_ranges;
|
uint8_t num_sack_ranges;
|
||||||
uint32_t sack_left_edge[MAX_TCP_SACK_RANGES];
|
uint32_t sack_left_edge[MAX_TCP_SACK_RANGES];
|
||||||
uint32_t sack_right_edge[MAX_TCP_SACK_RANGES];
|
uint32_t sack_right_edge[MAX_TCP_SACK_RANGES];
|
||||||
@ -57,6 +72,9 @@ struct segment {
|
|||||||
struct tcp_graph {
|
struct tcp_graph {
|
||||||
tcp_graph_type type;
|
tcp_graph_type type;
|
||||||
|
|
||||||
|
/* RTT sampling method (for RTT graphs only) */
|
||||||
|
uint8_t rtt_sampling;
|
||||||
|
|
||||||
/* The stream this graph will show */
|
/* The stream this graph will show */
|
||||||
address src_address;
|
address src_address;
|
||||||
uint16_t src_port;
|
uint16_t src_port;
|
||||||
@ -98,12 +116,28 @@ struct rtt_unack {
|
|||||||
unsigned int end_seqno;
|
unsigned int end_seqno;
|
||||||
};
|
};
|
||||||
|
|
||||||
int rtt_is_retrans(struct rtt_unack * , unsigned int );
|
/**
|
||||||
|
* Check if a sequence number is currently in the Unacked list,
|
||||||
|
* typically for avoiding adding redundant sequences.
|
||||||
|
* In practice, the retrans meaning in this particular code is different
|
||||||
|
* from TCP's one and would rather cover Keep-Alives and Spurious Retrans.
|
||||||
|
*
|
||||||
|
* @param list The list containing the Unacked sequences
|
||||||
|
* @param seqno The sequence number to be searched for in the Unacked list
|
||||||
|
* @return true if the list contains the sequence number, false otherwise
|
||||||
|
*/
|
||||||
|
bool rtt_is_retrans(struct rtt_unack *list, unsigned int seqno);
|
||||||
|
|
||||||
struct rtt_unack *rtt_get_new_unack(double , unsigned int , unsigned int );
|
struct rtt_unack *rtt_get_new_unack(double , unsigned int , unsigned int );
|
||||||
void rtt_put_unack_on_list(struct rtt_unack ** , struct rtt_unack * );
|
void rtt_put_unack_on_list(struct rtt_unack ** , struct rtt_unack * );
|
||||||
void rtt_delete_unack_from_list(struct rtt_unack ** , struct rtt_unack * );
|
void rtt_delete_unack_from_list(struct rtt_unack ** , struct rtt_unack * );
|
||||||
void rtt_destroy_unack_list(struct rtt_unack ** );
|
void rtt_destroy_unack_list(struct rtt_unack ** );
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
tcp_seq_eq(uint32_t s1, uint32_t s2) {
|
||||||
|
return (int32_t)(s1 - s2) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
tcp_seq_before(uint32_t s1, uint32_t s2) {
|
tcp_seq_before(uint32_t s1, uint32_t s2) {
|
||||||
return (int32_t)(s1 - s2) < 0;
|
return (int32_t)(s1 - s2) < 0;
|
||||||
@ -119,7 +153,8 @@ tcp_seq_after(uint32_t s1, uint32_t s2) {
|
|||||||
return (int32_t)(s1 - s2) > 0;
|
return (int32_t)(s1 - s2) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int tcp_seq_before_or_eq(uint32_t s1, uint32_t s2) {
|
static inline int
|
||||||
|
tcp_seq_before_or_eq(uint32_t s1, uint32_t s2) {
|
||||||
return !tcp_seq_after(s1, s2);
|
return !tcp_seq_after(s1, s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user