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
5051enum mbr_state {
5152 MBR_QUARANTINED ,
@@ -59,16 +60,22 @@ enum mbr_state {
5960struct 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
7076struct 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 {
8693static 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+
89104u16 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+
94114static 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 */
265337void 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+
305401static 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+ */
371498void 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 ;
439579drop :
440580 kfree_skb (skb );
0 commit comments