]> Git Repo - linux.git/blame - net/tipc/group.c
tipc: adjustment to group member FSM
[linux.git] / net / tipc / group.c
CommitLineData
75da2163
JM
1/*
2 * net/tipc/group.c: TIPC group messaging code
3 *
4 * Copyright (c) 2017, Ericsson AB
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the names of the copyright holders nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * Alternatively, this software may be distributed under the terms of the
20 * GNU General Public License ("GPL") version 2 as published by the Free
21 * Software Foundation.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
36#include "core.h"
37#include "addr.h"
38#include "group.h"
39#include "bcast.h"
40#include "server.h"
41#include "msg.h"
42#include "socket.h"
43#include "node.h"
44#include "name_table.h"
45#include "subscr.h"
46
47#define ADV_UNIT (((MAX_MSG_SIZE + MAX_H_SIZE) / FLOWCTL_BLK_SZ) + 1)
48#define ADV_IDLE ADV_UNIT
b7d42635 49#define ADV_ACTIVE (ADV_UNIT * 12)
75da2163
JM
50
51enum mbr_state {
75da2163
JM
52 MBR_DISCOVERED,
53 MBR_JOINING,
54 MBR_PUBLISHED,
55 MBR_JOINED,
04d7b574
JM
56 MBR_PENDING,
57 MBR_ACTIVE,
58 MBR_RECLAIMING,
59 MBR_REMITTED,
75da2163
JM
60 MBR_LEAVING
61};
62
63struct tipc_member {
64 struct rb_node tree_node;
65 struct list_head list;
38266ca1 66 struct list_head small_win;
ae236fb2 67 struct sk_buff *event_msg;
b87a5ea3 68 struct sk_buff_head deferredq;
b7d42635 69 struct tipc_group *group;
75da2163
JM
70 u32 node;
71 u32 port;
31c82a2d 72 u32 instance;
75da2163 73 enum mbr_state state;
b7d42635
JM
74 u16 advertised;
75 u16 window;
75da2163 76 u16 bc_rcv_nxt;
a3bada70 77 u16 bc_syncpt;
2f487712 78 u16 bc_acked;
b7d42635 79 bool usr_pending;
75da2163
JM
80};
81
82struct tipc_group {
83 struct rb_root members;
38266ca1 84 struct list_head small_win;
04d7b574
JM
85 struct list_head pending;
86 struct list_head active;
75da2163
JM
87 struct tipc_nlist dests;
88 struct net *net;
89 int subid;
90 u32 type;
91 u32 instance;
92 u32 domain;
93 u32 scope;
94 u32 portid;
95 u16 member_cnt;
04d7b574
JM
96 u16 active_cnt;
97 u16 max_active;
75da2163 98 u16 bc_snd_nxt;
2f487712 99 u16 bc_ackers;
75da2163 100 bool loopback;
ae236fb2 101 bool events;
75da2163
JM
102};
103
104static void tipc_group_proto_xmit(struct tipc_group *grp, struct tipc_member *m,
105 int mtyp, struct sk_buff_head *xmitq);
106
04d7b574
JM
107static void tipc_group_decr_active(struct tipc_group *grp,
108 struct tipc_member *m)
109{
f9c935db
JM
110 if (m->state == MBR_ACTIVE || m->state == MBR_RECLAIMING ||
111 m->state == MBR_REMITTED)
04d7b574
JM
112 grp->active_cnt--;
113}
114
b7d42635
JM
115static int tipc_group_rcvbuf_limit(struct tipc_group *grp)
116{
04d7b574 117 int max_active, active_pool, idle_pool;
b7d42635
JM
118 int mcnt = grp->member_cnt + 1;
119
04d7b574
JM
120 /* Limit simultaneous reception from other members */
121 max_active = min(mcnt / 8, 64);
122 max_active = max(max_active, 16);
123 grp->max_active = max_active;
124
125 /* Reserve blocks for active and idle members */
126 active_pool = max_active * ADV_ACTIVE;
127 idle_pool = (mcnt - max_active) * ADV_IDLE;
128
b7d42635 129 /* Scale to bytes, considering worst-case truesize/msgsize ratio */
04d7b574 130 return (active_pool + idle_pool) * FLOWCTL_BLK_SZ * 4;
b7d42635
JM
131}
132
75da2163
JM
133u16 tipc_group_bc_snd_nxt(struct tipc_group *grp)
134{
135 return grp->bc_snd_nxt;
136}
137
38266ca1 138static bool tipc_group_is_receiver(struct tipc_member *m)
b7d42635 139{
0233493a 140 return m && m->state != MBR_JOINING && m->state != MBR_LEAVING;
b7d42635
JM
141}
142
38266ca1 143static bool tipc_group_is_sender(struct tipc_member *m)
75da2163
JM
144{
145 return m && m->state >= MBR_JOINED;
146}
147
ee106d7f
JM
148u32 tipc_group_exclude(struct tipc_group *grp)
149{
150 if (!grp->loopback)
151 return grp->portid;
152 return 0;
153}
154
75da2163
JM
155int tipc_group_size(struct tipc_group *grp)
156{
157 return grp->member_cnt;
158}
159
160struct tipc_group *tipc_group_create(struct net *net, u32 portid,
161 struct tipc_group_req *mreq)
162{
163 struct tipc_group *grp;
164 u32 type = mreq->type;
165
166 grp = kzalloc(sizeof(*grp), GFP_ATOMIC);
167 if (!grp)
168 return NULL;
169 tipc_nlist_init(&grp->dests, tipc_own_addr(net));
38266ca1 170 INIT_LIST_HEAD(&grp->small_win);
04d7b574
JM
171 INIT_LIST_HEAD(&grp->active);
172 INIT_LIST_HEAD(&grp->pending);
75da2163
JM
173 grp->members = RB_ROOT;
174 grp->net = net;
175 grp->portid = portid;
176 grp->domain = addr_domain(net, mreq->scope);
177 grp->type = type;
178 grp->instance = mreq->instance;
179 grp->scope = mreq->scope;
180 grp->loopback = mreq->flags & TIPC_GROUP_LOOPBACK;
ae236fb2 181 grp->events = mreq->flags & TIPC_GROUP_MEMBER_EVTS;
75da2163
JM
182 if (tipc_topsrv_kern_subscr(net, portid, type, 0, ~0, &grp->subid))
183 return grp;
184 kfree(grp);
185 return NULL;
186}
187
188void tipc_group_delete(struct net *net, struct tipc_group *grp)
189{
190 struct rb_root *tree = &grp->members;
191 struct tipc_member *m, *tmp;
192 struct sk_buff_head xmitq;
193
194 __skb_queue_head_init(&xmitq);
195
196 rbtree_postorder_for_each_entry_safe(m, tmp, tree, tree_node) {
197 tipc_group_proto_xmit(grp, m, GRP_LEAVE_MSG, &xmitq);
198 list_del(&m->list);
199 kfree(m);
200 }
201 tipc_node_distr_xmit(net, &xmitq);
202 tipc_nlist_purge(&grp->dests);
203 tipc_topsrv_kern_unsubscr(net, grp->subid);
204 kfree(grp);
205}
206
207struct tipc_member *tipc_group_find_member(struct tipc_group *grp,
208 u32 node, u32 port)
209{
210 struct rb_node *n = grp->members.rb_node;
211 u64 nkey, key = (u64)node << 32 | port;
212 struct tipc_member *m;
213
214 while (n) {
215 m = container_of(n, struct tipc_member, tree_node);
216 nkey = (u64)m->node << 32 | m->port;
217 if (key < nkey)
218 n = n->rb_left;
219 else if (key > nkey)
220 n = n->rb_right;
221 else
222 return m;
223 }
224 return NULL;
225}
226
27bd9ec0
JM
227static struct tipc_member *tipc_group_find_dest(struct tipc_group *grp,
228 u32 node, u32 port)
229{
230 struct tipc_member *m;
231
232 m = tipc_group_find_member(grp, node, port);
38266ca1 233 if (m && tipc_group_is_receiver(m))
27bd9ec0
JM
234 return m;
235 return NULL;
236}
237
75da2163
JM
238static struct tipc_member *tipc_group_find_node(struct tipc_group *grp,
239 u32 node)
240{
241 struct tipc_member *m;
242 struct rb_node *n;
243
244 for (n = rb_first(&grp->members); n; n = rb_next(n)) {
245 m = container_of(n, struct tipc_member, tree_node);
246 if (m->node == node)
247 return m;
248 }
249 return NULL;
250}
251
252static void tipc_group_add_to_tree(struct tipc_group *grp,
253 struct tipc_member *m)
254{
255 u64 nkey, key = (u64)m->node << 32 | m->port;
256 struct rb_node **n, *parent = NULL;
257 struct tipc_member *tmp;
258
259 n = &grp->members.rb_node;
260 while (*n) {
261 tmp = container_of(*n, struct tipc_member, tree_node);
262 parent = *n;
263 tmp = container_of(parent, struct tipc_member, tree_node);
264 nkey = (u64)tmp->node << 32 | tmp->port;
265 if (key < nkey)
266 n = &(*n)->rb_left;
267 else if (key > nkey)
268 n = &(*n)->rb_right;
269 else
270 return;
271 }
272 rb_link_node(&m->tree_node, parent, n);
273 rb_insert_color(&m->tree_node, &grp->members);
274}
275
276static struct tipc_member *tipc_group_create_member(struct tipc_group *grp,
277 u32 node, u32 port,
278 int state)
279{
280 struct tipc_member *m;
281
282 m = kzalloc(sizeof(*m), GFP_ATOMIC);
283 if (!m)
284 return NULL;
285 INIT_LIST_HEAD(&m->list);
38266ca1 286 INIT_LIST_HEAD(&m->small_win);
b87a5ea3 287 __skb_queue_head_init(&m->deferredq);
b7d42635 288 m->group = grp;
75da2163
JM
289 m->node = node;
290 m->port = port;
2f487712 291 m->bc_acked = grp->bc_snd_nxt - 1;
75da2163
JM
292 grp->member_cnt++;
293 tipc_group_add_to_tree(grp, m);
294 tipc_nlist_add(&grp->dests, m->node);
295 m->state = state;
296 return m;
297}
298
299void tipc_group_add_member(struct tipc_group *grp, u32 node, u32 port)
300{
301 tipc_group_create_member(grp, node, port, MBR_DISCOVERED);
302}
303
304static void tipc_group_delete_member(struct tipc_group *grp,
305 struct tipc_member *m)
306{
307 rb_erase(&m->tree_node, &grp->members);
308 grp->member_cnt--;
2f487712
JM
309
310 /* Check if we were waiting for replicast ack from this member */
311 if (grp->bc_ackers && less(m->bc_acked, grp->bc_snd_nxt - 1))
312 grp->bc_ackers--;
313
75da2163 314 list_del_init(&m->list);
38266ca1 315 list_del_init(&m->small_win);
04d7b574 316 tipc_group_decr_active(grp, m);
75da2163
JM
317
318 /* If last member on a node, remove node from dest list */
319 if (!tipc_group_find_node(grp, m->node))
320 tipc_nlist_del(&grp->dests, m->node);
321
322 kfree(m);
323}
324
325struct tipc_nlist *tipc_group_dests(struct tipc_group *grp)
326{
327 return &grp->dests;
328}
329
330void tipc_group_self(struct tipc_group *grp, struct tipc_name_seq *seq,
331 int *scope)
332{
333 seq->type = grp->type;
334 seq->lower = grp->instance;
335 seq->upper = grp->instance;
336 *scope = grp->scope;
337}
338
b7d42635
JM
339void tipc_group_update_member(struct tipc_member *m, int len)
340{
341 struct tipc_group *grp = m->group;
342 struct tipc_member *_m, *tmp;
343
38266ca1 344 if (!tipc_group_is_receiver(m))
b7d42635
JM
345 return;
346
347 m->window -= len;
348
349 if (m->window >= ADV_IDLE)
350 return;
351
38266ca1 352 list_del_init(&m->small_win);
b7d42635 353
38266ca1
JM
354 /* Sort member into small_window members' list */
355 list_for_each_entry_safe(_m, tmp, &grp->small_win, small_win) {
d84d1b3b
JM
356 if (_m->window > m->window)
357 break;
b7d42635 358 }
d84d1b3b 359 list_add_tail(&m->small_win, &_m->small_win);
b7d42635
JM
360}
361
2f487712 362void tipc_group_update_bc_members(struct tipc_group *grp, int len, bool ack)
75da2163 363{
2f487712 364 u16 prev = grp->bc_snd_nxt - 1;
b7d42635
JM
365 struct tipc_member *m;
366 struct rb_node *n;
0a3d805c 367 u16 ackers = 0;
b7d42635
JM
368
369 for (n = rb_first(&grp->members); n; n = rb_next(n)) {
370 m = container_of(n, struct tipc_member, tree_node);
38266ca1 371 if (tipc_group_is_receiver(m)) {
b7d42635 372 tipc_group_update_member(m, len);
2f487712 373 m->bc_acked = prev;
0a3d805c 374 ackers++;
2f487712 375 }
b7d42635 376 }
2f487712
JM
377
378 /* Mark number of acknowledges to expect, if any */
379 if (ack)
0a3d805c 380 grp->bc_ackers = ackers;
75da2163
JM
381 grp->bc_snd_nxt++;
382}
383
27bd9ec0
JM
384bool tipc_group_cong(struct tipc_group *grp, u32 dnode, u32 dport,
385 int len, struct tipc_member **mbr)
b7d42635 386{
27bd9ec0 387 struct sk_buff_head xmitq;
b7d42635 388 struct tipc_member *m;
27bd9ec0
JM
389 int adv, state;
390
391 m = tipc_group_find_dest(grp, dnode, dport);
392 *mbr = m;
393 if (!m)
394 return false;
395 if (m->usr_pending)
396 return true;
397 if (m->window >= len)
398 return false;
399 m->usr_pending = true;
400
401 /* If not fully advertised, do it now to prevent mutual blocking */
402 adv = m->advertised;
403 state = m->state;
404 if (state < MBR_JOINED)
405 return true;
406 if (state == MBR_JOINED && adv == ADV_IDLE)
407 return true;
04d7b574
JM
408 if (state == MBR_ACTIVE && adv == ADV_ACTIVE)
409 return true;
410 if (state == MBR_PENDING && adv == ADV_IDLE)
411 return true;
27bd9ec0
JM
412 skb_queue_head_init(&xmitq);
413 tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, &xmitq);
414 tipc_node_distr_xmit(grp->net, &xmitq);
415 return true;
416}
417
418bool tipc_group_bc_cong(struct tipc_group *grp, int len)
419{
420 struct tipc_member *m = NULL;
b7d42635 421
2f487712
JM
422 /* If prev bcast was replicast, reject until all receivers have acked */
423 if (grp->bc_ackers)
424 return true;
425
38266ca1 426 if (list_empty(&grp->small_win))
b7d42635
JM
427 return false;
428
38266ca1 429 m = list_first_entry(&grp->small_win, struct tipc_member, small_win);
b7d42635
JM
430 if (m->window >= len)
431 return false;
432
27bd9ec0 433 return tipc_group_cong(grp, m->node, m->port, len, &m);
b7d42635
JM
434}
435
b87a5ea3
JM
436/* tipc_group_sort_msg() - sort msg into queue by bcast sequence number
437 */
438static void tipc_group_sort_msg(struct sk_buff *skb, struct sk_buff_head *defq)
439{
440 struct tipc_msg *_hdr, *hdr = buf_msg(skb);
441 u16 bc_seqno = msg_grp_bc_seqno(hdr);
442 struct sk_buff *_skb, *tmp;
443 int mtyp = msg_type(hdr);
444
a3bada70 445 /* Bcast/mcast may be bypassed by ucast or other bcast, - sort it in */
b87a5ea3
JM
446 if (mtyp == TIPC_GRP_BCAST_MSG || mtyp == TIPC_GRP_MCAST_MSG) {
447 skb_queue_walk_safe(defq, _skb, tmp) {
448 _hdr = buf_msg(_skb);
449 if (!less(bc_seqno, msg_grp_bc_seqno(_hdr)))
450 continue;
451 __skb_queue_before(defq, _skb, skb);
452 return;
453 }
454 /* Bcast was not bypassed, - add to tail */
455 }
456 /* Unicasts are never bypassed, - always add to tail */
457 __skb_queue_tail(defq, skb);
458}
459
75da2163
JM
460/* tipc_group_filter_msg() - determine if we should accept arriving message
461 */
462void tipc_group_filter_msg(struct tipc_group *grp, struct sk_buff_head *inputq,
463 struct sk_buff_head *xmitq)
464{
465 struct sk_buff *skb = __skb_dequeue(inputq);
a3bada70 466 bool ack, deliver, update, leave = false;
b87a5ea3 467 struct sk_buff_head *defq;
75da2163
JM
468 struct tipc_member *m;
469 struct tipc_msg *hdr;
470 u32 node, port;
b87a5ea3 471 int mtyp, blks;
75da2163
JM
472
473 if (!skb)
474 return;
475
476 hdr = buf_msg(skb);
75da2163
JM
477 node = msg_orignode(hdr);
478 port = msg_origport(hdr);
479
480 if (!msg_in_group(hdr))
481 goto drop;
482
483 m = tipc_group_find_member(grp, node, port);
38266ca1 484 if (!tipc_group_is_sender(m))
75da2163
JM
485 goto drop;
486
b87a5ea3
JM
487 if (less(msg_grp_bc_seqno(hdr), m->bc_rcv_nxt))
488 goto drop;
5b8dddb6 489
b87a5ea3
JM
490 TIPC_SKB_CB(skb)->orig_member = m->instance;
491 defq = &m->deferredq;
492 tipc_group_sort_msg(skb, defq);
493
494 while ((skb = skb_peek(defq))) {
495 hdr = buf_msg(skb);
496 mtyp = msg_type(hdr);
2e724dca 497 blks = msg_blocks(hdr);
b87a5ea3 498 deliver = true;
2f487712 499 ack = false;
b87a5ea3
JM
500 update = false;
501
502 if (more(msg_grp_bc_seqno(hdr), m->bc_rcv_nxt))
503 break;
504
505 /* Decide what to do with message */
506 switch (mtyp) {
507 case TIPC_GRP_MCAST_MSG:
508 if (msg_nameinst(hdr) != grp->instance) {
509 update = true;
510 deliver = false;
511 }
512 /* Fall thru */
513 case TIPC_GRP_BCAST_MSG:
514 m->bc_rcv_nxt++;
2f487712 515 ack = msg_grp_bc_ack_req(hdr);
b87a5ea3
JM
516 break;
517 case TIPC_GRP_UCAST_MSG:
518 break;
a3bada70
JM
519 case TIPC_GRP_MEMBER_EVT:
520 if (m->state == MBR_LEAVING)
521 leave = true;
522 if (!grp->events)
523 deliver = false;
524 break;
b87a5ea3
JM
525 default:
526 break;
5b8dddb6 527 }
5b8dddb6 528
b87a5ea3
JM
529 /* Execute decisions */
530 __skb_dequeue(defq);
531 if (deliver)
532 __skb_queue_tail(inputq, skb);
533 else
534 kfree_skb(skb);
535
2f487712
JM
536 if (ack)
537 tipc_group_proto_xmit(grp, m, GRP_ACK_MSG, xmitq);
538
a3bada70 539 if (leave) {
a3bada70 540 __skb_queue_purge(defq);
e0e853ac 541 tipc_group_delete_member(grp, m);
a3bada70
JM
542 break;
543 }
b87a5ea3
JM
544 if (!update)
545 continue;
75da2163 546
b87a5ea3
JM
547 tipc_group_update_rcv_win(grp, blks, node, port, xmitq);
548 }
75da2163
JM
549 return;
550drop:
551 kfree_skb(skb);
552}
553
b7d42635
JM
554void tipc_group_update_rcv_win(struct tipc_group *grp, int blks, u32 node,
555 u32 port, struct sk_buff_head *xmitq)
556{
04d7b574
JM
557 struct list_head *active = &grp->active;
558 int max_active = grp->max_active;
559 int reclaim_limit = max_active * 3 / 4;
560 int active_cnt = grp->active_cnt;
f9c935db 561 struct tipc_member *m, *rm, *pm;
b7d42635
JM
562
563 m = tipc_group_find_member(grp, node, port);
564 if (!m)
565 return;
566
567 m->advertised -= blks;
568
569 switch (m->state) {
570 case MBR_JOINED:
4ea5dab5
JM
571 /* First, decide if member can go active */
572 if (active_cnt <= max_active) {
573 m->state = MBR_ACTIVE;
574 list_add_tail(&m->list, active);
575 grp->active_cnt++;
576 tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq);
577 } else {
578 m->state = MBR_PENDING;
579 list_add_tail(&m->list, &grp->pending);
580 }
581
582 if (active_cnt < reclaim_limit)
583 break;
584
585 /* Reclaim from oldest active member, if possible */
586 if (!list_empty(active)) {
04d7b574
JM
587 rm = list_first_entry(active, struct tipc_member, list);
588 rm->state = MBR_RECLAIMING;
8d5dee21 589 list_del_init(&rm->list);
04d7b574 590 tipc_group_proto_xmit(grp, rm, GRP_RECLAIM_MSG, xmitq);
04d7b574
JM
591 break;
592 }
4ea5dab5
JM
593 /* Nobody to reclaim from; - revert oldest pending to JOINED */
594 pm = list_first_entry(&grp->pending, struct tipc_member, list);
595 list_del_init(&pm->list);
596 pm->state = MBR_JOINED;
597 tipc_group_proto_xmit(grp, pm, GRP_ADV_MSG, xmitq);
598 break;
04d7b574
JM
599 case MBR_ACTIVE:
600 if (!list_is_last(&m->list, &grp->active))
601 list_move_tail(&m->list, &grp->active);
602 if (m->advertised > (ADV_ACTIVE * 3 / 4))
603 break;
604 tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq);
605 break;
606 case MBR_REMITTED:
607 if (m->advertised > ADV_IDLE)
608 break;
609 m->state = MBR_JOINED;
8d5dee21 610 grp->active_cnt--;
04d7b574
JM
611 if (m->advertised < ADV_IDLE) {
612 pr_warn_ratelimited("Rcv unexpected msg after REMIT\n");
b7d42635 613 tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq);
04d7b574 614 }
8d5dee21 615
f9c935db
JM
616 if (list_empty(&grp->pending))
617 return;
618
619 /* Set oldest pending member to active and advertise */
620 pm = list_first_entry(&grp->pending, struct tipc_member, list);
621 pm->state = MBR_ACTIVE;
622 list_move_tail(&pm->list, &grp->active);
623 grp->active_cnt++;
624 tipc_group_proto_xmit(grp, pm, GRP_ADV_MSG, xmitq);
b7d42635 625 break;
04d7b574 626 case MBR_RECLAIMING:
b7d42635
JM
627 case MBR_DISCOVERED:
628 case MBR_JOINING:
629 case MBR_LEAVING:
630 default:
631 break;
632 }
633}
634
75da2163
JM
635static void tipc_group_proto_xmit(struct tipc_group *grp, struct tipc_member *m,
636 int mtyp, struct sk_buff_head *xmitq)
637{
638 struct tipc_msg *hdr;
639 struct sk_buff *skb;
b7d42635 640 int adv = 0;
75da2163
JM
641
642 skb = tipc_msg_create(GROUP_PROTOCOL, mtyp, INT_H_SIZE, 0,
643 m->node, tipc_own_addr(grp->net),
644 m->port, grp->portid, 0);
645 if (!skb)
646 return;
647
04d7b574 648 if (m->state == MBR_ACTIVE)
b7d42635 649 adv = ADV_ACTIVE - m->advertised;
04d7b574
JM
650 else if (m->state == MBR_JOINED || m->state == MBR_PENDING)
651 adv = ADV_IDLE - m->advertised;
b7d42635 652
75da2163 653 hdr = buf_msg(skb);
b7d42635
JM
654
655 if (mtyp == GRP_JOIN_MSG) {
75da2163 656 msg_set_grp_bc_syncpt(hdr, grp->bc_snd_nxt);
b7d42635
JM
657 msg_set_adv_win(hdr, adv);
658 m->advertised += adv;
a3bada70
JM
659 } else if (mtyp == GRP_LEAVE_MSG) {
660 msg_set_grp_bc_syncpt(hdr, grp->bc_snd_nxt);
b7d42635
JM
661 } else if (mtyp == GRP_ADV_MSG) {
662 msg_set_adv_win(hdr, adv);
663 m->advertised += adv;
2f487712
JM
664 } else if (mtyp == GRP_ACK_MSG) {
665 msg_set_grp_bc_acked(hdr, m->bc_rcv_nxt);
04d7b574
JM
666 } else if (mtyp == GRP_REMIT_MSG) {
667 msg_set_grp_remitted(hdr, m->window);
b7d42635 668 }
23483399 669 msg_set_dest_droppable(hdr, true);
75da2163
JM
670 __skb_queue_tail(xmitq, skb);
671}
672
b7d42635
JM
673void tipc_group_proto_rcv(struct tipc_group *grp, bool *usr_wakeup,
674 struct tipc_msg *hdr, struct sk_buff_head *inputq,
75da2163
JM
675 struct sk_buff_head *xmitq)
676{
677 u32 node = msg_orignode(hdr);
678 u32 port = msg_origport(hdr);
04d7b574 679 struct tipc_member *m, *pm;
a3bada70 680 struct tipc_msg *ehdr;
04d7b574 681 u16 remitted, in_flight;
75da2163
JM
682
683 if (!grp)
684 return;
685
686 m = tipc_group_find_member(grp, node, port);
687
688 switch (msg_type(hdr)) {
689 case GRP_JOIN_MSG:
690 if (!m)
691 m = tipc_group_create_member(grp, node, port,
0233493a 692 MBR_JOINING);
75da2163
JM
693 if (!m)
694 return;
a3bada70
JM
695 m->bc_syncpt = msg_grp_bc_syncpt(hdr);
696 m->bc_rcv_nxt = m->bc_syncpt;
b7d42635 697 m->window += msg_adv_win(hdr);
75da2163
JM
698
699 /* Wait until PUBLISH event is received */
ae236fb2 700 if (m->state == MBR_DISCOVERED) {
75da2163 701 m->state = MBR_JOINING;
ae236fb2 702 } else if (m->state == MBR_PUBLISHED) {
75da2163 703 m->state = MBR_JOINED;
b7d42635
JM
704 *usr_wakeup = true;
705 m->usr_pending = false;
706 tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq);
a3bada70
JM
707 ehdr = buf_msg(m->event_msg);
708 msg_set_grp_bc_seqno(ehdr, m->bc_syncpt);
ae236fb2
JM
709 __skb_queue_tail(inputq, m->event_msg);
710 }
38266ca1 711 list_del_init(&m->small_win);
bb25c385 712 tipc_group_update_member(m, 0);
75da2163
JM
713 return;
714 case GRP_LEAVE_MSG:
715 if (!m)
716 return;
a3bada70 717 m->bc_syncpt = msg_grp_bc_syncpt(hdr);
3f42f5fe 718 list_del_init(&m->list);
38266ca1 719 list_del_init(&m->small_win);
3f42f5fe 720 *usr_wakeup = true;
75da2163
JM
721
722 /* Wait until WITHDRAW event is received */
723 if (m->state != MBR_LEAVING) {
04d7b574 724 tipc_group_decr_active(grp, m);
75da2163
JM
725 m->state = MBR_LEAVING;
726 return;
727 }
728 /* Otherwise deliver already received WITHDRAW event */
a3bada70
JM
729 ehdr = buf_msg(m->event_msg);
730 msg_set_grp_bc_seqno(ehdr, m->bc_syncpt);
ae236fb2 731 __skb_queue_tail(inputq, m->event_msg);
b7d42635
JM
732 return;
733 case GRP_ADV_MSG:
734 if (!m)
735 return;
736 m->window += msg_adv_win(hdr);
737 *usr_wakeup = m->usr_pending;
738 m->usr_pending = false;
38266ca1 739 list_del_init(&m->small_win);
75da2163 740 return;
2f487712
JM
741 case GRP_ACK_MSG:
742 if (!m)
743 return;
744 m->bc_acked = msg_grp_bc_acked(hdr);
745 if (--grp->bc_ackers)
746 break;
747 *usr_wakeup = true;
748 m->usr_pending = false;
749 return;
04d7b574
JM
750 case GRP_RECLAIM_MSG:
751 if (!m)
752 return;
753 *usr_wakeup = m->usr_pending;
754 m->usr_pending = false;
755 tipc_group_proto_xmit(grp, m, GRP_REMIT_MSG, xmitq);
756 m->window = ADV_IDLE;
757 return;
758 case GRP_REMIT_MSG:
759 if (!m || m->state != MBR_RECLAIMING)
760 return;
761
04d7b574
JM
762 remitted = msg_grp_remitted(hdr);
763
764 /* Messages preceding the REMIT still in receive queue */
765 if (m->advertised > remitted) {
766 m->state = MBR_REMITTED;
767 in_flight = m->advertised - remitted;
f9c935db
JM
768 m->advertised = ADV_IDLE + in_flight;
769 return;
04d7b574 770 }
8d5dee21 771 /* This should never happen */
04d7b574 772 if (m->advertised < remitted)
8d5dee21 773 pr_warn_ratelimited("Unexpected REMIT msg\n");
04d7b574 774
8d5dee21
JM
775 /* All messages preceding the REMIT have been read */
776 m->state = MBR_JOINED;
f9c935db 777 grp->active_cnt--;
8d5dee21 778 m->advertised = ADV_IDLE;
04d7b574
JM
779
780 /* Set oldest pending member to active and advertise */
781 if (list_empty(&grp->pending))
782 return;
783 pm = list_first_entry(&grp->pending, struct tipc_member, list);
784 pm->state = MBR_ACTIVE;
785 list_move_tail(&pm->list, &grp->active);
786 grp->active_cnt++;
787 if (pm->advertised <= (ADV_ACTIVE * 3 / 4))
788 tipc_group_proto_xmit(grp, pm, GRP_ADV_MSG, xmitq);
789 return;
75da2163
JM
790 default:
791 pr_warn("Received unknown GROUP_PROTO message\n");
792 }
793}
794
b7d42635
JM
795/* tipc_group_member_evt() - receive and handle a member up/down event
796 */
75da2163 797void tipc_group_member_evt(struct tipc_group *grp,
b7d42635
JM
798 bool *usr_wakeup,
799 int *sk_rcvbuf,
75da2163 800 struct sk_buff *skb,
ae236fb2 801 struct sk_buff_head *inputq,
75da2163
JM
802 struct sk_buff_head *xmitq)
803{
804 struct tipc_msg *hdr = buf_msg(skb);
805 struct tipc_event *evt = (void *)msg_data(hdr);
ae236fb2 806 u32 instance = evt->found_lower;
75da2163
JM
807 u32 node = evt->port.node;
808 u32 port = evt->port.ref;
ae236fb2 809 int event = evt->event;
75da2163
JM
810 struct tipc_member *m;
811 struct net *net;
a3bada70 812 bool node_up;
75da2163
JM
813 u32 self;
814
815 if (!grp)
816 goto drop;
817
818 net = grp->net;
819 self = tipc_own_addr(net);
820 if (!grp->loopback && node == self && port == grp->portid)
821 goto drop;
822
ae236fb2
JM
823 /* Convert message before delivery to user */
824 msg_set_hdr_sz(hdr, GROUP_H_SIZE);
825 msg_set_user(hdr, TIPC_CRITICAL_IMPORTANCE);
826 msg_set_type(hdr, TIPC_GRP_MEMBER_EVT);
827 msg_set_origport(hdr, port);
828 msg_set_orignode(hdr, node);
829 msg_set_nametype(hdr, grp->type);
830 msg_set_grp_evt(hdr, event);
831
75da2163
JM
832 m = tipc_group_find_member(grp, node, port);
833
ae236fb2 834 if (event == TIPC_PUBLISHED) {
75da2163
JM
835 if (!m)
836 m = tipc_group_create_member(grp, node, port,
837 MBR_DISCOVERED);
838 if (!m)
839 goto drop;
840
ae236fb2
JM
841 /* Hold back event if JOIN message not yet received */
842 if (m->state == MBR_DISCOVERED) {
843 m->event_msg = skb;
75da2163 844 m->state = MBR_PUBLISHED;
ae236fb2 845 } else {
a3bada70 846 msg_set_grp_bc_seqno(hdr, m->bc_syncpt);
ae236fb2 847 __skb_queue_tail(inputq, skb);
75da2163 848 m->state = MBR_JOINED;
b7d42635
JM
849 *usr_wakeup = true;
850 m->usr_pending = false;
ae236fb2
JM
851 }
852 m->instance = instance;
853 TIPC_SKB_CB(skb)->orig_member = m->instance;
75da2163 854 tipc_group_proto_xmit(grp, m, GRP_JOIN_MSG, xmitq);
d84d1b3b 855 tipc_group_update_member(m, 0);
ae236fb2 856 } else if (event == TIPC_WITHDRAWN) {
75da2163
JM
857 if (!m)
858 goto drop;
859
ae236fb2
JM
860 TIPC_SKB_CB(skb)->orig_member = m->instance;
861
2f487712 862 *usr_wakeup = true;
b7d42635 863 m->usr_pending = false;
a3bada70 864 node_up = tipc_node_is_up(net, node);
3a33a19b
JM
865 m->event_msg = NULL;
866
867 if (node_up) {
868 /* Hold back event if a LEAVE msg should be expected */
869 if (m->state != MBR_LEAVING) {
870 m->event_msg = skb;
871 tipc_group_decr_active(grp, m);
872 m->state = MBR_LEAVING;
873 } else {
a3bada70 874 msg_set_grp_bc_seqno(hdr, m->bc_syncpt);
3a33a19b
JM
875 __skb_queue_tail(inputq, skb);
876 }
877 } else {
878 if (m->state != MBR_LEAVING) {
879 tipc_group_decr_active(grp, m);
880 m->state = MBR_LEAVING;
a3bada70 881 msg_set_grp_bc_seqno(hdr, m->bc_rcv_nxt);
3a33a19b
JM
882 } else {
883 msg_set_grp_bc_seqno(hdr, m->bc_syncpt);
884 }
ae236fb2 885 __skb_queue_tail(inputq, skb);
ae236fb2 886 }
3f42f5fe 887 list_del_init(&m->list);
38266ca1 888 list_del_init(&m->small_win);
75da2163 889 }
b7d42635 890 *sk_rcvbuf = tipc_group_rcvbuf_limit(grp);
ae236fb2 891 return;
75da2163
JM
892drop:
893 kfree_skb(skb);
894}
This page took 0.235271 seconds and 4 git commands to generate.