Skip to content

Commit b7d4263

Browse files
Jon Maloydavem330
authored andcommitted
tipc: introduce flow control for group broadcast messages
We introduce an end-to-end flow control mechanism for group broadcast messages. This ensures that no messages are ever lost because of destination receive buffer overflow, with minimal impact on performance. For now, the algorithm is based on the assumption that there is only one active transmitter at any moment in time. Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Acked-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent ae236fb commit b7d4263

4 files changed

Lines changed: 190 additions & 22 deletions

File tree

net/tipc/group.c

Lines changed: 144 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646

4747
#define ADV_UNIT (((MAX_MSG_SIZE + MAX_H_SIZE) / FLOWCTL_BLK_SZ) + 1)
4848
#define ADV_IDLE ADV_UNIT
49+
#define ADV_ACTIVE (ADV_UNIT * 12)
4950

5051
enum mbr_state {
5152
MBR_QUARANTINED,
@@ -59,16 +60,22 @@ enum mbr_state {
5960
struct tipc_member {
6061
struct rb_node tree_node;
6162
struct list_head list;
63+
struct list_head congested;
6264
struct sk_buff *event_msg;
65+
struct tipc_group *group;
6366
u32 node;
6467
u32 port;
6568
u32 instance;
6669
enum mbr_state state;
70+
u16 advertised;
71+
u16 window;
6772
u16 bc_rcv_nxt;
73+
bool usr_pending;
6874
};
6975

7076
struct tipc_group {
7177
struct rb_root members;
78+
struct list_head congested;
7279
struct tipc_nlist dests;
7380
struct net *net;
7481
int subid;
@@ -86,11 +93,24 @@ struct tipc_group {
8693
static void tipc_group_proto_xmit(struct tipc_group *grp, struct tipc_member *m,
8794
int mtyp, struct sk_buff_head *xmitq);
8895

96+
static int tipc_group_rcvbuf_limit(struct tipc_group *grp)
97+
{
98+
int mcnt = grp->member_cnt + 1;
99+
100+
/* Scale to bytes, considering worst-case truesize/msgsize ratio */
101+
return mcnt * ADV_ACTIVE * FLOWCTL_BLK_SZ * 4;
102+
}
103+
89104
u16 tipc_group_bc_snd_nxt(struct tipc_group *grp)
90105
{
91106
return grp->bc_snd_nxt;
92107
}
93108

109+
static bool tipc_group_is_enabled(struct tipc_member *m)
110+
{
111+
return m->state != MBR_QUARANTINED && m->state != MBR_LEAVING;
112+
}
113+
94114
static bool tipc_group_is_receiver(struct tipc_member *m)
95115
{
96116
return m && m->state >= MBR_JOINED;
@@ -111,6 +131,7 @@ struct tipc_group *tipc_group_create(struct net *net, u32 portid,
111131
if (!grp)
112132
return NULL;
113133
tipc_nlist_init(&grp->dests, tipc_own_addr(net));
134+
INIT_LIST_HEAD(&grp->congested);
114135
grp->members = RB_ROOT;
115136
grp->net = net;
116137
grp->portid = portid;
@@ -213,6 +234,8 @@ static struct tipc_member *tipc_group_create_member(struct tipc_group *grp,
213234
if (!m)
214235
return NULL;
215236
INIT_LIST_HEAD(&m->list);
237+
INIT_LIST_HEAD(&m->congested);
238+
m->group = grp;
216239
m->node = node;
217240
m->port = port;
218241
grp->member_cnt++;
@@ -233,6 +256,7 @@ static void tipc_group_delete_member(struct tipc_group *grp,
233256
rb_erase(&m->tree_node, &grp->members);
234257
grp->member_cnt--;
235258
list_del_init(&m->list);
259+
list_del_init(&m->congested);
236260

237261
/* If last member on a node, remove node from dest list */
238262
if (!tipc_group_find_node(grp, m->node))
@@ -255,11 +279,59 @@ void tipc_group_self(struct tipc_group *grp, struct tipc_name_seq *seq,
255279
*scope = grp->scope;
256280
}
257281

258-
void tipc_group_update_bc_members(struct tipc_group *grp)
282+
void tipc_group_update_member(struct tipc_member *m, int len)
283+
{
284+
struct tipc_group *grp = m->group;
285+
struct tipc_member *_m, *tmp;
286+
287+
if (!tipc_group_is_enabled(m))
288+
return;
289+
290+
m->window -= len;
291+
292+
if (m->window >= ADV_IDLE)
293+
return;
294+
295+
if (!list_empty(&m->congested))
296+
return;
297+
298+
/* Sort member into congested members' list */
299+
list_for_each_entry_safe(_m, tmp, &grp->congested, congested) {
300+
if (m->window > _m->window)
301+
continue;
302+
list_add_tail(&m->congested, &_m->congested);
303+
return;
304+
}
305+
list_add_tail(&m->congested, &grp->congested);
306+
}
307+
308+
void tipc_group_update_bc_members(struct tipc_group *grp, int len)
259309
{
310+
struct tipc_member *m;
311+
struct rb_node *n;
312+
313+
for (n = rb_first(&grp->members); n; n = rb_next(n)) {
314+
m = container_of(n, struct tipc_member, tree_node);
315+
if (tipc_group_is_enabled(m))
316+
tipc_group_update_member(m, len);
317+
}
260318
grp->bc_snd_nxt++;
261319
}
262320

321+
bool tipc_group_bc_cong(struct tipc_group *grp, int len)
322+
{
323+
struct tipc_member *m;
324+
325+
if (list_empty(&grp->congested))
326+
return false;
327+
328+
m = list_first_entry(&grp->congested, struct tipc_member, congested);
329+
if (m->window >= len)
330+
return false;
331+
332+
return true;
333+
}
334+
263335
/* tipc_group_filter_msg() - determine if we should accept arriving message
264336
*/
265337
void tipc_group_filter_msg(struct tipc_group *grp, struct sk_buff_head *inputq,
@@ -302,26 +374,61 @@ void tipc_group_filter_msg(struct tipc_group *grp, struct sk_buff_head *inputq,
302374
kfree_skb(skb);
303375
}
304376

377+
void tipc_group_update_rcv_win(struct tipc_group *grp, int blks, u32 node,
378+
u32 port, struct sk_buff_head *xmitq)
379+
{
380+
struct tipc_member *m;
381+
382+
m = tipc_group_find_member(grp, node, port);
383+
if (!m)
384+
return;
385+
386+
m->advertised -= blks;
387+
388+
switch (m->state) {
389+
case MBR_JOINED:
390+
if (m->advertised <= (ADV_ACTIVE - ADV_UNIT))
391+
tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq);
392+
break;
393+
case MBR_DISCOVERED:
394+
case MBR_JOINING:
395+
case MBR_LEAVING:
396+
default:
397+
break;
398+
}
399+
}
400+
305401
static void tipc_group_proto_xmit(struct tipc_group *grp, struct tipc_member *m,
306402
int mtyp, struct sk_buff_head *xmitq)
307403
{
308404
struct tipc_msg *hdr;
309405
struct sk_buff *skb;
406+
int adv = 0;
310407

311408
skb = tipc_msg_create(GROUP_PROTOCOL, mtyp, INT_H_SIZE, 0,
312409
m->node, tipc_own_addr(grp->net),
313410
m->port, grp->portid, 0);
314411
if (!skb)
315412
return;
316413

414+
if (m->state == MBR_JOINED)
415+
adv = ADV_ACTIVE - m->advertised;
416+
317417
hdr = buf_msg(skb);
318-
if (mtyp == GRP_JOIN_MSG)
418+
419+
if (mtyp == GRP_JOIN_MSG) {
319420
msg_set_grp_bc_syncpt(hdr, grp->bc_snd_nxt);
421+
msg_set_adv_win(hdr, adv);
422+
m->advertised += adv;
423+
} else if (mtyp == GRP_ADV_MSG) {
424+
msg_set_adv_win(hdr, adv);
425+
m->advertised += adv;
426+
}
320427
__skb_queue_tail(xmitq, skb);
321428
}
322429

323-
void tipc_group_proto_rcv(struct tipc_group *grp, struct tipc_msg *hdr,
324-
struct sk_buff_head *inputq,
430+
void tipc_group_proto_rcv(struct tipc_group *grp, bool *usr_wakeup,
431+
struct tipc_msg *hdr, struct sk_buff_head *inputq,
325432
struct sk_buff_head *xmitq)
326433
{
327434
u32 node = msg_orignode(hdr);
@@ -341,14 +448,22 @@ void tipc_group_proto_rcv(struct tipc_group *grp, struct tipc_msg *hdr,
341448
if (!m)
342449
return;
343450
m->bc_rcv_nxt = msg_grp_bc_syncpt(hdr);
451+
m->window += msg_adv_win(hdr);
344452

345453
/* Wait until PUBLISH event is received */
346454
if (m->state == MBR_DISCOVERED) {
347455
m->state = MBR_JOINING;
348456
} else if (m->state == MBR_PUBLISHED) {
349457
m->state = MBR_JOINED;
458+
*usr_wakeup = true;
459+
m->usr_pending = false;
460+
tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq);
350461
__skb_queue_tail(inputq, m->event_msg);
351462
}
463+
if (m->window < ADV_IDLE)
464+
tipc_group_update_member(m, 0);
465+
else
466+
list_del_init(&m->congested);
352467
return;
353468
case GRP_LEAVE_MSG:
354469
if (!m)
@@ -361,14 +476,28 @@ void tipc_group_proto_rcv(struct tipc_group *grp, struct tipc_msg *hdr,
361476
}
362477
/* Otherwise deliver already received WITHDRAW event */
363478
__skb_queue_tail(inputq, m->event_msg);
479+
*usr_wakeup = m->usr_pending;
364480
tipc_group_delete_member(grp, m);
481+
list_del_init(&m->congested);
482+
return;
483+
case GRP_ADV_MSG:
484+
if (!m)
485+
return;
486+
m->window += msg_adv_win(hdr);
487+
*usr_wakeup = m->usr_pending;
488+
m->usr_pending = false;
489+
list_del_init(&m->congested);
365490
return;
366491
default:
367492
pr_warn("Received unknown GROUP_PROTO message\n");
368493
}
369494
}
370495

496+
/* tipc_group_member_evt() - receive and handle a member up/down event
497+
*/
371498
void tipc_group_member_evt(struct tipc_group *grp,
499+
bool *usr_wakeup,
500+
int *sk_rcvbuf,
372501
struct sk_buff *skb,
373502
struct sk_buff_head *inputq,
374503
struct sk_buff_head *xmitq)
@@ -416,16 +545,25 @@ void tipc_group_member_evt(struct tipc_group *grp,
416545
} else {
417546
__skb_queue_tail(inputq, skb);
418547
m->state = MBR_JOINED;
548+
*usr_wakeup = true;
549+
m->usr_pending = false;
419550
}
420551
m->instance = instance;
421552
TIPC_SKB_CB(skb)->orig_member = m->instance;
422553
tipc_group_proto_xmit(grp, m, GRP_JOIN_MSG, xmitq);
554+
if (m->window < ADV_IDLE)
555+
tipc_group_update_member(m, 0);
556+
else
557+
list_del_init(&m->congested);
423558
} else if (event == TIPC_WITHDRAWN) {
424559
if (!m)
425560
goto drop;
426561

427562
TIPC_SKB_CB(skb)->orig_member = m->instance;
428563

564+
*usr_wakeup = m->usr_pending;
565+
m->usr_pending = false;
566+
429567
/* Hold back event if more messages might be expected */
430568
if (m->state != MBR_LEAVING && tipc_node_is_up(net, node)) {
431569
m->event_msg = skb;
@@ -434,7 +572,9 @@ void tipc_group_member_evt(struct tipc_group *grp,
434572
__skb_queue_tail(inputq, skb);
435573
tipc_group_delete_member(grp, m);
436574
}
575+
list_del_init(&m->congested);
437576
}
577+
*sk_rcvbuf = tipc_group_rcvbuf_limit(grp);
438578
return;
439579
drop:
440580
kfree_skb(skb);

net/tipc/group.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,18 @@ void tipc_group_self(struct tipc_group *grp, struct tipc_name_seq *seq,
5252
void tipc_group_filter_msg(struct tipc_group *grp,
5353
struct sk_buff_head *inputq,
5454
struct sk_buff_head *xmitq);
55-
void tipc_group_member_evt(struct tipc_group *grp,
56-
struct sk_buff *skb,
55+
void tipc_group_member_evt(struct tipc_group *grp, bool *wakeup,
56+
int *sk_rcvbuf, struct sk_buff *skb,
5757
struct sk_buff_head *inputq,
5858
struct sk_buff_head *xmitq);
59-
void tipc_group_proto_rcv(struct tipc_group *grp,
59+
void tipc_group_proto_rcv(struct tipc_group *grp, bool *wakeup,
6060
struct tipc_msg *hdr,
6161
struct sk_buff_head *inputq,
6262
struct sk_buff_head *xmitq);
63-
void tipc_group_update_bc_members(struct tipc_group *grp);
63+
void tipc_group_update_bc_members(struct tipc_group *grp, int len);
64+
bool tipc_group_bc_cong(struct tipc_group *grp, int len);
65+
void tipc_group_update_rcv_win(struct tipc_group *grp, int blks, u32 node,
66+
u32 port, struct sk_buff_head *xmitq);
6467
u16 tipc_group_bc_snd_nxt(struct tipc_group *grp);
6568
int tipc_group_size(struct tipc_group *grp);
6669
#endif

net/tipc/msg.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,7 @@ static inline void msg_set_nameupper(struct tipc_msg *m, u32 n)
538538
*/
539539
#define GRP_JOIN_MSG 0
540540
#define GRP_LEAVE_MSG 1
541+
#define GRP_ADV_MSG 2
541542

542543
/*
543544
* Word 1
@@ -790,12 +791,12 @@ static inline void msg_set_conn_ack(struct tipc_msg *m, u32 n)
790791
msg_set_bits(m, 9, 16, 0xffff, n);
791792
}
792793

793-
static inline u32 msg_adv_win(struct tipc_msg *m)
794+
static inline u16 msg_adv_win(struct tipc_msg *m)
794795
{
795796
return msg_bits(m, 9, 0, 0xffff);
796797
}
797798

798-
static inline void msg_set_adv_win(struct tipc_msg *m, u32 n)
799+
static inline void msg_set_adv_win(struct tipc_msg *m, u16 n)
799800
{
800801
msg_set_bits(m, 9, 0, 0xffff, n);
801802
}

0 commit comments

Comments
 (0)