Commit a00344bd authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 2d0d21c1 04d7b574
...@@ -231,6 +231,21 @@ struct sockaddr_tipc { ...@@ -231,6 +231,21 @@ struct sockaddr_tipc {
#define TIPC_SOCK_RECVQ_DEPTH 132 /* Default: none (read only) */ #define TIPC_SOCK_RECVQ_DEPTH 132 /* Default: none (read only) */
#define TIPC_MCAST_BROADCAST 133 /* Default: TIPC selects. No arg */ #define TIPC_MCAST_BROADCAST 133 /* Default: TIPC selects. No arg */
#define TIPC_MCAST_REPLICAST 134 /* 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) * Maximum sizes of TIPC bearer-related names (including terminating NULL)
......
...@@ -8,7 +8,7 @@ tipc-y += addr.o bcast.o bearer.o \ ...@@ -8,7 +8,7 @@ tipc-y += addr.o bcast.o bearer.o \
core.o link.o discover.o msg.o \ core.o link.o discover.o msg.o \
name_distr.o subscr.o monitor.o name_table.o net.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 \ 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_UDP) += udp_media.o
tipc-$(CONFIG_TIPC_MEDIA_IB) += ib_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, ...@@ -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, static int tipc_rcast_xmit(struct net *net, struct sk_buff_head *pkts,
struct tipc_nlist *dests, u16 *cong_link_cnt) struct tipc_nlist *dests, u16 *cong_link_cnt)
{ {
struct tipc_dest *dst, *tmp;
struct sk_buff_head _pkts; struct sk_buff_head _pkts;
struct u32_item *n, *tmp; u32 dnode, selector;
u32 dst, selector;
selector = msg_link_selector(buf_msg(skb_peek(pkts))); selector = msg_link_selector(buf_msg(skb_peek(pkts)));
skb_queue_head_init(&_pkts); skb_queue_head_init(&_pkts);
list_for_each_entry_safe(n, tmp, &dests->list, list) { list_for_each_entry_safe(dst, tmp, &dests->list, list) {
dst = n->value; dnode = dst->node;
if (!tipc_msg_pskb_copy(dst, pkts, &_pkts)) if (!tipc_msg_pskb_copy(dnode, pkts, &_pkts))
return -ENOMEM; return -ENOMEM;
/* Any other return value than -ELINKCONG is ignored */ /* 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)++; (*cong_link_cnt)++;
} }
return 0; return 0;
...@@ -554,7 +554,7 @@ void tipc_nlist_add(struct tipc_nlist *nl, u32 node) ...@@ -554,7 +554,7 @@ void tipc_nlist_add(struct tipc_nlist *nl, u32 node)
{ {
if (node == nl->self) if (node == nl->self)
nl->local = true; nl->local = true;
else if (u32_push(&nl->list, node)) else if (tipc_dest_push(&nl->list, node, 0))
nl->remote++; nl->remote++;
} }
...@@ -562,13 +562,13 @@ void tipc_nlist_del(struct tipc_nlist *nl, u32 node) ...@@ -562,13 +562,13 @@ void tipc_nlist_del(struct tipc_nlist *nl, u32 node)
{ {
if (node == nl->self) if (node == nl->self)
nl->local = false; nl->local = false;
else if (u32_del(&nl->list, node)) else if (tipc_dest_del(&nl->list, node, 0))
nl->remote--; nl->remote--;
} }
void tipc_nlist_purge(struct tipc_nlist *nl) void tipc_nlist_purge(struct tipc_nlist *nl)
{ {
u32_list_purge(&nl->list); tipc_dest_list_purge(&nl->list);
nl->remote = 0; nl->remote = 0;
nl->local = 0; nl->local = 0;
} }
...@@ -132,6 +132,11 @@ static inline struct list_head *tipc_nodes(struct net *net) ...@@ -132,6 +132,11 @@ static inline struct list_head *tipc_nodes(struct net *net)
return &tipc_net(net)->node_list; 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) static inline unsigned int tipc_hashfn(u32 addr)
{ {
return addr & (NODE_HTABLE_SIZE - 1); return addr & (NODE_HTABLE_SIZE - 1);
......
This diff is collapsed.
/*
* 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, ...@@ -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, static bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb,
struct sk_buff_head *inputq) struct sk_buff_head *inputq)
{ {
struct sk_buff_head *mc_inputq = l->bc_rcvlink->inputq;
struct tipc_msg *hdr = buf_msg(skb); struct tipc_msg *hdr = buf_msg(skb);
switch (msg_user(hdr)) { switch (msg_user(hdr)) {
...@@ -1046,12 +1047,14 @@ static bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb, ...@@ -1046,12 +1047,14 @@ static bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb,
case TIPC_MEDIUM_IMPORTANCE: case TIPC_MEDIUM_IMPORTANCE:
case TIPC_HIGH_IMPORTANCE: case TIPC_HIGH_IMPORTANCE:
case TIPC_CRITICAL_IMPORTANCE: case TIPC_CRITICAL_IMPORTANCE:
if (unlikely(msg_type(hdr) == TIPC_MCAST_MSG)) { if (unlikely(msg_in_group(hdr) || msg_mcast(hdr))) {
skb_queue_tail(l->bc_rcvlink->inputq, skb); skb_queue_tail(mc_inputq, skb);
return true; return true;
} }
case CONN_MANAGER: case CONN_MANAGER:
skb_queue_tail(inputq, skb); return true;
case GROUP_PROTOCOL:
skb_queue_tail(mc_inputq, skb);
return true; return true;
case NAME_DISTRIBUTOR: case NAME_DISTRIBUTOR:
l->bc_rcvlink->state = LINK_ESTABLISHED; l->bc_rcvlink->state = LINK_ESTABLISHED;
......
...@@ -666,3 +666,10 @@ void __tipc_skb_queue_sorted(struct sk_buff_head *list, u16 seqno, ...@@ -666,3 +666,10 @@ void __tipc_skb_queue_sorted(struct sk_buff_head *list, u16 seqno,
} }
kfree_skb(skb); 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);
}
/* /*
* net/tipc/msg.h: Include file for TIPC message header routines * 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 * Copyright (c) 2005-2008, 2010-2011, Wind River Systems
* All rights reserved. * All rights reserved.
* *
...@@ -61,10 +61,14 @@ struct plist; ...@@ -61,10 +61,14 @@ struct plist;
/* /*
* Payload message types * Payload message types
*/ */
#define TIPC_CONN_MSG 0 #define TIPC_CONN_MSG 0
#define TIPC_MCAST_MSG 1 #define TIPC_MCAST_MSG 1
#define TIPC_NAMED_MSG 2 #define TIPC_NAMED_MSG 2
#define TIPC_DIRECT_MSG 3 #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 * Internal message users
...@@ -73,11 +77,13 @@ struct plist; ...@@ -73,11 +77,13 @@ struct plist;
#define MSG_BUNDLER 6 #define MSG_BUNDLER 6
#define LINK_PROTOCOL 7 #define LINK_PROTOCOL 7
#define CONN_MANAGER 8 #define CONN_MANAGER 8
#define GROUP_PROTOCOL 9
#define TUNNEL_PROTOCOL 10 #define TUNNEL_PROTOCOL 10
#define NAME_DISTRIBUTOR 11 #define NAME_DISTRIBUTOR 11
#define MSG_FRAGMENTER 12 #define MSG_FRAGMENTER 12
#define LINK_CONFIG 13 #define LINK_CONFIG 13
#define SOCK_WAKEUP 14 /* pseudo user */ #define SOCK_WAKEUP 14 /* pseudo user */
#define TOP_SRV 15 /* pseudo user */
/* /*
* Message header sizes * Message header sizes
...@@ -86,6 +92,7 @@ struct plist; ...@@ -86,6 +92,7 @@ struct plist;
#define BASIC_H_SIZE 32 /* Basic payload message */ #define BASIC_H_SIZE 32 /* Basic payload message */
#define NAMED_H_SIZE 40 /* Named payload message */ #define NAMED_H_SIZE 40 /* Named payload message */
#define MCAST_H_SIZE 44 /* Multicast 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 INT_H_SIZE 40 /* Internal messages */
#define MIN_H_SIZE 24 /* Smallest legal TIPC header size */ #define MIN_H_SIZE 24 /* Smallest legal TIPC header size */
#define MAX_H_SIZE 60 /* Largest possible TIPC header size */ #define MAX_H_SIZE 60 /* Largest possible TIPC header size */
...@@ -96,6 +103,7 @@ struct plist; ...@@ -96,6 +103,7 @@ struct plist;
struct tipc_skb_cb { struct tipc_skb_cb {
u32 bytes_read; u32 bytes_read;
u32 orig_member;
struct sk_buff *tail; struct sk_buff *tail;
bool validated; bool validated;
u16 chain_imp; u16 chain_imp;
...@@ -188,6 +196,11 @@ static inline u32 msg_size(struct tipc_msg *m) ...@@ -188,6 +196,11 @@ static inline u32 msg_size(struct tipc_msg *m)
return msg_bits(m, 0, 0, 0x1ffff); 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) static inline u32 msg_data_sz(struct tipc_msg *m)
{ {
return msg_size(m) - msg_hdr_sz(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) ...@@ -251,6 +264,18 @@ static inline void msg_set_type(struct tipc_msg *m, u32 n)
msg_set_bits(m, 1, 29, 0x7, 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) static inline u32 msg_named(struct tipc_msg *m)
{ {
return msg_type(m) == TIPC_NAMED_MSG; return msg_type(m) == TIPC_NAMED_MSG;
...@@ -258,7 +283,10 @@ static inline u32 msg_named(struct tipc_msg *m) ...@@ -258,7 +283,10 @@ static inline u32 msg_named(struct tipc_msg *m)
static inline u32 msg_mcast(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) 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) ...@@ -513,6 +541,16 @@ static inline void msg_set_nameupper(struct tipc_msg *m, u32 n)
#define DSC_REQ_MSG 0 #define DSC_REQ_MSG 0
#define DSC_RESP_MSG 1 #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 * Word 1
*/ */
...@@ -764,12 +802,12 @@ static inline void msg_set_conn_ack(struct tipc_msg *m, u32 n) ...@@ -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); 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); 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); 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) ...@@ -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); 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) static inline bool msg_peer_link_is_up(struct tipc_msg *m)
{ {
if (likely(msg_user(m) != LINK_PROTOCOL)) if (likely(msg_user(m) != LINK_PROTOCOL))
...@@ -818,6 +918,8 @@ static inline bool msg_is_reset(struct tipc_msg *hdr) ...@@ -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); struct sk_buff *tipc_buf_acquire(u32 size, gfp_t gfp);
bool tipc_msg_validate(struct sk_buff *skb); bool tipc_msg_validate(struct sk_buff *skb);
bool tipc_msg_reverse(u32 own_addr, struct sk_buff **skb, int err); 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, void tipc_msg_init(u32 own_addr, struct tipc_msg *m, u32 user, u32 type,
u32 hsize, u32 destnode); u32 hsize, u32 destnode);
struct sk_buff *tipc_msg_create(uint user, uint type, uint hdr_sz, struct sk_buff *tipc_msg_create(uint user, uint type, uint hdr_sz,
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include "bcast.h" #include "bcast.h"
#include "addr.h" #include "addr.h"
#include "node.h" #include "node.h"
#include "group.h"
#include <net/genetlink.h> #include <net/genetlink.h>
#define TIPC_NAMETBL_SIZE 1024 /* must be a power of 2 */ #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, ...@@ -596,18 +597,47 @@ u32 tipc_nametbl_translate(struct net *net, u32 type, u32 instance,
return ref; return ref;
} }
/** bool tipc_nametbl_lookup(struct net *net, u32 type, u32 instance, u32 domain,
* tipc_nametbl_mc_translate - find multicast destinations struct list_head *dsts, int *dstcnt, u32 exclude,
* bool all)
* Creates list of all local ports that overlap the given multicast address; {
* also determines if any off-node ports overlap. u32 self = tipc_own_addr(net);
* struct publication *publ;
* Note: Publications with a scope narrower than 'limit' are ignored. struct name_info *info;
* (i.e. local node-scope publications mustn't receive messages arriving struct name_seq *seq;
* from another node, even if the multcast link brought it here) struct sub_seq *sseq;
*
* Returns non-zero if any off-node ports overlap 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, int tipc_nametbl_mc_translate(struct net *net, u32 type, u32 lower, u32 upper,
u32 limit, struct list_head *dports) u32 limit, struct list_head *dports)
{ {
...@@ -634,7 +664,7 @@ int tipc_nametbl_mc_translate(struct net *net, u32 type, u32 lower, u32 upper, ...@@ -634,7 +664,7 @@ int tipc_nametbl_mc_translate(struct net *net, u32 type, u32 lower, u32 upper,
info = sseq->info; info = sseq->info;
list_for_each_entry(publ, &info->node_list, node_list) { list_for_each_entry(publ, &info->node_list, node_list) {
if (publ->scope <= limit) 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) 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, ...@@ -679,6 +709,37 @@ void tipc_nametbl_lookup_dst_nodes(struct net *net, u32 type, u32 lower,
rcu_read_unlock(); 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 * 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) ...@@ -1057,78 +1118,79 @@ int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len; 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) { list_for_each_entry(dst, l, list) {
if (item->value == value) if (dst->value != value)
return true; 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 (tipc_dest_find(l, node, port))
if (item->value == value)
return false;
}
item = kmalloc(sizeof(*item), GFP_ATOMIC);
if (unlikely(!item))
return false; return false;
item->value = value; dst = kmalloc(sizeof(*dst), GFP_ATOMIC);
list_add(&item->list, l); if (unlikely(!dst))
return false;
dst->value = value;
list_add(&dst->list, l);
return true; 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; struct tipc_dest *dst;
u32 value = 0;
if (list_empty(l)) if (list_empty(l))
return 0; return false;
item = list_first_entry(l, typeof(*item), list); dst = list_first_entry(l, typeof(*dst), list);
value = item->value; if (port)
list_del(&item->list); *port = dst->port;
kfree(item); if (node)
return value; *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) { dst = tipc_dest_find(l, node, port);
if (item->value != value) if (!dst)
continue; return false;
list_del(&item->list); list_del(&dst->list);
kfree(item); kfree(dst);
return true; return true;
}
return false;
} }
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_for_each_entry_safe(dst, tmp, l, list) {
list_del(&item->list); list_del(&dst->list);
kfree(item); 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; int i = 0;
list_for_each_entry(item, l, list) { list_for_each_entry(dst, l, list) {
i++; i++;
} }
return i; return i;
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
struct tipc_subscription; struct tipc_subscription;
struct tipc_plist; struct tipc_plist;
struct tipc_nlist; struct tipc_nlist;
struct tipc_group;
/* /*
* TIPC name types reserved for internal TIPC use (both current and planned) * 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); ...@@ -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); 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, int tipc_nametbl_mc_translate(struct net *net, u32 type, u32 lower, u32 upper,
u32 limit, struct list_head *dports); 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, void tipc_nametbl_lookup_dst_nodes(struct net *net, u32 type, u32 lower,
u32 upper, u32 domain, u32 upper, u32 domain,
struct tipc_nlist *nodes); 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, struct publication *tipc_nametbl_publish(struct net *net, u32 type, u32 lower,
u32 upper, u32 scope, u32 port_ref, u32 upper, u32 scope, u32 port_ref,
u32 key); u32 key);
...@@ -120,16 +126,22 @@ void tipc_nametbl_unsubscribe(struct tipc_subscription *s); ...@@ -120,16 +126,22 @@ void tipc_nametbl_unsubscribe(struct tipc_subscription *s);
int tipc_nametbl_init(struct net *net); int tipc_nametbl_init(struct net *net);
void tipc_nametbl_stop(struct net *net); void tipc_nametbl_stop(struct net *net);
struct u32_item { struct tipc_dest {
struct list_head list; struct list_head list;
u32 value; union {
struct {
u32 port;
u32 node;
};
u64 value;
};
}; };
bool u32_push(struct list_head *l, u32 value); struct tipc_dest *tipc_dest_find(struct list_head *l, u32 node, u32 port);
u32 u32_pop(struct list_head *l); bool tipc_dest_push(struct list_head *l, u32 node, u32 port);
bool u32_find(struct list_head *l, u32 value); bool tipc_dest_pop(struct list_head *l, u32 *node, u32 *port);
bool u32_del(struct list_head *l, u32 value); bool tipc_dest_del(struct list_head *l, u32 node, u32 port);
void u32_list_purge(struct list_head *l); void tipc_dest_list_purge(struct list_head *l);
int u32_list_len(struct list_head *l); int tipc_dest_list_len(struct list_head *l);
#endif #endif
...@@ -157,7 +157,7 @@ static void tipc_node_timeout(unsigned long data); ...@@ -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 void tipc_node_fsm_evt(struct tipc_node *n, int evt);
static struct tipc_node *tipc_node_find(struct net *net, u32 addr); static struct tipc_node *tipc_node_find(struct net *net, u32 addr);
static void tipc_node_put(struct tipc_node *node); 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 { struct tipc_sock_conn {
u32 port; u32 port;
...@@ -657,7 +657,7 @@ static void __tipc_node_link_down(struct tipc_node *n, int *bearer_id, ...@@ -657,7 +657,7 @@ static void __tipc_node_link_down(struct tipc_node *n, int *bearer_id,
*slot1 = i; *slot1 = i;
} }
if (!tipc_node_is_up(n)) { if (!node_is_up(n)) {
if (tipc_link_peer_is_down(l)) if (tipc_link_peer_is_down(l))
tipc_node_fsm_evt(n, PEER_LOST_CONTACT_EVT); tipc_node_fsm_evt(n, PEER_LOST_CONTACT_EVT);
tipc_node_fsm_evt(n, SELF_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) ...@@ -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); 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; 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, void tipc_node_check_dest(struct net *net, u32 onode,
struct tipc_bearer *b, struct tipc_bearer *b,
u16 capabilities, u32 signature, u16 capabilities, u32 signature,
...@@ -1149,7 +1165,7 @@ static int __tipc_nl_add_node(struct tipc_nl_msg *msg, struct tipc_node *node) ...@@ -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)) if (nla_put_u32(msg->skb, TIPC_NLA_NODE_ADDR, node->addr))
goto attr_msg_full; 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)) if (nla_put_flag(msg->skb, TIPC_NLA_NODE_UP))
goto attr_msg_full; goto attr_msg_full;
...@@ -1238,6 +1254,22 @@ int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dnode, ...@@ -1238,6 +1254,22 @@ int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dnode,
return 0; 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) void tipc_node_broadcast(struct net *net, struct sk_buff *skb)
{ {
struct sk_buff *txskb; struct sk_buff *txskb;
...@@ -1249,7 +1281,7 @@ void tipc_node_broadcast(struct net *net, struct sk_buff *skb) ...@@ -1249,7 +1281,7 @@ void tipc_node_broadcast(struct net *net, struct sk_buff *skb)
dst = n->addr; dst = n->addr;
if (in_own_node(net, dst)) if (in_own_node(net, dst))
continue; continue;
if (!tipc_node_is_up(n)) if (!node_is_up(n))
continue; continue;
txskb = pskb_copy(skb, GFP_ATOMIC); txskb = pskb_copy(skb, GFP_ATOMIC);
if (!txskb) if (!txskb)
......
...@@ -48,7 +48,8 @@ enum { ...@@ -48,7 +48,8 @@ enum {
TIPC_BCAST_SYNCH = (1 << 1), TIPC_BCAST_SYNCH = (1 << 1),
TIPC_BCAST_STATE_NACK = (1 << 2), TIPC_BCAST_STATE_NACK = (1 << 2),
TIPC_BLOCK_FLOWCTL = (1 << 3), 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 | \ #define TIPC_NODE_CAPABILITIES (TIPC_BCAST_SYNCH | \
...@@ -68,6 +69,7 @@ int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 node, ...@@ -68,6 +69,7 @@ int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 node,
char *linkname, size_t len); char *linkname, size_t len);
int tipc_node_xmit(struct net *net, struct sk_buff_head *list, u32 dnode, int tipc_node_xmit(struct net *net, struct sk_buff_head *list, u32 dnode,
int selector); 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, int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dest,
u32 selector); u32 selector);
void tipc_node_subscribe(struct net *net, struct list_head *subscr, u32 addr); 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); ...@@ -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); 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); void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port);
int tipc_node_get_mtu(struct net *net, u32 addr, u32 sel); 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); 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(struct sk_buff *skb, struct netlink_callback *cb);
int tipc_nl_node_dump_link(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 @@ ...@@ -36,6 +36,8 @@
#include "server.h" #include "server.h"
#include "core.h" #include "core.h"
#include "socket.h" #include "socket.h"
#include "addr.h"
#include "msg.h"
#include <net/sock.h> #include <net/sock.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -105,13 +107,11 @@ static void tipc_conn_kref_release(struct kref *kref) ...@@ -105,13 +107,11 @@ static void tipc_conn_kref_release(struct kref *kref)
kernel_bind(sock, (struct sockaddr *)saddr, sizeof(*saddr)); kernel_bind(sock, (struct sockaddr *)saddr, sizeof(*saddr));
sock_release(sock); sock_release(sock);
con->sock = NULL; 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); tipc_clean_outqueues(con);
kfree(con); kfree(con);
} }
...@@ -197,7 +197,8 @@ static void tipc_close_conn(struct tipc_conn *con) ...@@ -197,7 +197,8 @@ static void tipc_close_conn(struct tipc_conn *con)
struct tipc_server *s = con->server; struct tipc_server *s = con->server;
if (test_and_clear_bit(CF_CONNECTED, &con->flags)) { if (test_and_clear_bit(CF_CONNECTED, &con->flags)) {
tipc_unregister_callbacks(con); if (con->sock)
tipc_unregister_callbacks(con);
if (con->conid) if (con->conid)
s->tipc_conn_release(con->conid, con->usr_data); s->tipc_conn_release(con->conid, con->usr_data);
...@@ -207,8 +208,8 @@ static void tipc_close_conn(struct tipc_conn *con) ...@@ -207,8 +208,8 @@ static void tipc_close_conn(struct tipc_conn *con)
* are harmless for us here as we have already deleted this * are harmless for us here as we have already deleted this
* connection from server connection list. * 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); conn_put(con);
} }
} }
...@@ -487,38 +488,104 @@ void tipc_conn_terminate(struct tipc_server *s, int conid) ...@@ -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) static void tipc_send_to_sock(struct tipc_conn *con)
{ {
int count = 0;
struct tipc_server *s = con->server; struct tipc_server *s = con->server;
struct outqueue_entry *e; struct outqueue_entry *e;
struct tipc_event *evt;
struct msghdr msg; struct msghdr msg;
int count = 0;
int ret; int ret;
spin_lock_bh(&con->outqueue_lock); spin_lock_bh(&con->outqueue_lock);
while (test_bit(CF_CONNECTED, &con->flags)) { while (test_bit(CF_CONNECTED, &con->flags)) {
e = list_entry(con->outqueue.next, struct outqueue_entry, e = list_entry(con->outqueue.next, struct outqueue_entry, list);
list);
if ((struct list_head *) e == &con->outqueue) if ((struct list_head *) e == &con->outqueue)
break; break;
spin_unlock_bh(&con->outqueue_lock);
memset(&msg, 0, sizeof(msg)); spin_unlock_bh(&con->outqueue_lock);
msg.msg_flags = MSG_DONTWAIT;
if (s->type == SOCK_DGRAM || s->type == SOCK_RDM) { if (con->sock) {
msg.msg_name = &e->dest; memset(&msg, 0, sizeof(msg));
msg.msg_namelen = sizeof(struct sockaddr_tipc); msg.msg_flags = MSG_DONTWAIT;
} if (s->type == SOCK_DGRAM || s->type == SOCK_RDM) {
ret = kernel_sendmsg(con->sock, &msg, &e->iov, 1, msg.msg_name = &e->dest;
e->iov.iov_len); msg.msg_namelen = sizeof(struct sockaddr_tipc);
if (ret == -EWOULDBLOCK || ret == 0) { }
cond_resched(); ret = kernel_sendmsg(con->sock, &msg, &e->iov, 1,
goto out; e->iov.iov_len);
} else if (ret < 0) { if (ret == -EWOULDBLOCK || ret == 0) {
goto send_err; 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);
} }
/* Don't starve users filling buffers */ /* Don't starve users filling buffers */
if (++count >= MAX_SEND_MSG_COUNT) { if (++count >= MAX_SEND_MSG_COUNT) {
cond_resched(); cond_resched();
......
...@@ -83,13 +83,16 @@ struct tipc_server { ...@@ -83,13 +83,16 @@ struct tipc_server {
int tipc_conn_sendmsg(struct tipc_server *s, int conid, int tipc_conn_sendmsg(struct tipc_server *s, int conid,
struct sockaddr_tipc *addr, void *data, size_t len); 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 * tipc_conn_terminate - terminate connection with server
* *
* Note: Must call it in process context since it might sleep * Note: Must call it in process context since it might sleep
*/ */
void tipc_conn_terminate(struct tipc_server *s, int conid); void tipc_conn_terminate(struct tipc_server *s, int conid);
int tipc_server_start(struct tipc_server *s); int tipc_server_start(struct tipc_server *s);
void tipc_server_stop(struct tipc_server *s); void tipc_server_stop(struct tipc_server *s);
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment