Skip to content

Commit ed9420d

Browse files
Tuong Liengregkh
authored andcommitted
tipc: fix unlimited bundling of small messages
[ Upstream commit e95584a ] We have identified a problem with the "oversubscription" policy in the link transmission code. When small messages are transmitted, and the sending link has reached the transmit window limit, those messages will be bundled and put into the link backlog queue. However, bundles of data messages are counted at the 'CRITICAL' level, so that the counter for that level, instead of the counter for the real, bundled message's level is the one being increased. Subsequent, to-be-bundled data messages at non-CRITICAL levels continue to be tested against the unchanged counter for their own level, while contributing to an unrestrained increase at the CRITICAL backlog level. This leaves a gap in congestion control algorithm for small messages that can result in starvation for other users or a "real" CRITICAL user. Even that eventually can lead to buffer exhaustion & link reset. We fix this by keeping a 'target_bskb' buffer pointer at each levels, then when bundling, we only bundle messages at the same importance level only. This way, we know exactly how many slots a certain level have occupied in the queue, so can manage level congestion accurately. By bundling messages at the same level, we even have more benefits. Let consider this: - One socket sends 64-byte messages at the 'CRITICAL' level; - Another sends 4096-byte messages at the 'LOW' level; When a 64-byte message comes and is bundled the first time, we put the overhead of message bundle to it (+ 40-byte header, data copy, etc.) for later use, but the next message can be a 4096-byte one that cannot be bundled to the previous one. This means the last bundle carries only one payload message which is totally inefficient, as for the receiver also! Later on, another 64-byte message comes, now we make a new bundle and the same story repeats... With the new bundling algorithm, this will not happen, the 64-byte messages will be bundled together even when the 4096-byte message(s) comes in between. However, if the 4096-byte messages are sent at the same level i.e. 'CRITICAL', the bundling algorithm will again cause the same overhead. Also, the same will happen even with only one socket sending small messages at a rate close to the link transmit's one, so that, when one message is bundled, it's transmitted shortly. Then, another message comes, a new bundle is created and so on... We will solve this issue radically by another patch. Fixes: 365ad35 ("tipc: reduce risk of user starvation during link congestion") Reported-by: Hoang Le <hoang.h.le@dektech.com.au> 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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent a1afd82 commit ed9420d

2 files changed

Lines changed: 19 additions & 15 deletions

File tree

net/tipc/link.c

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ struct tipc_link {
161161
struct {
162162
u16 len;
163163
u16 limit;
164+
struct sk_buff *target_bskb;
164165
} backlog[5];
165166
u16 snd_nxt;
166167
u16 last_retransm;
@@ -846,6 +847,7 @@ static void link_prepare_wakeup(struct tipc_link *l)
846847
void tipc_link_reset(struct tipc_link *l)
847848
{
848849
struct sk_buff_head list;
850+
u32 imp;
849851

850852
__skb_queue_head_init(&list);
851853

@@ -864,11 +866,10 @@ void tipc_link_reset(struct tipc_link *l)
864866
__skb_queue_purge(&l->transmq);
865867
__skb_queue_purge(&l->deferdq);
866868
__skb_queue_purge(&l->backlogq);
867-
l->backlog[TIPC_LOW_IMPORTANCE].len = 0;
868-
l->backlog[TIPC_MEDIUM_IMPORTANCE].len = 0;
869-
l->backlog[TIPC_HIGH_IMPORTANCE].len = 0;
870-
l->backlog[TIPC_CRITICAL_IMPORTANCE].len = 0;
871-
l->backlog[TIPC_SYSTEM_IMPORTANCE].len = 0;
869+
for (imp = 0; imp <= TIPC_SYSTEM_IMPORTANCE; imp++) {
870+
l->backlog[imp].len = 0;
871+
l->backlog[imp].target_bskb = NULL;
872+
}
872873
kfree_skb(l->reasm_buf);
873874
kfree_skb(l->failover_reasm_skb);
874875
l->reasm_buf = NULL;
@@ -909,7 +910,7 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,
909910
u16 bc_ack = l->bc_rcvlink->rcv_nxt - 1;
910911
struct sk_buff_head *transmq = &l->transmq;
911912
struct sk_buff_head *backlogq = &l->backlogq;
912-
struct sk_buff *skb, *_skb, *bskb;
913+
struct sk_buff *skb, *_skb, **tskb;
913914
int pkt_cnt = skb_queue_len(list);
914915
int rc = 0;
915916

@@ -955,19 +956,21 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,
955956
seqno++;
956957
continue;
957958
}
958-
if (tipc_msg_bundle(skb_peek_tail(backlogq), hdr, mtu)) {
959+
tskb = &l->backlog[imp].target_bskb;
960+
if (tipc_msg_bundle(*tskb, hdr, mtu)) {
959961
kfree_skb(__skb_dequeue(list));
960962
l->stats.sent_bundled++;
961963
continue;
962964
}
963-
if (tipc_msg_make_bundle(&bskb, hdr, mtu, l->addr)) {
965+
if (tipc_msg_make_bundle(tskb, hdr, mtu, l->addr)) {
964966
kfree_skb(__skb_dequeue(list));
965-
__skb_queue_tail(backlogq, bskb);
966-
l->backlog[msg_importance(buf_msg(bskb))].len++;
967+
__skb_queue_tail(backlogq, *tskb);
968+
l->backlog[imp].len++;
967969
l->stats.sent_bundled++;
968970
l->stats.sent_bundles++;
969971
continue;
970972
}
973+
l->backlog[imp].target_bskb = NULL;
971974
l->backlog[imp].len += skb_queue_len(list);
972975
skb_queue_splice_tail_init(list, backlogq);
973976
}
@@ -983,6 +986,7 @@ static void tipc_link_advance_backlog(struct tipc_link *l,
983986
u16 seqno = l->snd_nxt;
984987
u16 ack = l->rcv_nxt - 1;
985988
u16 bc_ack = l->bc_rcvlink->rcv_nxt - 1;
989+
u32 imp;
986990

987991
while (skb_queue_len(&l->transmq) < l->window) {
988992
skb = skb_peek(&l->backlogq);
@@ -993,7 +997,10 @@ static void tipc_link_advance_backlog(struct tipc_link *l,
993997
break;
994998
__skb_dequeue(&l->backlogq);
995999
hdr = buf_msg(skb);
996-
l->backlog[msg_importance(hdr)].len--;
1000+
imp = msg_importance(hdr);
1001+
l->backlog[imp].len--;
1002+
if (unlikely(skb == l->backlog[imp].target_bskb))
1003+
l->backlog[imp].target_bskb = NULL;
9971004
__skb_queue_tail(&l->transmq, skb);
9981005
__skb_queue_tail(xmitq, _skb);
9991006
TIPC_SKB_CB(skb)->ackers = l->ackers;

net/tipc/msg.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -484,10 +484,7 @@ bool tipc_msg_make_bundle(struct sk_buff **skb, struct tipc_msg *msg,
484484
bmsg = buf_msg(_skb);
485485
tipc_msg_init(msg_prevnode(msg), bmsg, MSG_BUNDLER, 0,
486486
INT_H_SIZE, dnode);
487-
if (msg_isdata(msg))
488-
msg_set_importance(bmsg, TIPC_CRITICAL_IMPORTANCE);
489-
else
490-
msg_set_importance(bmsg, TIPC_SYSTEM_IMPORTANCE);
487+
msg_set_importance(bmsg, msg_importance(msg));
491488
msg_set_seqno(bmsg, msg_seqno(msg));
492489
msg_set_ack(bmsg, msg_ack(msg));
493490
msg_set_bcast_ack(bmsg, msg_bcast_ack(msg));

0 commit comments

Comments
 (0)