Skip to content

Commit a69b6e3

Browse files
implement SFR algorithm for multi-homing
Initial Version for SFR algorithm. Known issue: the performance gain is little or even worse - the transmit speed is slower than simply single-homing. Need more investigations on this issue.
1 parent 17d62f2 commit a69b6e3

File tree

2 files changed

+135
-61
lines changed

2 files changed

+135
-61
lines changed

net/sctp/cmt.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,18 @@
1313

1414
char* cmt_print_trxpt(struct sctp_transport *t)
1515
{
16-
static char ret[128];
16+
static char ret[256];
1717
memset(ret, 0, sizeof(ret));
1818
if (!t)
1919
return ret;
20-
snprintf(ret, sizeof(ret), "trxpt@%p[addr=%pISc,state=%d,cwnd=%d,ssthresh=%d,pcumack=0x%x,find_pc=%d,new_pc=%d],",
20+
snprintf(ret, sizeof(ret), "trxpt@%p[addr=%pISc,state=%d,cwnd=%d,ssthresh=%d,sfr.saw_newack=%d,sfr.highest=0x%x,cuc.pcumack=0x%x,cuc.find_pc=%d,cuc.new_pc=%d],",
2121
t,
2222
&t->ipaddr.sa,
2323
t->state,
2424
t->cwnd,
2525
t->ssthresh,
26+
t->cmt_sfr.saw_newack,
27+
t->cmt_sfr.hisfd,
2628
t->cmt_cuc.pseudo_cumack,
2729
t->cmt_cuc.find_pseudo_cumack,
2830
t->cmt_cuc.new_pseudo_cumack);
@@ -94,7 +96,7 @@ char* cmt_print_queued_tsn(struct list_head *queue, struct sctp_transport *trans
9496
tsn = ntohl(tchunk->subh.data_hdr->tsn);
9597
ret = snprintf(buf + strlen(buf),
9698
sizeof(buf) - strlen(buf),
97-
tchunk->tsn_gap_acked? "0x%x_A, ": "0x%x, ",
99+
tchunk->tsn_gap_acked? "0x%x(A), ": "0x%x, ",
98100
tsn);
99101
// success when return value is non-negative and less than n
100102
if(!(ret > 0 && ret < sizeof(buf) - strlen(buf)))

net/sctp/outqueue.c

Lines changed: 130 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@
5959
#include <net/sctp/sm.h>
6060
#include <net/sctp/cmt.h>
6161

62+
#ifdef pr_debug
63+
#undef pr_debug
64+
#endif
65+
66+
#define pr_debug(fmt, ...) ;
67+
68+
6269
/* Declare internal functions here. */
6370
static int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn);
6471
static void sctp_check_transmitted(struct sctp_outq *q,
@@ -201,6 +208,31 @@ static inline int sctp_cacc_skip(struct sctp_transport *primary,
201208
return 0;
202209
}
203210

211+
/** CMT-SFR algorithm
212+
*/
213+
static inline int sctp_cmt_sfr(struct sctp_transport *transport,
214+
__u32 tsn)
215+
{
216+
if (!transport) {
217+
// cmt_debug("***********transport is null!***************\n");
218+
dump_stack();
219+
return 1;
220+
}
221+
// say 1. 6 was sent through A; 789 through B.
222+
// 2. The corresponding ack is 6,[8-9]
223+
//
224+
// Then the B.hisfd == 9
225+
// 7 is regarded as missing
226+
if (transport->cmt_sfr.saw_newack &&
227+
TSN_lt(tsn, transport->cmt_sfr.hisfd)) {
228+
// cmt_debug("---->counter ++\n");
229+
return 1;
230+
}
231+
232+
// cmt_debug("---->eliminate unneceseary counter++!\n");
233+
return 0;
234+
235+
}
204236
/* Initialize an existing sctp_outq. This does the boring stuff.
205237
* You still need to define handlers if you really want to DO
206238
* something with this structure...
@@ -1033,7 +1065,7 @@ use_retran: if (new_transport->state == SCTP_UNCONFIRMED)
10331065
*/
10341066
if (transport == asoc->peer.active_path
10351067
&& asoc->peer.retran_path != asoc->peer.active_path) {
1036-
cmt_debug("%s: switch to retran\n", __func__);
1068+
// cmt_debug("%s: switch to retran\n", __func__);
10371069
new_transport = asoc->peer.retran_path;
10381070
goto use_retran;
10391071
}
@@ -1168,34 +1200,38 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_chunk *chunk)
11681200
/* Grab the association's destination address list. */
11691201
transport_list = &asoc->peer.transport_addr_list;
11701202

1171-
// int c = 0;
1172-
// static char buf[256];
1173-
// memset(buf, 0, sizeof(buf));
1174-
// list_for_each_entry(transport, transport_list,
1175-
// transports)
1176-
// c += snprintf(
1177-
// buf + c,
1178-
// sizeof(buf) - c,
1179-
// "trxpt|%p|cwnd=%d|ssthresh=%d|,",
1180-
// transport,
1181-
// transport->cwnd,
1182-
// transport->ssthresh);
1183-
//
1184-
// cmt_debug("%s: %s\n", __func__, buf);
1185-
1186-
1187-
// cmt_debug("%s: %s\n", __func__, cmt_print_assoc(asoc));
1188-
// to_console = cmt_print_queued_tsn(&q->retransmit, NULL);
1189-
// cmt_debug("%s\n", to_console);
1190-
//
1191-
// list_for_each_entry(transport, transport_list, transports) {
1192-
// to_console = cmt_print_queued_tsn(&transport->transmitted, transport);
1193-
// cmt_debug("%s\n", to_console);
1194-
// }
1195-
//
1196-
// to_console = cmt_print_sackhdr(sack);
1197-
// cmt_debug("%s\n", to_console);
1198-
1203+
int c = 0;
1204+
static char buf[256];
1205+
memset(buf, 0, sizeof(buf));
1206+
list_for_each_entry(transport, transport_list,
1207+
transports)
1208+
c += snprintf(
1209+
buf + c,
1210+
sizeof(buf) - c,
1211+
"trxpt|%p|cwnd=%d|ssthresh=%d|,",
1212+
transport,
1213+
transport->cwnd,
1214+
transport->ssthresh);
1215+
1216+
cmt_debug("%s: %s\n", __func__, buf);
1217+
1218+
1219+
/* // print association
1220+
cmt_debug("%s: %s\n", __func__, cmt_print_assoc(asoc));
1221+
1222+
// print what's in the retransmit queue
1223+
to_console = cmt_print_queued_tsn(&q->retransmit, NULL);
1224+
cmt_debug("%s\n", to_console);
1225+
1226+
// print what's in the queues.
1227+
list_for_each_entry(transport, transport_list, transports) {
1228+
to_console = cmt_print_queued_tsn(&transport->transmitted, transport);
1229+
cmt_debug("%s\n", to_console);
1230+
}
1231+
1232+
to_console = cmt_print_sackhdr(sack);
1233+
cmt_debug("%s\n", to_console);
1234+
*/
11991235
/* Print the context END */
12001236

12011237
sack_ctsn = ntohl(sack->cum_tsn_ack);
@@ -1238,6 +1274,18 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_chunk *chunk)
12381274
}
12391275
}
12401276

