]>
git.ipfire.org Git - thirdparty/kernel/stable.git/blob - net/tipc/group.c
2 * net/tipc/group.c: TIPC group messaging code
4 * Copyright (c) 2017, Ericsson AB
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
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.
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.
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.
44 #include "name_table.h"
47 #define ADV_UNIT (((MAX_MSG_SIZE + MAX_H_SIZE) / FLOWCTL_BLK_SZ) + 1)
48 #define ADV_IDLE ADV_UNIT
60 struct rb_node tree_node
;
61 struct list_head list
;
62 struct sk_buff
*event_msg
;
71 struct rb_root members
;
72 struct tipc_nlist dests
;
86 static void tipc_group_proto_xmit(struct tipc_group
*grp
, struct tipc_member
*m
,
87 int mtyp
, struct sk_buff_head
*xmitq
);
89 u16
tipc_group_bc_snd_nxt(struct tipc_group
*grp
)
91 return grp
->bc_snd_nxt
;
94 static bool tipc_group_is_receiver(struct tipc_member
*m
)
96 return m
&& m
->state
>= MBR_JOINED
;
99 int tipc_group_size(struct tipc_group
*grp
)
101 return grp
->member_cnt
;
104 struct tipc_group
*tipc_group_create(struct net
*net
, u32 portid
,
105 struct tipc_group_req
*mreq
)
107 struct tipc_group
*grp
;
108 u32 type
= mreq
->type
;
110 grp
= kzalloc(sizeof(*grp
), GFP_ATOMIC
);
113 tipc_nlist_init(&grp
->dests
, tipc_own_addr(net
));
114 grp
->members
= RB_ROOT
;
116 grp
->portid
= portid
;
117 grp
->domain
= addr_domain(net
, mreq
->scope
);
119 grp
->instance
= mreq
->instance
;
120 grp
->scope
= mreq
->scope
;
121 grp
->loopback
= mreq
->flags
& TIPC_GROUP_LOOPBACK
;
122 grp
->events
= mreq
->flags
& TIPC_GROUP_MEMBER_EVTS
;
123 if (tipc_topsrv_kern_subscr(net
, portid
, type
, 0, ~0, &grp
->subid
))
129 void tipc_group_delete(struct net
*net
, struct tipc_group
*grp
)
131 struct rb_root
*tree
= &grp
->members
;
132 struct tipc_member
*m
, *tmp
;
133 struct sk_buff_head xmitq
;
135 __skb_queue_head_init(&xmitq
);
137 rbtree_postorder_for_each_entry_safe(m
, tmp
, tree
, tree_node
) {
138 tipc_group_proto_xmit(grp
, m
, GRP_LEAVE_MSG
, &xmitq
);
142 tipc_node_distr_xmit(net
, &xmitq
);
143 tipc_nlist_purge(&grp
->dests
);
144 tipc_topsrv_kern_unsubscr(net
, grp
->subid
);
148 struct tipc_member
*tipc_group_find_member(struct tipc_group
*grp
,
151 struct rb_node
*n
= grp
->members
.rb_node
;
152 u64 nkey
, key
= (u64
)node
<< 32 | port
;
153 struct tipc_member
*m
;
156 m
= container_of(n
, struct tipc_member
, tree_node
);
157 nkey
= (u64
)m
->node
<< 32 | m
->port
;
168 static struct tipc_member
*tipc_group_find_node(struct tipc_group
*grp
,
171 struct tipc_member
*m
;
174 for (n
= rb_first(&grp
->members
); n
; n
= rb_next(n
)) {
175 m
= container_of(n
, struct tipc_member
, tree_node
);
182 static void tipc_group_add_to_tree(struct tipc_group
*grp
,
183 struct tipc_member
*m
)
185 u64 nkey
, key
= (u64
)m
->node
<< 32 | m
->port
;
186 struct rb_node
**n
, *parent
= NULL
;
187 struct tipc_member
*tmp
;
189 n
= &grp
->members
.rb_node
;
191 tmp
= container_of(*n
, struct tipc_member
, tree_node
);
193 tmp
= container_of(parent
, struct tipc_member
, tree_node
);
194 nkey
= (u64
)tmp
->node
<< 32 | tmp
->port
;
202 rb_link_node(&m
->tree_node
, parent
, n
);
203 rb_insert_color(&m
->tree_node
, &grp
->members
);
206 static struct tipc_member
*tipc_group_create_member(struct tipc_group
*grp
,
210 struct tipc_member
*m
;
212 m
= kzalloc(sizeof(*m
), GFP_ATOMIC
);
215 INIT_LIST_HEAD(&m
->list
);
219 tipc_group_add_to_tree(grp
, m
);
220 tipc_nlist_add(&grp
->dests
, m
->node
);
225 void tipc_group_add_member(struct tipc_group
*grp
, u32 node
, u32 port
)
227 tipc_group_create_member(grp
, node
, port
, MBR_DISCOVERED
);
230 static void tipc_group_delete_member(struct tipc_group
*grp
,
231 struct tipc_member
*m
)
233 rb_erase(&m
->tree_node
, &grp
->members
);
235 list_del_init(&m
->list
);
237 /* If last member on a node, remove node from dest list */
238 if (!tipc_group_find_node(grp
, m
->node
))
239 tipc_nlist_del(&grp
->dests
, m
->node
);
244 struct tipc_nlist
*tipc_group_dests(struct tipc_group
*grp
)
249 void tipc_group_self(struct tipc_group
*grp
, struct tipc_name_seq
*seq
,
252 seq
->type
= grp
->type
;
253 seq
->lower
= grp
->instance
;
254 seq
->upper
= grp
->instance
;
258 void tipc_group_update_bc_members(struct tipc_group
*grp
)
263 /* tipc_group_filter_msg() - determine if we should accept arriving message
265 void tipc_group_filter_msg(struct tipc_group
*grp
, struct sk_buff_head
*inputq
,
266 struct sk_buff_head
*xmitq
)
268 struct sk_buff
*skb
= __skb_dequeue(inputq
);
269 struct tipc_member
*m
;
270 struct tipc_msg
*hdr
;
278 mtyp
= msg_type(hdr
);
279 node
= msg_orignode(hdr
);
280 port
= msg_origport(hdr
);
282 if (!msg_in_group(hdr
))
285 if (mtyp
== TIPC_GRP_MEMBER_EVT
) {
288 __skb_queue_tail(inputq
, skb
);
292 m
= tipc_group_find_member(grp
, node
, port
);
293 if (!tipc_group_is_receiver(m
))
296 TIPC_SKB_CB(skb
)->orig_member
= m
->instance
;
297 __skb_queue_tail(inputq
, skb
);
299 m
->bc_rcv_nxt
= msg_grp_bc_seqno(hdr
) + 1;
305 static void tipc_group_proto_xmit(struct tipc_group
*grp
, struct tipc_member
*m
,
306 int mtyp
, struct sk_buff_head
*xmitq
)
308 struct tipc_msg
*hdr
;
311 skb
= tipc_msg_create(GROUP_PROTOCOL
, mtyp
, INT_H_SIZE
, 0,
312 m
->node
, tipc_own_addr(grp
->net
),
313 m
->port
, grp
->portid
, 0);
318 if (mtyp
== GRP_JOIN_MSG
)
319 msg_set_grp_bc_syncpt(hdr
, grp
->bc_snd_nxt
);
320 __skb_queue_tail(xmitq
, skb
);
323 void tipc_group_proto_rcv(struct tipc_group
*grp
, struct tipc_msg
*hdr
,
324 struct sk_buff_head
*inputq
,
325 struct sk_buff_head
*xmitq
)
327 u32 node
= msg_orignode(hdr
);
328 u32 port
= msg_origport(hdr
);
329 struct tipc_member
*m
;
334 m
= tipc_group_find_member(grp
, node
, port
);
336 switch (msg_type(hdr
)) {
339 m
= tipc_group_create_member(grp
, node
, port
,
343 m
->bc_rcv_nxt
= msg_grp_bc_syncpt(hdr
);
345 /* Wait until PUBLISH event is received */
346 if (m
->state
== MBR_DISCOVERED
) {
347 m
->state
= MBR_JOINING
;
348 } else if (m
->state
== MBR_PUBLISHED
) {
349 m
->state
= MBR_JOINED
;
350 __skb_queue_tail(inputq
, m
->event_msg
);
357 /* Wait until WITHDRAW event is received */
358 if (m
->state
!= MBR_LEAVING
) {
359 m
->state
= MBR_LEAVING
;
362 /* Otherwise deliver already received WITHDRAW event */
363 __skb_queue_tail(inputq
, m
->event_msg
);
364 tipc_group_delete_member(grp
, m
);
367 pr_warn("Received unknown GROUP_PROTO message\n");
371 void tipc_group_member_evt(struct tipc_group
*grp
,
373 struct sk_buff_head
*inputq
,
374 struct sk_buff_head
*xmitq
)
376 struct tipc_msg
*hdr
= buf_msg(skb
);
377 struct tipc_event
*evt
= (void *)msg_data(hdr
);
378 u32 instance
= evt
->found_lower
;
379 u32 node
= evt
->port
.node
;
380 u32 port
= evt
->port
.ref
;
381 int event
= evt
->event
;
382 struct tipc_member
*m
;
390 self
= tipc_own_addr(net
);
391 if (!grp
->loopback
&& node
== self
&& port
== grp
->portid
)
394 /* Convert message before delivery to user */
395 msg_set_hdr_sz(hdr
, GROUP_H_SIZE
);
396 msg_set_user(hdr
, TIPC_CRITICAL_IMPORTANCE
);
397 msg_set_type(hdr
, TIPC_GRP_MEMBER_EVT
);
398 msg_set_origport(hdr
, port
);
399 msg_set_orignode(hdr
, node
);
400 msg_set_nametype(hdr
, grp
->type
);
401 msg_set_grp_evt(hdr
, event
);
403 m
= tipc_group_find_member(grp
, node
, port
);
405 if (event
== TIPC_PUBLISHED
) {
407 m
= tipc_group_create_member(grp
, node
, port
,
412 /* Hold back event if JOIN message not yet received */
413 if (m
->state
== MBR_DISCOVERED
) {
415 m
->state
= MBR_PUBLISHED
;
417 __skb_queue_tail(inputq
, skb
);
418 m
->state
= MBR_JOINED
;
420 m
->instance
= instance
;
421 TIPC_SKB_CB(skb
)->orig_member
= m
->instance
;
422 tipc_group_proto_xmit(grp
, m
, GRP_JOIN_MSG
, xmitq
);
423 } else if (event
== TIPC_WITHDRAWN
) {
427 TIPC_SKB_CB(skb
)->orig_member
= m
->instance
;
429 /* Hold back event if more messages might be expected */
430 if (m
->state
!= MBR_LEAVING
&& tipc_node_is_up(net
, node
)) {
432 m
->state
= MBR_LEAVING
;
434 __skb_queue_tail(inputq
, skb
);
435 tipc_group_delete_member(grp
, m
);