mirror of https://gitee.com/openkylin/linux.git
Merge branch 'tipc-comm-groups'
Jon Maloy says: ==================== tipc: Introduce Communcation Group feature With this commit series we introduce a 'Group Communication' feature in order to resolve the datagram and multicast flow control problem. This new feature makes it possible for a user to instantiate multiple private virtual brokerless message buses by just creating and joining member sockets. The main features are as follows: --------------------------------- - Sockets can join a group via a new setsockopt() call TIPC_GROUP_JOIN. If it is the first socket of the group this implies creation of the group. This call takes four parameters: 'type' serves as group identifier, 'instance' serves as member identifier, and 'scope' indicates the visibility of the group (node/cluster/zone). Finally, 'flags' indicates different options for the socket joining the group. For the time being, there are only two such flags: 1) 'LOOPBACK' indicates if the creator of the socket wants to receive a copy of broadcast or multicast messages it sends to the group, 2) EVENTS indicates if it wants to receive membership (JOINED/LEFT) events for the other members of the group. - Groups are closed, i.e., sockets which have not joined a group will not be able to send messages to or receive messages from members of the group, and vice versa. A socket can only be member of one group at a time. - There are four transmission modes. 1: Unicast. The sender transmits a message using the port identity (node:port tuple) of the receiving socket. 2: Anycast. The sender transmits a message using a port name (type: instance:scope) of one of the receiving sockets. If more than one member socket matches the given address a destination is selected according to a round-robin algorithm, but also considering the destination load (advertised window size) as an additional criteria. 3: Multicast. The sender transmits a message using a port name (type:instance:scope) of one or more of the receiving sockets. All sockets in the group matching the given address will receive a copy of the message. 4: Broadcast. The sender transmits a message using the primtive send(). All members of the group, irrespective of their member identity (instance) number receive a copy of the message. - TIPC broadcast is used for carrying messages in mode 3 or 4 when this is deemed more efficient, i.e., depending on number of actual destinations. - All transmission modes are flow controlled, so that messages never are dropped or rejected, just like we are used to from connection oriented communication. A special algorithm guarantees that this is true even for multipoint-to-point communication, i.e., at occasions where many source sockets may decide to send simultaneously towards the same destination socket. - Sequence order is always guaranteed, even between the different transmission modes. - Member join/leave events are received in all other member sockets in guaranteed order. I.e., a 'JOINED' (an empty message with the OOB bit set) will always be received before the first data message from a new member, and a 'LEAVE' (like 'JOINED', but with EOR bit set) will always arrive after the last data message from a leaving member. ----- v2: Reordered variable declarations in descending length order, as per feedback from David Miller. This was done as far as permitted by the the initialization order. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
a00344bd1b
|
@ -231,6 +231,21 @@ struct sockaddr_tipc {
|
|||
#define TIPC_SOCK_RECVQ_DEPTH 132 /* Default: none (read only) */
|
||||
#define TIPC_MCAST_BROADCAST 133 /* Default: TIPC selects. No arg */
|
||||
#define TIPC_MCAST_REPLICAST 134 /* Default: TIPC selects. No arg */
|
||||
#define TIPC_GROUP_JOIN 135 /* Takes struct tipc_group_req* */
|
||||
#define TIPC_GROUP_LEAVE 136 /* No argument */
|
||||
|
||||
/*
|
||||
* Flag values
|
||||
*/
|
||||
#define TIPC_GROUP_LOOPBACK 0x1 /* Receive copy of sent msg when match */
|
||||
#define TIPC_GROUP_MEMBER_EVTS 0x2 /* Receive membership events in socket */
|
||||
|
||||
struct tipc_group_req {
|
||||
__u32 type; /* group id */
|
||||
__u32 instance; /* member id */
|
||||
__u32 scope; /* zone/cluster/node */
|
||||
__u32 flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* Maximum sizes of TIPC bearer-related names (including terminating NULL)
|
||||
|
|
|
@ -8,7 +8,7 @@ tipc-y += addr.o bcast.o bearer.o \
|
|||
core.o link.o discover.o msg.o \
|
||||
name_distr.o subscr.o monitor.o name_table.o net.o \
|
||||
netlink.o netlink_compat.o node.o socket.o eth_media.o \
|
||||
server.o socket.o
|
||||
server.o socket.o group.o
|
||||
|
||||
tipc-$(CONFIG_TIPC_MEDIA_UDP) += udp_media.o
|
||||
tipc-$(CONFIG_TIPC_MEDIA_IB) += ib_media.o
|
||||
|
|
|
@ -258,20 +258,20 @@ static int tipc_bcast_xmit(struct net *net, struct sk_buff_head *pkts,
|
|||
static int tipc_rcast_xmit(struct net *net, struct sk_buff_head *pkts,
|
||||
struct tipc_nlist *dests, u16 *cong_link_cnt)
|
||||
{
|
||||
struct tipc_dest *dst, *tmp;
|
||||
struct sk_buff_head _pkts;
|
||||
struct u32_item *n, *tmp;
|
||||
u32 dst, selector;
|
||||
u32 dnode, selector;
|
||||
|
||||
selector = msg_link_selector(buf_msg(skb_peek(pkts)));
|
||||
skb_queue_head_init(&_pkts);
|
||||
|
||||
list_for_each_entry_safe(n, tmp, &dests->list, list) {
|
||||
dst = n->value;
|
||||
if (!tipc_msg_pskb_copy(dst, pkts, &_pkts))
|
||||
list_for_each_entry_safe(dst, tmp, &dests->list, list) {
|
||||
dnode = dst->node;
|
||||
if (!tipc_msg_pskb_copy(dnode, pkts, &_pkts))
|
||||
return -ENOMEM;
|
||||
|
||||
/* Any other return value than -ELINKCONG is ignored */
|
||||
if (tipc_node_xmit(net, &_pkts, dst, selector) == -ELINKCONG)
|
||||
if (tipc_node_xmit(net, &_pkts, dnode, selector) == -ELINKCONG)
|
||||
(*cong_link_cnt)++;
|
||||
}
|
||||
return 0;
|
||||
|
@ -554,7 +554,7 @@ void tipc_nlist_add(struct tipc_nlist *nl, u32 node)
|
|||
{
|
||||
if (node == nl->self)
|
||||
nl->local = true;
|
||||
else if (u32_push(&nl->list, node))
|
||||
else if (tipc_dest_push(&nl->list, node, 0))
|
||||
nl->remote++;
|
||||
}
|
||||
|
||||
|
@ -562,13 +562,13 @@ void tipc_nlist_del(struct tipc_nlist *nl, u32 node)
|
|||
{
|
||||
if (node == nl->self)
|
||||
nl->local = false;
|
||||
else if (u32_del(&nl->list, node))
|
||||
else if (tipc_dest_del(&nl->list, node, 0))
|
||||
nl->remote--;
|
||||
}
|
||||
|
||||
void tipc_nlist_purge(struct tipc_nlist *nl)
|
||||
{
|
||||
u32_list_purge(&nl->list);
|
||||
tipc_dest_list_purge(&nl->list);
|
||||
nl->remote = 0;
|
||||
nl->local = 0;
|
||||
}
|
||||
|
|
|
@ -132,6 +132,11 @@ static inline struct list_head *tipc_nodes(struct net *net)
|
|||
return &tipc_net(net)->node_list;
|
||||
}
|
||||
|
||||
static inline struct tipc_server *tipc_topsrv(struct net *net)
|
||||
{
|
||||
return tipc_net(net)->topsrv;
|
||||
}
|
||||
|
||||
static inline unsigned int tipc_hashfn(u32 addr)
|
||||
{
|
||||
return addr & (NODE_HTABLE_SIZE - 1);
|
||||
|
|
|
@ -0,0 +1,871 @@
|
|||
/*
|
||||
* net/tipc/group.c: TIPC group messaging code
|
||||
*
|
||||
* Copyright (c) 2017, Ericsson AB
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#include "addr.h"
|
||||
#include "group.h"
|
||||
#include "bcast.h"
|
||||
#include "server.h"
|
||||
#include "msg.h"
|
||||
#include "socket.h"
|
||||
#include "node.h"
|
||||
#include "name_table.h"
|
||||
#include "subscr.h"
|
||||
|
||||
#define ADV_UNIT (((MAX_MSG_SIZE + MAX_H_SIZE) / FLOWCTL_BLK_SZ) + 1)
|
||||
#define ADV_IDLE ADV_UNIT
|
||||
#define ADV_ACTIVE (ADV_UNIT * 12)
|
||||
|
||||
enum mbr_state {
|
||||
MBR_QUARANTINED,
|
||||
MBR_DISCOVERED,
|
||||
MBR_JOINING,
|
||||
MBR_PUBLISHED,
|
||||
MBR_JOINED,
|
||||
MBR_PENDING,
|
||||
MBR_ACTIVE,
|
||||
MBR_RECLAIMING,
|
||||
MBR_REMITTED,
|
||||
MBR_LEAVING
|
||||
};
|
||||
|
||||
struct tipc_member {
|
||||
struct rb_node tree_node;
|
||||
struct list_head list;
|
||||
struct list_head congested;
|
||||
struct sk_buff *event_msg;
|
||||
struct sk_buff_head deferredq;
|
||||
struct tipc_group *group;
|
||||
u32 node;
|
||||
u32 port;
|
||||
u32 instance;
|
||||
enum mbr_state state;
|
||||
u16 advertised;
|
||||
u16 window;
|
||||
u16 bc_rcv_nxt;
|
||||
u16 bc_syncpt;
|
||||
u16 bc_acked;
|
||||
bool usr_pending;
|
||||
};
|
||||
|
||||
struct tipc_group {
|
||||
struct rb_root members;
|
||||
struct list_head congested;
|
||||
struct list_head pending;
|
||||
struct list_head active;
|
||||
struct list_head reclaiming;
|
||||
struct tipc_nlist dests;
|
||||
struct net *net;
|
||||
int subid;
|
||||
u32 type;
|
||||
u32 instance;
|
||||
u32 domain;
|
||||
u32 scope;
|
||||
u32 portid;
|
||||
u16 member_cnt;
|
||||
u16 active_cnt;
|
||||
u16 max_active;
|
||||
u16 bc_snd_nxt;
|
||||
u16 bc_ackers;
|
||||
bool loopback;
|
||||
bool events;
|
||||
};
|
||||
|
||||
static void tipc_group_proto_xmit(struct tipc_group *grp, struct tipc_member *m,
|
||||
int mtyp, struct sk_buff_head *xmitq);
|
||||
|
||||
static void tipc_group_decr_active(struct tipc_group *grp,
|
||||
struct tipc_member *m)
|
||||
{
|
||||
if (m->state == MBR_ACTIVE || m->state == MBR_RECLAIMING)
|
||||
grp->active_cnt--;
|
||||
}
|
||||
|
||||
static int tipc_group_rcvbuf_limit(struct tipc_group *grp)
|
||||
{
|
||||
int max_active, active_pool, idle_pool;
|
||||
int mcnt = grp->member_cnt + 1;
|
||||
|
||||
/* Limit simultaneous reception from other members */
|
||||
max_active = min(mcnt / 8, 64);
|
||||
max_active = max(max_active, 16);
|
||||
grp->max_active = max_active;
|
||||
|
||||
/* Reserve blocks for active and idle members */
|
||||
active_pool = max_active * ADV_ACTIVE;
|
||||
idle_pool = (mcnt - max_active) * ADV_IDLE;
|
||||
|
||||
/* Scale to bytes, considering worst-case truesize/msgsize ratio */
|
||||
return (active_pool + idle_pool) * FLOWCTL_BLK_SZ * 4;
|
||||
}
|
||||
|
||||
u16 tipc_group_bc_snd_nxt(struct tipc_group *grp)
|
||||
{
|
||||
return grp->bc_snd_nxt;
|
||||
}
|
||||
|
||||
static bool tipc_group_is_enabled(struct tipc_member *m)
|
||||
{
|
||||
return m->state != MBR_QUARANTINED && m->state != MBR_LEAVING;
|
||||
}
|
||||
|
||||
static bool tipc_group_is_receiver(struct tipc_member *m)
|
||||
{
|
||||
return m && m->state >= MBR_JOINED;
|
||||
}
|
||||
|
||||
u32 tipc_group_exclude(struct tipc_group *grp)
|
||||
{
|
||||
if (!grp->loopback)
|
||||
return grp->portid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tipc_group_size(struct tipc_group *grp)
|
||||
{
|
||||
return grp->member_cnt;
|
||||
}
|
||||
|
||||
struct tipc_group *tipc_group_create(struct net *net, u32 portid,
|
||||
struct tipc_group_req *mreq)
|
||||
{
|
||||
struct tipc_group *grp;
|
||||
u32 type = mreq->type;
|
||||
|
||||
grp = kzalloc(sizeof(*grp), GFP_ATOMIC);
|
||||
if (!grp)
|
||||
return NULL;
|
||||
tipc_nlist_init(&grp->dests, tipc_own_addr(net));
|
||||
INIT_LIST_HEAD(&grp->congested);
|
||||
INIT_LIST_HEAD(&grp->active);
|
||||
INIT_LIST_HEAD(&grp->pending);
|
||||
INIT_LIST_HEAD(&grp->reclaiming);
|
||||
grp->members = RB_ROOT;
|
||||
grp->net = net;
|
||||
grp->portid = portid;
|
||||
grp->domain = addr_domain(net, mreq->scope);
|
||||
grp->type = type;
|
||||
grp->instance = mreq->instance;
|
||||
grp->scope = mreq->scope;
|
||||
grp->loopback = mreq->flags & TIPC_GROUP_LOOPBACK;
|
||||
grp->events = mreq->flags & TIPC_GROUP_MEMBER_EVTS;
|
||||
if (tipc_topsrv_kern_subscr(net, portid, type, 0, ~0, &grp->subid))
|
||||
return grp;
|
||||
kfree(grp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void tipc_group_delete(struct net *net, struct tipc_group *grp)
|
||||
{
|
||||
struct rb_root *tree = &grp->members;
|
||||
struct tipc_member *m, *tmp;
|
||||
struct sk_buff_head xmitq;
|
||||
|
||||
__skb_queue_head_init(&xmitq);
|
||||
|
||||
rbtree_postorder_for_each_entry_safe(m, tmp, tree, tree_node) {
|
||||
tipc_group_proto_xmit(grp, m, GRP_LEAVE_MSG, &xmitq);
|
||||
list_del(&m->list);
|
||||
kfree(m);
|
||||
}
|
||||
tipc_node_distr_xmit(net, &xmitq);
|
||||
tipc_nlist_purge(&grp->dests);
|
||||
tipc_topsrv_kern_unsubscr(net, grp->subid);
|
||||
kfree(grp);
|
||||
}
|
||||
|
||||
struct tipc_member *tipc_group_find_member(struct tipc_group *grp,
|
||||
u32 node, u32 port)
|
||||
{
|
||||
struct rb_node *n = grp->members.rb_node;
|
||||
u64 nkey, key = (u64)node << 32 | port;
|
||||
struct tipc_member *m;
|
||||
|
||||
while (n) {
|
||||
m = container_of(n, struct tipc_member, tree_node);
|
||||
nkey = (u64)m->node << 32 | m->port;
|
||||
if (key < nkey)
|
||||
n = n->rb_left;
|
||||
else if (key > nkey)
|
||||
n = n->rb_right;
|
||||
else
|
||||
return m;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct tipc_member *tipc_group_find_dest(struct tipc_group *grp,
|
||||
u32 node, u32 port)
|
||||
{
|
||||
struct tipc_member *m;
|
||||
|
||||
m = tipc_group_find_member(grp, node, port);
|
||||
if (m && tipc_group_is_enabled(m))
|
||||
return m;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct tipc_member *tipc_group_find_node(struct tipc_group *grp,
|
||||
u32 node)
|
||||
{
|
||||
struct tipc_member *m;
|
||||
struct rb_node *n;
|
||||
|
||||
for (n = rb_first(&grp->members); n; n = rb_next(n)) {
|
||||
m = container_of(n, struct tipc_member, tree_node);
|
||||
if (m->node == node)
|
||||
return m;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void tipc_group_add_to_tree(struct tipc_group *grp,
|
||||
struct tipc_member *m)
|
||||
{
|
||||
u64 nkey, key = (u64)m->node << 32 | m->port;
|
||||
struct rb_node **n, *parent = NULL;
|
||||
struct tipc_member *tmp;
|
||||
|
||||
n = &grp->members.rb_node;
|
||||
while (*n) {
|
||||
tmp = container_of(*n, struct tipc_member, tree_node);
|
||||
parent = *n;
|
||||
tmp = container_of(parent, struct tipc_member, tree_node);
|
||||
nkey = (u64)tmp->node << 32 | tmp->port;
|
||||
if (key < nkey)
|
||||
n = &(*n)->rb_left;
|
||||
else if (key > nkey)
|
||||
n = &(*n)->rb_right;
|
||||
else
|
||||
return;
|
||||
}
|
||||
rb_link_node(&m->tree_node, parent, n);
|
||||
rb_insert_color(&m->tree_node, &grp->members);
|
||||
}
|
||||
|
||||
static struct tipc_member *tipc_group_create_member(struct tipc_group *grp,
|
||||
u32 node, u32 port,
|
||||
int state)
|
||||
{
|
||||
struct tipc_member *m;
|
||||
|
||||
m = kzalloc(sizeof(*m), GFP_ATOMIC);
|
||||
if (!m)
|
||||
return NULL;
|
||||
INIT_LIST_HEAD(&m->list);
|
||||
INIT_LIST_HEAD(&m->congested);
|
||||
__skb_queue_head_init(&m->deferredq);
|
||||
m->group = grp;
|
||||
m->node = node;
|
||||
m->port = port;
|
||||
m->bc_acked = grp->bc_snd_nxt - 1;
|
||||
grp->member_cnt++;
|
||||
tipc_group_add_to_tree(grp, m);
|
||||
tipc_nlist_add(&grp->dests, m->node);
|
||||
m->state = state;
|
||||
return m;
|
||||
}
|
||||
|
||||
void tipc_group_add_member(struct tipc_group *grp, u32 node, u32 port)
|
||||
{
|
||||
tipc_group_create_member(grp, node, port, MBR_DISCOVERED);
|
||||
}
|
||||
|
||||
static void tipc_group_delete_member(struct tipc_group *grp,
|
||||
struct tipc_member *m)
|
||||
{
|
||||
rb_erase(&m->tree_node, &grp->members);
|
||||
grp->member_cnt--;
|
||||
|
||||
/* Check if we were waiting for replicast ack from this member */
|
||||
if (grp->bc_ackers && less(m->bc_acked, grp->bc_snd_nxt - 1))
|
||||
grp->bc_ackers--;
|
||||
|
||||
list_del_init(&m->list);
|
||||
list_del_init(&m->congested);
|
||||
tipc_group_decr_active(grp, m);
|
||||
|
||||
/* If last member on a node, remove node from dest list */
|
||||
if (!tipc_group_find_node(grp, m->node))
|
||||
tipc_nlist_del(&grp->dests, m->node);
|
||||
|
||||
kfree(m);
|
||||
}
|
||||
|
||||
struct tipc_nlist *tipc_group_dests(struct tipc_group *grp)
|
||||
{
|
||||
return &grp->dests;
|
||||
}
|
||||
|
||||
void tipc_group_self(struct tipc_group *grp, struct tipc_name_seq *seq,
|
||||
int *scope)
|
||||
{
|
||||
seq->type = grp->type;
|
||||
seq->lower = grp->instance;
|
||||
seq->upper = grp->instance;
|
||||
*scope = grp->scope;
|
||||
}
|
||||
|
||||
void tipc_group_update_member(struct tipc_member *m, int len)
|
||||
{
|
||||
struct tipc_group *grp = m->group;
|
||||
struct tipc_member *_m, *tmp;
|
||||
|
||||
if (!tipc_group_is_enabled(m))
|
||||
return;
|
||||
|
||||
m->window -= len;
|
||||
|
||||
if (m->window >= ADV_IDLE)
|
||||
return;
|
||||
|
||||
if (!list_empty(&m->congested))
|
||||
return;
|
||||
|
||||
/* Sort member into congested members' list */
|
||||
list_for_each_entry_safe(_m, tmp, &grp->congested, congested) {
|
||||
if (m->window > _m->window)
|
||||
continue;
|
||||
list_add_tail(&m->congested, &_m->congested);
|
||||
return;
|
||||
}
|
||||
list_add_tail(&m->congested, &grp->congested);
|
||||
}
|
||||
|
||||
void tipc_group_update_bc_members(struct tipc_group *grp, int len, bool ack)
|
||||
{
|
||||
u16 prev = grp->bc_snd_nxt - 1;
|
||||
struct tipc_member *m;
|
||||
struct rb_node *n;
|
||||
|
||||
for (n = rb_first(&grp->members); n; n = rb_next(n)) {
|
||||
m = container_of(n, struct tipc_member, tree_node);
|
||||
if (tipc_group_is_enabled(m)) {
|
||||
tipc_group_update_member(m, len);
|
||||
m->bc_acked = prev;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark number of acknowledges to expect, if any */
|
||||
if (ack)
|
||||
grp->bc_ackers = grp->member_cnt;
|
||||
grp->bc_snd_nxt++;
|
||||
}
|
||||
|
||||
bool tipc_group_cong(struct tipc_group *grp, u32 dnode, u32 dport,
|
||||
int len, struct tipc_member **mbr)
|
||||
{
|
||||
struct sk_buff_head xmitq;
|
||||
struct tipc_member *m;
|
||||
int adv, state;
|
||||
|
||||
m = tipc_group_find_dest(grp, dnode, dport);
|
||||
*mbr = m;
|
||||
if (!m)
|
||||
return false;
|
||||
if (m->usr_pending)
|
||||
return true;
|
||||
if (m->window >= len)
|
||||
return false;
|
||||
m->usr_pending = true;
|
||||
|
||||
/* If not fully advertised, do it now to prevent mutual blocking */
|
||||
adv = m->advertised;
|
||||
state = m->state;
|
||||
if (state < MBR_JOINED)
|
||||
return true;
|
||||
if (state == MBR_JOINED && adv == ADV_IDLE)
|
||||
return true;
|
||||
if (state == MBR_ACTIVE && adv == ADV_ACTIVE)
|
||||
return true;
|
||||
if (state == MBR_PENDING && adv == ADV_IDLE)
|
||||
return true;
|
||||
skb_queue_head_init(&xmitq);
|
||||
tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, &xmitq);
|
||||
tipc_node_distr_xmit(grp->net, &xmitq);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tipc_group_bc_cong(struct tipc_group *grp, int len)
|
||||
{
|
||||
struct tipc_member *m = NULL;
|
||||
|
||||
/* If prev bcast was replicast, reject until all receivers have acked */
|
||||
if (grp->bc_ackers)
|
||||
return true;
|
||||
|
||||
if (list_empty(&grp->congested))
|
||||
return false;
|
||||
|
||||
m = list_first_entry(&grp->congested, struct tipc_member, congested);
|
||||
if (m->window >= len)
|
||||
return false;
|
||||
|
||||
return tipc_group_cong(grp, m->node, m->port, len, &m);
|
||||
}
|
||||
|
||||
/* tipc_group_sort_msg() - sort msg into queue by bcast sequence number
|
||||
*/
|
||||
static void tipc_group_sort_msg(struct sk_buff *skb, struct sk_buff_head *defq)
|
||||
{
|
||||
struct tipc_msg *_hdr, *hdr = buf_msg(skb);
|
||||
u16 bc_seqno = msg_grp_bc_seqno(hdr);
|
||||
struct sk_buff *_skb, *tmp;
|
||||
int mtyp = msg_type(hdr);
|
||||
|
||||
/* Bcast/mcast may be bypassed by ucast or other bcast, - sort it in */
|
||||
if (mtyp == TIPC_GRP_BCAST_MSG || mtyp == TIPC_GRP_MCAST_MSG) {
|
||||
skb_queue_walk_safe(defq, _skb, tmp) {
|
||||
_hdr = buf_msg(_skb);
|
||||
if (!less(bc_seqno, msg_grp_bc_seqno(_hdr)))
|
||||
continue;
|
||||
__skb_queue_before(defq, _skb, skb);
|
||||
return;
|
||||
}
|
||||
/* Bcast was not bypassed, - add to tail */
|
||||
}
|
||||
/* Unicasts are never bypassed, - always add to tail */
|
||||
__skb_queue_tail(defq, skb);
|
||||
}
|
||||
|
||||
/* tipc_group_filter_msg() - determine if we should accept arriving message
|
||||
*/
|
||||
void tipc_group_filter_msg(struct tipc_group *grp, struct sk_buff_head *inputq,
|
||||
struct sk_buff_head *xmitq)
|
||||
{
|
||||
struct sk_buff *skb = __skb_dequeue(inputq);
|
||||
bool ack, deliver, update, leave = false;
|
||||
struct sk_buff_head *defq;
|
||||
struct tipc_member *m;
|
||||
struct tipc_msg *hdr;
|
||||
u32 node, port;
|
||||
int mtyp, blks;
|
||||
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
hdr = buf_msg(skb);
|
||||
node = msg_orignode(hdr);
|
||||
port = msg_origport(hdr);
|
||||
|
||||
if (!msg_in_group(hdr))
|
||||
goto drop;
|
||||
|
||||
m = tipc_group_find_member(grp, node, port);
|
||||
if (!tipc_group_is_receiver(m))
|
||||
goto drop;
|
||||
|
||||
if (less(msg_grp_bc_seqno(hdr), m->bc_rcv_nxt))
|
||||
goto drop;
|
||||
|
||||
TIPC_SKB_CB(skb)->orig_member = m->instance;
|
||||
defq = &m->deferredq;
|
||||
tipc_group_sort_msg(skb, defq);
|
||||
|
||||
while ((skb = skb_peek(defq))) {
|
||||
hdr = buf_msg(skb);
|
||||
mtyp = msg_type(hdr);
|
||||
deliver = true;
|
||||
ack = false;
|
||||
update = false;
|
||||
|
||||
if (more(msg_grp_bc_seqno(hdr), m->bc_rcv_nxt))
|
||||
break;
|
||||
|
||||
/* Decide what to do with message */
|
||||
switch (mtyp) {
|
||||
case TIPC_GRP_MCAST_MSG:
|
||||
if (msg_nameinst(hdr) != grp->instance) {
|
||||
update = true;
|
||||
deliver = false;
|
||||
}
|
||||
/* Fall thru */
|
||||
case TIPC_GRP_BCAST_MSG:
|
||||
m->bc_rcv_nxt++;
|
||||
ack = msg_grp_bc_ack_req(hdr);
|
||||
break;
|
||||
case TIPC_GRP_UCAST_MSG:
|
||||
break;
|
||||
case TIPC_GRP_MEMBER_EVT:
|
||||
if (m->state == MBR_LEAVING)
|
||||
leave = true;
|
||||
if (!grp->events)
|
||||
deliver = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Execute decisions */
|
||||
__skb_dequeue(defq);
|
||||
if (deliver)
|
||||
__skb_queue_tail(inputq, skb);
|
||||
else
|
||||
kfree_skb(skb);
|
||||
|
||||
if (ack)
|
||||
tipc_group_proto_xmit(grp, m, GRP_ACK_MSG, xmitq);
|
||||
|
||||
if (leave) {
|
||||
tipc_group_delete_member(grp, m);
|
||||
__skb_queue_purge(defq);
|
||||
break;
|
||||
}
|
||||
if (!update)
|
||||
continue;
|
||||
|
||||
blks = msg_blocks(hdr);
|
||||
tipc_group_update_rcv_win(grp, blks, node, port, xmitq);
|
||||
}
|
||||
return;
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
void tipc_group_update_rcv_win(struct tipc_group *grp, int blks, u32 node,
|
||||
u32 port, struct sk_buff_head *xmitq)
|
||||
{
|
||||
struct list_head *active = &grp->active;
|
||||
int max_active = grp->max_active;
|
||||
int reclaim_limit = max_active * 3 / 4;
|
||||
int active_cnt = grp->active_cnt;
|
||||
struct tipc_member *m, *rm;
|
||||
|
||||
m = tipc_group_find_member(grp, node, port);
|
||||
if (!m)
|
||||
return;
|
||||
|
||||
m->advertised -= blks;
|
||||
|
||||
switch (m->state) {
|
||||
case MBR_JOINED:
|
||||
/* Reclaim advertised space from least active member */
|
||||
if (!list_empty(active) && active_cnt >= reclaim_limit) {
|
||||
rm = list_first_entry(active, struct tipc_member, list);
|
||||
rm->state = MBR_RECLAIMING;
|
||||
list_move_tail(&rm->list, &grp->reclaiming);
|
||||
tipc_group_proto_xmit(grp, rm, GRP_RECLAIM_MSG, xmitq);
|
||||
}
|
||||
/* If max active, become pending and wait for reclaimed space */
|
||||
if (active_cnt >= max_active) {
|
||||
m->state = MBR_PENDING;
|
||||
list_add_tail(&m->list, &grp->pending);
|
||||
break;
|
||||
}
|
||||
/* Otherwise become active */
|
||||
m->state = MBR_ACTIVE;
|
||||
list_add_tail(&m->list, &grp->active);
|
||||
grp->active_cnt++;
|
||||
/* Fall through */
|
||||
case MBR_ACTIVE:
|
||||
if (!list_is_last(&m->list, &grp->active))
|
||||
list_move_tail(&m->list, &grp->active);
|
||||
if (m->advertised > (ADV_ACTIVE * 3 / 4))
|
||||
break;
|
||||
tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq);
|
||||
break;
|
||||
case MBR_REMITTED:
|
||||
if (m->advertised > ADV_IDLE)
|
||||
break;
|
||||
m->state = MBR_JOINED;
|
||||
if (m->advertised < ADV_IDLE) {
|
||||
pr_warn_ratelimited("Rcv unexpected msg after REMIT\n");
|
||||
tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq);
|
||||
}
|
||||
break;
|
||||
case MBR_RECLAIMING:
|
||||
case MBR_DISCOVERED:
|
||||
case MBR_JOINING:
|
||||
case MBR_LEAVING:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void tipc_group_proto_xmit(struct tipc_group *grp, struct tipc_member *m,
|
||||
int mtyp, struct sk_buff_head *xmitq)
|
||||
{
|
||||
struct tipc_msg *hdr;
|
||||
struct sk_buff *skb;
|
||||
int adv = 0;
|
||||
|
||||
skb = tipc_msg_create(GROUP_PROTOCOL, mtyp, INT_H_SIZE, 0,
|
||||
m->node, tipc_own_addr(grp->net),
|
||||
m->port, grp->portid, 0);
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
if (m->state == MBR_ACTIVE)
|
||||
adv = ADV_ACTIVE - m->advertised;
|
||||
else if (m->state == MBR_JOINED || m->state == MBR_PENDING)
|
||||
adv = ADV_IDLE - m->advertised;
|
||||
|
||||
hdr = buf_msg(skb);
|
||||
|
||||
if (mtyp == GRP_JOIN_MSG) {
|
||||
msg_set_grp_bc_syncpt(hdr, grp->bc_snd_nxt);
|
||||
msg_set_adv_win(hdr, adv);
|
||||
m->advertised += adv;
|
||||
} else if (mtyp == GRP_LEAVE_MSG) {
|
||||
msg_set_grp_bc_syncpt(hdr, grp->bc_snd_nxt);
|
||||
} else if (mtyp == GRP_ADV_MSG) {
|
||||
msg_set_adv_win(hdr, adv);
|
||||
m->advertised += adv;
|
||||
} else if (mtyp == GRP_ACK_MSG) {
|
||||
msg_set_grp_bc_acked(hdr, m->bc_rcv_nxt);
|
||||
} else if (mtyp == GRP_REMIT_MSG) {
|
||||
msg_set_grp_remitted(hdr, m->window);
|
||||
}
|
||||
__skb_queue_tail(xmitq, skb);
|
||||
}
|
||||
|
||||
void tipc_group_proto_rcv(struct tipc_group *grp, bool *usr_wakeup,
|
||||
struct tipc_msg *hdr, struct sk_buff_head *inputq,
|
||||
struct sk_buff_head *xmitq)
|
||||
{
|
||||
u32 node = msg_orignode(hdr);
|
||||
u32 port = msg_origport(hdr);
|
||||
struct tipc_member *m, *pm;
|
||||
struct tipc_msg *ehdr;
|
||||
u16 remitted, in_flight;
|
||||
|
||||
if (!grp)
|
||||
return;
|
||||
|
||||
m = tipc_group_find_member(grp, node, port);
|
||||
|
||||
switch (msg_type(hdr)) {
|
||||
case GRP_JOIN_MSG:
|
||||
if (!m)
|
||||
m = tipc_group_create_member(grp, node, port,
|
||||
MBR_QUARANTINED);
|
||||
if (!m)
|
||||
return;
|
||||
m->bc_syncpt = msg_grp_bc_syncpt(hdr);
|
||||
m->bc_rcv_nxt = m->bc_syncpt;
|
||||
m->window += msg_adv_win(hdr);
|
||||
|
||||
/* Wait until PUBLISH event is received */
|
||||
if (m->state == MBR_DISCOVERED) {
|
||||
m->state = MBR_JOINING;
|
||||
} else if (m->state == MBR_PUBLISHED) {
|
||||
m->state = MBR_JOINED;
|
||||
*usr_wakeup = true;
|
||||
m->usr_pending = false;
|
||||
tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq);
|
||||
ehdr = buf_msg(m->event_msg);
|
||||
msg_set_grp_bc_seqno(ehdr, m->bc_syncpt);
|
||||
__skb_queue_tail(inputq, m->event_msg);
|
||||
}
|
||||
if (m->window < ADV_IDLE)
|
||||
tipc_group_update_member(m, 0);
|
||||
else
|
||||
list_del_init(&m->congested);
|
||||
return;
|
||||
case GRP_LEAVE_MSG:
|
||||
if (!m)
|
||||
return;
|
||||
m->bc_syncpt = msg_grp_bc_syncpt(hdr);
|
||||
|
||||
/* Wait until WITHDRAW event is received */
|
||||
if (m->state != MBR_LEAVING) {
|
||||
tipc_group_decr_active(grp, m);
|
||||
m->state = MBR_LEAVING;
|
||||
return;
|
||||
}
|
||||
/* Otherwise deliver already received WITHDRAW event */
|
||||
ehdr = buf_msg(m->event_msg);
|
||||
msg_set_grp_bc_seqno(ehdr, m->bc_syncpt);
|
||||
__skb_queue_tail(inputq, m->event_msg);
|
||||
*usr_wakeup = true;
|
||||
list_del_init(&m->congested);
|
||||
return;
|
||||
case GRP_ADV_MSG:
|
||||
if (!m)
|
||||
return;
|
||||
m->window += msg_adv_win(hdr);
|
||||
*usr_wakeup = m->usr_pending;
|
||||
m->usr_pending = false;
|
||||
list_del_init(&m->congested);
|
||||
return;
|
||||
case GRP_ACK_MSG:
|
||||
if (!m)
|
||||
return;
|
||||
m->bc_acked = msg_grp_bc_acked(hdr);
|
||||
if (--grp->bc_ackers)
|
||||
break;
|
||||
*usr_wakeup = true;
|
||||
m->usr_pending = false;
|
||||
return;
|
||||
case GRP_RECLAIM_MSG:
|
||||
if (!m)
|
||||
return;
|
||||
*usr_wakeup = m->usr_pending;
|
||||
m->usr_pending = false;
|
||||
tipc_group_proto_xmit(grp, m, GRP_REMIT_MSG, xmitq);
|
||||
m->window = ADV_IDLE;
|
||||
return;
|
||||
case GRP_REMIT_MSG:
|
||||
if (!m || m->state != MBR_RECLAIMING)
|
||||
return;
|
||||
|
||||
list_del_init(&m->list);
|
||||
grp->active_cnt--;
|
||||
remitted = msg_grp_remitted(hdr);
|
||||
|
||||
/* Messages preceding the REMIT still in receive queue */
|
||||
if (m->advertised > remitted) {
|
||||
m->state = MBR_REMITTED;
|
||||
in_flight = m->advertised - remitted;
|
||||
}
|
||||
/* All messages preceding the REMIT have been read */
|
||||
if (m->advertised <= remitted) {
|
||||
m->state = MBR_JOINED;
|
||||
in_flight = 0;
|
||||
}
|
||||
/* ..and the REMIT overtaken by more messages => re-advertise */
|
||||
if (m->advertised < remitted)
|
||||
tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq);
|
||||
|
||||
m->advertised = ADV_IDLE + in_flight;
|
||||
|
||||
/* Set oldest pending member to active and advertise */
|
||||
if (list_empty(&grp->pending))
|
||||
return;
|
||||
pm = list_first_entry(&grp->pending, struct tipc_member, list);
|
||||
pm->state = MBR_ACTIVE;
|
||||
list_move_tail(&pm->list, &grp->active);
|
||||
grp->active_cnt++;
|
||||
if (pm->advertised <= (ADV_ACTIVE * 3 / 4))
|
||||
tipc_group_proto_xmit(grp, pm, GRP_ADV_MSG, xmitq);
|
||||
return;
|
||||
default:
|
||||
pr_warn("Received unknown GROUP_PROTO message\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* tipc_group_member_evt() - receive and handle a member up/down event
|
||||
*/
|
||||
void tipc_group_member_evt(struct tipc_group *grp,
|
||||
bool *usr_wakeup,
|
||||
int *sk_rcvbuf,
|
||||
struct sk_buff *skb,
|
||||
struct sk_buff_head *inputq,
|
||||
struct sk_buff_head *xmitq)
|
||||
{
|
||||
struct tipc_msg *hdr = buf_msg(skb);
|
||||
struct tipc_event *evt = (void *)msg_data(hdr);
|
||||
u32 instance = evt->found_lower;
|
||||
u32 node = evt->port.node;
|
||||
u32 port = evt->port.ref;
|
||||
int event = evt->event;
|
||||
struct tipc_member *m;
|
||||
struct net *net;
|
||||
bool node_up;
|
||||
u32 self;
|
||||
|
||||
if (!grp)
|
||||
goto drop;
|
||||
|
||||
net = grp->net;
|
||||
self = tipc_own_addr(net);
|
||||
if (!grp->loopback && node == self && port == grp->portid)
|
||||
goto drop;
|
||||
|
||||
/* Convert message before delivery to user */
|
||||
msg_set_hdr_sz(hdr, GROUP_H_SIZE);
|
||||
msg_set_user(hdr, TIPC_CRITICAL_IMPORTANCE);
|
||||
msg_set_type(hdr, TIPC_GRP_MEMBER_EVT);
|
||||
msg_set_origport(hdr, port);
|
||||
msg_set_orignode(hdr, node);
|
||||
msg_set_nametype(hdr, grp->type);
|
||||
msg_set_grp_evt(hdr, event);
|
||||
|
||||
m = tipc_group_find_member(grp, node, port);
|
||||
|
||||
if (event == TIPC_PUBLISHED) {
|
||||
if (!m)
|
||||
m = tipc_group_create_member(grp, node, port,
|
||||
MBR_DISCOVERED);
|
||||
if (!m)
|
||||
goto drop;
|
||||
|
||||
/* Hold back event if JOIN message not yet received */
|
||||
if (m->state == MBR_DISCOVERED) {
|
||||
m->event_msg = skb;
|
||||
m->state = MBR_PUBLISHED;
|
||||
} else {
|
||||
msg_set_grp_bc_seqno(hdr, m->bc_syncpt);
|
||||
__skb_queue_tail(inputq, skb);
|
||||
m->state = MBR_JOINED;
|
||||
*usr_wakeup = true;
|
||||
m->usr_pending = false;
|
||||
}
|
||||
m->instance = instance;
|
||||
TIPC_SKB_CB(skb)->orig_member = m->instance;
|
||||
tipc_group_proto_xmit(grp, m, GRP_JOIN_MSG, xmitq);
|
||||
if (m->window < ADV_IDLE)
|
||||
tipc_group_update_member(m, 0);
|
||||
else
|
||||
list_del_init(&m->congested);
|
||||
} else if (event == TIPC_WITHDRAWN) {
|
||||
if (!m)
|
||||
goto drop;
|
||||
|
||||
TIPC_SKB_CB(skb)->orig_member = m->instance;
|
||||
|
||||
*usr_wakeup = true;
|
||||
m->usr_pending = false;
|
||||
node_up = tipc_node_is_up(net, node);
|
||||
|
||||
/* Hold back event if more messages might be expected */
|
||||
if (m->state != MBR_LEAVING && node_up) {
|
||||
m->event_msg = skb;
|
||||
tipc_group_decr_active(grp, m);
|
||||
m->state = MBR_LEAVING;
|
||||
} else {
|
||||
if (node_up)
|
||||
msg_set_grp_bc_seqno(hdr, m->bc_syncpt);
|
||||
else
|
||||
msg_set_grp_bc_seqno(hdr, m->bc_rcv_nxt);
|
||||
__skb_queue_tail(inputq, skb);
|
||||
}
|
||||
list_del_init(&m->congested);
|
||||
}
|
||||
*sk_rcvbuf = tipc_group_rcvbuf_limit(grp);
|
||||
return;
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* net/tipc/group.h: Include file for TIPC group unicast/multicast functions
|
||||
*
|
||||
* Copyright (c) 2017, Ericsson AB
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _TIPC_GROUP_H
|
||||
#define _TIPC_GROUP_H
|
||||
|
||||
#include "core.h"
|
||||
|
||||
struct tipc_group;
|
||||
struct tipc_member;
|
||||
struct tipc_msg;
|
||||
|
||||
struct tipc_group *tipc_group_create(struct net *net, u32 portid,
|
||||
struct tipc_group_req *mreq);
|
||||
void tipc_group_delete(struct net *net, struct tipc_group *grp);
|
||||
void tipc_group_add_member(struct tipc_group *grp, u32 node, u32 port);
|
||||
struct tipc_nlist *tipc_group_dests(struct tipc_group *grp);
|
||||
void tipc_group_self(struct tipc_group *grp, struct tipc_name_seq *seq,
|
||||
int *scope);
|
||||
u32 tipc_group_exclude(struct tipc_group *grp);
|
||||
void tipc_group_filter_msg(struct tipc_group *grp,
|
||||
struct sk_buff_head *inputq,
|
||||
struct sk_buff_head *xmitq);
|
||||
void tipc_group_member_evt(struct tipc_group *grp, bool *wakeup,
|
||||
int *sk_rcvbuf, struct sk_buff *skb,
|
||||
struct sk_buff_head *inputq,
|
||||
struct sk_buff_head *xmitq);
|
||||
void tipc_group_proto_rcv(struct tipc_group *grp, bool *wakeup,
|
||||
struct tipc_msg *hdr,
|
||||
struct sk_buff_head *inputq,
|
||||
struct sk_buff_head *xmitq);
|
||||
void tipc_group_update_bc_members(struct tipc_group *grp, int len, bool ack);
|
||||
bool tipc_group_cong(struct tipc_group *grp, u32 dnode, u32 dport,
|
||||
int len, struct tipc_member **m);
|
||||
bool tipc_group_bc_cong(struct tipc_group *grp, int len);
|
||||
void tipc_group_update_rcv_win(struct tipc_group *grp, int blks, u32 node,
|
||||
u32 port, struct sk_buff_head *xmitq);
|
||||
u16 tipc_group_bc_snd_nxt(struct tipc_group *grp);
|
||||
void tipc_group_update_member(struct tipc_member *m, int len);
|
||||
int tipc_group_size(struct tipc_group *grp);
|
||||
#endif
|
|
@ -1039,6 +1039,7 @@ int tipc_link_retrans(struct tipc_link *l, struct tipc_link *nacker,
|
|||
static bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb,
|
||||
struct sk_buff_head *inputq)
|
||||
{
|
||||
struct sk_buff_head *mc_inputq = l->bc_rcvlink->inputq;
|
||||
struct tipc_msg *hdr = buf_msg(skb);
|
||||
|
||||
switch (msg_user(hdr)) {
|
||||
|
@ -1046,12 +1047,14 @@ static bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb,
|
|||
case TIPC_MEDIUM_IMPORTANCE:
|
||||
case TIPC_HIGH_IMPORTANCE:
|
||||
case TIPC_CRITICAL_IMPORTANCE:
|
||||
if (unlikely(msg_type(hdr) == TIPC_MCAST_MSG)) {
|
||||
skb_queue_tail(l->bc_rcvlink->inputq, skb);
|
||||
if (unlikely(msg_in_group(hdr) || msg_mcast(hdr))) {
|
||||
skb_queue_tail(mc_inputq, skb);
|
||||
return true;
|
||||
}
|
||||
case CONN_MANAGER:
|
||||
skb_queue_tail(inputq, skb);
|
||||
return true;
|
||||
case GROUP_PROTOCOL:
|
||||
skb_queue_tail(mc_inputq, skb);
|
||||
return true;
|
||||
case NAME_DISTRIBUTOR:
|
||||
l->bc_rcvlink->state = LINK_ESTABLISHED;
|
||||
|
|
|
@ -666,3 +666,10 @@ void __tipc_skb_queue_sorted(struct sk_buff_head *list, u16 seqno,
|
|||
}
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
void tipc_skb_reject(struct net *net, int err, struct sk_buff *skb,
|
||||
struct sk_buff_head *xmitq)
|
||||
{
|
||||
if (tipc_msg_reverse(tipc_own_addr(net), &skb, err))
|
||||
__skb_queue_tail(xmitq, skb);
|
||||
}
|
||||
|
|
118
net/tipc/msg.h
118
net/tipc/msg.h
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* net/tipc/msg.h: Include file for TIPC message header routines
|
||||
*
|
||||
* Copyright (c) 2000-2007, 2014-2015 Ericsson AB
|
||||
* Copyright (c) 2000-2007, 2014-2017 Ericsson AB
|
||||
* Copyright (c) 2005-2008, 2010-2011, Wind River Systems
|
||||
* All rights reserved.
|
||||
*
|
||||
|
@ -61,10 +61,14 @@ struct plist;
|
|||
/*
|
||||
* Payload message types
|
||||
*/
|
||||
#define TIPC_CONN_MSG 0
|
||||
#define TIPC_MCAST_MSG 1
|
||||
#define TIPC_NAMED_MSG 2
|
||||
#define TIPC_DIRECT_MSG 3
|
||||
#define TIPC_CONN_MSG 0
|
||||
#define TIPC_MCAST_MSG 1
|
||||
#define TIPC_NAMED_MSG 2
|
||||
#define TIPC_DIRECT_MSG 3
|
||||
#define TIPC_GRP_MEMBER_EVT 4
|
||||
#define TIPC_GRP_BCAST_MSG 5
|
||||
#define TIPC_GRP_MCAST_MSG 6
|
||||
#define TIPC_GRP_UCAST_MSG 7
|
||||
|
||||
/*
|
||||
* Internal message users
|
||||
|
@ -73,11 +77,13 @@ struct plist;
|
|||
#define MSG_BUNDLER 6
|
||||
#define LINK_PROTOCOL 7
|
||||
#define CONN_MANAGER 8
|
||||
#define GROUP_PROTOCOL 9
|
||||
#define TUNNEL_PROTOCOL 10
|
||||
#define NAME_DISTRIBUTOR 11
|
||||
#define MSG_FRAGMENTER 12
|
||||
#define LINK_CONFIG 13
|
||||
#define SOCK_WAKEUP 14 /* pseudo user */
|
||||
#define TOP_SRV 15 /* pseudo user */
|
||||
|
||||
/*
|
||||
* Message header sizes
|
||||
|
@ -86,6 +92,7 @@ struct plist;
|
|||
#define BASIC_H_SIZE 32 /* Basic payload message */
|
||||
#define NAMED_H_SIZE 40 /* Named payload message */
|
||||
#define MCAST_H_SIZE 44 /* Multicast payload message */
|
||||
#define GROUP_H_SIZE 44 /* Group payload message */
|
||||
#define INT_H_SIZE 40 /* Internal messages */
|
||||
#define MIN_H_SIZE 24 /* Smallest legal TIPC header size */
|
||||
#define MAX_H_SIZE 60 /* Largest possible TIPC header size */
|
||||
|
@ -96,6 +103,7 @@ struct plist;
|
|||
|
||||
struct tipc_skb_cb {
|
||||
u32 bytes_read;
|
||||
u32 orig_member;
|
||||
struct sk_buff *tail;
|
||||
bool validated;
|
||||
u16 chain_imp;
|
||||
|
@ -188,6 +196,11 @@ static inline u32 msg_size(struct tipc_msg *m)
|
|||
return msg_bits(m, 0, 0, 0x1ffff);
|
||||
}
|
||||
|
||||
static inline u32 msg_blocks(struct tipc_msg *m)
|
||||
{
|
||||
return (msg_size(m) / 1024) + 1;
|
||||
}
|
||||
|
||||
static inline u32 msg_data_sz(struct tipc_msg *m)
|
||||
{
|
||||
return msg_size(m) - msg_hdr_sz(m);
|
||||
|
@ -251,6 +264,18 @@ static inline void msg_set_type(struct tipc_msg *m, u32 n)
|
|||
msg_set_bits(m, 1, 29, 0x7, n);
|
||||
}
|
||||
|
||||
static inline int msg_in_group(struct tipc_msg *m)
|
||||
{
|
||||
int mtyp = msg_type(m);
|
||||
|
||||
return mtyp >= TIPC_GRP_MEMBER_EVT && mtyp <= TIPC_GRP_UCAST_MSG;
|
||||
}
|
||||
|
||||
static inline bool msg_is_grp_evt(struct tipc_msg *m)
|
||||
{
|
||||
return msg_type(m) == TIPC_GRP_MEMBER_EVT;
|
||||
}
|
||||
|
||||
static inline u32 msg_named(struct tipc_msg *m)
|
||||
{
|
||||
return msg_type(m) == TIPC_NAMED_MSG;
|
||||
|
@ -258,7 +283,10 @@ static inline u32 msg_named(struct tipc_msg *m)
|
|||
|
||||
static inline u32 msg_mcast(struct tipc_msg *m)
|
||||
{
|
||||
return msg_type(m) == TIPC_MCAST_MSG;
|
||||
int mtyp = msg_type(m);
|
||||
|
||||
return ((mtyp == TIPC_MCAST_MSG) || (mtyp == TIPC_GRP_BCAST_MSG) ||
|
||||
(mtyp == TIPC_GRP_MCAST_MSG));
|
||||
}
|
||||
|
||||
static inline u32 msg_connected(struct tipc_msg *m)
|
||||
|
@ -513,6 +541,16 @@ static inline void msg_set_nameupper(struct tipc_msg *m, u32 n)
|
|||
#define DSC_REQ_MSG 0
|
||||
#define DSC_RESP_MSG 1
|
||||
|
||||
/*
|
||||
* Group protocol message types
|
||||
*/
|
||||
#define GRP_JOIN_MSG 0
|
||||
#define GRP_LEAVE_MSG 1
|
||||
#define GRP_ADV_MSG 2
|
||||
#define GRP_ACK_MSG 3
|
||||
#define GRP_RECLAIM_MSG 4
|
||||
#define GRP_REMIT_MSG 5
|
||||
|
||||
/*
|
||||
* Word 1
|
||||
*/
|
||||
|
@ -764,12 +802,12 @@ static inline void msg_set_conn_ack(struct tipc_msg *m, u32 n)
|
|||
msg_set_bits(m, 9, 16, 0xffff, n);
|
||||
}
|
||||
|
||||
static inline u32 msg_adv_win(struct tipc_msg *m)
|
||||
static inline u16 msg_adv_win(struct tipc_msg *m)
|
||||
{
|
||||
return msg_bits(m, 9, 0, 0xffff);
|
||||
}
|
||||
|
||||
static inline void msg_set_adv_win(struct tipc_msg *m, u32 n)
|
||||
static inline void msg_set_adv_win(struct tipc_msg *m, u16 n)
|
||||
{
|
||||
msg_set_bits(m, 9, 0, 0xffff, n);
|
||||
}
|
||||
|
@ -794,6 +832,68 @@ static inline void msg_set_link_tolerance(struct tipc_msg *m, u32 n)
|
|||
msg_set_bits(m, 9, 0, 0xffff, n);
|
||||
}
|
||||
|
||||
static inline u16 msg_grp_bc_syncpt(struct tipc_msg *m)
|
||||
{
|
||||
return msg_bits(m, 9, 16, 0xffff);
|
||||
}
|
||||
|
||||
static inline void msg_set_grp_bc_syncpt(struct tipc_msg *m, u16 n)
|
||||
{
|
||||
msg_set_bits(m, 9, 16, 0xffff, n);
|
||||
}
|
||||
|
||||
static inline u16 msg_grp_bc_acked(struct tipc_msg *m)
|
||||
{
|
||||
return msg_bits(m, 9, 16, 0xffff);
|
||||
}
|
||||
|
||||
static inline void msg_set_grp_bc_acked(struct tipc_msg *m, u16 n)
|
||||
{
|
||||
msg_set_bits(m, 9, 16, 0xffff, n);
|
||||
}
|
||||
|
||||
static inline u16 msg_grp_remitted(struct tipc_msg *m)
|
||||
{
|
||||
return msg_bits(m, 9, 16, 0xffff);
|
||||
}
|
||||
|
||||
static inline void msg_set_grp_remitted(struct tipc_msg *m, u16 n)
|
||||
{
|
||||
msg_set_bits(m, 9, 16, 0xffff, n);
|
||||
}
|
||||
|
||||
/* Word 10
|
||||
*/
|
||||
static inline u16 msg_grp_evt(struct tipc_msg *m)
|
||||
{
|
||||
return msg_bits(m, 10, 0, 0x3);
|
||||
}
|
||||
|
||||
static inline void msg_set_grp_evt(struct tipc_msg *m, int n)
|
||||
{
|
||||
msg_set_bits(m, 10, 0, 0x3, n);
|
||||
}
|
||||
|
||||
static inline u16 msg_grp_bc_ack_req(struct tipc_msg *m)
|
||||
{
|
||||
return msg_bits(m, 10, 0, 0x1);
|
||||
}
|
||||
|
||||
static inline void msg_set_grp_bc_ack_req(struct tipc_msg *m, bool n)
|
||||
{
|
||||
msg_set_bits(m, 10, 0, 0x1, n);
|
||||
}
|
||||
|
||||
static inline u16 msg_grp_bc_seqno(struct tipc_msg *m)
|
||||
{
|
||||
return msg_bits(m, 10, 16, 0xffff);
|
||||
}
|
||||
|
||||
static inline void msg_set_grp_bc_seqno(struct tipc_msg *m, u32 n)
|
||||
{
|
||||
msg_set_bits(m, 10, 16, 0xffff, n);
|
||||
}
|
||||
|
||||
static inline bool msg_peer_link_is_up(struct tipc_msg *m)
|
||||
{
|
||||
if (likely(msg_user(m) != LINK_PROTOCOL))
|
||||
|
@ -818,6 +918,8 @@ static inline bool msg_is_reset(struct tipc_msg *hdr)
|
|||
struct sk_buff *tipc_buf_acquire(u32 size, gfp_t gfp);
|
||||
bool tipc_msg_validate(struct sk_buff *skb);
|
||||
bool tipc_msg_reverse(u32 own_addr, struct sk_buff **skb, int err);
|
||||
void tipc_skb_reject(struct net *net, int err, struct sk_buff *skb,
|
||||
struct sk_buff_head *xmitq);
|
||||
void tipc_msg_init(u32 own_addr, struct tipc_msg *m, u32 user, u32 type,
|
||||
u32 hsize, u32 destnode);
|
||||
struct sk_buff *tipc_msg_create(uint user, uint type, uint hdr_sz,
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "bcast.h"
|
||||
#include "addr.h"
|
||||
#include "node.h"
|
||||
#include "group.h"
|
||||
#include <net/genetlink.h>
|
||||
|
||||
#define TIPC_NAMETBL_SIZE 1024 /* must be a power of 2 */
|
||||
|
@ -596,18 +597,47 @@ u32 tipc_nametbl_translate(struct net *net, u32 type, u32 instance,
|
|||
return ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_nametbl_mc_translate - find multicast destinations
|
||||
*
|
||||
* Creates list of all local ports that overlap the given multicast address;
|
||||
* also determines if any off-node ports overlap.
|
||||
*
|
||||
* Note: Publications with a scope narrower than 'limit' are ignored.
|
||||
* (i.e. local node-scope publications mustn't receive messages arriving
|
||||
* from another node, even if the multcast link brought it here)
|
||||
*
|
||||
* Returns non-zero if any off-node ports overlap
|
||||
*/
|
||||
bool tipc_nametbl_lookup(struct net *net, u32 type, u32 instance, u32 domain,
|
||||
struct list_head *dsts, int *dstcnt, u32 exclude,
|
||||
bool all)
|
||||
{
|
||||
u32 self = tipc_own_addr(net);
|
||||
struct publication *publ;
|
||||
struct name_info *info;
|
||||
struct name_seq *seq;
|
||||
struct sub_seq *sseq;
|
||||
|
||||
if (!tipc_in_scope(domain, self))
|
||||
return false;
|
||||
|
||||
*dstcnt = 0;
|
||||
rcu_read_lock();
|
||||
seq = nametbl_find_seq(net, type);
|
||||
if (unlikely(!seq))
|
||||
goto exit;
|
||||
spin_lock_bh(&seq->lock);
|
||||
sseq = nameseq_find_subseq(seq, instance);
|
||||
if (likely(sseq)) {
|
||||
info = sseq->info;
|
||||
list_for_each_entry(publ, &info->zone_list, zone_list) {
|
||||
if (!tipc_in_scope(domain, publ->node))
|
||||
continue;
|
||||
if (publ->ref == exclude && publ->node == self)
|
||||
continue;
|
||||
tipc_dest_push(dsts, publ->node, publ->ref);
|
||||
(*dstcnt)++;
|
||||
if (all)
|
||||
continue;
|
||||
list_move_tail(&publ->zone_list, &info->zone_list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&seq->lock);
|
||||
exit:
|
||||
rcu_read_unlock();
|
||||
return !list_empty(dsts);
|
||||
}
|
||||
|
||||
int tipc_nametbl_mc_translate(struct net *net, u32 type, u32 lower, u32 upper,
|
||||
u32 limit, struct list_head *dports)
|
||||
{
|
||||
|
@ -634,7 +664,7 @@ int tipc_nametbl_mc_translate(struct net *net, u32 type, u32 lower, u32 upper,
|
|||
info = sseq->info;
|
||||
list_for_each_entry(publ, &info->node_list, node_list) {
|
||||
if (publ->scope <= limit)
|
||||
u32_push(dports, publ->ref);
|
||||
tipc_dest_push(dports, 0, publ->ref);
|
||||
}
|
||||
|
||||
if (info->cluster_list_size != info->node_list_size)
|
||||
|
@ -679,6 +709,37 @@ void tipc_nametbl_lookup_dst_nodes(struct net *net, u32 type, u32 lower,
|
|||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/* tipc_nametbl_build_group - build list of communication group members
|
||||
*/
|
||||
void tipc_nametbl_build_group(struct net *net, struct tipc_group *grp,
|
||||
u32 type, u32 domain)
|
||||
{
|
||||
struct sub_seq *sseq, *stop;
|
||||
struct name_info *info;
|
||||
struct publication *p;
|
||||
struct name_seq *seq;
|
||||
|
||||
rcu_read_lock();
|
||||
seq = nametbl_find_seq(net, type);
|
||||
if (!seq)
|
||||
goto exit;
|
||||
|
||||
spin_lock_bh(&seq->lock);
|
||||
sseq = seq->sseqs;
|
||||
stop = seq->sseqs + seq->first_free;
|
||||
for (; sseq != stop; sseq++) {
|
||||
info = sseq->info;
|
||||
list_for_each_entry(p, &info->zone_list, zone_list) {
|
||||
if (!tipc_in_scope(domain, p->node))
|
||||
continue;
|
||||
tipc_group_add_member(grp, p->node, p->ref);
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&seq->lock);
|
||||
exit:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* tipc_nametbl_publish - add name publication to network name tables
|
||||
*/
|
||||
|
@ -1057,78 +1118,79 @@ int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
return skb->len;
|
||||
}
|
||||
|
||||
bool u32_find(struct list_head *l, u32 value)
|
||||
struct tipc_dest *tipc_dest_find(struct list_head *l, u32 node, u32 port)
|
||||
{
|
||||
struct u32_item *item;
|
||||
u64 value = (u64)node << 32 | port;
|
||||
struct tipc_dest *dst;
|
||||
|
||||
list_for_each_entry(item, l, list) {
|
||||
if (item->value == value)
|
||||
return true;
|
||||
list_for_each_entry(dst, l, list) {
|
||||
if (dst->value != value)
|
||||
continue;
|
||||
return dst;
|
||||
}
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool u32_push(struct list_head *l, u32 value)
|
||||
bool tipc_dest_push(struct list_head *l, u32 node, u32 port)
|
||||
{
|
||||
struct u32_item *item;
|
||||
u64 value = (u64)node << 32 | port;
|
||||
struct tipc_dest *dst;
|
||||
|
||||
list_for_each_entry(item, l, list) {
|
||||
if (item->value == value)
|
||||
return false;
|
||||
}
|
||||
item = kmalloc(sizeof(*item), GFP_ATOMIC);
|
||||
if (unlikely(!item))
|
||||
if (tipc_dest_find(l, node, port))
|
||||
return false;
|
||||
|
||||
item->value = value;
|
||||
list_add(&item->list, l);
|
||||
dst = kmalloc(sizeof(*dst), GFP_ATOMIC);
|
||||
if (unlikely(!dst))
|
||||
return false;
|
||||
dst->value = value;
|
||||
list_add(&dst->list, l);
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 u32_pop(struct list_head *l)
|
||||
bool tipc_dest_pop(struct list_head *l, u32 *node, u32 *port)
|
||||
{
|
||||
struct u32_item *item;
|
||||
u32 value = 0;
|
||||
struct tipc_dest *dst;
|
||||
|
||||
if (list_empty(l))
|
||||
return 0;
|
||||
item = list_first_entry(l, typeof(*item), list);
|
||||
value = item->value;
|
||||
list_del(&item->list);
|
||||
kfree(item);
|
||||
return value;
|
||||
return false;
|
||||
dst = list_first_entry(l, typeof(*dst), list);
|
||||
if (port)
|
||||
*port = dst->port;
|
||||
if (node)
|
||||
*node = dst->node;
|
||||
list_del(&dst->list);
|
||||
kfree(dst);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool u32_del(struct list_head *l, u32 value)
|
||||
bool tipc_dest_del(struct list_head *l, u32 node, u32 port)
|
||||
{
|
||||
struct u32_item *item, *tmp;
|
||||
struct tipc_dest *dst;
|
||||
|
||||
list_for_each_entry_safe(item, tmp, l, list) {
|
||||
if (item->value != value)
|
||||
continue;
|
||||
list_del(&item->list);
|
||||
kfree(item);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
dst = tipc_dest_find(l, node, port);
|
||||
if (!dst)
|
||||
return false;
|
||||
list_del(&dst->list);
|
||||
kfree(dst);
|
||||
return true;
|
||||
}
|
||||
|
||||
void u32_list_purge(struct list_head *l)
|
||||
void tipc_dest_list_purge(struct list_head *l)
|
||||
{
|
||||
struct u32_item *item, *tmp;
|
||||
struct tipc_dest *dst, *tmp;
|
||||
|
||||
list_for_each_entry_safe(item, tmp, l, list) {
|
||||
list_del(&item->list);
|
||||
kfree(item);
|
||||
list_for_each_entry_safe(dst, tmp, l, list) {
|
||||
list_del(&dst->list);
|
||||
kfree(dst);
|
||||
}
|
||||
}
|
||||
|
||||
int u32_list_len(struct list_head *l)
|
||||
int tipc_dest_list_len(struct list_head *l)
|
||||
{
|
||||
struct u32_item *item;
|
||||
struct tipc_dest *dst;
|
||||
int i = 0;
|
||||
|
||||
list_for_each_entry(item, l, list) {
|
||||
list_for_each_entry(dst, l, list) {
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
struct tipc_subscription;
|
||||
struct tipc_plist;
|
||||
struct tipc_nlist;
|
||||
struct tipc_group;
|
||||
|
||||
/*
|
||||
* TIPC name types reserved for internal TIPC use (both current and planned)
|
||||
|
@ -101,9 +102,14 @@ int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb);
|
|||
u32 tipc_nametbl_translate(struct net *net, u32 type, u32 instance, u32 *node);
|
||||
int tipc_nametbl_mc_translate(struct net *net, u32 type, u32 lower, u32 upper,
|
||||
u32 limit, struct list_head *dports);
|
||||
void tipc_nametbl_build_group(struct net *net, struct tipc_group *grp,
|
||||
u32 type, u32 domain);
|
||||
void tipc_nametbl_lookup_dst_nodes(struct net *net, u32 type, u32 lower,
|
||||
u32 upper, u32 domain,
|
||||
struct tipc_nlist *nodes);
|
||||
bool tipc_nametbl_lookup(struct net *net, u32 type, u32 instance, u32 domain,
|
||||
struct list_head *dsts, int *dstcnt, u32 exclude,
|
||||
bool all);
|
||||
struct publication *tipc_nametbl_publish(struct net *net, u32 type, u32 lower,
|
||||
u32 upper, u32 scope, u32 port_ref,
|
||||
u32 key);
|
||||
|
@ -120,16 +126,22 @@ void tipc_nametbl_unsubscribe(struct tipc_subscription *s);
|
|||
int tipc_nametbl_init(struct net *net);
|
||||
void tipc_nametbl_stop(struct net *net);
|
||||
|
||||
struct u32_item {
|
||||
struct tipc_dest {
|
||||
struct list_head list;
|
||||
u32 value;
|
||||
union {
|
||||
struct {
|
||||
u32 port;
|
||||
u32 node;
|
||||
};
|
||||
u64 value;
|
||||
};
|
||||
};
|
||||
|
||||
bool u32_push(struct list_head *l, u32 value);
|
||||
u32 u32_pop(struct list_head *l);
|
||||
bool u32_find(struct list_head *l, u32 value);
|
||||
bool u32_del(struct list_head *l, u32 value);
|
||||
void u32_list_purge(struct list_head *l);
|
||||
int u32_list_len(struct list_head *l);
|
||||
struct tipc_dest *tipc_dest_find(struct list_head *l, u32 node, u32 port);
|
||||
bool tipc_dest_push(struct list_head *l, u32 node, u32 port);
|
||||
bool tipc_dest_pop(struct list_head *l, u32 *node, u32 *port);
|
||||
bool tipc_dest_del(struct list_head *l, u32 node, u32 port);
|
||||
void tipc_dest_list_purge(struct list_head *l);
|
||||
int tipc_dest_list_len(struct list_head *l);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -157,7 +157,7 @@ static void tipc_node_timeout(unsigned long data);
|
|||
static void tipc_node_fsm_evt(struct tipc_node *n, int evt);
|
||||
static struct tipc_node *tipc_node_find(struct net *net, u32 addr);
|
||||
static void tipc_node_put(struct tipc_node *node);
|
||||
static bool tipc_node_is_up(struct tipc_node *n);
|
||||
static bool node_is_up(struct tipc_node *n);
|
||||
|
||||
struct tipc_sock_conn {
|
||||
u32 port;
|
||||
|
@ -657,7 +657,7 @@ static void __tipc_node_link_down(struct tipc_node *n, int *bearer_id,
|
|||
*slot1 = i;
|
||||
}
|
||||
|
||||
if (!tipc_node_is_up(n)) {
|
||||
if (!node_is_up(n)) {
|
||||
if (tipc_link_peer_is_down(l))
|
||||
tipc_node_fsm_evt(n, PEER_LOST_CONTACT_EVT);
|
||||
tipc_node_fsm_evt(n, SELF_LOST_CONTACT_EVT);
|
||||
|
@ -717,11 +717,27 @@ static void tipc_node_link_down(struct tipc_node *n, int bearer_id, bool delete)
|
|||
tipc_sk_rcv(n->net, &le->inputq);
|
||||
}
|
||||
|
||||
static bool tipc_node_is_up(struct tipc_node *n)
|
||||
static bool node_is_up(struct tipc_node *n)
|
||||
{
|
||||
return n->active_links[0] != INVALID_BEARER_ID;
|
||||
}
|
||||
|
||||
bool tipc_node_is_up(struct net *net, u32 addr)
|
||||
{
|
||||
struct tipc_node *n;
|
||||
bool retval = false;
|
||||
|
||||
if (in_own_node(net, addr))
|
||||
return true;
|
||||
|
||||
n = tipc_node_find(net, addr);
|
||||
if (!n)
|
||||
return false;
|
||||
retval = node_is_up(n);
|
||||
tipc_node_put(n);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void tipc_node_check_dest(struct net *net, u32 onode,
|
||||
struct tipc_bearer *b,
|
||||
u16 capabilities, u32 signature,
|
||||
|
@ -1149,7 +1165,7 @@ static int __tipc_nl_add_node(struct tipc_nl_msg *msg, struct tipc_node *node)
|
|||
|
||||
if (nla_put_u32(msg->skb, TIPC_NLA_NODE_ADDR, node->addr))
|
||||
goto attr_msg_full;
|
||||
if (tipc_node_is_up(node))
|
||||
if (node_is_up(node))
|
||||
if (nla_put_flag(msg->skb, TIPC_NLA_NODE_UP))
|
||||
goto attr_msg_full;
|
||||
|
||||
|
@ -1238,6 +1254,22 @@ int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dnode,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* tipc_node_distr_xmit(): send single buffer msgs to individual destinations
|
||||
* Note: this is only for SYSTEM_IMPORTANCE messages, which cannot be rejected
|
||||
*/
|
||||
int tipc_node_distr_xmit(struct net *net, struct sk_buff_head *xmitq)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
u32 selector, dnode;
|
||||
|
||||
while ((skb = __skb_dequeue(xmitq))) {
|
||||
selector = msg_origport(buf_msg(skb));
|
||||
dnode = msg_destnode(buf_msg(skb));
|
||||
tipc_node_xmit_skb(net, skb, dnode, selector);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tipc_node_broadcast(struct net *net, struct sk_buff *skb)
|
||||
{
|
||||
struct sk_buff *txskb;
|
||||
|
@ -1249,7 +1281,7 @@ void tipc_node_broadcast(struct net *net, struct sk_buff *skb)
|
|||
dst = n->addr;
|
||||
if (in_own_node(net, dst))
|
||||
continue;
|
||||
if (!tipc_node_is_up(n))
|
||||
if (!node_is_up(n))
|
||||
continue;
|
||||
txskb = pskb_copy(skb, GFP_ATOMIC);
|
||||
if (!txskb)
|
||||
|
|
|
@ -48,7 +48,8 @@ enum {
|
|||
TIPC_BCAST_SYNCH = (1 << 1),
|
||||
TIPC_BCAST_STATE_NACK = (1 << 2),
|
||||
TIPC_BLOCK_FLOWCTL = (1 << 3),
|
||||
TIPC_BCAST_RCAST = (1 << 4)
|
||||
TIPC_BCAST_RCAST = (1 << 4),
|
||||
TIPC_MCAST_GROUPS = (1 << 5)
|
||||
};
|
||||
|
||||
#define TIPC_NODE_CAPABILITIES (TIPC_BCAST_SYNCH | \
|
||||
|
@ -68,6 +69,7 @@ int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 node,
|
|||
char *linkname, size_t len);
|
||||
int tipc_node_xmit(struct net *net, struct sk_buff_head *list, u32 dnode,
|
||||
int selector);
|
||||
int tipc_node_distr_xmit(struct net *net, struct sk_buff_head *list);
|
||||
int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dest,
|
||||
u32 selector);
|
||||
void tipc_node_subscribe(struct net *net, struct list_head *subscr, u32 addr);
|
||||
|
@ -76,6 +78,7 @@ void tipc_node_broadcast(struct net *net, struct sk_buff *skb);
|
|||
int tipc_node_add_conn(struct net *net, u32 dnode, u32 port, u32 peer_port);
|
||||
void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port);
|
||||
int tipc_node_get_mtu(struct net *net, u32 addr, u32 sel);
|
||||
bool tipc_node_is_up(struct net *net, u32 addr);
|
||||
u16 tipc_node_get_capabilities(struct net *net, u32 addr);
|
||||
int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb);
|
||||
int tipc_nl_node_dump_link(struct sk_buff *skb, struct netlink_callback *cb);
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
#include "server.h"
|
||||
#include "core.h"
|
||||
#include "socket.h"
|
||||
#include "addr.h"
|
||||
#include "msg.h"
|
||||
#include <net/sock.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
|
@ -105,13 +107,11 @@ static void tipc_conn_kref_release(struct kref *kref)
|
|||
kernel_bind(sock, (struct sockaddr *)saddr, sizeof(*saddr));
|
||||
sock_release(sock);
|
||||
con->sock = NULL;
|
||||
|
||||
spin_lock_bh(&s->idr_lock);
|
||||
idr_remove(&s->conn_idr, con->conid);
|
||||
s->idr_in_use--;
|
||||
spin_unlock_bh(&s->idr_lock);
|
||||
}
|
||||
|
||||
spin_lock_bh(&s->idr_lock);
|
||||
idr_remove(&s->conn_idr, con->conid);
|
||||
s->idr_in_use--;
|
||||
spin_unlock_bh(&s->idr_lock);
|
||||
tipc_clean_outqueues(con);
|
||||
kfree(con);
|
||||
}
|
||||
|
@ -197,7 +197,8 @@ static void tipc_close_conn(struct tipc_conn *con)
|
|||
struct tipc_server *s = con->server;
|
||||
|
||||
if (test_and_clear_bit(CF_CONNECTED, &con->flags)) {
|
||||
tipc_unregister_callbacks(con);
|
||||
if (con->sock)
|
||||
tipc_unregister_callbacks(con);
|
||||
|
||||
if (con->conid)
|
||||
s->tipc_conn_release(con->conid, con->usr_data);
|
||||
|
@ -207,8 +208,8 @@ static void tipc_close_conn(struct tipc_conn *con)
|
|||
* are harmless for us here as we have already deleted this
|
||||
* connection from server connection list.
|
||||
*/
|
||||
kernel_sock_shutdown(con->sock, SHUT_RDWR);
|
||||
|
||||
if (con->sock)
|
||||
kernel_sock_shutdown(con->sock, SHUT_RDWR);
|
||||
conn_put(con);
|
||||
}
|
||||
}
|
||||
|
@ -487,38 +488,104 @@ void tipc_conn_terminate(struct tipc_server *s, int conid)
|
|||
}
|
||||
}
|
||||
|
||||
bool tipc_topsrv_kern_subscr(struct net *net, u32 port, u32 type,
|
||||
u32 lower, u32 upper, int *conid)
|
||||
{
|
||||
struct tipc_subscriber *scbr;
|
||||
struct tipc_subscr sub;
|
||||
struct tipc_server *s;
|
||||
struct tipc_conn *con;
|
||||
|
||||
sub.seq.type = type;
|
||||
sub.seq.lower = lower;
|
||||
sub.seq.upper = upper;
|
||||
sub.timeout = TIPC_WAIT_FOREVER;
|
||||
sub.filter = TIPC_SUB_PORTS;
|
||||
*(u32 *)&sub.usr_handle = port;
|
||||
|
||||
con = tipc_alloc_conn(tipc_topsrv(net));
|
||||
if (!con)
|
||||
return false;
|
||||
|
||||
*conid = con->conid;
|
||||
s = con->server;
|
||||
scbr = s->tipc_conn_new(*conid);
|
||||
if (!scbr) {
|
||||
tipc_close_conn(con);
|
||||
return false;
|
||||
}
|
||||
|
||||
con->usr_data = scbr;
|
||||
con->sock = NULL;
|
||||
s->tipc_conn_recvmsg(net, *conid, NULL, scbr, &sub, sizeof(sub));
|
||||
return true;
|
||||
}
|
||||
|
||||
void tipc_topsrv_kern_unsubscr(struct net *net, int conid)
|
||||
{
|
||||
struct tipc_conn *con;
|
||||
|
||||
con = tipc_conn_lookup(tipc_topsrv(net), conid);
|
||||
if (!con)
|
||||
return;
|
||||
tipc_close_conn(con);
|
||||
conn_put(con);
|
||||
}
|
||||
|
||||
static void tipc_send_kern_top_evt(struct net *net, struct tipc_event *evt)
|
||||
{
|
||||
u32 port = *(u32 *)&evt->s.usr_handle;
|
||||
u32 self = tipc_own_addr(net);
|
||||
struct sk_buff_head evtq;
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = tipc_msg_create(TOP_SRV, 0, INT_H_SIZE, sizeof(*evt),
|
||||
self, self, port, port, 0);
|
||||
if (!skb)
|
||||
return;
|
||||
msg_set_dest_droppable(buf_msg(skb), true);
|
||||
memcpy(msg_data(buf_msg(skb)), evt, sizeof(*evt));
|
||||
skb_queue_head_init(&evtq);
|
||||
__skb_queue_tail(&evtq, skb);
|
||||
tipc_sk_rcv(net, &evtq);
|
||||
}
|
||||
|
||||
static void tipc_send_to_sock(struct tipc_conn *con)
|
||||
{
|
||||
int count = 0;
|
||||
struct tipc_server *s = con->server;
|
||||
struct outqueue_entry *e;
|
||||
struct tipc_event *evt;
|
||||
struct msghdr msg;
|
||||
int count = 0;
|
||||
int ret;
|
||||
|
||||
spin_lock_bh(&con->outqueue_lock);
|
||||
while (test_bit(CF_CONNECTED, &con->flags)) {
|
||||
e = list_entry(con->outqueue.next, struct outqueue_entry,
|
||||
list);
|
||||
e = list_entry(con->outqueue.next, struct outqueue_entry, list);
|
||||
if ((struct list_head *) e == &con->outqueue)
|
||||
break;
|
||||
|
||||
spin_unlock_bh(&con->outqueue_lock);
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_flags = MSG_DONTWAIT;
|
||||
|
||||
if (s->type == SOCK_DGRAM || s->type == SOCK_RDM) {
|
||||
msg.msg_name = &e->dest;
|
||||
msg.msg_namelen = sizeof(struct sockaddr_tipc);
|
||||
if (con->sock) {
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_flags = MSG_DONTWAIT;
|
||||
if (s->type == SOCK_DGRAM || s->type == SOCK_RDM) {
|
||||
msg.msg_name = &e->dest;
|
||||
msg.msg_namelen = sizeof(struct sockaddr_tipc);
|
||||
}
|
||||
ret = kernel_sendmsg(con->sock, &msg, &e->iov, 1,
|
||||
e->iov.iov_len);
|
||||
if (ret == -EWOULDBLOCK || ret == 0) {
|
||||
cond_resched();
|
||||
goto out;
|
||||
} else if (ret < 0) {
|
||||
goto send_err;
|
||||
}
|
||||
} else {
|
||||
evt = e->iov.iov_base;
|
||||
tipc_send_kern_top_evt(s->net, evt);
|
||||
}
|
||||
ret = kernel_sendmsg(con->sock, &msg, &e->iov, 1,
|
||||
e->iov.iov_len);
|
||||
if (ret == -EWOULDBLOCK || ret == 0) {
|
||||
cond_resched();
|
||||
goto out;
|
||||
} else if (ret < 0) {
|
||||
goto send_err;
|
||||
}
|
||||
|
||||
/* Don't starve users filling buffers */
|
||||
if (++count >= MAX_SEND_MSG_COUNT) {
|
||||
cond_resched();
|
||||
|
|
|
@ -83,13 +83,16 @@ struct tipc_server {
|
|||
int tipc_conn_sendmsg(struct tipc_server *s, int conid,
|
||||
struct sockaddr_tipc *addr, void *data, size_t len);
|
||||
|
||||
bool tipc_topsrv_kern_subscr(struct net *net, u32 port, u32 type,
|
||||
u32 lower, u32 upper, int *conid);
|
||||
void tipc_topsrv_kern_unsubscr(struct net *net, int conid);
|
||||
|
||||
/**
|
||||
* tipc_conn_terminate - terminate connection with server
|
||||
*
|
||||
* Note: Must call it in process context since it might sleep
|
||||
*/
|
||||
void tipc_conn_terminate(struct tipc_server *s, int conid);
|
||||
|
||||
int tipc_server_start(struct tipc_server *s);
|
||||
|
||||
void tipc_server_stop(struct tipc_server *s);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue