aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTuong Lien <tuong.t.lien@dektech.com.au>2019-04-04 00:09:52 -0400
committerDavid S. Miller <davem@davemloft.net>2019-04-04 21:29:25 -0400
commit382f598fb66b14a8451f2794abf70ea7b5826c96 (patch)
tree5d25199c0053b40e74a797c16c2d17dfe29d4479
parent9195948fbf3406f75b1f133ddb57304169c44341 (diff)
tipc: reduce duplicate packets for unicast traffic
For unicast transmission, the current NACK sending althorithm is over- active that forces the sending side to retransmit a packet that is not really lost but just arrived at the receiving side with some delay, or even retransmit same packets that have already been retransmitted before. As a result, many duplicates are observed also under normal condition, ie. without packet loss. One example case is: node1 transmits 1 2 3 4 10 5 6 7 8 9, when node2 receives packet #10, it puts into the deferdq. When the packet #5 comes it sends NACK with gap [6 - 9]. However, shortly after that, when packet #6 arrives, it pulls out packet #10 from the deferfq, but it is still out of order, so it makes another NACK with gap [7 - 9] and so on ... Finally, node1 has to retransmit the packets 5 6 7 8 9 a number of times, but in fact all the packets are not lost at all, so duplicates! This commit reduces duplicates by changing the condition to send NACK, also restricting the retransmissions on individual packets via a timer of about 1ms. However, it also needs to say that too tricky condition for NACKs or too long timeout value for retransmissions will result in performance reducing! The criterias in this commit are found to be effective for both the requirements to reduce duplicates but not affect performance. The tipc_link_rcv() is also improved to only dequeue skb from the link deferdq if it is expected (ie. its seqno <= rcv_nxt). Acked-by: Ying Xue <ying.xue@windriver.com> Acked-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: Tuong Lien <tuong.t.lien@dektech.com.au> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/tipc/link.c26
-rw-r--r--net/tipc/msg.h21
2 files changed, 37 insertions, 10 deletions
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 5aee1ed23ba9..1f2cde0d025f 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -209,6 +209,7 @@ enum {
209}; 209};
210 210
211#define TIPC_BC_RETR_LIM msecs_to_jiffies(10) /* [ms] */ 211#define TIPC_BC_RETR_LIM msecs_to_jiffies(10) /* [ms] */
212#define TIPC_UC_RETR_TIME (jiffies + msecs_to_jiffies(1))
212 213
213/* 214/*
214 * Interval between NACKs when packets arrive out of order 215 * Interval between NACKs when packets arrive out of order
@@ -1305,6 +1306,10 @@ next_gap_ack:
1305 kfree_skb(skb); 1306 kfree_skb(skb);
1306 } else if (less_eq(seqno, acked + gap)) { 1307 } else if (less_eq(seqno, acked + gap)) {
1307 /* retransmit skb */ 1308 /* retransmit skb */
1309 if (time_before(jiffies, TIPC_SKB_CB(skb)->nxt_retr))
1310 continue;
1311 TIPC_SKB_CB(skb)->nxt_retr = TIPC_UC_RETR_TIME;
1312
1308 _skb = __pskb_copy(skb, MIN_H_SIZE, GFP_ATOMIC); 1313 _skb = __pskb_copy(skb, MIN_H_SIZE, GFP_ATOMIC);
1309 if (!_skb) 1314 if (!_skb)
1310 continue; 1315 continue;
@@ -1380,6 +1385,7 @@ static int tipc_link_build_nack_msg(struct tipc_link *l,
1380 struct sk_buff_head *xmitq) 1385 struct sk_buff_head *xmitq)
1381{ 1386{
1382 u32 def_cnt = ++l->stats.deferred_recv; 1387 u32 def_cnt = ++l->stats.deferred_recv;
1388 u32 defq_len = skb_queue_len(&l->deferdq);
1383 int match1, match2; 1389 int match1, match2;
1384 1390
1385 if (link_is_bc_rcvlink(l)) { 1391 if (link_is_bc_rcvlink(l)) {
@@ -1390,7 +1396,7 @@ static int tipc_link_build_nack_msg(struct tipc_link *l,
1390 return 0; 1396 return 0;
1391 } 1397 }
1392 1398
1393 if ((skb_queue_len(&l->deferdq) == 1) || !(def_cnt % TIPC_NACK_INTV)) 1399 if (defq_len >= 3 && !((defq_len - 3) % 16))
1394 tipc_link_build_proto_msg(l, STATE_MSG, 0, 0, 0, 0, 0, xmitq); 1400 tipc_link_build_proto_msg(l, STATE_MSG, 0, 0, 0, 0, 0, xmitq);
1395 return 0; 1401 return 0;
1396} 1402}
@@ -1404,29 +1410,29 @@ int tipc_link_rcv(struct tipc_link *l, struct sk_buff *skb,
1404 struct sk_buff_head *xmitq) 1410 struct sk_buff_head *xmitq)
1405{ 1411{
1406 struct sk_buff_head *defq = &l->deferdq; 1412 struct sk_buff_head *defq = &l->deferdq;
1407 struct tipc_msg *hdr; 1413 struct tipc_msg *hdr = buf_msg(skb);
1408 u16 seqno, rcv_nxt, win_lim; 1414 u16 seqno, rcv_nxt, win_lim;
1409 int rc = 0; 1415 int rc = 0;
1410 1416
1417 /* Verify and update link state */
1418 if (unlikely(msg_user(hdr) == LINK_PROTOCOL))
1419 return tipc_link_proto_rcv(l, skb, xmitq);
1420
1421 /* Don't send probe at next timeout expiration */
1422 l->silent_intv_cnt = 0;
1423
1411 do { 1424 do {
1412 hdr = buf_msg(skb); 1425 hdr = buf_msg(skb);
1413 seqno = msg_seqno(hdr); 1426 seqno = msg_seqno(hdr);
1414 rcv_nxt = l->rcv_nxt; 1427 rcv_nxt = l->rcv_nxt;
1415 win_lim = rcv_nxt + TIPC_MAX_LINK_WIN; 1428 win_lim = rcv_nxt + TIPC_MAX_LINK_WIN;
1416 1429
1417 /* Verify and update link state */
1418 if (unlikely(msg_user(hdr) == LINK_PROTOCOL))
1419 return tipc_link_proto_rcv(l, skb, xmitq);
1420
1421 if (unlikely(!link_is_up(l))) { 1430 if (unlikely(!link_is_up(l))) {
1422 if (l->state == LINK_ESTABLISHING) 1431 if (l->state == LINK_ESTABLISHING)
1423 rc = TIPC_LINK_UP_EVT; 1432 rc = TIPC_LINK_UP_EVT;
1424 goto drop; 1433 goto drop;
1425 } 1434 }
1426 1435
1427 /* Don't send probe at next timeout expiration */
1428 l->silent_intv_cnt = 0;
1429
1430 /* Drop if outside receive window */ 1436 /* Drop if outside receive window */
1431 if (unlikely(less(seqno, rcv_nxt) || more(seqno, win_lim))) { 1437 if (unlikely(less(seqno, rcv_nxt) || more(seqno, win_lim))) {
1432 l->stats.duplicates++; 1438 l->stats.duplicates++;
@@ -1457,7 +1463,7 @@ int tipc_link_rcv(struct tipc_link *l, struct sk_buff *skb,
1457 rc |= tipc_link_build_state_msg(l, xmitq); 1463 rc |= tipc_link_build_state_msg(l, xmitq);
1458 if (unlikely(rc & ~TIPC_LINK_SND_STATE)) 1464 if (unlikely(rc & ~TIPC_LINK_SND_STATE))
1459 break; 1465 break;
1460 } while ((skb = __skb_dequeue(defq))); 1466 } while ((skb = __tipc_skb_dequeue(defq, l->rcv_nxt)));
1461 1467
1462 return rc; 1468 return rc;
1463drop: 1469drop:
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
index ec5c511a9c9c..8de02ad6e352 100644
--- a/net/tipc/msg.h
+++ b/net/tipc/msg.h
@@ -1151,4 +1151,25 @@ static inline void tipc_skb_queue_splice_tail_init(struct sk_buff_head *list,
1151 tipc_skb_queue_splice_tail(&tmp, head); 1151 tipc_skb_queue_splice_tail(&tmp, head);
1152} 1152}
1153 1153
1154/* __tipc_skb_dequeue() - dequeue the head skb according to expected seqno
1155 * @list: list to be dequeued from
1156 * @seqno: seqno of the expected msg
1157 *
1158 * returns skb dequeued from the list if its seqno is less than or equal to
1159 * the expected one, otherwise the skb is still hold
1160 *
1161 * Note: must be used with appropriate locks held only
1162 */
1163static inline struct sk_buff *__tipc_skb_dequeue(struct sk_buff_head *list,
1164 u16 seqno)
1165{
1166 struct sk_buff *skb = skb_peek(list);
1167
1168 if (skb && less_eq(buf_seqno(skb), seqno)) {
1169 __skb_unlink(skb, list);
1170 return skb;
1171 }
1172 return NULL;
1173}
1174
1154#endif 1175#endif