1277+
/* CMT-SFR
1278+
* On receipt of a SACK containing gap report
1279+
* 1.for each destination address d(i), initialize
1280+
* d(i).saw_newack = false
1281+
*/
1282+
if (gap_ack_blocks) {
1283+
list_for_each_entry(transport, transport_list, transports) {
1284+
transport->cmt_sfr.saw_newack = false;
1285+
transport->cmt_sfr.hisfd = asoc->c.initial_tsn;
1286+
}
1287+
}
1288+
12411289
/* Get the highest TSN in the sack. */
12421290
highest_tsn = sack_ctsn;
12431291
if (gap_ack_blocks)
@@ -1277,6 +1325,10 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_chunk *chunk)
12771325
accum_moved = 1;
12781326
}
12791327

1328+
// list_for_each_entry(transport, transport_list, transports) {
1329+
// cmt_debug("===========>%s \n", cmt_print_trxpt(transport));
1330+
// }
1331+
12801332
if (gap_ack_blocks) {
12811333

12821334
if (asoc->fast_recovery && accum_moved)
@@ -1447,9 +1499,43 @@ static void sctp_check_transmitted(struct sctp_outq *q,
14471499
if (!tchunk->transport)
14481500
migrate_bytes += sctp_data_size(tchunk);
14491501
forward_progress = true;
1502+
1503+
1504+
// TODO: For each retransmit,
1505+
// The tsn->transport would be set to the
1506+
// latest path, to which it's sent.
1507+
// CMT-SFR 2) for each TSN t(a) being newly
1508+
// acked
1509+
// set d(a).saw_newack=true;
1510+
// CMT-SFR 3) set highest_in_sack_for_dest
1511+
if (transport) {// use tchunk -> transport instead
1512+
transport->cmt_sfr.saw_newack = true;
1513+
if (TSN_lt(transport->cmt_sfr.hisfd, tsn))
1514+
transport->cmt_sfr.hisfd = tsn;
1515+
}
1516+
1517+
/*
1518+
* SFR-CACC algorithm:
1519+
* 2) If the SACK contains gap acks
1520+
* and the flag CHANGEOVER_ACTIVE is
1521+
* set the receiver of the SACK MUST
1522+
* take the following action:
1523+
*
1524+
* B) For each TSN t being acked that
1525+
* has not been acked in any SACK so
1526+
* far, set cacc_saw_newack to 1 for
1527+
* the destination that the TSN was
1528+
* sent to.
1529+
*/
1530+
if (transport && sack->num_gap_ack_blocks &&
1531+
q->asoc->peer.primary_path->cacc.
1532+
changeover_active)
1533+
transport->cacc.cacc_saw_newack = 1;
1534+
1535+
14501536
}
14511537

1452-
if (TSN_lte(tsn, sack_ctsn)) {
1538+
if (TSN_lte(tsn, sack_ctsn)) {// CXZ: cum acked
14531539
/* RFC 2960 6.3.2 Retransmission Timer Rules
14541540
*
14551541
* R3) Whenever a SACK is received
@@ -1461,32 +1547,11 @@ static void sctp_check_transmitted(struct sctp_outq *q,
14611547
*/
14621548
restart_timer = 1;
14631549
forward_progress = true;
1464-
1465-
if (!tchunk->tsn_gap_acked) {
1466-
/*
1467-
* SFR-CACC algorithm:
1468-
* 2) If the SACK contains gap acks
1469-
* and the flag CHANGEOVER_ACTIVE is
1470-
* set the receiver of the SACK MUST
1471-
* take the following action:
1472-
*
1473-
* B) For each TSN t being acked that
1474-
* has not been acked in any SACK so
1475-
* far, set cacc_saw_newack to 1 for
1476-
* the destination that the TSN was
1477-
* sent to.
1478-
*/
1479-
if (transport &&
1480-
sack->num_gap_ack_blocks &&
1481-
q->asoc->peer.primary_path->cacc.
1482-
changeover_active)
1483-
transport->cacc.cacc_saw_newack
1484-
= 1;
1485-
}
1486-
14871550
list_add_tail(&tchunk->transmitted_list,
14881551
&q->sacked);
1489-
} else {
1552+
1553+
1554+
} else {// gap acked
14901555
/* RFC2960 7.2.4, sctpimpguide-05 2.8.2
14911556
* M2) Each time a SACK arrives reporting
14921557
* 'Stray DATA chunk(s)' record the highest TSN
@@ -1668,13 +1733,20 @@ static void sctp_mark_missing(struct sctp_outq *q,
16681733
/* SFR-CACC may require us to skip marking
16691734
* this chunk as missing.
16701735
*/
1671-
if (!transport || !sctp_cacc_skip(primary,
1736+
if (!transport || (
1737+
!sctp_cacc_skip(primary,
16721738
chunk->transport,
1673-
count_of_newacks, tsn)) {
1739+
count_of_newacks, tsn)
1740+
1741+
&&
1742+
1743+
sctp_cmt_sfr(chunk->transport, tsn)
1744+
1745+
)) {
16741746
chunk->tsn_missing_report++;
16751747

1676-
pr_debug("%s: tsn:0x%x missing counter:%d\n",
1677-
__func__, tsn, chunk->tsn_missing_report);
1748+
pr_debug("%s: tsn:0x%x missing counter:%d, reason: cacc=%d, sfr=%d\n",
1749+
__func__, tsn, chunk->tsn_missing_report, cacc, sfr);
16781750
}
16791751
}
16801752
/*

0 commit comments

Comments
 (0)