Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# TIPC configuration
#
menuconfig TIPC
tristate "The TIPC Protocol"
depends on INET
help
The Transparent Inter Process Communication (TIPC) protocol is
specially designed for intra cluster communication. This protocol
originates from Ericsson where it has been used in carrier grade
cluster applications for many years.
For more information about TIPC, see http://tipc.sourceforge.net.
This protocol support is also available as a module ( = code which
can be inserted in and removed from the running kernel whenever you
want). The module will be called tipc. If you want to compile it
as a module, say M here and read <file:Documentation/kbuild/modules.rst>.
If in doubt, say N.
config TIPC_MEDIA_IB
bool "InfiniBand media type support"
depends on TIPC && INFINIBAND_IPOIB
help
Saying Y here will enable support for running TIPC on
IP-over-InfiniBand devices.
config TIPC_MEDIA_UDP
bool "IP/UDP media type support"
depends on TIPC
select NET_UDP_TUNNEL
default y
help
Saying Y here will enable support for running TIPC over IP/UDP
config TIPC_CRYPTO
bool "TIPC encryption support"
depends on TIPC
select CRYPTO
select CRYPTO_AES
select CRYPTO_GCM
default y
help
Saying Y here will enable support for TIPC encryption.
All TIPC messages will be encrypted/decrypted by using the currently most
advanced algorithm: AEAD AES-GCM (like IPSec or TLS) before leaving/
entering the TIPC stack.
Key setting from user-space is performed via netlink by a user program
(e.g. the iproute2 'tipc' tool).
config TIPC_DIAG
tristate "TIPC: socket monitoring interface"
depends on TIPC
default y
help
Support for TIPC socket monitoring interface used by ss tool.
If unsure, say Y.
+22
View File
@@ -0,0 +1,22 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the Linux TIPC layer
#
obj-$(CONFIG_TIPC) := tipc.o
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 \
topsrv.o group.o trace.o
CFLAGS_trace.o += -I$(src)
tipc-$(CONFIG_TIPC_MEDIA_UDP) += udp_media.o
tipc-$(CONFIG_TIPC_MEDIA_IB) += ib_media.o
tipc-$(CONFIG_SYSCTL) += sysctl.o
tipc-$(CONFIG_TIPC_CRYPTO) += crypto.o
obj-$(CONFIG_TIPC_DIAG) += tipc_diag.o
tipc_diag-y += diag.o
+124
View File
@@ -0,0 +1,124 @@
/*
* net/tipc/addr.c: TIPC address utility routines
*
* Copyright (c) 2000-2006, 2018, Ericsson AB
* Copyright (c) 2004-2005, 2010-2011, Wind River Systems
* Copyright (c) 2020-2021, Red Hat Inc
* 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 "addr.h"
#include "core.h"
bool tipc_in_scope(bool legacy_format, u32 domain, u32 addr)
{
if (!domain || (domain == addr))
return true;
if (!legacy_format)
return false;
if (domain == tipc_cluster_mask(addr)) /* domain <Z.C.0> */
return true;
if (domain == (addr & TIPC_ZONE_CLUSTER_MASK)) /* domain <Z.C.0> */
return true;
if (domain == (addr & TIPC_ZONE_MASK)) /* domain <Z.0.0> */
return true;
return false;
}
void tipc_set_node_id(struct net *net, u8 *id)
{
struct tipc_net *tn = tipc_net(net);
memcpy(tn->node_id, id, NODE_ID_LEN);
tipc_nodeid2string(tn->node_id_string, id);
tn->trial_addr = hash128to32(id);
pr_info("Node identity %s, cluster identity %u\n",
tipc_own_id_string(net), tn->net_id);
}
void tipc_set_node_addr(struct net *net, u32 addr)
{
struct tipc_net *tn = tipc_net(net);
u8 node_id[NODE_ID_LEN] = {0,};
tn->node_addr = addr;
if (!tipc_own_id(net)) {
sprintf(node_id, "%x", addr);
tipc_set_node_id(net, node_id);
}
tn->trial_addr = addr;
tn->addr_trial_end = jiffies;
pr_info("Node number set to %u\n", addr);
}
int tipc_nodeid2string(char *str, u8 *id)
{
int i;
u8 c;
/* Already a string ? */
for (i = 0; i < NODE_ID_LEN; i++) {
c = id[i];
if (c >= '0' && c <= '9')
continue;
if (c >= 'A' && c <= 'Z')
continue;
if (c >= 'a' && c <= 'z')
continue;
if (c == '.')
continue;
if (c == ':')
continue;
if (c == '_')
continue;
if (c == '-')
continue;
if (c == '@')
continue;
if (c != 0)
break;
}
if (i == NODE_ID_LEN) {
memcpy(str, id, NODE_ID_LEN);
str[NODE_ID_LEN] = 0;
return i;
}
/* Translate to hex string */
for (i = 0; i < NODE_ID_LEN; i++)
sprintf(&str[2 * i], "%02x", id[i]);
/* Strip off trailing zeroes */
for (i = NODE_ID_STR_LEN - 2; str[i] == '0'; i--)
str[i] = 0;
return i + 1;
}
+135
View File
@@ -0,0 +1,135 @@
/*
* net/tipc/addr.h: Include file for TIPC address utility routines
*
* Copyright (c) 2000-2006, 2018, Ericsson AB
* Copyright (c) 2004-2005, Wind River Systems
* Copyright (c) 2020-2021, Red Hat Inc
* 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_ADDR_H
#define _TIPC_ADDR_H
#include <linux/types.h>
#include <linux/tipc.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include "core.h"
/* Struct tipc_uaddr: internal version of struct sockaddr_tipc.
* Must be kept aligned both regarding field positions and size.
*/
struct tipc_uaddr {
unsigned short family;
unsigned char addrtype;
signed char scope;
union {
struct {
struct tipc_service_addr sa;
u32 lookup_node;
};
struct tipc_service_range sr;
struct tipc_socket_addr sk;
};
};
static inline void tipc_uaddr(struct tipc_uaddr *ua, u32 atype, u32 scope,
u32 type, u32 lower, u32 upper)
{
ua->family = AF_TIPC;
ua->addrtype = atype;
ua->scope = scope;
ua->sr.type = type;
ua->sr.lower = lower;
ua->sr.upper = upper;
}
static inline bool tipc_uaddr_valid(struct tipc_uaddr *ua, int len)
{
u32 atype;
if (len < sizeof(struct sockaddr_tipc))
return false;
atype = ua->addrtype;
if (ua->family != AF_TIPC)
return false;
if (atype == TIPC_SERVICE_ADDR || atype == TIPC_SOCKET_ADDR)
return true;
if (atype == TIPC_SERVICE_RANGE)
return ua->sr.upper >= ua->sr.lower;
return false;
}
static inline u32 tipc_own_addr(struct net *net)
{
return tipc_net(net)->node_addr;
}
static inline u8 *tipc_own_id(struct net *net)
{
struct tipc_net *tn = tipc_net(net);
if (!strlen(tn->node_id_string))
return NULL;
return tn->node_id;
}
static inline char *tipc_own_id_string(struct net *net)
{
return tipc_net(net)->node_id_string;
}
static inline u32 tipc_cluster_mask(u32 addr)
{
return addr & TIPC_ZONE_CLUSTER_MASK;
}
static inline int tipc_node2scope(u32 node)
{
return node ? TIPC_NODE_SCOPE : TIPC_CLUSTER_SCOPE;
}
static inline int tipc_scope2node(struct net *net, int sc)
{
return sc != TIPC_NODE_SCOPE ? 0 : tipc_own_addr(net);
}
static inline int in_own_node(struct net *net, u32 addr)
{
return addr == tipc_own_addr(net) || !addr;
}
bool tipc_in_scope(bool legacy_format, u32 domain, u32 addr);
void tipc_set_node_id(struct net *net, u8 *id);
void tipc_set_node_addr(struct net *net, u32 addr);
int tipc_nodeid2string(char *str, u8 *id);
#endif
+870
View File
@@ -0,0 +1,870 @@
/*
* net/tipc/bcast.c: TIPC broadcast code
*
* Copyright (c) 2004-2006, 2014-2017, Ericsson AB
* Copyright (c) 2004, Intel Corporation.
* Copyright (c) 2005, 2010-2011, Wind River Systems
* 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 <linux/tipc_config.h>
#include "socket.h"
#include "msg.h"
#include "bcast.h"
#include "link.h"
#include "name_table.h"
#define BCLINK_WIN_DEFAULT 50 /* bcast link window size (default) */
#define BCLINK_WIN_MIN 32 /* bcast minimum link window size */
const char tipc_bclink_name[] = "broadcast-link";
unsigned long sysctl_tipc_bc_retruni __read_mostly;
/**
* struct tipc_bc_base - base structure for keeping broadcast send state
* @link: broadcast send link structure
* @inputq: data input queue; will only carry SOCK_WAKEUP messages
* @dests: array keeping number of reachable destinations per bearer
* @primary_bearer: a bearer having links to all broadcast destinations, if any
* @bcast_support: indicates if primary bearer, if any, supports broadcast
* @force_bcast: forces broadcast for multicast traffic
* @rcast_support: indicates if all peer nodes support replicast
* @force_rcast: forces replicast for multicast traffic
* @rc_ratio: dest count as percentage of cluster size where send method changes
* @bc_threshold: calculated from rc_ratio; if dests > threshold use broadcast
*/
struct tipc_bc_base {
struct tipc_link *link;
struct sk_buff_head inputq;
int dests[MAX_BEARERS];
int primary_bearer;
bool bcast_support;
bool force_bcast;
bool rcast_support;
bool force_rcast;
int rc_ratio;
int bc_threshold;
};
static struct tipc_bc_base *tipc_bc_base(struct net *net)
{
return tipc_net(net)->bcbase;
}
/* tipc_bcast_get_mtu(): -get the MTU currently used by broadcast link
* Note: the MTU is decremented to give room for a tunnel header, in
* case the message needs to be sent as replicast
*/
int tipc_bcast_get_mtu(struct net *net)
{
return tipc_link_mss(tipc_bc_sndlink(net));
}
void tipc_bcast_toggle_rcast(struct net *net, bool supp)
{
tipc_bc_base(net)->rcast_support = supp;
}
static void tipc_bcbase_calc_bc_threshold(struct net *net)
{
struct tipc_bc_base *bb = tipc_bc_base(net);
int cluster_size = tipc_link_bc_peers(tipc_bc_sndlink(net));
bb->bc_threshold = 1 + (cluster_size * bb->rc_ratio / 100);
}
/* tipc_bcbase_select_primary(): find a bearer with links to all destinations,
* if any, and make it primary bearer
*/
static void tipc_bcbase_select_primary(struct net *net)
{
struct tipc_bc_base *bb = tipc_bc_base(net);
int all_dests = tipc_link_bc_peers(bb->link);
int max_win = tipc_link_max_win(bb->link);
int min_win = tipc_link_min_win(bb->link);
int i, mtu, prim;
bb->primary_bearer = INVALID_BEARER_ID;
bb->bcast_support = true;
if (!all_dests)
return;
for (i = 0; i < MAX_BEARERS; i++) {
if (!bb->dests[i])
continue;
mtu = tipc_bearer_mtu(net, i);
if (mtu < tipc_link_mtu(bb->link)) {
tipc_link_set_mtu(bb->link, mtu);
tipc_link_set_queue_limits(bb->link,
min_win,
max_win);
}
bb->bcast_support &= tipc_bearer_bcast_support(net, i);
if (bb->dests[i] < all_dests)
continue;
bb->primary_bearer = i;
/* Reduce risk that all nodes select same primary */
if ((i ^ tipc_own_addr(net)) & 1)
break;
}
prim = bb->primary_bearer;
if (prim != INVALID_BEARER_ID)
bb->bcast_support = tipc_bearer_bcast_support(net, prim);
}
void tipc_bcast_inc_bearer_dst_cnt(struct net *net, int bearer_id)
{
struct tipc_bc_base *bb = tipc_bc_base(net);
tipc_bcast_lock(net);
bb->dests[bearer_id]++;
tipc_bcbase_select_primary(net);
tipc_bcast_unlock(net);
}
void tipc_bcast_dec_bearer_dst_cnt(struct net *net, int bearer_id)
{
struct tipc_bc_base *bb = tipc_bc_base(net);
tipc_bcast_lock(net);
bb->dests[bearer_id]--;
tipc_bcbase_select_primary(net);
tipc_bcast_unlock(net);
}
/* tipc_bcbase_xmit - broadcast a packet queue across one or more bearers
*
* Note that number of reachable destinations, as indicated in the dests[]
* array, may transitionally differ from the number of destinations indicated
* in each sent buffer. We can sustain this. Excess destination nodes will
* drop and never acknowledge the unexpected packets, and missing destinations
* will either require retransmission (if they are just about to be added to
* the bearer), or be removed from the buffer's 'ackers' counter (if they
* just went down)
*/
static void tipc_bcbase_xmit(struct net *net, struct sk_buff_head *xmitq)
{
int bearer_id;
struct tipc_bc_base *bb = tipc_bc_base(net);
struct sk_buff *skb, *_skb;
struct sk_buff_head _xmitq;
if (skb_queue_empty(xmitq))
return;
/* The typical case: at least one bearer has links to all nodes */
bearer_id = bb->primary_bearer;
if (bearer_id >= 0) {
tipc_bearer_bc_xmit(net, bearer_id, xmitq);
return;
}
/* We have to transmit across all bearers */
__skb_queue_head_init(&_xmitq);
for (bearer_id = 0; bearer_id < MAX_BEARERS; bearer_id++) {
if (!bb->dests[bearer_id])
continue;
skb_queue_walk(xmitq, skb) {
_skb = pskb_copy_for_clone(skb, GFP_ATOMIC);
if (!_skb)
break;
__skb_queue_tail(&_xmitq, _skb);
}
tipc_bearer_bc_xmit(net, bearer_id, &_xmitq);
}
__skb_queue_purge(xmitq);
__skb_queue_purge(&_xmitq);
}
static void tipc_bcast_select_xmit_method(struct net *net, int dests,
struct tipc_mc_method *method)
{
struct tipc_bc_base *bb = tipc_bc_base(net);
unsigned long exp = method->expires;
/* Broadcast supported by used bearer/bearers? */
if (!bb->bcast_support) {
method->rcast = true;
return;
}
/* Any destinations which don't support replicast ? */
if (!bb->rcast_support) {
method->rcast = false;
return;
}
/* Can current method be changed ? */
method->expires = jiffies + TIPC_METHOD_EXPIRE;
if (method->mandatory)
return;
if (!(tipc_net(net)->capabilities & TIPC_MCAST_RBCTL) &&
time_before(jiffies, exp))
return;
/* Configuration as force 'broadcast' method */
if (bb->force_bcast) {
method->rcast = false;
return;
}
/* Configuration as force 'replicast' method */
if (bb->force_rcast) {
method->rcast = true;
return;
}
/* Configuration as 'autoselect' or default method */
/* Determine method to use now */
method->rcast = dests <= bb->bc_threshold;
}
/* tipc_bcast_xmit - broadcast the buffer chain to all external nodes
* @net: the applicable net namespace
* @pkts: chain of buffers containing message
* @cong_link_cnt: set to 1 if broadcast link is congested, otherwise 0
* Consumes the buffer chain.
* Returns 0 if success, otherwise errno: -EHOSTUNREACH,-EMSGSIZE
*/
int tipc_bcast_xmit(struct net *net, struct sk_buff_head *pkts,
u16 *cong_link_cnt)
{
struct tipc_link *l = tipc_bc_sndlink(net);
struct sk_buff_head xmitq;
int rc = 0;
__skb_queue_head_init(&xmitq);
tipc_bcast_lock(net);
if (tipc_link_bc_peers(l))
rc = tipc_link_xmit(l, pkts, &xmitq);
tipc_bcast_unlock(net);
tipc_bcbase_xmit(net, &xmitq);
__skb_queue_purge(pkts);
if (rc == -ELINKCONG) {
*cong_link_cnt = 1;
rc = 0;
}
return rc;
}
/* tipc_rcast_xmit - replicate and send a message to given destination nodes
* @net: the applicable net namespace
* @pkts: chain of buffers containing message
* @dests: list of destination nodes
* @cong_link_cnt: returns number of congested links
* @cong_links: returns identities of congested links
* Returns 0 if success, otherwise errno
*/
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;
u32 dnode, selector;
selector = msg_link_selector(buf_msg(skb_peek(pkts)));
__skb_queue_head_init(&_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, dnode, selector) == -ELINKCONG)
(*cong_link_cnt)++;
}
return 0;
}
/* tipc_mcast_send_sync - deliver a dummy message with SYN bit
* @net: the applicable net namespace
* @skb: socket buffer to copy
* @method: send method to be used
* @dests: destination nodes for message.
* Returns 0 if success, otherwise errno
*/
static int tipc_mcast_send_sync(struct net *net, struct sk_buff *skb,
struct tipc_mc_method *method,
struct tipc_nlist *dests)
{
struct tipc_msg *hdr, *_hdr;
struct sk_buff_head tmpq;
u16 cong_link_cnt = 0;
struct sk_buff *_skb;
int rc = 0;
/* Is a cluster supporting with new capabilities ? */
if (!(tipc_net(net)->capabilities & TIPC_MCAST_RBCTL))
return 0;
hdr = buf_msg(skb);
if (msg_user(hdr) == MSG_FRAGMENTER)
hdr = msg_inner_hdr(hdr);
if (msg_type(hdr) != TIPC_MCAST_MSG)
return 0;
/* Allocate dummy message */
_skb = tipc_buf_acquire(MCAST_H_SIZE, GFP_KERNEL);
if (!_skb)
return -ENOMEM;
/* Preparing for 'synching' header */
msg_set_syn(hdr, 1);
/* Copy skb's header into a dummy header */
skb_copy_to_linear_data(_skb, hdr, MCAST_H_SIZE);
skb_orphan(_skb);
/* Reverse method for dummy message */
_hdr = buf_msg(_skb);
msg_set_size(_hdr, MCAST_H_SIZE);
msg_set_is_rcast(_hdr, !msg_is_rcast(hdr));
msg_set_errcode(_hdr, TIPC_ERR_NO_PORT);
__skb_queue_head_init(&tmpq);
__skb_queue_tail(&tmpq, _skb);
if (method->rcast)
rc = tipc_bcast_xmit(net, &tmpq, &cong_link_cnt);
else
rc = tipc_rcast_xmit(net, &tmpq, dests, &cong_link_cnt);
/* This queue should normally be empty by now */
__skb_queue_purge(&tmpq);
return rc;
}
/* tipc_mcast_xmit - deliver message to indicated destination nodes
* and to identified node local sockets
* @net: the applicable net namespace
* @pkts: chain of buffers containing message
* @method: send method to be used
* @dests: destination nodes for message.
* @cong_link_cnt: returns number of encountered congested destination links
* Consumes buffer chain.
* Returns 0 if success, otherwise errno
*/
int tipc_mcast_xmit(struct net *net, struct sk_buff_head *pkts,
struct tipc_mc_method *method, struct tipc_nlist *dests,
u16 *cong_link_cnt)
{
struct sk_buff_head inputq, localq;
bool rcast = method->rcast;
struct tipc_msg *hdr;
struct sk_buff *skb;
int rc = 0;
skb_queue_head_init(&inputq);
__skb_queue_head_init(&localq);
/* Clone packets before they are consumed by next call */
if (dests->local && !tipc_msg_reassemble(pkts, &localq)) {
rc = -ENOMEM;
goto exit;
}
/* Send according to determined transmit method */
if (dests->remote) {
tipc_bcast_select_xmit_method(net, dests->remote, method);
skb = skb_peek(pkts);
hdr = buf_msg(skb);
if (msg_user(hdr) == MSG_FRAGMENTER)
hdr = msg_inner_hdr(hdr);
msg_set_is_rcast(hdr, method->rcast);
/* Switch method ? */
if (rcast != method->rcast) {
rc = tipc_mcast_send_sync(net, skb, method, dests);
if (unlikely(rc)) {
pr_err("Unable to send SYN: method %d, rc %d\n",
rcast, rc);
goto exit;
}
}
if (method->rcast)
rc = tipc_rcast_xmit(net, pkts, dests, cong_link_cnt);
else
rc = tipc_bcast_xmit(net, pkts, cong_link_cnt);
}
if (dests->local) {
tipc_loopback_trace(net, &localq);
tipc_sk_mcast_rcv(net, &localq, &inputq);
}
exit:
/* This queue should normally be empty by now */
__skb_queue_purge(pkts);
return rc;
}
/* tipc_bcast_rcv - receive a broadcast packet, and deliver to rcv link
*
* RCU is locked, no other locks set
*/
int tipc_bcast_rcv(struct net *net, struct tipc_link *l, struct sk_buff *skb)
{
struct tipc_msg *hdr = buf_msg(skb);
struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq;
struct sk_buff_head xmitq;
int rc;
__skb_queue_head_init(&xmitq);
if (msg_mc_netid(hdr) != tipc_netid(net) || !tipc_link_is_up(l)) {
kfree_skb(skb);
return 0;
}
tipc_bcast_lock(net);
if (msg_user(hdr) == BCAST_PROTOCOL)
rc = tipc_link_bc_nack_rcv(l, skb, &xmitq);
else
rc = tipc_link_rcv(l, skb, NULL);
tipc_bcast_unlock(net);
tipc_bcbase_xmit(net, &xmitq);
/* Any socket wakeup messages ? */
if (!skb_queue_empty(inputq))
tipc_sk_rcv(net, inputq);
return rc;
}
/* tipc_bcast_ack_rcv - receive and handle a broadcast acknowledge
*
* RCU is locked, no other locks set
*/
void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l,
struct tipc_msg *hdr)
{
struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq;
u16 acked = msg_bcast_ack(hdr);
struct sk_buff_head xmitq;
/* Ignore bc acks sent by peer before bcast synch point was received */
if (msg_bc_ack_invalid(hdr))
return;
__skb_queue_head_init(&xmitq);
tipc_bcast_lock(net);
tipc_link_bc_ack_rcv(l, acked, 0, NULL, &xmitq, NULL);
tipc_bcast_unlock(net);
tipc_bcbase_xmit(net, &xmitq);
/* Any socket wakeup messages ? */
if (!skb_queue_empty(inputq))
tipc_sk_rcv(net, inputq);
}
/* tipc_bcast_synch_rcv - check and update rcv link with peer's send state
*
* RCU is locked, no other locks set
*/
int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l,
struct tipc_msg *hdr,
struct sk_buff_head *retrq, bool *valid)
{
struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq;
struct tipc_gap_ack_blks *ga;
struct sk_buff_head xmitq;
int rc = 0;
u16 glen;
__skb_queue_head_init(&xmitq);
tipc_bcast_lock(net);
if (msg_type(hdr) != STATE_MSG) {
tipc_link_bc_init_rcv(l, hdr);
} else if (!msg_bc_ack_invalid(hdr)) {
glen = tipc_get_gap_ack_blks(&ga, l, hdr, false);
if (glen > msg_data_sz(hdr)) {
/* Malformed Gap ACK blocks; caller drops the msg */
*valid = false;
} else {
if (!sysctl_tipc_bc_retruni)
retrq = &xmitq;
rc = tipc_link_bc_ack_rcv(l, msg_bcast_ack(hdr),
msg_bc_gap(hdr), ga, &xmitq,
retrq);
rc |= tipc_link_bc_sync_rcv(l, hdr, &xmitq);
}
}
tipc_bcast_unlock(net);
tipc_bcbase_xmit(net, &xmitq);
/* Any socket wakeup messages ? */
if (!skb_queue_empty(inputq))
tipc_sk_rcv(net, inputq);
return rc;
}
/* tipc_bcast_add_peer - add a peer node to broadcast link and bearer
*
* RCU is locked, node lock is set
*/
void tipc_bcast_add_peer(struct net *net, struct tipc_link *uc_l,
struct sk_buff_head *xmitq)
{
struct tipc_link *snd_l = tipc_bc_sndlink(net);
tipc_bcast_lock(net);
tipc_link_add_bc_peer(snd_l, uc_l, xmitq);
tipc_bcbase_select_primary(net);
tipc_bcbase_calc_bc_threshold(net);
tipc_bcast_unlock(net);
}
/* tipc_bcast_remove_peer - remove a peer node from broadcast link and bearer
*
* RCU is locked, node lock is set
*/
void tipc_bcast_remove_peer(struct net *net, struct tipc_link *rcv_l)
{
struct tipc_link *snd_l = tipc_bc_sndlink(net);
struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq;
struct sk_buff_head xmitq;
__skb_queue_head_init(&xmitq);
tipc_bcast_lock(net);
tipc_link_remove_bc_peer(snd_l, rcv_l, &xmitq);
tipc_bcbase_select_primary(net);
tipc_bcbase_calc_bc_threshold(net);
tipc_bcast_unlock(net);
tipc_bcbase_xmit(net, &xmitq);
/* Any socket wakeup messages ? */
if (!skb_queue_empty(inputq))
tipc_sk_rcv(net, inputq);
}
int tipc_bclink_reset_stats(struct net *net, struct tipc_link *l)
{
if (!l)
return -ENOPROTOOPT;
tipc_bcast_lock(net);
tipc_link_reset_stats(l);
tipc_bcast_unlock(net);
return 0;
}
static int tipc_bc_link_set_queue_limits(struct net *net, u32 max_win)
{
struct tipc_link *l = tipc_bc_sndlink(net);
if (!l)
return -ENOPROTOOPT;
if (max_win < BCLINK_WIN_MIN)
max_win = BCLINK_WIN_MIN;
if (max_win > TIPC_MAX_LINK_WIN)
return -EINVAL;
tipc_bcast_lock(net);
tipc_link_set_queue_limits(l, tipc_link_min_win(l), max_win);
tipc_bcast_unlock(net);
return 0;
}
static int tipc_bc_link_set_broadcast_mode(struct net *net, u32 bc_mode)
{
struct tipc_bc_base *bb = tipc_bc_base(net);
switch (bc_mode) {
case BCLINK_MODE_BCAST:
if (!bb->bcast_support)
return -ENOPROTOOPT;
bb->force_bcast = true;
bb->force_rcast = false;
break;
case BCLINK_MODE_RCAST:
if (!bb->rcast_support)
return -ENOPROTOOPT;
bb->force_bcast = false;
bb->force_rcast = true;
break;
case BCLINK_MODE_SEL:
if (!bb->bcast_support || !bb->rcast_support)
return -ENOPROTOOPT;
bb->force_bcast = false;
bb->force_rcast = false;
break;
default:
return -EINVAL;
}
return 0;
}
static int tipc_bc_link_set_broadcast_ratio(struct net *net, u32 bc_ratio)
{
struct tipc_bc_base *bb = tipc_bc_base(net);
if (!bb->bcast_support || !bb->rcast_support)
return -ENOPROTOOPT;
if (bc_ratio > 100 || bc_ratio <= 0)
return -EINVAL;
bb->rc_ratio = bc_ratio;
tipc_bcast_lock(net);
tipc_bcbase_calc_bc_threshold(net);
tipc_bcast_unlock(net);
return 0;
}
int tipc_nl_bc_link_set(struct net *net, struct nlattr *attrs[])
{
int err;
u32 win;
u32 bc_mode;
u32 bc_ratio;
struct nlattr *props[TIPC_NLA_PROP_MAX + 1];
if (!attrs[TIPC_NLA_LINK_PROP])
return -EINVAL;
err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_LINK_PROP], props);
if (err)
return err;
if (!props[TIPC_NLA_PROP_WIN] &&
!props[TIPC_NLA_PROP_BROADCAST] &&
!props[TIPC_NLA_PROP_BROADCAST_RATIO]) {
return -EOPNOTSUPP;
}
if (props[TIPC_NLA_PROP_BROADCAST]) {
bc_mode = nla_get_u32(props[TIPC_NLA_PROP_BROADCAST]);
err = tipc_bc_link_set_broadcast_mode(net, bc_mode);
}
if (!err && props[TIPC_NLA_PROP_BROADCAST_RATIO]) {
bc_ratio = nla_get_u32(props[TIPC_NLA_PROP_BROADCAST_RATIO]);
err = tipc_bc_link_set_broadcast_ratio(net, bc_ratio);
}
if (!err && props[TIPC_NLA_PROP_WIN]) {
win = nla_get_u32(props[TIPC_NLA_PROP_WIN]);
err = tipc_bc_link_set_queue_limits(net, win);
}
return err;
}
int tipc_bcast_init(struct net *net)
{
struct tipc_net *tn = tipc_net(net);
struct tipc_bc_base *bb = NULL;
struct tipc_link *l = NULL;
bb = kzalloc_obj(*bb);
if (!bb)
goto enomem;
tn->bcbase = bb;
spin_lock_init(&tipc_net(net)->bclock);
if (!tipc_link_bc_create(net, 0, 0, NULL,
one_page_mtu,
BCLINK_WIN_DEFAULT,
BCLINK_WIN_DEFAULT,
0,
&bb->inputq,
NULL,
NULL,
&l))
goto enomem;
bb->link = l;
tn->bcl = l;
bb->rc_ratio = 10;
bb->rcast_support = true;
return 0;
enomem:
kfree(bb);
kfree(l);
return -ENOMEM;
}
void tipc_bcast_stop(struct net *net)
{
struct tipc_net *tn = net_generic(net, tipc_net_id);
synchronize_net();
kfree(tn->bcbase);
kfree(tn->bcl);
}
void tipc_nlist_init(struct tipc_nlist *nl, u32 self)
{
memset(nl, 0, sizeof(*nl));
INIT_LIST_HEAD(&nl->list);
nl->self = self;
}
void tipc_nlist_add(struct tipc_nlist *nl, u32 node)
{
if (node == nl->self)
nl->local = true;
else if (tipc_dest_push(&nl->list, node, 0))
nl->remote++;
}
void tipc_nlist_del(struct tipc_nlist *nl, u32 node)
{
if (node == nl->self)
nl->local = false;
else if (tipc_dest_del(&nl->list, node, 0))
nl->remote--;
}
void tipc_nlist_purge(struct tipc_nlist *nl)
{
tipc_dest_list_purge(&nl->list);
nl->remote = 0;
nl->local = false;
}
u32 tipc_bcast_get_mode(struct net *net)
{
struct tipc_bc_base *bb = tipc_bc_base(net);
if (bb->force_bcast)
return BCLINK_MODE_BCAST;
if (bb->force_rcast)
return BCLINK_MODE_RCAST;
if (bb->bcast_support && bb->rcast_support)
return BCLINK_MODE_SEL;
return 0;
}
u32 tipc_bcast_get_broadcast_ratio(struct net *net)
{
struct tipc_bc_base *bb = tipc_bc_base(net);
return bb->rc_ratio;
}
void tipc_mcast_filter_msg(struct net *net, struct sk_buff_head *defq,
struct sk_buff_head *inputq)
{
struct sk_buff *skb, *_skb, *tmp;
struct tipc_msg *hdr, *_hdr;
bool match = false;
u32 node, port;
skb = skb_peek(inputq);
if (!skb)
return;
hdr = buf_msg(skb);
if (likely(!msg_is_syn(hdr) && skb_queue_empty(defq)))
return;
node = msg_orignode(hdr);
if (node == tipc_own_addr(net))
return;
port = msg_origport(hdr);
/* Has the twin SYN message already arrived ? */
skb_queue_walk(defq, _skb) {
_hdr = buf_msg(_skb);
if (msg_orignode(_hdr) != node)
continue;
if (msg_origport(_hdr) != port)
continue;
match = true;
break;
}
if (!match) {
if (!msg_is_syn(hdr))
return;
__skb_dequeue(inputq);
__skb_queue_tail(defq, skb);
return;
}
/* Deliver non-SYN message from other link, otherwise queue it */
if (!msg_is_syn(hdr)) {
if (msg_is_rcast(hdr) != msg_is_rcast(_hdr))
return;
__skb_dequeue(inputq);
__skb_queue_tail(defq, skb);
return;
}
/* Queue non-SYN/SYN message from same link */
if (msg_is_rcast(hdr) == msg_is_rcast(_hdr)) {
__skb_dequeue(inputq);
__skb_queue_tail(defq, skb);
return;
}
/* Matching SYN messages => return the one with data, if any */
__skb_unlink(_skb, defq);
if (msg_data_sz(hdr)) {
kfree_skb(_skb);
} else {
__skb_dequeue(inputq);
kfree_skb(skb);
__skb_queue_tail(inputq, _skb);
}
/* Deliver subsequent non-SYN messages from same peer */
skb_queue_walk_safe(defq, _skb, tmp) {
_hdr = buf_msg(_skb);
if (msg_orignode(_hdr) != node)
continue;
if (msg_origport(_hdr) != port)
continue;
if (msg_is_syn(_hdr))
break;
__skb_unlink(_skb, defq);
__skb_queue_tail(inputq, _skb);
}
}
+127
View File
@@ -0,0 +1,127 @@
/*
* net/tipc/bcast.h: Include file for TIPC broadcast code
*
* Copyright (c) 2003-2006, 2014-2015, Ericsson AB
* Copyright (c) 2005, 2010-2011, Wind River Systems
* 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_BCAST_H
#define _TIPC_BCAST_H
#include "core.h"
struct tipc_node;
struct tipc_msg;
struct tipc_nl_msg;
struct tipc_nlist;
struct tipc_nitem;
extern const char tipc_bclink_name[];
extern unsigned long sysctl_tipc_bc_retruni;
#define TIPC_METHOD_EXPIRE msecs_to_jiffies(5000)
#define BCLINK_MODE_BCAST 0x1
#define BCLINK_MODE_RCAST 0x2
#define BCLINK_MODE_SEL 0x4
struct tipc_nlist {
struct list_head list;
u32 self;
u16 remote;
bool local;
};
void tipc_nlist_init(struct tipc_nlist *nl, u32 self);
void tipc_nlist_purge(struct tipc_nlist *nl);
void tipc_nlist_add(struct tipc_nlist *nl, u32 node);
void tipc_nlist_del(struct tipc_nlist *nl, u32 node);
/* Cookie to be used between socket and broadcast layer
* @rcast: replicast (instead of broadcast) was used at previous xmit
* @mandatory: broadcast/replicast indication was set by user
* @deferredq: defer queue to make message in order
* @expires: re-evaluate non-mandatory transmit method if we are past this
*/
struct tipc_mc_method {
bool rcast;
bool mandatory;
struct sk_buff_head deferredq;
unsigned long expires;
};
int tipc_bcast_init(struct net *net);
void tipc_bcast_stop(struct net *net);
void tipc_bcast_add_peer(struct net *net, struct tipc_link *l,
struct sk_buff_head *xmitq);
void tipc_bcast_remove_peer(struct net *net, struct tipc_link *rcv_bcl);
void tipc_bcast_inc_bearer_dst_cnt(struct net *net, int bearer_id);
void tipc_bcast_dec_bearer_dst_cnt(struct net *net, int bearer_id);
int tipc_bcast_get_mtu(struct net *net);
void tipc_bcast_toggle_rcast(struct net *net, bool supp);
int tipc_mcast_xmit(struct net *net, struct sk_buff_head *pkts,
struct tipc_mc_method *method, struct tipc_nlist *dests,
u16 *cong_link_cnt);
int tipc_bcast_xmit(struct net *net, struct sk_buff_head *pkts,
u16 *cong_link_cnt);
int tipc_bcast_rcv(struct net *net, struct tipc_link *l, struct sk_buff *skb);
void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l,
struct tipc_msg *hdr);
int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l,
struct tipc_msg *hdr,
struct sk_buff_head *retrq, bool *valid);
int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg,
struct tipc_link *bcl);
int tipc_nl_bc_link_set(struct net *net, struct nlattr *attrs[]);
int tipc_bclink_reset_stats(struct net *net, struct tipc_link *l);
u32 tipc_bcast_get_mode(struct net *net);
u32 tipc_bcast_get_broadcast_ratio(struct net *net);
void tipc_mcast_filter_msg(struct net *net, struct sk_buff_head *defq,
struct sk_buff_head *inputq);
static inline void tipc_bcast_lock(struct net *net)
{
spin_lock_bh(&tipc_net(net)->bclock);
}
static inline void tipc_bcast_unlock(struct net *net)
{
spin_unlock_bh(&tipc_net(net)->bclock);
}
static inline struct tipc_link *tipc_bc_sndlink(struct net *net)
{
return tipc_net(net)->bcl;
}
#endif
File diff suppressed because it is too large Load Diff
+266
View File
@@ -0,0 +1,266 @@
/*
* net/tipc/bearer.h: Include file for TIPC bearer code
*
* Copyright (c) 1996-2006, 2013-2016, Ericsson AB
* Copyright (c) 2005, 2010-2011, Wind River Systems
* 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_BEARER_H
#define _TIPC_BEARER_H
#include "netlink.h"
#include "core.h"
#include "msg.h"
#include <net/genetlink.h>
#define MAX_MEDIA 3
/* Identifiers associated with TIPC message header media address info
* - address info field is 32 bytes long
* - the field's actual content and length is defined per media
* - remaining unused bytes in the field are set to zero
*/
#define TIPC_MEDIA_INFO_SIZE 32
#define TIPC_MEDIA_TYPE_OFFSET 3
#define TIPC_MEDIA_ADDR_OFFSET 4
/*
* Identifiers of supported TIPC media types
*/
#define TIPC_MEDIA_TYPE_ETH 1
#define TIPC_MEDIA_TYPE_IB 2
#define TIPC_MEDIA_TYPE_UDP 3
/* Minimum bearer MTU */
#define TIPC_MIN_BEARER_MTU (MAX_H_SIZE + INT_H_SIZE)
/* Identifiers for distinguishing between broadcast/multicast and replicast
*/
#define TIPC_BROADCAST_SUPPORT 1
#define TIPC_REPLICAST_SUPPORT 2
/**
* struct tipc_media_addr - destination address used by TIPC bearers
* @value: address info (format defined by media)
* @media_id: TIPC media type identifier
* @broadcast: non-zero if address is a broadcast address
*/
struct tipc_media_addr {
u8 value[TIPC_MEDIA_INFO_SIZE];
u8 media_id;
u8 broadcast;
};
struct tipc_bearer;
/**
* struct tipc_media - Media specific info exposed to generic bearer layer
* @send_msg: routine which handles buffer transmission
* @enable_media: routine which enables a media
* @disable_media: routine which disables a media
* @addr2str: convert media address format to string
* @addr2msg: convert from media addr format to discovery msg addr format
* @msg2addr: convert from discovery msg addr format to media addr format
* @raw2addr: convert from raw addr format to media addr format
* @priority: default link (and bearer) priority
* @tolerance: default time (in ms) before declaring link failure
* @min_win: minimum window (in packets) before declaring link congestion
* @max_win: maximum window (in packets) before declaring link congestion
* @mtu: max packet size bearer can support for media type not dependent on
* underlying device MTU
* @type_id: TIPC media identifier
* @hwaddr_len: TIPC media address len
* @name: media name
*/
struct tipc_media {
int (*send_msg)(struct net *net, struct sk_buff *buf,
struct tipc_bearer *b,
struct tipc_media_addr *dest);
int (*enable_media)(struct net *net, struct tipc_bearer *b,
struct nlattr *attr[]);
void (*disable_media)(struct tipc_bearer *b);
int (*addr2str)(struct tipc_media_addr *addr,
char *strbuf,
int bufsz);
int (*addr2msg)(char *msg, struct tipc_media_addr *addr);
int (*msg2addr)(struct tipc_bearer *b,
struct tipc_media_addr *addr,
char *msg);
int (*raw2addr)(struct tipc_bearer *b,
struct tipc_media_addr *addr,
const char *raw);
u32 priority;
u32 tolerance;
u32 min_win;
u32 max_win;
u32 mtu;
u32 type_id;
u32 hwaddr_len;
char name[TIPC_MAX_MEDIA_NAME];
};
/**
* struct tipc_bearer - Generic TIPC bearer structure
* @media_ptr: pointer to additional media-specific information about bearer
* @mtu: max packet size bearer can support
* @addr: media-specific address associated with bearer
* @name: bearer name (format = media:interface)
* @media: ptr to media structure associated with bearer
* @bcast_addr: media address used in broadcasting
* @pt: packet type for bearer
* @rcu: rcu struct for tipc_bearer
* @priority: default link priority for bearer
* @min_win: minimum window (in packets) before declaring link congestion
* @max_win: maximum window (in packets) before declaring link congestion
* @tolerance: default link tolerance for bearer
* @domain: network domain to which links can be established
* @identity: array index of this bearer within TIPC bearer array
* @disc: ptr to link setup request
* @net_plane: network plane ('A' through 'H') currently associated with bearer
* @encap_hlen: encap headers length
* @up: bearer up flag (bit 0)
* @refcnt: tipc_bearer reference counter
*
* Note: media-specific code is responsible for initialization of the fields
* indicated below when a bearer is enabled; TIPC's generic bearer code takes
* care of initializing all other fields.
*/
struct tipc_bearer {
void __rcu *media_ptr; /* initialized by media */
u32 mtu; /* initialized by media */
struct tipc_media_addr addr; /* initialized by media */
char name[TIPC_MAX_BEARER_NAME];
struct tipc_media *media;
struct tipc_media_addr bcast_addr;
struct packet_type pt;
struct rcu_head rcu;
u32 priority;
u32 min_win;
u32 max_win;
u32 tolerance;
u32 domain;
u32 identity;
struct tipc_discoverer *disc;
char net_plane;
u16 encap_hlen;
unsigned long up;
refcount_t refcnt;
};
struct tipc_bearer_names {
char media_name[TIPC_MAX_MEDIA_NAME];
char if_name[TIPC_MAX_IF_NAME];
};
/*
* TIPC routines available to supported media types
*/
void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b);
/*
* Routines made available to TIPC by supported media types
*/
extern struct tipc_media eth_media_info;
#ifdef CONFIG_TIPC_MEDIA_IB
extern struct tipc_media ib_media_info;
#endif
#ifdef CONFIG_TIPC_MEDIA_UDP
extern struct tipc_media udp_media_info;
#endif
int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info);
int __tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info);
int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info);
int __tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info);
int tipc_nl_bearer_dump(struct sk_buff *skb, struct netlink_callback *cb);
int tipc_nl_bearer_get(struct sk_buff *skb, struct genl_info *info);
int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info);
int __tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info);
int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info);
int tipc_nl_media_dump(struct sk_buff *skb, struct netlink_callback *cb);
int tipc_nl_media_get(struct sk_buff *skb, struct genl_info *info);
int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info);
int __tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info);
int tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a);
int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b,
struct nlattr *attrs[]);
bool tipc_bearer_hold(struct tipc_bearer *b);
void tipc_bearer_put(struct tipc_bearer *b);
void tipc_disable_l2_media(struct tipc_bearer *b);
int tipc_l2_send_msg(struct net *net, struct sk_buff *buf,
struct tipc_bearer *b, struct tipc_media_addr *dest);
void tipc_bearer_add_dest(struct net *net, u32 bearer_id, u32 dest);
void tipc_bearer_remove_dest(struct net *net, u32 bearer_id, u32 dest);
struct tipc_bearer *tipc_bearer_find(struct net *net, const char *name);
int tipc_bearer_get_name(struct net *net, char *name, u32 bearer_id);
struct tipc_media *tipc_media_find(const char *name);
int tipc_bearer_setup(void);
void tipc_bearer_cleanup(void);
void tipc_bearer_stop(struct net *net);
int tipc_bearer_mtu(struct net *net, u32 bearer_id);
int tipc_bearer_min_mtu(struct net *net, u32 bearer_id);
bool tipc_bearer_bcast_support(struct net *net, u32 bearer_id);
void tipc_bearer_xmit_skb(struct net *net, u32 bearer_id,
struct sk_buff *skb,
struct tipc_media_addr *dest);
void tipc_bearer_xmit(struct net *net, u32 bearer_id,
struct sk_buff_head *xmitq,
struct tipc_media_addr *dst,
struct tipc_node *__dnode);
void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id,
struct sk_buff_head *xmitq);
void tipc_clone_to_loopback(struct net *net, struct sk_buff_head *pkts);
int tipc_attach_loopback(struct net *net);
void tipc_detach_loopback(struct net *net);
static inline void tipc_loopback_trace(struct net *net,
struct sk_buff_head *pkts)
{
if (unlikely(dev_nit_active(net->loopback_dev)))
tipc_clone_to_loopback(net, pkts);
}
/* check if device MTU is too low for tipc headers */
static inline bool tipc_mtu_bad(struct net_device *dev)
{
if (dev->mtu >= TIPC_MIN_BEARER_MTU)
return false;
netdev_warn(dev, "MTU too low for tipc bearer\n");
return true;
}
#endif /* _TIPC_BEARER_H */
+234
View File
@@ -0,0 +1,234 @@
/*
* net/tipc/core.c: TIPC module code
*
* Copyright (c) 2003-2006, 2013, Ericsson AB
* Copyright (c) 2005-2006, 2010-2013, Wind River Systems
* 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 "name_table.h"
#include "subscr.h"
#include "bearer.h"
#include "net.h"
#include "socket.h"
#include "bcast.h"
#include "node.h"
#include "crypto.h"
#include <linux/module.h>
#include <linux/wait_bit.h>
/* configurable TIPC parameters */
unsigned int tipc_net_id __read_mostly;
int sysctl_tipc_rmem[3] __read_mostly; /* min/default/max */
static int __net_init tipc_init_net(struct net *net)
{
struct tipc_net *tn = net_generic(net, tipc_net_id);
int err;
tn->net_id = 4711;
tn->node_addr = 0;
tn->trial_addr = 0;
tn->addr_trial_end = 0;
tn->capabilities = TIPC_NODE_CAPABILITIES;
INIT_WORK(&tn->work, tipc_net_finalize_work);
memset(tn->node_id, 0, sizeof(tn->node_id));
memset(tn->node_id_string, 0, sizeof(tn->node_id_string));
tn->mon_threshold = TIPC_DEF_MON_THRESHOLD;
get_random_bytes(&tn->random, sizeof(int));
INIT_LIST_HEAD(&tn->node_list);
spin_lock_init(&tn->node_list_lock);
#ifdef CONFIG_TIPC_CRYPTO
err = tipc_crypto_start(&tn->crypto_tx, net, NULL);
if (err)
goto out_crypto;
#endif
err = tipc_sk_rht_init(net);
if (err)
goto out_sk_rht;
err = tipc_nametbl_init(net);
if (err)
goto out_nametbl;
err = tipc_bcast_init(net);
if (err)
goto out_bclink;
err = tipc_attach_loopback(net);
if (err)
goto out_bclink;
return 0;
out_bclink:
tipc_nametbl_stop(net);
out_nametbl:
tipc_sk_rht_destroy(net);
out_sk_rht:
#ifdef CONFIG_TIPC_CRYPTO
tipc_crypto_stop(&tn->crypto_tx);
out_crypto:
#endif
return err;
}
static void __net_exit tipc_exit_net(struct net *net)
{
struct tipc_net *tn = tipc_net(net);
tipc_detach_loopback(net);
tipc_net_stop(net);
/* Make sure the tipc_net_finalize_work() finished */
cancel_work_sync(&tn->work);
tipc_bcast_stop(net);
tipc_nametbl_stop(net);
tipc_sk_rht_destroy(net);
#ifdef CONFIG_TIPC_CRYPTO
tipc_crypto_stop(&tipc_net(net)->crypto_tx);
#endif
wait_var_event(&tn->wq_count, atomic_read(&tn->wq_count) == 0);
}
static void __net_exit tipc_pernet_pre_exit(struct net *net)
{
tipc_node_pre_cleanup_net(net);
}
static struct pernet_operations tipc_pernet_pre_exit_ops = {
.pre_exit = tipc_pernet_pre_exit,
};
static struct pernet_operations tipc_net_ops = {
.init = tipc_init_net,
.exit = tipc_exit_net,
.id = &tipc_net_id,
.size = sizeof(struct tipc_net),
};
static struct pernet_operations tipc_topsrv_net_ops = {
.init = tipc_topsrv_init_net,
.exit = tipc_topsrv_exit_net,
};
static int __init tipc_init(void)
{
int err;
pr_info("Activated (version " TIPC_MOD_VER ")\n");
sysctl_tipc_rmem[0] = RCVBUF_MIN;
sysctl_tipc_rmem[1] = RCVBUF_DEF;
sysctl_tipc_rmem[2] = RCVBUF_MAX;
err = tipc_register_sysctl();
if (err)
goto out_sysctl;
err = register_pernet_device(&tipc_net_ops);
if (err)
goto out_pernet;
err = tipc_socket_init();
if (err)
goto out_socket;
err = register_pernet_device(&tipc_topsrv_net_ops);
if (err)
goto out_pernet_topsrv;
err = register_pernet_subsys(&tipc_pernet_pre_exit_ops);
if (err)
goto out_register_pernet_subsys;
err = tipc_bearer_setup();
if (err)
goto out_bearer;
err = tipc_netlink_start();
if (err)
goto out_netlink;
err = tipc_netlink_compat_start();
if (err)
goto out_netlink_compat;
pr_info("Started in single node mode\n");
return 0;
out_netlink_compat:
tipc_netlink_stop();
out_netlink:
tipc_bearer_cleanup();
out_bearer:
unregister_pernet_subsys(&tipc_pernet_pre_exit_ops);
out_register_pernet_subsys:
unregister_pernet_device(&tipc_topsrv_net_ops);
out_pernet_topsrv:
tipc_socket_stop();
out_socket:
unregister_pernet_device(&tipc_net_ops);
out_pernet:
tipc_unregister_sysctl();
out_sysctl:
pr_err("Unable to start in single node mode\n");
return err;
}
static void __exit tipc_exit(void)
{
tipc_netlink_compat_stop();
tipc_netlink_stop();
tipc_bearer_cleanup();
unregister_pernet_subsys(&tipc_pernet_pre_exit_ops);
unregister_pernet_device(&tipc_topsrv_net_ops);
tipc_socket_stop();
unregister_pernet_device(&tipc_net_ops);
tipc_unregister_sysctl();
/* TODO: Wait for all timers that called call_rcu() to finish before
* calling rcu_barrier().
*/
rcu_barrier();
pr_info("Deactivated\n");
}
module_init(tipc_init);
module_exit(tipc_exit);
MODULE_DESCRIPTION("TIPC: Transparent Inter Process Communication");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(TIPC_MOD_VER);
+228
View File
@@ -0,0 +1,228 @@
/*
* net/tipc/core.h: Include file for TIPC global declarations
*
* Copyright (c) 2005-2006, 2013-2018 Ericsson AB
* Copyright (c) 2005-2007, 2010-2013, Wind River Systems
* Copyright (c) 2020, Red Hat Inc
* 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_CORE_H
#define _TIPC_CORE_H
#include <linux/tipc.h>
#include <linux/tipc_config.h>
#include <linux/tipc_netlink.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/hex.h>
#include <linux/mm.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/atomic.h>
#include <linux/netdevice.h>
#include <linux/in.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/rtnetlink.h>
#include <linux/etherdevice.h>
#include <net/netns/generic.h>
#include <linux/rhashtable.h>
#include <net/genetlink.h>
#include <net/netns/hash.h>
#ifdef pr_fmt
#undef pr_fmt
#endif
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
struct tipc_node;
struct tipc_bearer;
struct tipc_bc_base;
struct tipc_link;
struct tipc_topsrv;
struct tipc_monitor;
#ifdef CONFIG_TIPC_CRYPTO
struct tipc_crypto;
#endif
#define TIPC_MOD_VER "2.0.0"
#define NODE_HTABLE_SIZE 512
#define MAX_BEARERS 3
#define TIPC_DEF_MON_THRESHOLD 32
#define NODE_ID_LEN 16
#define NODE_ID_STR_LEN (NODE_ID_LEN * 2 + 1)
extern unsigned int tipc_net_id __read_mostly;
extern int sysctl_tipc_rmem[3] __read_mostly;
extern int sysctl_tipc_named_timeout __read_mostly;
struct tipc_net {
u8 node_id[NODE_ID_LEN];
u32 node_addr;
u32 trial_addr;
unsigned long addr_trial_end;
char node_id_string[NODE_ID_STR_LEN];
int net_id;
int random;
bool legacy_addr_format;
/* Node table and node list */
spinlock_t node_list_lock;
struct hlist_head node_htable[NODE_HTABLE_SIZE];
struct list_head node_list;
u32 num_nodes;
u32 num_links;
/* Neighbor monitoring list */
struct tipc_monitor *monitors[MAX_BEARERS];
int mon_threshold;
/* Bearer list */
struct tipc_bearer __rcu *bearer_list[MAX_BEARERS + 1];
/* Broadcast link */
spinlock_t bclock;
struct tipc_bc_base *bcbase;
struct tipc_link *bcl;
/* Socket hash table */
struct rhashtable sk_rht;
/* Name table */
spinlock_t nametbl_lock;
struct name_table *nametbl;
/* Topology subscription server */
struct tipc_topsrv *topsrv;
atomic_t subscription_count;
/* Cluster capabilities */
u16 capabilities;
/* Tracing of node internal messages */
struct packet_type loopback_pt;
#ifdef CONFIG_TIPC_CRYPTO
/* TX crypto handler */
struct tipc_crypto *crypto_tx;
#endif
/* Work item for net finalize */
struct work_struct work;
/* The numbers of work queues in schedule */
atomic_t wq_count;
};
static inline struct tipc_net *tipc_net(struct net *net)
{
return net_generic(net, tipc_net_id);
}
static inline int tipc_netid(struct net *net)
{
return tipc_net(net)->net_id;
}
static inline struct list_head *tipc_nodes(struct net *net)
{
return &tipc_net(net)->node_list;
}
static inline struct name_table *tipc_name_table(struct net *net)
{
return tipc_net(net)->nametbl;
}
static inline struct tipc_topsrv *tipc_topsrv(struct net *net)
{
return tipc_net(net)->topsrv;
}
static inline unsigned int tipc_hashfn(u32 addr)
{
return addr & (NODE_HTABLE_SIZE - 1);
}
static inline u16 mod(u16 x)
{
return x & 0xffffu;
}
static inline int less_eq(u16 left, u16 right)
{
return mod(right - left) < 32768u;
}
static inline int more(u16 left, u16 right)
{
return !less_eq(left, right);
}
static inline int less(u16 left, u16 right)
{
return less_eq(left, right) && (mod(right) != mod(left));
}
static inline int tipc_in_range(u16 val, u16 min, u16 max)
{
return !less(val, min) && !more(val, max);
}
static inline u32 tipc_net_hash_mixes(struct net *net, int tn_rand)
{
return net_hash_mix(&init_net) ^ net_hash_mix(net) ^ tn_rand;
}
static inline u32 hash128to32(char *bytes)
{
__be32 *tmp = (__be32 *)bytes;
u32 res;
res = ntohl(tmp[0] ^ tmp[1] ^ tmp[2] ^ tmp[3]);
if (likely(res))
return res;
return ntohl(tmp[0] | tmp[1] | tmp[2] | tmp[3]);
}
#ifdef CONFIG_SYSCTL
int tipc_register_sysctl(void);
void tipc_unregister_sysctl(void);
#else
#define tipc_register_sysctl() 0
#define tipc_unregister_sysctl()
#endif
#endif
File diff suppressed because it is too large Load Diff
+200
View File
@@ -0,0 +1,200 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* net/tipc/crypto.h: Include file for TIPC crypto
*
* Copyright (c) 2019, 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.
*/
#ifdef CONFIG_TIPC_CRYPTO
#ifndef _TIPC_CRYPTO_H
#define _TIPC_CRYPTO_H
#include "core.h"
#include "node.h"
#include "msg.h"
#include "bearer.h"
#define TIPC_EVERSION 7
/* AEAD aes(gcm) */
#define TIPC_AES_GCM_KEY_SIZE_128 16
#define TIPC_AES_GCM_KEY_SIZE_192 24
#define TIPC_AES_GCM_KEY_SIZE_256 32
#define TIPC_AES_GCM_SALT_SIZE 4
#define TIPC_AES_GCM_IV_SIZE 12
#define TIPC_AES_GCM_TAG_SIZE 16
/*
* TIPC crypto modes:
* - CLUSTER_KEY:
* One single key is used for both TX & RX in all nodes in the cluster.
* - PER_NODE_KEY:
* Each nodes in the cluster has one TX key, for RX a node needs to know
* its peers' TX key for the decryption of messages from those nodes.
*/
enum {
CLUSTER_KEY = 1,
PER_NODE_KEY = (1 << 1),
};
extern int sysctl_tipc_max_tfms __read_mostly;
extern int sysctl_tipc_key_exchange_enabled __read_mostly;
/*
* TIPC encryption message format:
*
* 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
* 1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* w0:|Ver=7| User |D|TX |RX |K|M|N| Rsvd |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* w1:| Seqno |
* w2:| (8 octets) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* w3:\ Prevnode \
* / (4 or 16 octets) /
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* \ \
* / Encrypted complete TIPC V2 header and user data /
* \ \
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | |
* | AuthTag |
* | (16 octets) |
* | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* Word0:
* Ver : = 7 i.e. TIPC encryption message version
* User : = 7 (for LINK_PROTOCOL); = 13 (for LINK_CONFIG) or = 0
* D : The destined bit i.e. the message's destination node is
* "known" or not at the message encryption
* TX : TX key used for the message encryption
* RX : Currently RX active key corresponding to the destination
* node's TX key (when the "D" bit is set)
* K : Keep-alive bit (for RPS, LINK_PROTOCOL/STATE_MSG only)
* M : Bit indicates if sender has master key
* N : Bit indicates if sender has no RX keys corresponding to the
* receiver's TX (when the "D" bit is set)
* Rsvd : Reserved bit, field
* Word1-2:
* Seqno : The 64-bit sequence number of the encrypted message, also
* part of the nonce used for the message encryption/decryption
* Word3-:
* Prevnode: The source node address, or ID in case LINK_CONFIG only
* AuthTag : The authentication tag for the message integrity checking
* generated by the message encryption
*/
struct tipc_ehdr {
union {
struct {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 destined:1,
user:4,
version:3;
__u8 reserved_1:1,
rx_nokey:1,
master_key:1,
keepalive:1,
rx_key_active:2,
tx_key:2;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u8 version:3,
user:4,
destined:1;
__u8 tx_key:2,
rx_key_active:2,
keepalive:1,
master_key:1,
rx_nokey:1,
reserved_1:1;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__be16 reserved_2;
} __packed;
__be32 w0;
};
__be64 seqno;
union {
__be32 addr;
__u8 id[NODE_ID_LEN]; /* For a LINK_CONFIG message only! */
};
#define EHDR_SIZE (offsetof(struct tipc_ehdr, addr) + sizeof(__be32))
#define EHDR_CFG_SIZE (sizeof(struct tipc_ehdr))
#define EHDR_MIN_SIZE (EHDR_SIZE)
#define EHDR_MAX_SIZE (EHDR_CFG_SIZE)
#define EMSG_OVERHEAD (EHDR_SIZE + TIPC_AES_GCM_TAG_SIZE)
} __packed;
int tipc_crypto_start(struct tipc_crypto **crypto, struct net *net,
struct tipc_node *node);
void tipc_crypto_stop(struct tipc_crypto **crypto);
void tipc_crypto_timeout(struct tipc_crypto *rx);
int tipc_crypto_xmit(struct net *net, struct sk_buff **skb,
struct tipc_bearer *b, struct tipc_media_addr *dst,
struct tipc_node *__dnode);
int tipc_crypto_rcv(struct net *net, struct tipc_crypto *rx,
struct sk_buff **skb, struct tipc_bearer *b);
int tipc_crypto_key_init(struct tipc_crypto *c, struct tipc_aead_key *ukey,
u8 mode, bool master_key);
void tipc_crypto_key_flush(struct tipc_crypto *c);
int tipc_crypto_key_distr(struct tipc_crypto *tx, u8 key,
struct tipc_node *dest);
void tipc_crypto_msg_rcv(struct net *net, struct sk_buff *skb);
void tipc_crypto_rekeying_sched(struct tipc_crypto *tx, bool changed,
u32 new_intv);
int tipc_aead_key_validate(struct tipc_aead_key *ukey, struct genl_info *info);
bool tipc_ehdr_validate(struct sk_buff *skb);
static inline u32 msg_key_gen(struct tipc_msg *m)
{
return msg_bits(m, 4, 16, 0xffff);
}
static inline void msg_set_key_gen(struct tipc_msg *m, u32 gen)
{
msg_set_bits(m, 4, 16, 0xffff, gen);
}
static inline u32 msg_key_mode(struct tipc_msg *m)
{
return msg_bits(m, 4, 0, 0xf);
}
static inline void msg_set_key_mode(struct tipc_msg *m, u32 mode)
{
msg_set_bits(m, 4, 0, 0xf, mode);
}
#endif /* _TIPC_CRYPTO_H */
#endif
+118
View File
@@ -0,0 +1,118 @@
/*
* net/tipc/diag.c: TIPC socket diag
*
* Copyright (c) 2018, 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 "ASIS"
* 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 "socket.h"
#include <linux/sock_diag.h>
#include <linux/tipc_sockets_diag.h>
static u64 __tipc_diag_gen_cookie(struct sock *sk)
{
u32 res[2];
sock_diag_save_cookie(sk, res);
return *((u64 *)res);
}
static int __tipc_add_sock_diag(struct sk_buff *skb,
struct netlink_callback *cb,
struct tipc_sock *tsk)
{
struct tipc_sock_diag_req *req = nlmsg_data(cb->nlh);
struct nlmsghdr *nlh;
int err;
nlh = nlmsg_put_answer(skb, cb, SOCK_DIAG_BY_FAMILY, 0,
NLM_F_MULTI);
if (!nlh)
return -EMSGSIZE;
err = tipc_sk_fill_sock_diag(skb, cb, tsk, req->tidiag_states,
__tipc_diag_gen_cookie);
if (err)
return err;
nlmsg_end(skb, nlh);
return 0;
}
static int tipc_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
return tipc_nl_sk_walk(skb, cb, __tipc_add_sock_diag);
}
static int tipc_sock_diag_handler_dump(struct sk_buff *skb,
struct nlmsghdr *h)
{
int hdrlen = sizeof(struct tipc_sock_diag_req);
struct net *net = sock_net(skb->sk);
if (nlmsg_len(h) < hdrlen)
return -EINVAL;
if (h->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = {
.start = tipc_dump_start,
.dump = tipc_diag_dump,
.done = tipc_dump_done,
};
netlink_dump_start(net->diag_nlsk, skb, h, &c);
return 0;
}
return -EOPNOTSUPP;
}
static const struct sock_diag_handler tipc_sock_diag_handler = {
.owner = THIS_MODULE,
.family = AF_TIPC,
.dump = tipc_sock_diag_handler_dump,
};
static int __init tipc_diag_init(void)
{
return sock_diag_register(&tipc_sock_diag_handler);
}
static void __exit tipc_diag_exit(void)
{
sock_diag_unregister(&tipc_sock_diag_handler);
}
module_init(tipc_diag_init);
module_exit(tipc_diag_exit);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("TIPC socket monitoring via SOCK_DIAG");
MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, AF_TIPC);
+430
View File
@@ -0,0 +1,430 @@
/*
* net/tipc/discover.c
*
* Copyright (c) 2003-2006, 2014-2018, Ericsson AB
* Copyright (c) 2005-2006, 2010-2011, Wind River Systems
* 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 "node.h"
#include "discover.h"
/* min delay during bearer start up */
#define TIPC_DISC_INIT msecs_to_jiffies(125)
/* max delay if bearer has no links */
#define TIPC_DISC_FAST msecs_to_jiffies(1000)
/* max delay if bearer has links */
#define TIPC_DISC_SLOW msecs_to_jiffies(60000)
/* indicates no timer in use */
#define TIPC_DISC_INACTIVE 0xffffffff
/**
* struct tipc_discoverer - information about an ongoing link setup request
* @bearer_id: identity of bearer issuing requests
* @net: network namespace instance
* @dest: destination address for request messages
* @domain: network domain to which links can be established
* @num_nodes: number of nodes currently discovered (i.e. with an active link)
* @lock: spinlock for controlling access to requests
* @skb: request message to be (repeatedly) sent
* @timer: timer governing period between requests
* @timer_intv: current interval between requests (in ms)
* @rcu: RCU head for deferred freeing
*/
struct tipc_discoverer {
u32 bearer_id;
struct tipc_media_addr dest;
struct net *net;
u32 domain;
int num_nodes;
spinlock_t lock;
struct sk_buff *skb;
struct timer_list timer;
unsigned long timer_intv;
struct rcu_head rcu;
};
/**
* tipc_disc_init_msg - initialize a link setup message
* @net: the applicable net namespace
* @skb: buffer containing message
* @mtyp: message type (request or response)
* @b: ptr to bearer issuing message
*/
static void tipc_disc_init_msg(struct net *net, struct sk_buff *skb,
u32 mtyp, struct tipc_bearer *b)
{
struct tipc_net *tn = tipc_net(net);
u32 dest_domain = b->domain;
struct tipc_msg *hdr;
hdr = buf_msg(skb);
tipc_msg_init(tn->trial_addr, hdr, LINK_CONFIG, mtyp,
MAX_H_SIZE, dest_domain);
msg_set_size(hdr, MAX_H_SIZE + NODE_ID_LEN);
msg_set_non_seq(hdr, 1);
msg_set_node_sig(hdr, tn->random);
msg_set_node_capabilities(hdr, TIPC_NODE_CAPABILITIES);
msg_set_dest_domain(hdr, dest_domain);
msg_set_bc_netid(hdr, tn->net_id);
b->media->addr2msg(msg_media_addr(hdr), &b->addr);
msg_set_peer_net_hash(hdr, tipc_net_hash_mixes(net, tn->random));
msg_set_node_id(hdr, tipc_own_id(net));
}
static void tipc_disc_msg_xmit(struct net *net, u32 mtyp, u32 dst,
u32 src, u32 sugg_addr,
struct tipc_media_addr *maddr,
struct tipc_bearer *b)
{
struct tipc_msg *hdr;
struct sk_buff *skb;
skb = tipc_buf_acquire(MAX_H_SIZE + NODE_ID_LEN, GFP_ATOMIC);
if (!skb)
return;
hdr = buf_msg(skb);
tipc_disc_init_msg(net, skb, mtyp, b);
msg_set_sugg_node_addr(hdr, sugg_addr);
msg_set_dest_domain(hdr, dst);
tipc_bearer_xmit_skb(net, b->identity, skb, maddr);
}
/**
* disc_dupl_alert - issue node address duplication alert
* @b: pointer to bearer detecting duplication
* @node_addr: duplicated node address
* @media_addr: media address advertised by duplicated node
*/
static void disc_dupl_alert(struct tipc_bearer *b, u32 node_addr,
struct tipc_media_addr *media_addr)
{
char media_addr_str[64];
tipc_media_addr_printf(media_addr_str, sizeof(media_addr_str),
media_addr);
pr_warn("Duplicate %x using %s seen on <%s>\n", node_addr,
media_addr_str, b->name);
}
/* tipc_disc_addr_trial(): - handle an address uniqueness trial from peer
* Returns true if message should be dropped by caller, i.e., if it is a
* trial message or we are inside trial period. Otherwise false.
*/
static bool tipc_disc_addr_trial_msg(struct tipc_discoverer *d,
struct tipc_media_addr *maddr,
struct tipc_bearer *b,
u32 dst, u32 src,
u32 sugg_addr,
u8 *peer_id,
int mtyp)
{
struct net *net = d->net;
struct tipc_net *tn = tipc_net(net);
u32 self = tipc_own_addr(net);
bool trial = time_before(jiffies, tn->addr_trial_end) && !self;
if (mtyp == DSC_TRIAL_FAIL_MSG) {
if (!trial)
return true;
/* Ignore if somebody else already gave new suggestion */
if (dst != tn->trial_addr)
return true;
/* Otherwise update trial address and restart trial period */
tn->trial_addr = sugg_addr;
msg_set_prevnode(buf_msg(d->skb), sugg_addr);
tn->addr_trial_end = jiffies + msecs_to_jiffies(1000);
return true;
}
/* Apply trial address if we just left trial period */
if (!trial && !self) {
schedule_work(&tn->work);
msg_set_prevnode(buf_msg(d->skb), tn->trial_addr);
msg_set_type(buf_msg(d->skb), DSC_REQ_MSG);
}
/* Accept regular link requests/responses only after trial period */
if (mtyp != DSC_TRIAL_MSG)
return trial;
sugg_addr = tipc_node_try_addr(net, peer_id, src);
if (sugg_addr)
tipc_disc_msg_xmit(net, DSC_TRIAL_FAIL_MSG, src,
self, sugg_addr, maddr, b);
return true;
}
/**
* tipc_disc_rcv - handle incoming discovery message (request or response)
* @net: applicable net namespace
* @skb: buffer containing message
* @b: bearer that message arrived on
*/
void tipc_disc_rcv(struct net *net, struct sk_buff *skb,
struct tipc_bearer *b)
{
struct tipc_net *tn = tipc_net(net);
struct tipc_msg *hdr = buf_msg(skb);
u32 pnet_hash = msg_peer_net_hash(hdr);
u16 caps = msg_node_capabilities(hdr);
bool legacy = tn->legacy_addr_format;
u32 sugg = msg_sugg_node_addr(hdr);
u32 signature = msg_node_sig(hdr);
u8 peer_id[NODE_ID_LEN] = {0,};
u32 dst = msg_dest_domain(hdr);
u32 net_id = msg_bc_netid(hdr);
struct tipc_media_addr maddr;
u32 src = msg_prevnode(hdr);
u32 mtyp = msg_type(hdr);
bool dupl_addr = false;
bool respond = false;
u32 self;
int err;
if (skb_linearize(skb)) {
kfree_skb(skb);
return;
}
hdr = buf_msg(skb);
if (caps & TIPC_NODE_ID128)
memcpy(peer_id, msg_node_id(hdr), NODE_ID_LEN);
else
sprintf(peer_id, "%x", src);
err = b->media->msg2addr(b, &maddr, msg_media_addr(hdr));
kfree_skb(skb);
if (err || maddr.broadcast) {
pr_warn_ratelimited("Rcv corrupt discovery message\n");
return;
}
/* Ignore discovery messages from own node */
if (!memcmp(&maddr, &b->addr, sizeof(maddr)))
return;
if (net_id != tn->net_id)
return;
if (tipc_disc_addr_trial_msg(b->disc, &maddr, b, dst,
src, sugg, peer_id, mtyp))
return;
self = tipc_own_addr(net);
/* Message from somebody using this node's address */
if (in_own_node(net, src)) {
disc_dupl_alert(b, self, &maddr);
return;
}
if (!tipc_in_scope(legacy, dst, self))
return;
if (!tipc_in_scope(legacy, b->domain, src))
return;
tipc_node_check_dest(net, src, peer_id, b, caps, signature, pnet_hash,
&maddr, &respond, &dupl_addr);
if (dupl_addr)
disc_dupl_alert(b, src, &maddr);
if (!respond)
return;
if (mtyp != DSC_REQ_MSG)
return;
tipc_disc_msg_xmit(net, DSC_RESP_MSG, src, self, 0, &maddr, b);
}
/* tipc_disc_add_dest - increment set of discovered nodes
*/
void tipc_disc_add_dest(struct tipc_discoverer *d)
{
spin_lock_bh(&d->lock);
d->num_nodes++;
spin_unlock_bh(&d->lock);
}
/* tipc_disc_remove_dest - decrement set of discovered nodes
*/
void tipc_disc_remove_dest(struct tipc_discoverer *d)
{
int intv, num;
spin_lock_bh(&d->lock);
d->num_nodes--;
num = d->num_nodes;
intv = d->timer_intv;
if (!num && (intv == TIPC_DISC_INACTIVE || intv > TIPC_DISC_FAST)) {
d->timer_intv = TIPC_DISC_INIT;
mod_timer(&d->timer, jiffies + d->timer_intv);
}
spin_unlock_bh(&d->lock);
}
/* tipc_disc_timeout - send a periodic link setup request
* Called whenever a link setup request timer associated with a bearer expires.
* - Keep doubling time between sent request until limit is reached;
* - Hold at fast polling rate if we don't have any associated nodes
* - Otherwise hold at slow polling rate
*/
static void tipc_disc_timeout(struct timer_list *t)
{
struct tipc_discoverer *d = timer_container_of(d, t, timer);
struct tipc_net *tn = tipc_net(d->net);
struct tipc_media_addr maddr;
struct sk_buff *skb = NULL;
struct net *net = d->net;
u32 bearer_id;
spin_lock_bh(&d->lock);
/* Stop searching if only desired node has been found */
if (tipc_node(d->domain) && d->num_nodes) {
d->timer_intv = TIPC_DISC_INACTIVE;
goto exit;
}
/* Did we just leave trial period ? */
if (!time_before(jiffies, tn->addr_trial_end) && !tipc_own_addr(net)) {
mod_timer(&d->timer, jiffies + TIPC_DISC_INIT);
spin_unlock_bh(&d->lock);
schedule_work(&tn->work);
return;
}
/* Adjust timeout interval according to discovery phase */
if (time_before(jiffies, tn->addr_trial_end)) {
d->timer_intv = TIPC_DISC_INIT;
} else {
d->timer_intv *= 2;
if (d->num_nodes && d->timer_intv > TIPC_DISC_SLOW)
d->timer_intv = TIPC_DISC_SLOW;
else if (!d->num_nodes && d->timer_intv > TIPC_DISC_FAST)
d->timer_intv = TIPC_DISC_FAST;
msg_set_type(buf_msg(d->skb), DSC_REQ_MSG);
msg_set_prevnode(buf_msg(d->skb), tn->trial_addr);
}
mod_timer(&d->timer, jiffies + d->timer_intv);
memcpy(&maddr, &d->dest, sizeof(maddr));
skb = skb_clone(d->skb, GFP_ATOMIC);
bearer_id = d->bearer_id;
exit:
spin_unlock_bh(&d->lock);
if (skb)
tipc_bearer_xmit_skb(net, bearer_id, skb, &maddr);
}
/**
* tipc_disc_create - create object to send periodic link setup requests
* @net: the applicable net namespace
* @b: ptr to bearer issuing requests
* @dest: destination address for request messages
* @skb: pointer to created frame
*
* Return: 0 if successful, otherwise -errno.
*/
int tipc_disc_create(struct net *net, struct tipc_bearer *b,
struct tipc_media_addr *dest, struct sk_buff **skb)
{
struct tipc_net *tn = tipc_net(net);
struct tipc_discoverer *d;
d = kmalloc_obj(*d, GFP_ATOMIC);
if (!d)
return -ENOMEM;
d->skb = tipc_buf_acquire(MAX_H_SIZE + NODE_ID_LEN, GFP_ATOMIC);
if (!d->skb) {
kfree(d);
return -ENOMEM;
}
tipc_disc_init_msg(net, d->skb, DSC_REQ_MSG, b);
/* Do we need an address trial period first ? */
if (!tipc_own_addr(net)) {
tn->addr_trial_end = jiffies + msecs_to_jiffies(1000);
msg_set_type(buf_msg(d->skb), DSC_TRIAL_MSG);
}
memcpy(&d->dest, dest, sizeof(*dest));
d->net = net;
d->bearer_id = b->identity;
d->domain = b->domain;
d->num_nodes = 0;
d->timer_intv = TIPC_DISC_INIT;
spin_lock_init(&d->lock);
timer_setup(&d->timer, tipc_disc_timeout, 0);
mod_timer(&d->timer, jiffies + d->timer_intv);
b->disc = d;
*skb = skb_clone(d->skb, GFP_ATOMIC);
return 0;
}
static void tipc_disc_free_rcu(struct rcu_head *rp)
{
struct tipc_discoverer *d = container_of(rp, struct tipc_discoverer,
rcu);
kfree_skb(d->skb);
kfree(d);
}
/**
* tipc_disc_delete - destroy object sending periodic link setup requests
* @d: ptr to link dest structure
*/
void tipc_disc_delete(struct tipc_discoverer *d)
{
timer_shutdown_sync(&d->timer);
call_rcu(&d->rcu, tipc_disc_free_rcu);
}
/**
* tipc_disc_reset - reset object to send periodic link setup requests
* @net: the applicable net namespace
* @b: ptr to bearer issuing requests
*/
void tipc_disc_reset(struct net *net, struct tipc_bearer *b)
{
struct tipc_discoverer *d = b->disc;
struct tipc_media_addr maddr;
struct sk_buff *skb;
spin_lock_bh(&d->lock);
tipc_disc_init_msg(net, d->skb, DSC_REQ_MSG, b);
d->net = net;
d->bearer_id = b->identity;
d->domain = b->domain;
d->num_nodes = 0;
d->timer_intv = TIPC_DISC_INIT;
memcpy(&maddr, &d->dest, sizeof(maddr));
mod_timer(&d->timer, jiffies + d->timer_intv);
skb = skb_clone(d->skb, GFP_ATOMIC);
spin_unlock_bh(&d->lock);
if (skb)
tipc_bearer_xmit_skb(net, b->identity, skb, &maddr);
}
+51
View File
@@ -0,0 +1,51 @@
/*
* net/tipc/discover.h
*
* Copyright (c) 2003-2006, Ericsson AB
* Copyright (c) 2005, 2010-2011, Wind River Systems
* 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_DISCOVER_H
#define _TIPC_DISCOVER_H
struct tipc_discoverer;
int tipc_disc_create(struct net *net, struct tipc_bearer *b_ptr,
struct tipc_media_addr *dest, struct sk_buff **skb);
void tipc_disc_delete(struct tipc_discoverer *req);
void tipc_disc_reset(struct net *net, struct tipc_bearer *b_ptr);
void tipc_disc_add_dest(struct tipc_discoverer *req);
void tipc_disc_remove_dest(struct tipc_discoverer *req);
void tipc_disc_rcv(struct net *net, struct sk_buff *buf,
struct tipc_bearer *b_ptr);
#endif
+98
View File
@@ -0,0 +1,98 @@
/*
* net/tipc/eth_media.c: Ethernet bearer support for TIPC
*
* Copyright (c) 2001-2007, 2013-2014, Ericsson AB
* Copyright (c) 2005-2008, 2011-2013, Wind River Systems
* 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 "bearer.h"
/* Convert Ethernet address (media address format) to string */
static int tipc_eth_addr2str(struct tipc_media_addr *addr,
char *strbuf, int bufsz)
{
if (bufsz < 18) /* 18 = strlen("aa:bb:cc:dd:ee:ff\0") */
return 1;
sprintf(strbuf, "%pM", addr->value);
return 0;
}
/* Convert from media address format to discovery message addr format */
static int tipc_eth_addr2msg(char *msg, struct tipc_media_addr *addr)
{
memset(msg, 0, TIPC_MEDIA_INFO_SIZE);
msg[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_ETH;
memcpy(msg + TIPC_MEDIA_ADDR_OFFSET, addr->value, ETH_ALEN);
return 0;
}
/* Convert raw mac address format to media addr format */
static int tipc_eth_raw2addr(struct tipc_bearer *b,
struct tipc_media_addr *addr,
const char *msg)
{
memset(addr, 0, sizeof(*addr));
ether_addr_copy(addr->value, msg);
addr->media_id = TIPC_MEDIA_TYPE_ETH;
addr->broadcast = is_broadcast_ether_addr(addr->value);
return 0;
}
/* Convert discovery msg addr format to Ethernet media addr format */
static int tipc_eth_msg2addr(struct tipc_bearer *b,
struct tipc_media_addr *addr,
char *msg)
{
/* Skip past preamble: */
msg += TIPC_MEDIA_ADDR_OFFSET;
return tipc_eth_raw2addr(b, addr, msg);
}
/* Ethernet media registration info */
struct tipc_media eth_media_info = {
.send_msg = tipc_l2_send_msg,
.enable_media = tipc_enable_l2_media,
.disable_media = tipc_disable_l2_media,
.addr2str = tipc_eth_addr2str,
.addr2msg = tipc_eth_addr2msg,
.msg2addr = tipc_eth_msg2addr,
.raw2addr = tipc_eth_raw2addr,
.priority = TIPC_DEF_LINK_PRI,
.tolerance = TIPC_DEF_LINK_TOL,
.min_win = TIPC_DEF_LINK_WIN,
.max_win = TIPC_MAX_LINK_WIN,
.type_id = TIPC_MEDIA_TYPE_ETH,
.hwaddr_len = ETH_ALEN,
.name = "eth"
};
+963
View File
@@ -0,0 +1,963 @@
/*
* net/tipc/group.c: TIPC group messaging code
*
* Copyright (c) 2017, Ericsson AB
* Copyright (c) 2020, Red Hat Inc
* 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 "topsrv.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_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 small_win;
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;
};
struct tipc_group {
struct rb_root members;
struct list_head small_win;
struct list_head pending;
struct list_head active;
struct tipc_nlist dests;
struct net *net;
int subid;
u32 type;
u32 instance;
u32 scope;
u32 portid;
u16 member_cnt;
u16 active_cnt;
u16 max_active;
u16 bc_snd_nxt;
u16 bc_ackers;
bool *open;
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_open(struct tipc_member *m, bool *wakeup)
{
*wakeup = false;
if (list_empty(&m->small_win))
return;
list_del_init(&m->small_win);
*m->group->open = true;
*wakeup = true;
}
static void tipc_group_decr_active(struct tipc_group *grp,
struct tipc_member *m)
{
if (m->state == MBR_ACTIVE || m->state == MBR_RECLAIMING ||
m->state == MBR_REMITTED)
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_receiver(struct tipc_member *m)
{
return m && m->state != MBR_JOINING && m->state != MBR_LEAVING;
}
static bool tipc_group_is_sender(struct tipc_member *m)
{
return m && m->state != MBR_JOINING && m->state != MBR_PUBLISHED;
}
u32 tipc_group_exclude(struct tipc_group *grp)
{
if (!grp->loopback)
return grp->portid;
return 0;
}
struct tipc_group *tipc_group_create(struct net *net, u32 portid,
struct tipc_group_req *mreq,
bool *group_is_open)
{
u32 filter = TIPC_SUB_PORTS | TIPC_SUB_NO_STATUS;
bool global = mreq->scope != TIPC_NODE_SCOPE;
struct tipc_group *grp;
u32 type = mreq->type;
grp = kzalloc_obj(*grp, GFP_ATOMIC);
if (!grp)
return NULL;
tipc_nlist_init(&grp->dests, tipc_own_addr(net));
INIT_LIST_HEAD(&grp->small_win);
INIT_LIST_HEAD(&grp->active);
INIT_LIST_HEAD(&grp->pending);
grp->members = RB_ROOT;
grp->net = net;
grp->portid = portid;
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;
grp->open = group_is_open;
*grp->open = false;
filter |= global ? TIPC_SUB_CLUSTER_SCOPE : TIPC_SUB_NODE_SCOPE;
if (tipc_topsrv_kern_subscr(net, portid, type, 0, ~0,
filter, &grp->subid))
return grp;
kfree(grp);
return NULL;
}
void tipc_group_join(struct net *net, struct tipc_group *grp, int *sk_rcvbuf)
{
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_JOIN_MSG, &xmitq);
tipc_group_update_member(m, 0);
}
tipc_node_distr_xmit(net, &xmitq);
*sk_rcvbuf = tipc_group_rcvbuf_limit(grp);
}
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);
__skb_queue_purge(&m->deferredq);
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);
}
static 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_receiver(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 int 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 -EEXIST;
}
rb_link_node(&m->tree_node, parent, n);
rb_insert_color(&m->tree_node, &grp->members);
return 0;
}
static struct tipc_member *tipc_group_create_member(struct tipc_group *grp,
u32 node, u32 port,
u32 instance, int state)
{
struct tipc_member *m;
int ret;
m = kzalloc_obj(*m, GFP_ATOMIC);
if (!m)
return NULL;
INIT_LIST_HEAD(&m->list);
INIT_LIST_HEAD(&m->small_win);
__skb_queue_head_init(&m->deferredq);
m->group = grp;
m->node = node;
m->port = port;
m->instance = instance;
m->bc_acked = grp->bc_snd_nxt - 1;
ret = tipc_group_add_to_tree(grp, m);
if (ret < 0) {
kfree(m);
return NULL;
}
grp->member_cnt++;
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, u32 instance)
{
tipc_group_create_member(grp, node, port, instance, MBR_PUBLISHED);
}
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->small_win);
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_service_range *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_receiver(m))
return;
m->window -= len;
if (m->window >= ADV_IDLE)
return;
list_del_init(&m->small_win);
/* Sort member into small_window members' list */
list_for_each_entry_safe(_m, tmp, &grp->small_win, small_win) {
if (_m->window > m->window)
break;
}
list_add_tail(&m->small_win, &_m->small_win);
}
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;
u16 ackers = 0;
for (n = rb_first(&grp->members); n; n = rb_next(n)) {
m = container_of(n, struct tipc_member, tree_node);
if (tipc_group_is_receiver(m)) {
tipc_group_update_member(m, len);
m->bc_acked = prev;
ackers++;
}
}
/* Mark number of acknowledges to expect, if any */
if (ack)
grp->bc_ackers = ackers;
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);
if (!tipc_group_is_receiver(m)) {
*mbr = NULL;
return false;
}
*mbr = m;
if (m->window >= len)
return false;
*grp->open = false;
/* If not fully advertised, do it now to prevent mutual blocking */
adv = m->advertised;
state = m->state;
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) {
*grp->open = false;
return true;
}
if (list_empty(&grp->small_win))
return false;
m = list_first_entry(&grp->small_win, struct tipc_member, small_win);
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_sender(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);
blks = msg_blocks(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;
}
fallthrough;
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) {
__skb_queue_purge(defq);
tipc_group_delete_member(grp, m);
break;
}
if (!update)
continue;
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, *pm;
m = tipc_group_find_member(grp, node, port);
if (!m)
return;
m->advertised -= blks;
switch (m->state) {
case MBR_JOINED:
/* First, decide if member can go active */
if (active_cnt <= max_active) {
m->state = MBR_ACTIVE;
list_add_tail(&m->list, active);
grp->active_cnt++;
tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq);
} else {
m->state = MBR_PENDING;
list_add_tail(&m->list, &grp->pending);
}
if (active_cnt < reclaim_limit)
break;
/* Reclaim from oldest active member, if possible */
if (!list_empty(active)) {
rm = list_first_entry(active, struct tipc_member, list);
rm->state = MBR_RECLAIMING;
list_del_init(&rm->list);
tipc_group_proto_xmit(grp, rm, GRP_RECLAIM_MSG, xmitq);
break;
}
/* Nobody to reclaim from; - revert oldest pending to JOINED */
pm = list_first_entry(&grp->pending, struct tipc_member, list);
list_del_init(&pm->list);
pm->state = MBR_JOINED;
tipc_group_proto_xmit(grp, pm, GRP_ADV_MSG, xmitq);
break;
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;
grp->active_cnt--;
if (m->advertised < ADV_IDLE) {
pr_warn_ratelimited("Rcv unexpected msg after REMIT\n");
tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq);
}
if (list_empty(&grp->pending))
return;
/* Set oldest pending member to active and advertise */
pm = list_first_entry(&grp->pending, struct tipc_member, list);
pm->state = MBR_ACTIVE;
list_move_tail(&pm->list, &grp->active);
grp->active_cnt++;
tipc_group_proto_xmit(grp, pm, GRP_ADV_MSG, xmitq);
break;
case MBR_RECLAIMING:
case MBR_JOINING:
case MBR_LEAVING:
default:
break;
}
}
static void tipc_group_create_event(struct tipc_group *grp,
struct tipc_member *m,
u32 event, u16 seqno,
struct sk_buff_head *inputq)
{ u32 dnode = tipc_own_addr(grp->net);
struct tipc_event evt;
struct sk_buff *skb;
struct tipc_msg *hdr;
memset(&evt, 0, sizeof(evt));
evt.event = event;
evt.found_lower = m->instance;
evt.found_upper = m->instance;
evt.port.ref = m->port;
evt.port.node = m->node;
evt.s.seq.type = grp->type;
evt.s.seq.lower = m->instance;
evt.s.seq.upper = m->instance;
skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_GRP_MEMBER_EVT,
GROUP_H_SIZE, sizeof(evt), dnode, m->node,
grp->portid, m->port, 0);
if (!skb)
return;
hdr = buf_msg(skb);
msg_set_nametype(hdr, grp->type);
msg_set_grp_evt(hdr, event);
msg_set_dest_droppable(hdr, true);
msg_set_grp_bc_seqno(hdr, seqno);
memcpy(msg_data(hdr), &evt, sizeof(evt));
TIPC_SKB_CB(skb)->orig_member = m->instance;
__skb_queue_tail(inputq, skb);
}
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);
}
msg_set_dest_droppable(hdr, true);
__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;
u16 remitted, in_flight;
u16 acked;
if (!grp)
return;
if (grp->scope == TIPC_NODE_SCOPE && node != tipc_own_addr(grp->net))
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,
0, MBR_JOINING);
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 necessary */
if (m->state != MBR_PUBLISHED)
return;
/* Member can be taken into service */
m->state = MBR_JOINED;
tipc_group_open(m, usr_wakeup);
tipc_group_update_member(m, 0);
tipc_group_proto_xmit(grp, m, GRP_ADV_MSG, xmitq);
tipc_group_create_event(grp, m, TIPC_PUBLISHED,
m->bc_syncpt, inputq);
return;
case GRP_LEAVE_MSG:
if (!m)
return;
m->bc_syncpt = msg_grp_bc_syncpt(hdr);
list_del_init(&m->list);
tipc_group_open(m, usr_wakeup);
tipc_group_decr_active(grp, m);
m->state = MBR_LEAVING;
tipc_group_create_event(grp, m, TIPC_WITHDRAWN,
m->bc_syncpt, inputq);
return;
case GRP_ADV_MSG:
if (!m)
return;
m->window += msg_adv_win(hdr);
tipc_group_open(m, usr_wakeup);
return;
case GRP_ACK_MSG:
if (!m)
return;
acked = msg_grp_bc_acked(hdr);
if (less_eq(acked, m->bc_acked))
return;
m->bc_acked = acked;
if (--grp->bc_ackers)
return;
list_del_init(&m->small_win);
*m->group->open = true;
*usr_wakeup = true;
tipc_group_update_member(m, 0);
return;
case GRP_RECLAIM_MSG:
if (!m)
return;
tipc_group_proto_xmit(grp, m, GRP_REMIT_MSG, xmitq);
m->window = ADV_IDLE;
tipc_group_open(m, usr_wakeup);
return;
case GRP_REMIT_MSG:
if (!m || m->state != MBR_RECLAIMING)
return;
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;
m->advertised = ADV_IDLE + in_flight;
return;
}
/* This should never happen */
if (m->advertised < remitted)
pr_warn_ratelimited("Unexpected REMIT msg\n");
/* All messages preceding the REMIT have been read */
m->state = MBR_JOINED;
grp->active_cnt--;
m->advertised = ADV_IDLE;
/* 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 tipc_msg *hdr,
struct sk_buff_head *inputq,
struct sk_buff_head *xmitq)
{
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;
u32 self;
if (!grp)
return;
net = grp->net;
self = tipc_own_addr(net);
if (!grp->loopback && node == self && port == grp->portid)
return;
m = tipc_group_find_member(grp, node, port);
switch (event) {
case TIPC_PUBLISHED:
/* Send and wait for arrival of JOIN message if necessary */
if (!m) {
m = tipc_group_create_member(grp, node, port, instance,
MBR_PUBLISHED);
if (!m)
break;
tipc_group_update_member(m, 0);
tipc_group_proto_xmit(grp, m, GRP_JOIN_MSG, xmitq);
break;
}
if (m->state != MBR_JOINING)
break;
/* Member can be taken into service */
m->instance = instance;
m->state = MBR_JOINED;
tipc_group_open(m, usr_wakeup);
tipc_group_update_member(m, 0);
tipc_group_proto_xmit(grp, m, GRP_JOIN_MSG, xmitq);
tipc_group_create_event(grp, m, TIPC_PUBLISHED,
m->bc_syncpt, inputq);
break;
case TIPC_WITHDRAWN:
if (!m)
break;
tipc_group_decr_active(grp, m);
m->state = MBR_LEAVING;
list_del_init(&m->list);
tipc_group_open(m, usr_wakeup);
/* Only send event if no LEAVE message can be expected */
if (!tipc_node_is_up(net, node))
tipc_group_create_event(grp, m, TIPC_WITHDRAWN,
m->bc_rcv_nxt, inputq);
break;
default:
break;
}
*sk_rcvbuf = tipc_group_rcvbuf_limit(grp);
}
int tipc_group_fill_sock_diag(struct tipc_group *grp, struct sk_buff *skb)
{
struct nlattr *group = nla_nest_start_noflag(skb, TIPC_NLA_SOCK_GROUP);
if (!group)
return -EMSGSIZE;
if (nla_put_u32(skb, TIPC_NLA_SOCK_GROUP_ID,
grp->type) ||
nla_put_u32(skb, TIPC_NLA_SOCK_GROUP_INSTANCE,
grp->instance) ||
nla_put_u32(skb, TIPC_NLA_SOCK_GROUP_BC_SEND_NEXT,
grp->bc_snd_nxt))
goto group_msg_cancel;
if (grp->scope == TIPC_NODE_SCOPE)
if (nla_put_flag(skb, TIPC_NLA_SOCK_GROUP_NODE_SCOPE))
goto group_msg_cancel;
if (grp->scope == TIPC_CLUSTER_SCOPE)
if (nla_put_flag(skb, TIPC_NLA_SOCK_GROUP_CLUSTER_SCOPE))
goto group_msg_cancel;
if (*grp->open)
if (nla_put_flag(skb, TIPC_NLA_SOCK_GROUP_OPEN))
goto group_msg_cancel;
nla_nest_end(skb, group);
return 0;
group_msg_cancel:
nla_nest_cancel(skb, group);
return -1;
}
+77
View File
@@ -0,0 +1,77 @@
/*
* net/tipc/group.h: Include file for TIPC group unicast/multicast functions
*
* Copyright (c) 2017, Ericsson AB
* Copyright (c) 2020, Red Hat Inc
* 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,
bool *group_is_open);
void tipc_group_join(struct net *net, struct tipc_group *grp, int *sk_rcv_buf);
void tipc_group_delete(struct net *net, struct tipc_group *grp);
void tipc_group_add_member(struct tipc_group *grp, u32 node,
u32 port, u32 instance);
struct tipc_nlist *tipc_group_dests(struct tipc_group *grp);
void tipc_group_self(struct tipc_group *grp, struct tipc_service_range *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 tipc_msg *hdr,
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_fill_sock_diag(struct tipc_group *grp, struct sk_buff *skb);
#endif
+104
View File
@@ -0,0 +1,104 @@
/*
* net/tipc/ib_media.c: Infiniband bearer support for TIPC
*
* Copyright (c) 2013 Patrick McHardy <kaber@trash.net>
*
* Based on eth_media.c, which carries the following copyright notice:
*
* Copyright (c) 2001-2007, Ericsson AB
* Copyright (c) 2005-2008, 2011, Wind River Systems
* 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 <linux/if_infiniband.h>
#include "core.h"
#include "bearer.h"
#define TIPC_MAX_IB_LINK_WIN 500
/* convert InfiniBand address (media address format) media address to string */
static int tipc_ib_addr2str(struct tipc_media_addr *a, char *str_buf,
int str_size)
{
if (str_size < 60) /* 60 = 19 * strlen("xx:") + strlen("xx\0") */
return 1;
sprintf(str_buf, "%20phC", a->value);
return 0;
}
/* Convert from media address format to discovery message addr format */
static int tipc_ib_addr2msg(char *msg, struct tipc_media_addr *addr)
{
memset(msg, 0, TIPC_MEDIA_INFO_SIZE);
memcpy(msg, addr->value, INFINIBAND_ALEN);
return 0;
}
/* Convert raw InfiniBand address format to media addr format */
static int tipc_ib_raw2addr(struct tipc_bearer *b,
struct tipc_media_addr *addr,
const char *msg)
{
memset(addr, 0, sizeof(*addr));
memcpy(addr->value, msg, INFINIBAND_ALEN);
addr->media_id = TIPC_MEDIA_TYPE_IB;
addr->broadcast = !memcmp(msg, b->bcast_addr.value,
INFINIBAND_ALEN);
return 0;
}
/* Convert discovery msg addr format to InfiniBand media addr format */
static int tipc_ib_msg2addr(struct tipc_bearer *b,
struct tipc_media_addr *addr,
char *msg)
{
return tipc_ib_raw2addr(b, addr, msg);
}
/* InfiniBand media registration info */
struct tipc_media ib_media_info = {
.send_msg = tipc_l2_send_msg,
.enable_media = tipc_enable_l2_media,
.disable_media = tipc_disable_l2_media,
.addr2str = tipc_ib_addr2str,
.addr2msg = tipc_ib_addr2msg,
.msg2addr = tipc_ib_msg2addr,
.raw2addr = tipc_ib_raw2addr,
.priority = TIPC_DEF_LINK_PRI,
.tolerance = TIPC_DEF_LINK_TOL,
.min_win = TIPC_DEF_LINK_WIN,
.max_win = TIPC_MAX_IB_LINK_WIN,
.type_id = TIPC_MEDIA_TYPE_IB,
.hwaddr_len = INFINIBAND_ALEN,
.name = "ib"
};
File diff suppressed because it is too large Load Diff
+158
View File
@@ -0,0 +1,158 @@
/*
* net/tipc/link.h: Include file for TIPC link code
*
* Copyright (c) 1995-2006, 2013-2014, Ericsson AB
* Copyright (c) 2004-2005, 2010-2011, Wind River Systems
* 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_LINK_H
#define _TIPC_LINK_H
#include <net/genetlink.h>
#include "msg.h"
#include "node.h"
/* TIPC-specific error codes
*/
#define ELINKCONG EAGAIN /* link congestion <=> resource unavailable */
/* Link FSM events:
*/
enum {
LINK_ESTABLISH_EVT = 0xec1ab1e,
LINK_PEER_RESET_EVT = 0x9eed0e,
LINK_FAILURE_EVT = 0xfa110e,
LINK_RESET_EVT = 0x10ca1d0e,
LINK_FAILOVER_BEGIN_EVT = 0xfa110bee,
LINK_FAILOVER_END_EVT = 0xfa110ede,
LINK_SYNCH_BEGIN_EVT = 0xc1ccbee,
LINK_SYNCH_END_EVT = 0xc1ccede
};
/* Events returned from link at packet reception or at timeout
*/
enum {
TIPC_LINK_UP_EVT = 1,
TIPC_LINK_DOWN_EVT = (1 << 1),
TIPC_LINK_SND_STATE = (1 << 2)
};
/* Starting value for maximum packet size negotiation on unicast links
* (unless bearer MTU is less)
*/
#define MAX_PKT_DEFAULT 1500
bool tipc_link_create(struct net *net, char *if_name, int bearer_id,
int tolerance, char net_plane, u32 mtu, int priority,
u32 min_win, u32 max_win, u32 session, u32 ownnode,
u32 peer, u8 *peer_id, u16 peer_caps,
struct tipc_link *bc_sndlink,
struct tipc_link *bc_rcvlink,
struct sk_buff_head *inputq,
struct sk_buff_head *namedq,
struct tipc_link **link);
bool tipc_link_bc_create(struct net *net, u32 ownnode, u32 peer, u8 *peer_id,
int mtu, u32 min_win, u32 max_win, u16 peer_caps,
struct sk_buff_head *inputq,
struct sk_buff_head *namedq,
struct tipc_link *bc_sndlink,
struct tipc_link **link);
void tipc_link_tnl_prepare(struct tipc_link *l, struct tipc_link *tnl,
int mtyp, struct sk_buff_head *xmitq);
void tipc_link_create_dummy_tnl_msg(struct tipc_link *tnl,
struct sk_buff_head *xmitq);
void tipc_link_failover_prepare(struct tipc_link *l, struct tipc_link *tnl,
struct sk_buff_head *xmitq);
void tipc_link_build_reset_msg(struct tipc_link *l, struct sk_buff_head *xmitq);
int tipc_link_fsm_evt(struct tipc_link *l, int evt);
bool tipc_link_is_up(struct tipc_link *l);
bool tipc_link_peer_is_down(struct tipc_link *l);
bool tipc_link_is_reset(struct tipc_link *l);
bool tipc_link_is_establishing(struct tipc_link *l);
bool tipc_link_is_synching(struct tipc_link *l);
bool tipc_link_is_failingover(struct tipc_link *l);
bool tipc_link_is_blocked(struct tipc_link *l);
void tipc_link_set_active(struct tipc_link *l, bool active);
void tipc_link_reset(struct tipc_link *l);
void tipc_link_reset_stats(struct tipc_link *l);
int tipc_link_xmit(struct tipc_link *link, struct sk_buff_head *list,
struct sk_buff_head *xmitq);
struct sk_buff_head *tipc_link_inputq(struct tipc_link *l);
u16 tipc_link_rcv_nxt(struct tipc_link *l);
u16 tipc_link_acked(struct tipc_link *l);
u32 tipc_link_id(struct tipc_link *l);
char *tipc_link_name(struct tipc_link *l);
u32 tipc_link_state(struct tipc_link *l);
char tipc_link_plane(struct tipc_link *l);
int tipc_link_prio(struct tipc_link *l);
int tipc_link_min_win(struct tipc_link *l);
int tipc_link_max_win(struct tipc_link *l);
void tipc_link_update_caps(struct tipc_link *l, u16 capabilities);
bool tipc_link_validate_msg(struct tipc_link *l, struct tipc_msg *hdr);
unsigned long tipc_link_tolerance(struct tipc_link *l);
void tipc_link_set_tolerance(struct tipc_link *l, u32 tol,
struct sk_buff_head *xmitq);
void tipc_link_set_prio(struct tipc_link *l, u32 prio,
struct sk_buff_head *xmitq);
void tipc_link_set_abort_limit(struct tipc_link *l, u32 limit);
void tipc_link_set_queue_limits(struct tipc_link *l, u32 min_win, u32 max_win);
int __tipc_nl_add_link(struct net *net, struct tipc_nl_msg *msg,
struct tipc_link *link, int nlflags);
int tipc_nl_parse_link_prop(struct nlattr *prop, struct nlattr *props[]);
int tipc_link_timeout(struct tipc_link *l, struct sk_buff_head *xmitq);
int tipc_link_rcv(struct tipc_link *l, struct sk_buff *skb,
struct sk_buff_head *xmitq);
int tipc_link_build_state_msg(struct tipc_link *l, struct sk_buff_head *xmitq);
void tipc_link_add_bc_peer(struct tipc_link *snd_l,
struct tipc_link *uc_l,
struct sk_buff_head *xmitq);
void tipc_link_remove_bc_peer(struct tipc_link *snd_l,
struct tipc_link *rcv_l,
struct sk_buff_head *xmitq);
int tipc_link_bc_peers(struct tipc_link *l);
void tipc_link_set_mtu(struct tipc_link *l, int mtu);
int tipc_link_mtu(struct tipc_link *l);
int tipc_link_mss(struct tipc_link *l);
u16 tipc_get_gap_ack_blks(struct tipc_gap_ack_blks **ga, struct tipc_link *l,
struct tipc_msg *hdr, bool uc);
int tipc_link_bc_ack_rcv(struct tipc_link *l, u16 acked, u16 gap,
struct tipc_gap_ack_blks *ga,
struct sk_buff_head *xmitq,
struct sk_buff_head *retrq);
void tipc_link_bc_init_rcv(struct tipc_link *l, struct tipc_msg *hdr);
int tipc_link_bc_sync_rcv(struct tipc_link *l, struct tipc_msg *hdr,
struct sk_buff_head *xmitq);
int tipc_link_bc_nack_rcv(struct tipc_link *l, struct sk_buff *skb,
struct sk_buff_head *xmitq);
bool tipc_link_too_silent(struct tipc_link *l);
struct net *tipc_link_net(struct tipc_link *l);
#endif
+875
View File
@@ -0,0 +1,875 @@
/*
* net/tipc/monitor.c
*
* Copyright (c) 2016, 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 <net/genetlink.h>
#include "core.h"
#include "addr.h"
#include "monitor.h"
#include "bearer.h"
#define MAX_MON_DOMAIN 64
#define MON_TIMEOUT 120000
#define MAX_PEER_DOWN_EVENTS 4
/* struct tipc_mon_domain: domain record to be transferred between peers
* @len: actual size of domain record
* @gen: current generation of sender's domain
* @ack_gen: most recent generation of self's domain acked by peer
* @member_cnt: number of domain member nodes described in this record
* @up_map: bit map indicating which of the members the sender considers up
* @members: identity of the domain members
*/
struct tipc_mon_domain {
u16 len;
u16 gen;
u16 ack_gen;
u16 member_cnt;
u64 up_map;
u32 members[MAX_MON_DOMAIN];
};
/* struct tipc_peer: state of a peer node and its domain
* @addr: tipc node identity of peer
* @head_map: shows which other nodes currently consider peer 'up'
* @domain: most recent domain record from peer
* @hash: position in hashed lookup list
* @list: position in linked list, in circular ascending order by 'addr'
* @applied: number of reported domain members applied on this monitor list
* @is_up: peer is up as seen from this node
* @is_head: peer is assigned domain head as seen from this node
* @is_local: peer is in local domain and should be continuously monitored
* @down_cnt: - numbers of other peers which have reported this on lost
*/
struct tipc_peer {
u32 addr;
struct tipc_mon_domain *domain;
struct hlist_node hash;
struct list_head list;
u8 applied;
u8 down_cnt;
bool is_up;
bool is_head;
bool is_local;
};
struct tipc_monitor {
struct hlist_head peers[NODE_HTABLE_SIZE];
int peer_cnt;
struct tipc_peer *self;
rwlock_t lock;
struct tipc_mon_domain cache;
u16 list_gen;
u16 dom_gen;
struct net *net;
struct timer_list timer;
unsigned long timer_intv;
};
static struct tipc_monitor *tipc_monitor(struct net *net, int bearer_id)
{
return tipc_net(net)->monitors[bearer_id];
}
const int tipc_max_domain_size = sizeof(struct tipc_mon_domain);
static inline u16 mon_cpu_to_le16(u16 val)
{
return (__force __u16)htons(val);
}
static inline u32 mon_cpu_to_le32(u32 val)
{
return (__force __u32)htonl(val);
}
static inline u64 mon_cpu_to_le64(u64 val)
{
return (__force __u64)cpu_to_be64(val);
}
static inline u16 mon_le16_to_cpu(u16 val)
{
return ntohs((__force __be16)val);
}
static inline u32 mon_le32_to_cpu(u32 val)
{
return ntohl((__force __be32)val);
}
static inline u64 mon_le64_to_cpu(u64 val)
{
return be64_to_cpu((__force __be64)val);
}
/* dom_rec_len(): actual length of domain record for transport
*/
static int dom_rec_len(struct tipc_mon_domain *dom, u16 mcnt)
{
return (offsetof(struct tipc_mon_domain, members)) + (mcnt * sizeof(u32));
}
/* dom_size() : calculate size of own domain based on number of peers
*/
static int dom_size(int peers)
{
int i = 0;
while ((i * i) < peers)
i++;
return min(i, MAX_MON_DOMAIN);
}
static void map_set(u64 *up_map, int i, unsigned int v)
{
*up_map &= ~(1ULL << i);
*up_map |= ((u64)v << i);
}
static int map_get(u64 up_map, int i)
{
return (up_map & (1ULL << i)) >> i;
}
static struct tipc_peer *peer_prev(struct tipc_peer *peer)
{
return list_last_entry(&peer->list, struct tipc_peer, list);
}
static struct tipc_peer *peer_nxt(struct tipc_peer *peer)
{
return list_first_entry(&peer->list, struct tipc_peer, list);
}
static struct tipc_peer *peer_head(struct tipc_peer *peer)
{
while (!peer->is_head)
peer = peer_prev(peer);
return peer;
}
static struct tipc_peer *get_peer(struct tipc_monitor *mon, u32 addr)
{
struct tipc_peer *peer;
unsigned int thash = tipc_hashfn(addr);
hlist_for_each_entry(peer, &mon->peers[thash], hash) {
if (peer->addr == addr)
return peer;
}
return NULL;
}
static struct tipc_peer *get_self(struct net *net, int bearer_id)
{
struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
return mon->self;
}
static inline bool tipc_mon_is_active(struct net *net, struct tipc_monitor *mon)
{
struct tipc_net *tn = tipc_net(net);
return mon->peer_cnt > tn->mon_threshold;
}
/* mon_identify_lost_members() : - identify amd mark potentially lost members
*/
static void mon_identify_lost_members(struct tipc_peer *peer,
struct tipc_mon_domain *dom_bef,
int applied_bef)
{
struct tipc_peer *member = peer;
struct tipc_mon_domain *dom_aft = peer->domain;
int applied_aft = peer->applied;
int i;
for (i = 0; i < applied_bef; i++) {
member = peer_nxt(member);
/* Do nothing if self or peer already see member as down */
if (!member->is_up || !map_get(dom_bef->up_map, i))
continue;
/* Loss of local node must be detected by active probing */
if (member->is_local)
continue;
/* Start probing if member was removed from applied domain */
if (!applied_aft || (applied_aft < i)) {
member->down_cnt = 1;
continue;
}
/* Member loss is confirmed if it is still in applied domain */
if (!map_get(dom_aft->up_map, i))
member->down_cnt++;
}
}
/* mon_apply_domain() : match a peer's domain record against monitor list
*/
static void mon_apply_domain(struct tipc_monitor *mon,
struct tipc_peer *peer)
{
struct tipc_mon_domain *dom = peer->domain;
struct tipc_peer *member;
u32 addr;
int i;
if (!dom || !peer->is_up)
return;
/* Scan across domain members and match against monitor list */
peer->applied = 0;
member = peer_nxt(peer);
for (i = 0; i < dom->member_cnt; i++) {
addr = dom->members[i];
if (addr != member->addr)
return;
peer->applied++;
member = peer_nxt(member);
}
}
/* mon_update_local_domain() : update after peer addition/removal/up/down
*/
static void mon_update_local_domain(struct tipc_monitor *mon)
{
struct tipc_peer *self = mon->self;
struct tipc_mon_domain *cache = &mon->cache;
struct tipc_mon_domain *dom = self->domain;
struct tipc_peer *peer = self;
u64 prev_up_map = dom->up_map;
u16 member_cnt, i;
bool diff;
/* Update local domain size based on current size of cluster */
member_cnt = dom_size(mon->peer_cnt) - 1;
self->applied = member_cnt;
/* Update native and cached outgoing local domain records */
dom->len = dom_rec_len(dom, member_cnt);
diff = dom->member_cnt != member_cnt;
dom->member_cnt = member_cnt;
for (i = 0; i < member_cnt; i++) {
peer = peer_nxt(peer);
diff |= dom->members[i] != peer->addr;
dom->members[i] = peer->addr;
map_set(&dom->up_map, i, peer->is_up);
cache->members[i] = mon_cpu_to_le32(peer->addr);
}
diff |= dom->up_map != prev_up_map;
if (!diff)
return;
dom->gen = ++mon->dom_gen;
cache->len = mon_cpu_to_le16(dom->len);
cache->gen = mon_cpu_to_le16(dom->gen);
cache->member_cnt = mon_cpu_to_le16(member_cnt);
cache->up_map = mon_cpu_to_le64(dom->up_map);
mon_apply_domain(mon, self);
}
/* mon_update_neighbors() : update preceding neighbors of added/removed peer
*/
static void mon_update_neighbors(struct tipc_monitor *mon,
struct tipc_peer *peer)
{
int dz, i;
dz = dom_size(mon->peer_cnt);
for (i = 0; i < dz; i++) {
mon_apply_domain(mon, peer);
peer = peer_prev(peer);
}
}
/* mon_assign_roles() : reassign peer roles after a network change
* The monitor list is consistent at this stage; i.e., each peer is monitoring
* a set of domain members as matched between domain record and the monitor list
*/
static void mon_assign_roles(struct tipc_monitor *mon, struct tipc_peer *head)
{
struct tipc_peer *peer = peer_nxt(head);
struct tipc_peer *self = mon->self;
int i = 0;
for (; peer != self; peer = peer_nxt(peer)) {
peer->is_local = false;
/* Update domain member */
if (i++ < head->applied) {
peer->is_head = false;
if (head == self)
peer->is_local = true;
continue;
}
/* Assign next domain head */
if (!peer->is_up)
continue;
if (peer->is_head)
break;
head = peer;
head->is_head = true;
i = 0;
}
mon->list_gen++;
}
void tipc_mon_remove_peer(struct net *net, u32 addr, int bearer_id)
{
struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
struct tipc_peer *self;
struct tipc_peer *peer, *prev, *head;
if (!mon)
return;
self = get_self(net, bearer_id);
write_lock_bh(&mon->lock);
peer = get_peer(mon, addr);
if (!peer)
goto exit;
prev = peer_prev(peer);
list_del(&peer->list);
hlist_del(&peer->hash);
kfree(peer->domain);
kfree(peer);
mon->peer_cnt--;
head = peer_head(prev);
if (head == self)
mon_update_local_domain(mon);
mon_update_neighbors(mon, prev);
/* Revert to full-mesh monitoring if we reach threshold */
if (!tipc_mon_is_active(net, mon)) {
list_for_each_entry(peer, &self->list, list) {
kfree(peer->domain);
peer->domain = NULL;
peer->applied = 0;
}
}
mon_assign_roles(mon, head);
exit:
write_unlock_bh(&mon->lock);
}
static bool tipc_mon_add_peer(struct tipc_monitor *mon, u32 addr,
struct tipc_peer **peer)
{
struct tipc_peer *self = mon->self;
struct tipc_peer *cur, *prev, *p;
p = kzalloc_obj(*p, GFP_ATOMIC);
*peer = p;
if (!p)
return false;
p->addr = addr;
/* Add new peer to lookup list */
INIT_LIST_HEAD(&p->list);
hlist_add_head(&p->hash, &mon->peers[tipc_hashfn(addr)]);
/* Sort new peer into iterator list, in ascending circular order */
prev = self;
list_for_each_entry(cur, &self->list, list) {
if ((addr > prev->addr) && (addr < cur->addr))
break;
if (((addr < cur->addr) || (addr > prev->addr)) &&
(prev->addr > cur->addr))
break;
prev = cur;
}
list_add_tail(&p->list, &cur->list);
mon->peer_cnt++;
mon_update_neighbors(mon, p);
return true;
}
void tipc_mon_peer_up(struct net *net, u32 addr, int bearer_id)
{
struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
struct tipc_peer *self = get_self(net, bearer_id);
struct tipc_peer *peer, *head;
write_lock_bh(&mon->lock);
peer = get_peer(mon, addr);
if (!peer && !tipc_mon_add_peer(mon, addr, &peer))
goto exit;
peer->is_up = true;
head = peer_head(peer);
if (head == self)
mon_update_local_domain(mon);
mon_assign_roles(mon, head);
exit:
write_unlock_bh(&mon->lock);
}
void tipc_mon_peer_down(struct net *net, u32 addr, int bearer_id)
{
struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
struct tipc_peer *self;
struct tipc_peer *peer, *head;
struct tipc_mon_domain *dom;
int applied;
if (!mon)
return;
self = get_self(net, bearer_id);
write_lock_bh(&mon->lock);
peer = get_peer(mon, addr);
if (!peer) {
pr_warn("Mon: unknown link %x/%u DOWN\n", addr, bearer_id);
goto exit;
}
applied = peer->applied;
peer->applied = 0;
dom = peer->domain;
peer->domain = NULL;
if (peer->is_head)
mon_identify_lost_members(peer, dom, applied);
kfree(dom);
peer->is_up = false;
peer->is_head = false;
peer->is_local = false;
peer->down_cnt = 0;
head = peer_head(peer);
if (head == self)
mon_update_local_domain(mon);
mon_assign_roles(mon, head);
exit:
write_unlock_bh(&mon->lock);
}
/* tipc_mon_rcv - process monitor domain event message
*/
void tipc_mon_rcv(struct net *net, void *data, u16 dlen, u32 addr,
struct tipc_mon_state *state, int bearer_id)
{
struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
struct tipc_mon_domain *arrv_dom = data;
struct tipc_mon_domain dom_bef;
struct tipc_mon_domain *dom;
struct tipc_peer *peer;
u16 new_member_cnt = mon_le16_to_cpu(arrv_dom->member_cnt);
int new_dlen = dom_rec_len(arrv_dom, new_member_cnt);
u16 new_gen = mon_le16_to_cpu(arrv_dom->gen);
u16 acked_gen = mon_le16_to_cpu(arrv_dom->ack_gen);
u16 arrv_dlen = mon_le16_to_cpu(arrv_dom->len);
bool probing = state->probing;
int i, applied_bef;
state->probing = false;
/* Sanity check received domain record */
if (new_member_cnt > MAX_MON_DOMAIN)
return;
if (dlen < dom_rec_len(arrv_dom, 0))
return;
if (dlen != dom_rec_len(arrv_dom, new_member_cnt))
return;
if (dlen < new_dlen || arrv_dlen != new_dlen)
return;
/* Synch generation numbers with peer if link just came up */
if (!state->synched) {
state->peer_gen = new_gen - 1;
state->acked_gen = acked_gen;
state->synched = true;
}
if (more(acked_gen, state->acked_gen))
state->acked_gen = acked_gen;
/* Drop duplicate unless we are waiting for a probe response */
if (!more(new_gen, state->peer_gen) && !probing)
return;
write_lock_bh(&mon->lock);
peer = get_peer(mon, addr);
if (!peer || !peer->is_up)
goto exit;
/* Peer is confirmed, stop any ongoing probing */
peer->down_cnt = 0;
/* Task is done for duplicate record */
if (!more(new_gen, state->peer_gen))
goto exit;
state->peer_gen = new_gen;
/* Cache current domain record for later use */
dom_bef.member_cnt = 0;
dom = peer->domain;
if (dom)
memcpy(&dom_bef, dom, dom->len);
/* Transform and store received domain record */
if (!dom || (dom->len < new_dlen)) {
kfree(dom);
dom = kmalloc(new_dlen, GFP_ATOMIC);
peer->domain = dom;
if (!dom)
goto exit;
}
dom->len = new_dlen;
dom->gen = new_gen;
dom->member_cnt = new_member_cnt;
dom->up_map = mon_le64_to_cpu(arrv_dom->up_map);
for (i = 0; i < new_member_cnt; i++)
dom->members[i] = mon_le32_to_cpu(arrv_dom->members[i]);
/* Update peers affected by this domain record */
applied_bef = peer->applied;
mon_apply_domain(mon, peer);
mon_identify_lost_members(peer, &dom_bef, applied_bef);
mon_assign_roles(mon, peer_head(peer));
exit:
write_unlock_bh(&mon->lock);
}
void tipc_mon_prep(struct net *net, void *data, int *dlen,
struct tipc_mon_state *state, int bearer_id)
{
struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
struct tipc_mon_domain *dom = data;
u16 gen = mon->dom_gen;
u16 len;
/* Send invalid record if not active */
if (!tipc_mon_is_active(net, mon)) {
dom->len = 0;
return;
}
/* Send only a dummy record with ack if peer has acked our last sent */
if (likely(state->acked_gen == gen)) {
len = dom_rec_len(dom, 0);
*dlen = len;
dom->len = mon_cpu_to_le16(len);
dom->gen = mon_cpu_to_le16(gen);
dom->ack_gen = mon_cpu_to_le16(state->peer_gen);
dom->member_cnt = 0;
return;
}
/* Send the full record */
read_lock_bh(&mon->lock);
len = mon_le16_to_cpu(mon->cache.len);
*dlen = len;
memcpy(data, &mon->cache, len);
read_unlock_bh(&mon->lock);
dom->ack_gen = mon_cpu_to_le16(state->peer_gen);
}
void tipc_mon_get_state(struct net *net, u32 addr,
struct tipc_mon_state *state,
int bearer_id)
{
struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
struct tipc_peer *peer;
if (!tipc_mon_is_active(net, mon)) {
state->probing = false;
state->monitoring = true;
return;
}
/* Used cached state if table has not changed */
if (!state->probing &&
(state->list_gen == mon->list_gen) &&
(state->acked_gen == mon->dom_gen))
return;
read_lock_bh(&mon->lock);
peer = get_peer(mon, addr);
if (peer) {
state->probing = state->acked_gen != mon->dom_gen;
state->probing |= peer->down_cnt;
state->reset |= peer->down_cnt >= MAX_PEER_DOWN_EVENTS;
state->monitoring = peer->is_local;
state->monitoring |= peer->is_head;
state->list_gen = mon->list_gen;
}
read_unlock_bh(&mon->lock);
}
static void mon_timeout(struct timer_list *t)
{
struct tipc_monitor *mon = timer_container_of(mon, t, timer);
struct tipc_peer *self;
int best_member_cnt = dom_size(mon->peer_cnt) - 1;
write_lock_bh(&mon->lock);
self = mon->self;
if (self && (best_member_cnt != self->applied)) {
mon_update_local_domain(mon);
mon_assign_roles(mon, self);
}
write_unlock_bh(&mon->lock);
mod_timer(&mon->timer, jiffies + mon->timer_intv);
}
int tipc_mon_create(struct net *net, int bearer_id)
{
struct tipc_net *tn = tipc_net(net);
struct tipc_monitor *mon;
struct tipc_peer *self;
struct tipc_mon_domain *dom;
if (tn->monitors[bearer_id])
return 0;
mon = kzalloc_obj(*mon, GFP_ATOMIC);
self = kzalloc_obj(*self, GFP_ATOMIC);
dom = kzalloc_obj(*dom, GFP_ATOMIC);
if (!mon || !self || !dom) {
kfree(mon);
kfree(self);
kfree(dom);
return -ENOMEM;
}
tn->monitors[bearer_id] = mon;
rwlock_init(&mon->lock);
mon->net = net;
mon->peer_cnt = 1;
mon->self = self;
self->domain = dom;
self->addr = tipc_own_addr(net);
self->is_up = true;
self->is_head = true;
INIT_LIST_HEAD(&self->list);
timer_setup(&mon->timer, mon_timeout, 0);
mon->timer_intv = msecs_to_jiffies(MON_TIMEOUT + (tn->random & 0xffff));
mod_timer(&mon->timer, jiffies + mon->timer_intv);
return 0;
}
void tipc_mon_delete(struct net *net, int bearer_id)
{
struct tipc_net *tn = tipc_net(net);
struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
struct tipc_peer *self;
struct tipc_peer *peer, *tmp;
if (!mon)
return;
self = get_self(net, bearer_id);
write_lock_bh(&mon->lock);
tn->monitors[bearer_id] = NULL;
list_for_each_entry_safe(peer, tmp, &self->list, list) {
list_del(&peer->list);
hlist_del(&peer->hash);
kfree(peer->domain);
kfree(peer);
}
mon->self = NULL;
write_unlock_bh(&mon->lock);
timer_shutdown_sync(&mon->timer);
kfree(self->domain);
kfree(self);
kfree(mon);
}
void tipc_mon_reinit_self(struct net *net)
{
struct tipc_monitor *mon;
int bearer_id;
for (bearer_id = 0; bearer_id < MAX_BEARERS; bearer_id++) {
mon = tipc_monitor(net, bearer_id);
if (!mon)
continue;
write_lock_bh(&mon->lock);
if (mon->self)
mon->self->addr = tipc_own_addr(net);
write_unlock_bh(&mon->lock);
}
}
int tipc_nl_monitor_set_threshold(struct net *net, u32 cluster_size)
{
struct tipc_net *tn = tipc_net(net);
if (cluster_size > TIPC_CLUSTER_SIZE)
return -EINVAL;
tn->mon_threshold = cluster_size;
return 0;
}
int tipc_nl_monitor_get_threshold(struct net *net)
{
struct tipc_net *tn = tipc_net(net);
return tn->mon_threshold;
}
static int __tipc_nl_add_monitor_peer(struct tipc_peer *peer,
struct tipc_nl_msg *msg)
{
struct tipc_mon_domain *dom = peer->domain;
struct nlattr *attrs;
void *hdr;
hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
NLM_F_MULTI, TIPC_NL_MON_PEER_GET);
if (!hdr)
return -EMSGSIZE;
attrs = nla_nest_start_noflag(msg->skb, TIPC_NLA_MON_PEER);
if (!attrs)
goto msg_full;
if (nla_put_u32(msg->skb, TIPC_NLA_MON_PEER_ADDR, peer->addr))
goto attr_msg_full;
if (nla_put_u32(msg->skb, TIPC_NLA_MON_PEER_APPLIED, peer->applied))
goto attr_msg_full;
if (peer->is_up)
if (nla_put_flag(msg->skb, TIPC_NLA_MON_PEER_UP))
goto attr_msg_full;
if (peer->is_local)
if (nla_put_flag(msg->skb, TIPC_NLA_MON_PEER_LOCAL))
goto attr_msg_full;
if (peer->is_head)
if (nla_put_flag(msg->skb, TIPC_NLA_MON_PEER_HEAD))
goto attr_msg_full;
if (dom) {
if (nla_put_u32(msg->skb, TIPC_NLA_MON_PEER_DOMGEN, dom->gen))
goto attr_msg_full;
if (nla_put_u64_64bit(msg->skb, TIPC_NLA_MON_PEER_UPMAP,
dom->up_map, TIPC_NLA_MON_PEER_PAD))
goto attr_msg_full;
if (nla_put(msg->skb, TIPC_NLA_MON_PEER_MEMBERS,
dom->member_cnt * sizeof(u32), &dom->members))
goto attr_msg_full;
}
nla_nest_end(msg->skb, attrs);
genlmsg_end(msg->skb, hdr);
return 0;
attr_msg_full:
nla_nest_cancel(msg->skb, attrs);
msg_full:
genlmsg_cancel(msg->skb, hdr);
return -EMSGSIZE;
}
int tipc_nl_add_monitor_peer(struct net *net, struct tipc_nl_msg *msg,
u32 bearer_id, u32 *prev_node)
{
struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
struct tipc_peer *peer;
if (!mon)
return -EINVAL;
read_lock_bh(&mon->lock);
peer = mon->self;
do {
if (*prev_node) {
if (peer->addr == *prev_node)
*prev_node = 0;
else
continue;
}
if (__tipc_nl_add_monitor_peer(peer, msg)) {
*prev_node = peer->addr;
read_unlock_bh(&mon->lock);
return -EMSGSIZE;
}
} while ((peer = peer_nxt(peer)) != mon->self);
read_unlock_bh(&mon->lock);
return 0;
}
int __tipc_nl_add_monitor(struct net *net, struct tipc_nl_msg *msg,
u32 bearer_id)
{
struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
char bearer_name[TIPC_MAX_BEARER_NAME];
struct nlattr *attrs;
void *hdr;
int ret;
ret = tipc_bearer_get_name(net, bearer_name, bearer_id);
if (ret || !mon)
return 0;
hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
NLM_F_MULTI, TIPC_NL_MON_GET);
if (!hdr)
return -EMSGSIZE;
attrs = nla_nest_start_noflag(msg->skb, TIPC_NLA_MON);
if (!attrs)
goto msg_full;
read_lock_bh(&mon->lock);
if (nla_put_u32(msg->skb, TIPC_NLA_MON_REF, bearer_id))
goto attr_msg_full;
if (tipc_mon_is_active(net, mon))
if (nla_put_flag(msg->skb, TIPC_NLA_MON_ACTIVE))
goto attr_msg_full;
if (nla_put_string(msg->skb, TIPC_NLA_MON_BEARER_NAME, bearer_name))
goto attr_msg_full;
if (nla_put_u32(msg->skb, TIPC_NLA_MON_PEERCNT, mon->peer_cnt))
goto attr_msg_full;
if (nla_put_u32(msg->skb, TIPC_NLA_MON_LISTGEN, mon->list_gen))
goto attr_msg_full;
read_unlock_bh(&mon->lock);
nla_nest_end(msg->skb, attrs);
genlmsg_end(msg->skb, hdr);
return 0;
attr_msg_full:
read_unlock_bh(&mon->lock);
nla_nest_cancel(msg->skb, attrs);
msg_full:
genlmsg_cancel(msg->skb, hdr);
return -EMSGSIZE;
}
+83
View File
@@ -0,0 +1,83 @@
/*
* net/tipc/monitor.h
*
* Copyright (c) 2015, 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_MONITOR_H
#define _TIPC_MONITOR_H
#include "netlink.h"
/* struct tipc_mon_state: link instance's cache of monitor list and domain state
* @list_gen: current generation of this node's monitor list
* @gen: current generation of this node's local domain
* @peer_gen: most recent domain generation received from peer
* @acked_gen: most recent generation of self's domain acked by peer
* @monitoring: this peer endpoint should continuously monitored
* @probing: peer endpoint should be temporarily probed for potential loss
* @synched: domain record's generation has been synched with peer after reset
*/
struct tipc_mon_state {
u16 list_gen;
u16 peer_gen;
u16 acked_gen;
bool monitoring :1;
bool probing :1;
bool reset :1;
bool synched :1;
};
int tipc_mon_create(struct net *net, int bearer_id);
void tipc_mon_delete(struct net *net, int bearer_id);
void tipc_mon_peer_up(struct net *net, u32 addr, int bearer_id);
void tipc_mon_peer_down(struct net *net, u32 addr, int bearer_id);
void tipc_mon_prep(struct net *net, void *data, int *dlen,
struct tipc_mon_state *state, int bearer_id);
void tipc_mon_rcv(struct net *net, void *data, u16 dlen, u32 addr,
struct tipc_mon_state *state, int bearer_id);
void tipc_mon_get_state(struct net *net, u32 addr,
struct tipc_mon_state *state,
int bearer_id);
void tipc_mon_remove_peer(struct net *net, u32 addr, int bearer_id);
int tipc_nl_monitor_set_threshold(struct net *net, u32 cluster_size);
int tipc_nl_monitor_get_threshold(struct net *net);
int __tipc_nl_add_monitor(struct net *net, struct tipc_nl_msg *msg,
u32 bearer_id);
int tipc_nl_add_monitor_peer(struct net *net, struct tipc_nl_msg *msg,
u32 bearer_id, u32 *prev_node);
void tipc_mon_reinit_self(struct net *net);
extern const int tipc_max_domain_size;
#endif
+867
View File
@@ -0,0 +1,867 @@
/*
* net/tipc/msg.c: TIPC message header routines
*
* Copyright (c) 2000-2006, 2014-2015, Ericsson AB
* Copyright (c) 2005, 2010-2011, Wind River Systems
* 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 <net/sock.h>
#include "core.h"
#include "msg.h"
#include "addr.h"
#include "name_table.h"
#include "crypto.h"
#define BUF_ALIGN(x) ALIGN(x, 4)
#define MAX_FORWARD_SIZE 1024
#ifdef CONFIG_TIPC_CRYPTO
#define BUF_HEADROOM ALIGN(((LL_MAX_HEADER + 48) + EHDR_MAX_SIZE), 16)
#define BUF_OVERHEAD (BUF_HEADROOM + TIPC_AES_GCM_TAG_SIZE)
#else
#define BUF_HEADROOM (LL_MAX_HEADER + 48)
#define BUF_OVERHEAD BUF_HEADROOM
#endif
const int one_page_mtu = PAGE_SIZE - SKB_DATA_ALIGN(BUF_OVERHEAD) -
SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
/**
* tipc_buf_acquire - creates a TIPC message buffer
* @size: message size (including TIPC header)
* @gfp: memory allocation flags
*
* Return: a new buffer with data pointers set to the specified size.
*
* NOTE:
* Headroom is reserved to allow prepending of a data link header.
* There may also be unrequested tailroom present at the buffer's end.
*/
struct sk_buff *tipc_buf_acquire(u32 size, gfp_t gfp)
{
struct sk_buff *skb;
skb = alloc_skb_fclone(BUF_OVERHEAD + size, gfp);
if (skb) {
skb_reserve(skb, BUF_HEADROOM);
skb_put(skb, size);
skb->next = NULL;
}
return skb;
}
void tipc_msg_init(u32 own_node, struct tipc_msg *m, u32 user, u32 type,
u32 hsize, u32 dnode)
{
memset(m, 0, hsize);
msg_set_version(m);
msg_set_user(m, user);
msg_set_hdr_sz(m, hsize);
msg_set_size(m, hsize);
msg_set_prevnode(m, own_node);
msg_set_type(m, type);
if (hsize > SHORT_H_SIZE) {
msg_set_orignode(m, own_node);
msg_set_destnode(m, dnode);
}
}
struct sk_buff *tipc_msg_create(uint user, uint type,
uint hdr_sz, uint data_sz, u32 dnode,
u32 onode, u32 dport, u32 oport, int errcode)
{
struct tipc_msg *msg;
struct sk_buff *buf;
buf = tipc_buf_acquire(hdr_sz + data_sz, GFP_ATOMIC);
if (unlikely(!buf))
return NULL;
msg = buf_msg(buf);
tipc_msg_init(onode, msg, user, type, hdr_sz, dnode);
msg_set_size(msg, hdr_sz + data_sz);
msg_set_origport(msg, oport);
msg_set_destport(msg, dport);
msg_set_errcode(msg, errcode);
return buf;
}
/* tipc_buf_append(): Append a buffer to the fragment list of another buffer
* @*headbuf: in: NULL for first frag, otherwise value returned from prev call
* out: set when successful non-complete reassembly, otherwise NULL
* @*buf: in: the buffer to append. Always defined
* out: head buf after successful complete reassembly, otherwise NULL
* Returns 1 when reassembly complete, otherwise 0
*/
int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
{
struct sk_buff *head = *headbuf;
struct sk_buff *frag = *buf;
struct sk_buff *tail = NULL;
struct tipc_msg *msg;
u32 fragid;
int delta;
bool headstolen;
if (!frag)
goto err;
msg = buf_msg(frag);
fragid = msg_type(msg);
frag->next = NULL;
skb_pull(frag, msg_hdr_sz(msg));
if (fragid == FIRST_FRAGMENT) {
if (unlikely(head))
goto err;
if (skb_has_frag_list(frag) && __skb_linearize(frag))
goto err;
*buf = NULL;
frag = skb_unshare(frag, GFP_ATOMIC);
if (unlikely(!frag))
goto err;
head = *headbuf = frag;
TIPC_SKB_CB(head)->tail = NULL;
return 0;
}
if (!head)
goto err;
/* Either the input skb ownership is transferred to headskb
* or the input skb is freed, clear the reference to avoid
* bad access on error path.
*/
*buf = NULL;
if (skb_try_coalesce(head, frag, &headstolen, &delta)) {
kfree_skb_partial(frag, headstolen);
} else {
tail = TIPC_SKB_CB(head)->tail;
if (!skb_has_frag_list(head))
skb_shinfo(head)->frag_list = frag;
else
tail->next = frag;
head->truesize += frag->truesize;
head->data_len += frag->len;
head->len += frag->len;
TIPC_SKB_CB(head)->tail = frag;
}
if (fragid == LAST_FRAGMENT) {
TIPC_SKB_CB(head)->validated = 0;
/* If the reassembled skb has been freed in
* tipc_msg_validate() because of an invalid truesize,
* then head will point to a newly allocated reassembled
* skb, while *headbuf points to freed reassembled skb.
* In such cases, correct *headbuf for freeing the newly
* allocated reassembled skb later.
*/
if (unlikely(!tipc_msg_validate(&head))) {
if (head != *headbuf)
*headbuf = head;
goto err;
}
*buf = head;
TIPC_SKB_CB(head)->tail = NULL;
*headbuf = NULL;
return 1;
}
return 0;
err:
kfree_skb(*buf);
kfree_skb(*headbuf);
*buf = *headbuf = NULL;
return 0;
}
/**
* tipc_msg_append(): Append data to tail of an existing buffer queue
* @_hdr: header to be used
* @m: the data to be appended
* @mss: max allowable size of buffer
* @dlen: size of data to be appended
* @txq: queue to append to
*
* Return: the number of 1k blocks appended or errno value
*/
int tipc_msg_append(struct tipc_msg *_hdr, struct msghdr *m, int dlen,
int mss, struct sk_buff_head *txq)
{
struct sk_buff *skb;
int accounted, total, curr;
int mlen, cpy, rem = dlen;
struct tipc_msg *hdr;
skb = skb_peek_tail(txq);
accounted = skb ? msg_blocks(buf_msg(skb)) : 0;
total = accounted;
do {
if (!skb || skb->len >= mss) {
skb = tipc_buf_acquire(mss, GFP_KERNEL);
if (unlikely(!skb))
return -ENOMEM;
skb_orphan(skb);
skb_trim(skb, MIN_H_SIZE);
hdr = buf_msg(skb);
skb_copy_to_linear_data(skb, _hdr, MIN_H_SIZE);
msg_set_hdr_sz(hdr, MIN_H_SIZE);
msg_set_size(hdr, MIN_H_SIZE);
__skb_queue_tail(txq, skb);
total += 1;
}
hdr = buf_msg(skb);
curr = msg_blocks(hdr);
mlen = msg_size(hdr);
cpy = min_t(size_t, rem, mss - mlen);
if (cpy != copy_from_iter(skb->data + mlen, cpy, &m->msg_iter))
return -EFAULT;
msg_set_size(hdr, mlen + cpy);
skb_put(skb, cpy);
rem -= cpy;
total += msg_blocks(hdr) - curr;
} while (rem > 0);
return total - accounted;
}
/* tipc_msg_validate - validate basic format of received message
*
* This routine ensures a TIPC message has an acceptable header, and at least
* as much data as the header indicates it should. The routine also ensures
* that the entire message header is stored in the main fragment of the message
* buffer, to simplify future access to message header fields.
*
* Note: Having extra info present in the message header or data areas is OK.
* TIPC will ignore the excess, under the assumption that it is optional info
* introduced by a later release of the protocol.
*/
bool tipc_msg_validate(struct sk_buff **_skb)
{
struct sk_buff *skb = *_skb;
struct tipc_msg *hdr;
int msz, hsz;
/* Ensure that flow control ratio condition is satisfied */
if (unlikely(skb->truesize / buf_roundup_len(skb) >= 4)) {
skb = skb_copy_expand(skb, BUF_HEADROOM, 0, GFP_ATOMIC);
if (!skb)
return false;
kfree_skb(*_skb);
*_skb = skb;
}
if (unlikely(TIPC_SKB_CB(skb)->validated))
return true;
if (unlikely(!pskb_may_pull(skb, MIN_H_SIZE)))
return false;
hsz = msg_hdr_sz(buf_msg(skb));
if (unlikely(hsz < MIN_H_SIZE) || (hsz > MAX_H_SIZE))
return false;
if (unlikely(!pskb_may_pull(skb, hsz)))
return false;
hdr = buf_msg(skb);
if (unlikely(msg_version(hdr) != TIPC_VERSION))
return false;
msz = msg_size(hdr);
if (unlikely(msz < hsz))
return false;
if (unlikely((msz - hsz) > TIPC_MAX_USER_MSG_SIZE))
return false;
if (unlikely(skb->len < msz))
return false;
TIPC_SKB_CB(skb)->validated = 1;
return true;
}
/**
* tipc_msg_fragment - build a fragment skb list for TIPC message
*
* @skb: TIPC message skb
* @hdr: internal msg header to be put on the top of the fragments
* @pktmax: max size of a fragment incl. the header
* @frags: returned fragment skb list
*
* Return: 0 if the fragmentation is successful, otherwise: -EINVAL
* or -ENOMEM
*/
int tipc_msg_fragment(struct sk_buff *skb, const struct tipc_msg *hdr,
int pktmax, struct sk_buff_head *frags)
{
int pktno, nof_fragms, dsz, dmax, eat;
struct tipc_msg *_hdr;
struct sk_buff *_skb;
u8 *data;
/* Non-linear buffer? */
if (skb_linearize(skb))
return -ENOMEM;
data = (u8 *)skb->data;
dsz = msg_size(buf_msg(skb));
dmax = pktmax - INT_H_SIZE;
if (dsz <= dmax || !dmax)
return -EINVAL;
nof_fragms = dsz / dmax + 1;
for (pktno = 1; pktno <= nof_fragms; pktno++) {
if (pktno < nof_fragms)
eat = dmax;
else
eat = dsz % dmax;
/* Allocate a new fragment */
_skb = tipc_buf_acquire(INT_H_SIZE + eat, GFP_ATOMIC);
if (!_skb)
goto error;
skb_orphan(_skb);
__skb_queue_tail(frags, _skb);
/* Copy header & data to the fragment */
skb_copy_to_linear_data(_skb, hdr, INT_H_SIZE);
skb_copy_to_linear_data_offset(_skb, INT_H_SIZE, data, eat);
data += eat;
/* Update the fragment's header */
_hdr = buf_msg(_skb);
msg_set_fragm_no(_hdr, pktno);
msg_set_nof_fragms(_hdr, nof_fragms);
msg_set_size(_hdr, INT_H_SIZE + eat);
}
return 0;
error:
__skb_queue_purge(frags);
__skb_queue_head_init(frags);
return -ENOMEM;
}
/**
* tipc_msg_build - create buffer chain containing specified header and data
* @mhdr: Message header, to be prepended to data
* @m: User message
* @offset: buffer offset for fragmented messages (FIXME)
* @dsz: Total length of user data
* @pktmax: Max packet size that can be used
* @list: Buffer or chain of buffers to be returned to caller
*
* Note that the recursive call we are making here is safe, since it can
* logically go only one further level down.
*
* Return: message data size or errno: -ENOMEM, -EFAULT
*/
int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset,
int dsz, int pktmax, struct sk_buff_head *list)
{
int mhsz = msg_hdr_sz(mhdr);
struct tipc_msg pkthdr;
int msz = mhsz + dsz;
int pktrem = pktmax;
struct sk_buff *skb;
int drem = dsz;
int pktno = 1;
char *pktpos;
int pktsz;
int rc;
msg_set_size(mhdr, msz);
/* No fragmentation needed? */
if (likely(msz <= pktmax)) {
skb = tipc_buf_acquire(msz, GFP_KERNEL);
/* Fall back to smaller MTU if node local message */
if (unlikely(!skb)) {
if (pktmax != MAX_MSG_SIZE)
return -ENOMEM;
rc = tipc_msg_build(mhdr, m, offset, dsz,
one_page_mtu, list);
if (rc != dsz)
return rc;
if (tipc_msg_assemble(list))
return dsz;
return -ENOMEM;
}
skb_orphan(skb);
__skb_queue_tail(list, skb);
skb_copy_to_linear_data(skb, mhdr, mhsz);
pktpos = skb->data + mhsz;
if (copy_from_iter_full(pktpos, dsz, &m->msg_iter))
return dsz;
rc = -EFAULT;
goto error;
}
/* Prepare reusable fragment header */
tipc_msg_init(msg_prevnode(mhdr), &pkthdr, MSG_FRAGMENTER,
FIRST_FRAGMENT, INT_H_SIZE, msg_destnode(mhdr));
msg_set_size(&pkthdr, pktmax);
msg_set_fragm_no(&pkthdr, pktno);
msg_set_importance(&pkthdr, msg_importance(mhdr));
/* Prepare first fragment */
skb = tipc_buf_acquire(pktmax, GFP_KERNEL);
if (!skb)
return -ENOMEM;
skb_orphan(skb);
__skb_queue_tail(list, skb);
pktpos = skb->data;
skb_copy_to_linear_data(skb, &pkthdr, INT_H_SIZE);
pktpos += INT_H_SIZE;
pktrem -= INT_H_SIZE;
skb_copy_to_linear_data_offset(skb, INT_H_SIZE, mhdr, mhsz);
pktpos += mhsz;
pktrem -= mhsz;
do {
if (drem < pktrem)
pktrem = drem;
if (!copy_from_iter_full(pktpos, pktrem, &m->msg_iter)) {
rc = -EFAULT;
goto error;
}
drem -= pktrem;
if (!drem)
break;
/* Prepare new fragment: */
if (drem < (pktmax - INT_H_SIZE))
pktsz = drem + INT_H_SIZE;
else
pktsz = pktmax;
skb = tipc_buf_acquire(pktsz, GFP_KERNEL);
if (!skb) {
rc = -ENOMEM;
goto error;
}
skb_orphan(skb);
__skb_queue_tail(list, skb);
msg_set_type(&pkthdr, FRAGMENT);
msg_set_size(&pkthdr, pktsz);
msg_set_fragm_no(&pkthdr, ++pktno);
skb_copy_to_linear_data(skb, &pkthdr, INT_H_SIZE);
pktpos = skb->data + INT_H_SIZE;
pktrem = pktsz - INT_H_SIZE;
} while (1);
msg_set_type(buf_msg(skb), LAST_FRAGMENT);
return dsz;
error:
__skb_queue_purge(list);
__skb_queue_head_init(list);
return rc;
}
/**
* tipc_msg_bundle - Append contents of a buffer to tail of an existing one
* @bskb: the bundle buffer to append to
* @msg: message to be appended
* @max: max allowable size for the bundle buffer
*
* Return: "true" if bundling has been performed, otherwise "false"
*/
static bool tipc_msg_bundle(struct sk_buff *bskb, struct tipc_msg *msg,
u32 max)
{
struct tipc_msg *bmsg = buf_msg(bskb);
u32 msz, bsz, offset, pad;
msz = msg_size(msg);
bsz = msg_size(bmsg);
offset = BUF_ALIGN(bsz);
pad = offset - bsz;
if (unlikely(skb_tailroom(bskb) < (pad + msz)))
return false;
if (unlikely(max < (offset + msz)))
return false;
skb_put(bskb, pad + msz);
skb_copy_to_linear_data_offset(bskb, offset, msg, msz);
msg_set_size(bmsg, offset + msz);
msg_set_msgcnt(bmsg, msg_msgcnt(bmsg) + 1);
return true;
}
/**
* tipc_msg_try_bundle - Try to bundle a new message to the last one
* @tskb: the last/target message to which the new one will be appended
* @skb: the new message skb pointer
* @mss: max message size (header inclusive)
* @dnode: destination node for the message
* @new_bundle: if this call made a new bundle or not
*
* Return: "true" if the new message skb is potential for bundling this time or
* later, in the case a bundling has been done this time, the skb is consumed
* (the skb pointer = NULL).
* Otherwise, "false" if the skb cannot be bundled at all.
*/
bool tipc_msg_try_bundle(struct sk_buff *tskb, struct sk_buff **skb, u32 mss,
u32 dnode, bool *new_bundle)
{
struct tipc_msg *msg, *inner, *outer;
u32 tsz;
/* First, check if the new buffer is suitable for bundling */
msg = buf_msg(*skb);
if (msg_user(msg) == MSG_FRAGMENTER)
return false;
if (msg_user(msg) == TUNNEL_PROTOCOL)
return false;
if (msg_user(msg) == BCAST_PROTOCOL)
return false;
if (mss <= INT_H_SIZE + msg_size(msg))
return false;
/* Ok, but the last/target buffer can be empty? */
if (unlikely(!tskb))
return true;
/* Is it a bundle already? Try to bundle the new message to it */
if (msg_user(buf_msg(tskb)) == MSG_BUNDLER) {
*new_bundle = false;
goto bundle;
}
/* Make a new bundle of the two messages if possible */
tsz = msg_size(buf_msg(tskb));
if (unlikely(mss < BUF_ALIGN(INT_H_SIZE + tsz) + msg_size(msg)))
return true;
if (unlikely(pskb_expand_head(tskb, INT_H_SIZE, mss - tsz - INT_H_SIZE,
GFP_ATOMIC)))
return true;
inner = buf_msg(tskb);
skb_push(tskb, INT_H_SIZE);
outer = buf_msg(tskb);
tipc_msg_init(msg_prevnode(inner), outer, MSG_BUNDLER, 0, INT_H_SIZE,
dnode);
msg_set_importance(outer, msg_importance(inner));
msg_set_size(outer, INT_H_SIZE + tsz);
msg_set_msgcnt(outer, 1);
*new_bundle = true;
bundle:
if (likely(tipc_msg_bundle(tskb, msg, mss))) {
consume_skb(*skb);
*skb = NULL;
}
return true;
}
/**
* tipc_msg_extract(): extract bundled inner packet from buffer
* @skb: buffer to be extracted from.
* @iskb: extracted inner buffer, to be returned
* @pos: position in outer message of msg to be extracted.
* Returns position of next msg.
* Consumes outer buffer when last packet extracted
* Return: true when there is an extracted buffer, otherwise false
*/
bool tipc_msg_extract(struct sk_buff *skb, struct sk_buff **iskb, int *pos)
{
struct tipc_msg *hdr, *ihdr;
int imsz;
*iskb = NULL;
if (unlikely(skb_linearize(skb)))
goto none;
hdr = buf_msg(skb);
if (unlikely(*pos > (msg_data_sz(hdr) - MIN_H_SIZE)))
goto none;
ihdr = (struct tipc_msg *)(msg_data(hdr) + *pos);
imsz = msg_size(ihdr);
if ((*pos + imsz) > msg_data_sz(hdr))
goto none;
*iskb = tipc_buf_acquire(imsz, GFP_ATOMIC);
if (!*iskb)
goto none;
skb_copy_to_linear_data(*iskb, ihdr, imsz);
if (unlikely(!tipc_msg_validate(iskb)))
goto none;
*pos += BUF_ALIGN(imsz);
return true;
none:
kfree_skb(skb);
kfree_skb(*iskb);
*iskb = NULL;
return false;
}
/**
* tipc_msg_reverse(): swap source and destination addresses and add error code
* @own_node: originating node id for reversed message
* @skb: buffer containing message to be reversed; will be consumed
* @err: error code to be set in message, if any
* Replaces consumed buffer with new one when successful
* Return: true if success, otherwise false
*/
bool tipc_msg_reverse(u32 own_node, struct sk_buff **skb, int err)
{
struct sk_buff *_skb = *skb;
struct tipc_msg *_hdr, *hdr;
int hlen, dlen;
if (skb_linearize(_skb))
goto exit;
_hdr = buf_msg(_skb);
dlen = min_t(uint, msg_data_sz(_hdr), MAX_FORWARD_SIZE);
hlen = msg_hdr_sz(_hdr);
if (msg_dest_droppable(_hdr))
goto exit;
if (msg_errcode(_hdr))
goto exit;
/* Never return SHORT header */
if (hlen == SHORT_H_SIZE)
hlen = BASIC_H_SIZE;
/* Don't return data along with SYN+, - sender has a clone */
if (msg_is_syn(_hdr) && err == TIPC_ERR_OVERLOAD)
dlen = 0;
/* Allocate new buffer to return */
*skb = tipc_buf_acquire(hlen + dlen, GFP_ATOMIC);
if (!*skb)
goto exit;
memcpy((*skb)->data, _skb->data, msg_hdr_sz(_hdr));
memcpy((*skb)->data + hlen, msg_data(_hdr), dlen);
/* Build reverse header in new buffer */
hdr = buf_msg(*skb);
msg_set_hdr_sz(hdr, hlen);
msg_set_errcode(hdr, err);
msg_set_non_seq(hdr, 0);
msg_set_origport(hdr, msg_destport(_hdr));
msg_set_destport(hdr, msg_origport(_hdr));
msg_set_destnode(hdr, msg_prevnode(_hdr));
msg_set_prevnode(hdr, own_node);
msg_set_orignode(hdr, own_node);
msg_set_size(hdr, hlen + dlen);
skb_orphan(_skb);
kfree_skb(_skb);
return true;
exit:
kfree_skb(_skb);
*skb = NULL;
return false;
}
bool tipc_msg_skb_clone(struct sk_buff_head *msg, struct sk_buff_head *cpy)
{
struct sk_buff *skb, *_skb;
skb_queue_walk(msg, skb) {
_skb = skb_clone(skb, GFP_ATOMIC);
if (!_skb) {
__skb_queue_purge(cpy);
pr_err_ratelimited("Failed to clone buffer chain\n");
return false;
}
__skb_queue_tail(cpy, _skb);
}
return true;
}
/**
* tipc_msg_lookup_dest(): try to find new destination for named message
* @net: pointer to associated network namespace
* @skb: the buffer containing the message.
* @err: error code to be used by caller if lookup fails
* Does not consume buffer
* Return: true if a destination is found, false otherwise
*/
bool tipc_msg_lookup_dest(struct net *net, struct sk_buff *skb, int *err)
{
struct tipc_msg *msg = buf_msg(skb);
u32 scope = msg_lookup_scope(msg);
u32 self = tipc_own_addr(net);
u32 inst = msg_nameinst(msg);
struct tipc_socket_addr sk;
struct tipc_uaddr ua;
if (!msg_isdata(msg))
return false;
if (!msg_named(msg))
return false;
if (msg_errcode(msg))
return false;
*err = TIPC_ERR_NO_NAME;
if (skb_linearize(skb))
return false;
msg = buf_msg(skb);
if (msg_reroute_cnt(msg))
return false;
tipc_uaddr(&ua, TIPC_SERVICE_RANGE, scope,
msg_nametype(msg), inst, inst);
sk.node = tipc_scope2node(net, scope);
if (!tipc_nametbl_lookup_anycast(net, &ua, &sk))
return false;
msg_incr_reroute_cnt(msg);
if (sk.node != self)
msg_set_prevnode(msg, self);
msg_set_destnode(msg, sk.node);
msg_set_destport(msg, sk.ref);
*err = TIPC_OK;
return true;
}
/* tipc_msg_assemble() - assemble chain of fragments into one message
*/
bool tipc_msg_assemble(struct sk_buff_head *list)
{
struct sk_buff *skb, *tmp = NULL;
if (skb_queue_len(list) == 1)
return true;
while ((skb = __skb_dequeue(list))) {
skb->next = NULL;
if (tipc_buf_append(&tmp, &skb)) {
__skb_queue_tail(list, skb);
return true;
}
if (!tmp)
break;
}
__skb_queue_purge(list);
__skb_queue_head_init(list);
pr_warn("Failed do assemble buffer\n");
return false;
}
/* tipc_msg_reassemble() - clone a buffer chain of fragments and
* reassemble the clones into one message
*/
bool tipc_msg_reassemble(struct sk_buff_head *list, struct sk_buff_head *rcvq)
{
struct sk_buff *skb, *_skb;
struct sk_buff *frag = NULL;
struct sk_buff *head = NULL;
int hdr_len;
/* Copy header if single buffer */
if (skb_queue_len(list) == 1) {
skb = skb_peek(list);
hdr_len = skb_headroom(skb) + msg_hdr_sz(buf_msg(skb));
_skb = __pskb_copy(skb, hdr_len, GFP_ATOMIC);
if (!_skb)
return false;
__skb_queue_tail(rcvq, _skb);
return true;
}
/* Clone all fragments and reassemble */
skb_queue_walk(list, skb) {
frag = skb_clone(skb, GFP_ATOMIC);
if (!frag)
goto error;
frag->next = NULL;
if (tipc_buf_append(&head, &frag))
break;
if (!head)
goto error;
}
__skb_queue_tail(rcvq, frag);
return true;
error:
pr_warn("Failed do clone local mcast rcv buffer\n");
kfree_skb(head);
return false;
}
bool tipc_msg_pskb_copy(u32 dst, struct sk_buff_head *msg,
struct sk_buff_head *cpy)
{
struct sk_buff *skb, *_skb;
skb_queue_walk(msg, skb) {
_skb = pskb_copy(skb, GFP_ATOMIC);
if (!_skb) {
__skb_queue_purge(cpy);
return false;
}
msg_set_destnode(buf_msg(_skb), dst);
__skb_queue_tail(cpy, _skb);
}
return true;
}
/* tipc_skb_queue_sorted(); sort pkt into list according to sequence number
* @list: list to be appended to
* @seqno: sequence number of buffer to add
* @skb: buffer to add
*/
bool __tipc_skb_queue_sorted(struct sk_buff_head *list, u16 seqno,
struct sk_buff *skb)
{
struct sk_buff *_skb, *tmp;
if (skb_queue_empty(list) || less(seqno, buf_seqno(skb_peek(list)))) {
__skb_queue_head(list, skb);
return true;
}
if (more(seqno, buf_seqno(skb_peek_tail(list)))) {
__skb_queue_tail(list, skb);
return true;
}
skb_queue_walk_safe(list, _skb, tmp) {
if (more(seqno, buf_seqno(_skb)))
continue;
if (seqno == buf_seqno(_skb))
break;
__skb_queue_before(list, _skb, skb);
return true;
}
kfree_skb(skb);
return false;
}
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);
}
File diff suppressed because it is too large Load Diff
+420
View File
@@ -0,0 +1,420 @@
/*
* net/tipc/name_distr.c: TIPC name distribution code
*
* Copyright (c) 2000-2006, 2014-2019, Ericsson AB
* Copyright (c) 2005, 2010-2011, Wind River Systems
* Copyright (c) 2020-2021, Red Hat Inc
* 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 "link.h"
#include "name_distr.h"
int sysctl_tipc_named_timeout __read_mostly = 2000;
/**
* publ_to_item - add publication info to a publication message
* @p: publication info
* @i: location of item in the message
*/
static void publ_to_item(struct distr_item *i, struct publication *p)
{
i->type = htonl(p->sr.type);
i->lower = htonl(p->sr.lower);
i->upper = htonl(p->sr.upper);
i->port = htonl(p->sk.ref);
i->key = htonl(p->key);
}
/**
* named_prepare_buf - allocate & initialize a publication message
* @net: the associated network namespace
* @type: message type
* @size: payload size
* @dest: destination node
*
* The buffer returned is of size INT_H_SIZE + payload size
*/
static struct sk_buff *named_prepare_buf(struct net *net, u32 type, u32 size,
u32 dest)
{
struct sk_buff *buf = tipc_buf_acquire(INT_H_SIZE + size, GFP_ATOMIC);
u32 self = tipc_own_addr(net);
struct tipc_msg *msg;
if (buf != NULL) {
msg = buf_msg(buf);
tipc_msg_init(self, msg, NAME_DISTRIBUTOR,
type, INT_H_SIZE, dest);
msg_set_size(msg, INT_H_SIZE + size);
}
return buf;
}
/**
* tipc_named_publish - tell other nodes about a new publication by this node
* @net: the associated network namespace
* @p: the new publication
*/
struct sk_buff *tipc_named_publish(struct net *net, struct publication *p)
{
struct name_table *nt = tipc_name_table(net);
struct distr_item *item;
struct sk_buff *skb;
if (p->scope == TIPC_NODE_SCOPE) {
list_add_tail_rcu(&p->binding_node, &nt->node_scope);
return NULL;
}
write_lock_bh(&nt->cluster_scope_lock);
list_add_tail(&p->binding_node, &nt->cluster_scope);
write_unlock_bh(&nt->cluster_scope_lock);
skb = named_prepare_buf(net, PUBLICATION, ITEM_SIZE, 0);
if (!skb) {
pr_warn("Publication distribution failure\n");
return NULL;
}
msg_set_named_seqno(buf_msg(skb), nt->snd_nxt++);
msg_set_non_legacy(buf_msg(skb));
item = (struct distr_item *)msg_data(buf_msg(skb));
publ_to_item(item, p);
return skb;
}
/**
* tipc_named_withdraw - tell other nodes about a withdrawn publication by this node
* @net: the associated network namespace
* @p: the withdrawn publication
*/
struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *p)
{
struct name_table *nt = tipc_name_table(net);
struct distr_item *item;
struct sk_buff *skb;
write_lock_bh(&nt->cluster_scope_lock);
list_del(&p->binding_node);
write_unlock_bh(&nt->cluster_scope_lock);
if (p->scope == TIPC_NODE_SCOPE)
return NULL;
skb = named_prepare_buf(net, WITHDRAWAL, ITEM_SIZE, 0);
if (!skb) {
pr_warn("Withdrawal distribution failure\n");
return NULL;
}
msg_set_named_seqno(buf_msg(skb), nt->snd_nxt++);
msg_set_non_legacy(buf_msg(skb));
item = (struct distr_item *)msg_data(buf_msg(skb));
publ_to_item(item, p);
return skb;
}
/**
* named_distribute - prepare name info for bulk distribution to another node
* @net: the associated network namespace
* @list: list of messages (buffers) to be returned from this function
* @dnode: node to be updated
* @pls: linked list of publication items to be packed into buffer chain
* @seqno: sequence number for this message
*/
static void named_distribute(struct net *net, struct sk_buff_head *list,
u32 dnode, struct list_head *pls, u16 seqno)
{
struct publication *publ;
struct sk_buff *skb = NULL;
struct distr_item *item = NULL;
u32 msg_dsz = ((tipc_node_get_mtu(net, dnode, 0, false) - INT_H_SIZE) /
ITEM_SIZE) * ITEM_SIZE;
u32 msg_rem = msg_dsz;
struct tipc_msg *hdr;
list_for_each_entry(publ, pls, binding_node) {
/* Prepare next buffer: */
if (!skb) {
skb = named_prepare_buf(net, PUBLICATION, msg_rem,
dnode);
if (!skb) {
pr_warn("Bulk publication failure\n");
return;
}
hdr = buf_msg(skb);
msg_set_bc_ack_invalid(hdr, true);
msg_set_bulk(hdr);
msg_set_non_legacy(hdr);
item = (struct distr_item *)msg_data(hdr);
}
/* Pack publication into message: */
publ_to_item(item, publ);
item++;
msg_rem -= ITEM_SIZE;
/* Append full buffer to list: */
if (!msg_rem) {
__skb_queue_tail(list, skb);
skb = NULL;
msg_rem = msg_dsz;
}
}
if (skb) {
hdr = buf_msg(skb);
msg_set_size(hdr, INT_H_SIZE + (msg_dsz - msg_rem));
skb_trim(skb, INT_H_SIZE + (msg_dsz - msg_rem));
__skb_queue_tail(list, skb);
}
hdr = buf_msg(skb_peek_tail(list));
msg_set_last_bulk(hdr);
msg_set_named_seqno(hdr, seqno);
}
/**
* tipc_named_node_up - tell specified node about all publications by this node
* @net: the associated network namespace
* @dnode: destination node
* @capabilities: peer node's capabilities
*/
void tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities)
{
struct name_table *nt = tipc_name_table(net);
struct tipc_net *tn = tipc_net(net);
struct sk_buff_head head;
u16 seqno;
__skb_queue_head_init(&head);
spin_lock_bh(&tn->nametbl_lock);
if (!(capabilities & TIPC_NAMED_BCAST))
nt->rc_dests++;
seqno = nt->snd_nxt;
spin_unlock_bh(&tn->nametbl_lock);
read_lock_bh(&nt->cluster_scope_lock);
named_distribute(net, &head, dnode, &nt->cluster_scope, seqno);
tipc_node_xmit(net, &head, dnode, 0);
read_unlock_bh(&nt->cluster_scope_lock);
}
/**
* tipc_publ_purge - remove publication associated with a failed node
* @net: the associated network namespace
* @p: the publication to remove
* @addr: failed node's address
*
* Invoked for each publication issued by a newly failed node.
* Removes publication structure from name table & deletes it.
*/
static void tipc_publ_purge(struct net *net, struct publication *p, u32 addr)
{
struct tipc_net *tn = tipc_net(net);
struct publication *_p;
struct tipc_uaddr ua;
tipc_uaddr(&ua, TIPC_SERVICE_RANGE, p->scope, p->sr.type,
p->sr.lower, p->sr.upper);
spin_lock_bh(&tn->nametbl_lock);
_p = tipc_nametbl_remove_publ(net, &ua, &p->sk, p->key);
if (_p)
tipc_node_unsubscribe(net, &_p->binding_node, addr);
spin_unlock_bh(&tn->nametbl_lock);
if (_p)
kfree_rcu(_p, rcu);
}
void tipc_publ_notify(struct net *net, struct list_head *nsub_list,
u32 addr, u16 capabilities)
{
struct name_table *nt = tipc_name_table(net);
struct tipc_net *tn = tipc_net(net);
struct publication *publ, *tmp;
list_for_each_entry_safe(publ, tmp, nsub_list, binding_node)
tipc_publ_purge(net, publ, addr);
spin_lock_bh(&tn->nametbl_lock);
if (!(capabilities & TIPC_NAMED_BCAST))
nt->rc_dests--;
spin_unlock_bh(&tn->nametbl_lock);
}
/**
* tipc_update_nametbl - try to process a nametable update and notify
* subscribers
* @net: the associated network namespace
* @i: location of item in the message
* @node: node address
* @dtype: name distributor message type
*
* tipc_nametbl_lock must be held.
* Return: the publication item if successful, otherwise NULL.
*/
static bool tipc_update_nametbl(struct net *net, struct distr_item *i,
u32 node, u32 dtype)
{
struct publication *p = NULL;
u32 lower = ntohl(i->lower);
u32 upper = ntohl(i->upper);
struct tipc_socket_addr sk;
u32 key = ntohl(i->key);
struct tipc_uaddr ua;
/* A peer-advertised binding with lower > upper can never be matched
* or withdrawn and would leak the publication; the local bind path
* rejects such ranges, so reject ranges learned from the network too.
*/
if (lower > upper)
return false;
tipc_uaddr(&ua, TIPC_SERVICE_RANGE, TIPC_CLUSTER_SCOPE,
ntohl(i->type), lower, upper);
sk.ref = ntohl(i->port);
sk.node = node;
if (dtype == PUBLICATION) {
p = tipc_nametbl_insert_publ(net, &ua, &sk, key);
if (p) {
tipc_node_subscribe(net, &p->binding_node, node);
return true;
}
} else if (dtype == WITHDRAWAL) {
p = tipc_nametbl_remove_publ(net, &ua, &sk, key);
if (p) {
tipc_node_unsubscribe(net, &p->binding_node, node);
kfree_rcu(p, rcu);
return true;
}
pr_warn_ratelimited("Failed to remove binding %u,%u from %u\n",
ua.sr.type, ua.sr.lower, node);
} else {
pr_warn_ratelimited("Unknown name table message received\n");
}
return false;
}
static struct sk_buff *tipc_named_dequeue(struct sk_buff_head *namedq,
u16 *rcv_nxt, bool *open)
{
struct sk_buff *skb, *tmp;
struct tipc_msg *hdr;
u16 seqno;
spin_lock_bh(&namedq->lock);
skb_queue_walk_safe(namedq, skb, tmp) {
if (unlikely(skb_linearize(skb))) {
__skb_unlink(skb, namedq);
kfree_skb(skb);
continue;
}
hdr = buf_msg(skb);
seqno = msg_named_seqno(hdr);
if (msg_is_last_bulk(hdr)) {
*rcv_nxt = seqno;
*open = true;
}
if (msg_is_bulk(hdr) || msg_is_legacy(hdr)) {
__skb_unlink(skb, namedq);
spin_unlock_bh(&namedq->lock);
return skb;
}
if (*open && (*rcv_nxt == seqno)) {
(*rcv_nxt)++;
__skb_unlink(skb, namedq);
spin_unlock_bh(&namedq->lock);
return skb;
}
if (less(seqno, *rcv_nxt)) {
__skb_unlink(skb, namedq);
kfree_skb(skb);
continue;
}
}
spin_unlock_bh(&namedq->lock);
return NULL;
}
/**
* tipc_named_rcv - process name table update messages sent by another node
* @net: the associated network namespace
* @namedq: queue to receive from
* @rcv_nxt: store last received seqno here
* @open: last bulk msg was received (FIXME)
*/
void tipc_named_rcv(struct net *net, struct sk_buff_head *namedq,
u16 *rcv_nxt, bool *open)
{
struct tipc_net *tn = tipc_net(net);
struct distr_item *item;
struct tipc_msg *hdr;
struct sk_buff *skb;
u32 count, node;
spin_lock_bh(&tn->nametbl_lock);
while ((skb = tipc_named_dequeue(namedq, rcv_nxt, open))) {
hdr = buf_msg(skb);
node = msg_orignode(hdr);
item = (struct distr_item *)msg_data(hdr);
count = msg_data_sz(hdr) / ITEM_SIZE;
while (count--) {
tipc_update_nametbl(net, item, node, msg_type(hdr));
item++;
}
kfree_skb(skb);
}
spin_unlock_bh(&tn->nametbl_lock);
}
/**
* tipc_named_reinit - re-initialize local publications
* @net: the associated network namespace
*
* This routine is called whenever TIPC networking is enabled.
* All name table entries published by this node are updated to reflect
* the node's new network address.
*/
void tipc_named_reinit(struct net *net)
{
struct name_table *nt = tipc_name_table(net);
struct tipc_net *tn = tipc_net(net);
struct publication *p;
u32 self = tipc_own_addr(net);
spin_lock_bh(&tn->nametbl_lock);
list_for_each_entry_rcu(p, &nt->node_scope, binding_node)
p->sk.node = self;
list_for_each_entry_rcu(p, &nt->cluster_scope, binding_node)
p->sk.node = self;
nt->rc_dests = 0;
spin_unlock_bh(&tn->nametbl_lock);
}
+79
View File
@@ -0,0 +1,79 @@
/*
* net/tipc/name_distr.h: Include file for TIPC name distribution code
*
* Copyright (c) 2000-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* 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_NAME_DISTR_H
#define _TIPC_NAME_DISTR_H
#include "name_table.h"
#define ITEM_SIZE sizeof(struct distr_item)
/**
* struct distr_item - publication info distributed to other nodes
* @type: name sequence type
* @lower: name sequence lower bound
* @upper: name sequence upper bound
* @port: publishing port reference
* @key: publication key
*
* ===> All fields are stored in network byte order. <===
*
* First 3 fields identify (name or) name sequence being published.
* Reference field uniquely identifies port that published name sequence.
* Key field uniquely identifies publication, in the event a port has
* multiple publications of the same name sequence.
*
* Note: There is no field that identifies the publishing node because it is
* the same for all items contained within a publication message.
*/
struct distr_item {
__be32 type;
__be32 lower;
__be32 upper;
__be32 port;
__be32 key;
};
struct sk_buff *tipc_named_publish(struct net *net, struct publication *publ);
struct sk_buff *tipc_named_withdraw(struct net *net, struct publication *publ);
void tipc_named_node_up(struct net *net, u32 dnode, u16 capabilities);
void tipc_named_rcv(struct net *net, struct sk_buff_head *namedq,
u16 *rcv_nxt, bool *open);
void tipc_named_reinit(struct net *net);
void tipc_publ_notify(struct net *net, struct list_head *nsub_list,
u32 addr, u16 capabilities);
#endif
File diff suppressed because it is too large Load Diff
+157
View File
@@ -0,0 +1,157 @@
/*
* net/tipc/name_table.h: Include file for TIPC name table code
*
* Copyright (c) 2000-2006, 2014-2018, Ericsson AB
* Copyright (c) 2004-2005, 2010-2011, Wind River Systems
* Copyright (c) 2020-2021, Red Hat Inc
* 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_NAME_TABLE_H
#define _TIPC_NAME_TABLE_H
struct tipc_subscription;
struct tipc_plist;
struct tipc_nlist;
struct tipc_group;
struct tipc_uaddr;
/*
* TIPC name types reserved for internal TIPC use (both current and planned)
*/
#define TIPC_ZM_SRV 3 /* zone master service name type */
#define TIPC_PUBL_SCOPE_NUM (TIPC_NODE_SCOPE + 1)
#define TIPC_NAMETBL_SIZE 1024 /* must be a power of 2 */
#define TIPC_ANY_SCOPE 10 /* Both node and cluster scope will match */
/**
* struct publication - info about a published service address or range
* @sr: service range represented by this publication
* @sk: address of socket bound to this publication
* @scope: scope of publication, TIPC_NODE_SCOPE or TIPC_CLUSTER_SCOPE
* @key: publication key, unique across the cluster
* @id: publication id
* @binding_node: all publications from the same node which bound this one
* - Remote publications: in node->publ_list;
* Used by node/name distr to withdraw publications when node is lost
* - Local/node scope publications: in name_table->node_scope list
* - Local/cluster scope publications: in name_table->cluster_scope list
* @binding_sock: all publications from the same socket which bound this one
* Used by socket to withdraw publications when socket is unbound/released
* @local_publ: list of identical publications made from this node
* Used by closest_first and multicast receive lookup algorithms
* @all_publ: all publications identical to this one, whatever node and scope
* Used by round-robin lookup algorithm
* @list: to form a list of publications in temporal order
* @rcu: RCU callback head used for deferred freeing
*/
struct publication {
struct tipc_service_range sr;
struct tipc_socket_addr sk;
u16 scope;
u32 key;
u32 id;
struct list_head binding_node;
struct list_head binding_sock;
struct list_head local_publ;
struct list_head all_publ;
struct list_head list;
struct rcu_head rcu;
};
/**
* struct name_table - table containing all existing port name publications
* @rcu: RCU callback head used for deferred freeing
* @services: name sequence hash lists
* @node_scope: all local publications with node scope
* - used by name_distr during re-init of name table
* @cluster_scope: all local publications with cluster scope
* - used by name_distr to send bulk updates to new nodes
* - used by name_distr during re-init of name table
* @cluster_scope_lock: lock for accessing @cluster_scope
* @local_publ_count: number of publications issued by this node
* @rc_dests: destination node counter
* @snd_nxt: next sequence number to be used
*/
struct name_table {
struct rcu_head rcu;
struct hlist_head services[TIPC_NAMETBL_SIZE];
struct list_head node_scope;
struct list_head cluster_scope;
rwlock_t cluster_scope_lock;
u32 local_publ_count;
u32 rc_dests;
u32 snd_nxt;
};
int tipc_nl_name_table_dump(struct sk_buff *skb, struct netlink_callback *cb);
bool tipc_nametbl_lookup_anycast(struct net *net, struct tipc_uaddr *ua,
struct tipc_socket_addr *sk);
void tipc_nametbl_lookup_mcast_sockets(struct net *net, struct tipc_uaddr *ua,
struct list_head *dports);
void tipc_nametbl_lookup_mcast_nodes(struct net *net, struct tipc_uaddr *ua,
struct tipc_nlist *nodes);
bool tipc_nametbl_lookup_group(struct net *net, struct tipc_uaddr *ua,
struct list_head *dsts, int *dstcnt,
u32 exclude, bool mcast);
void tipc_nametbl_build_group(struct net *net, struct tipc_group *grp,
struct tipc_uaddr *ua);
struct publication *tipc_nametbl_publish(struct net *net, struct tipc_uaddr *ua,
struct tipc_socket_addr *sk, u32 key);
void tipc_nametbl_withdraw(struct net *net, struct tipc_uaddr *ua,
struct tipc_socket_addr *sk, u32 key);
struct publication *tipc_nametbl_insert_publ(struct net *net,
struct tipc_uaddr *ua,
struct tipc_socket_addr *sk,
u32 key);
struct publication *tipc_nametbl_remove_publ(struct net *net,
struct tipc_uaddr *ua,
struct tipc_socket_addr *sk,
u32 key);
bool tipc_nametbl_subscribe(struct tipc_subscription *s);
void tipc_nametbl_unsubscribe(struct tipc_subscription *s);
int tipc_nametbl_init(struct net *net);
void tipc_nametbl_stop(struct net *net);
struct tipc_dest {
struct list_head list;
u32 port;
u32 node;
};
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);
#endif
+347
View File
@@ -0,0 +1,347 @@
/*
* net/tipc/net.c: TIPC network routing code
*
* Copyright (c) 1995-2006, 2014, Ericsson AB
* Copyright (c) 2005, 2010-2011, Wind River Systems
* 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 "net.h"
#include "name_distr.h"
#include "subscr.h"
#include "socket.h"
#include "node.h"
#include "bcast.h"
#include "link.h"
#include "netlink.h"
#include "monitor.h"
/*
* The TIPC locking policy is designed to ensure a very fine locking
* granularity, permitting complete parallel access to individual
* port and node/link instances. The code consists of four major
* locking domains, each protected with their own disjunct set of locks.
*
* 1: The bearer level.
* RTNL lock is used to serialize the process of configuring bearer
* on update side, and RCU lock is applied on read side to make
* bearer instance valid on both paths of message transmission and
* reception.
*
* 2: The node and link level.
* All node instances are saved into two tipc_node_list and node_htable
* lists. The two lists are protected by node_list_lock on write side,
* and they are guarded with RCU lock on read side. Especially node
* instance is destroyed only when TIPC module is removed, and we can
* confirm that there has no any user who is accessing the node at the
* moment. Therefore, Except for iterating the two lists within RCU
* protection, it's no needed to hold RCU that we access node instance
* in other places.
*
* In addition, all members in node structure including link instances
* are protected by node spin lock.
*
* 3: The transport level of the protocol.
* This consists of the structures port, (and its user level
* representations, such as user_port and tipc_sock), reference and
* tipc_user (port.c, reg.c, socket.c).
*
* This layer has four different locks:
* - The tipc_port spin_lock. This is protecting each port instance
* from parallel data access and removal. Since we can not place
* this lock in the port itself, it has been placed in the
* corresponding reference table entry, which has the same life
* cycle as the module. This entry is difficult to access from
* outside the TIPC core, however, so a pointer to the lock has
* been added in the port instance, -to be used for unlocking
* only.
* - A read/write lock to protect the reference table itself (teg.c).
* (Nobody is using read-only access to this, so it can just as
* well be changed to a spin_lock)
* - A spin lock to protect the registry of kernel/driver users (reg.c)
* - A global spin_lock (tipc_port_lock), which only task is to ensure
* consistency where more than one port is involved in an operation,
* i.e., when a port is part of a linked list of ports.
* There are two such lists; 'port_list', which is used for management,
* and 'wait_list', which is used to queue ports during congestion.
*
* 4: The name table (name_table.c, name_distr.c, subscription.c)
* - There is one big read/write-lock (tipc_nametbl_lock) protecting the
* overall name table structure. Nothing must be added/removed to
* this structure without holding write access to it.
* - There is one local spin_lock per sub_sequence, which can be seen
* as a sub-domain to the tipc_nametbl_lock domain. It is used only
* for translation operations, and is needed because a translation
* steps the root of the 'publication' linked list between each lookup.
* This is always used within the scope of a tipc_nametbl_lock(read).
* - A local spin_lock protecting the queue of subscriber events.
*/
static void tipc_net_finalize(struct net *net, u32 addr);
int tipc_net_init(struct net *net, u8 *node_id, u32 addr)
{
if (tipc_own_id(net)) {
pr_info("Cannot configure node identity twice\n");
return -1;
}
pr_info("Started in network mode\n");
if (node_id)
tipc_set_node_id(net, node_id);
if (addr)
tipc_net_finalize(net, addr);
return 0;
}
static void tipc_net_finalize(struct net *net, u32 addr)
{
struct tipc_net *tn = tipc_net(net);
struct tipc_socket_addr sk = {0, addr};
struct tipc_uaddr ua;
tipc_uaddr(&ua, TIPC_SERVICE_RANGE, TIPC_CLUSTER_SCOPE,
TIPC_NODE_STATE, addr, addr);
if (cmpxchg(&tn->node_addr, 0, addr))
return;
tipc_set_node_addr(net, addr);
tipc_named_reinit(net);
tipc_sk_reinit(net);
tipc_mon_reinit_self(net);
tipc_nametbl_publish(net, &ua, &sk, addr);
}
void tipc_net_finalize_work(struct work_struct *work)
{
struct tipc_net *tn = container_of(work, struct tipc_net, work);
rtnl_lock();
tipc_net_finalize(tipc_link_net(tn->bcl), tn->trial_addr);
rtnl_unlock();
}
void tipc_net_stop(struct net *net)
{
if (!tipc_own_id(net))
return;
rtnl_lock();
tipc_bearer_stop(net);
tipc_node_stop(net);
rtnl_unlock();
pr_info("Left network mode\n");
}
static int __tipc_nl_add_net(struct net *net, struct tipc_nl_msg *msg)
{
struct tipc_net *tn = net_generic(net, tipc_net_id);
u64 *w0 = (u64 *)&tn->node_id[0];
u64 *w1 = (u64 *)&tn->node_id[8];
struct nlattr *attrs;
void *hdr;
hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
NLM_F_MULTI, TIPC_NL_NET_GET);
if (!hdr)
return -EMSGSIZE;
attrs = nla_nest_start_noflag(msg->skb, TIPC_NLA_NET);
if (!attrs)
goto msg_full;
if (nla_put_u32(msg->skb, TIPC_NLA_NET_ID, tn->net_id))
goto attr_msg_full;
if (nla_put_u64_64bit(msg->skb, TIPC_NLA_NET_NODEID, *w0, 0))
goto attr_msg_full;
if (nla_put_u64_64bit(msg->skb, TIPC_NLA_NET_NODEID_W1, *w1, 0))
goto attr_msg_full;
nla_nest_end(msg->skb, attrs);
genlmsg_end(msg->skb, hdr);
return 0;
attr_msg_full:
nla_nest_cancel(msg->skb, attrs);
msg_full:
genlmsg_cancel(msg->skb, hdr);
return -EMSGSIZE;
}
int tipc_nl_net_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
struct net *net = sock_net(skb->sk);
int err;
int done = cb->args[0];
struct tipc_nl_msg msg;
if (done)
return 0;
msg.skb = skb;
msg.portid = NETLINK_CB(cb->skb).portid;
msg.seq = cb->nlh->nlmsg_seq;
err = __tipc_nl_add_net(net, &msg);
if (err)
goto out;
done = 1;
out:
cb->args[0] = done;
return skb->len;
}
int __tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
{
struct nlattr *attrs[TIPC_NLA_NET_MAX + 1];
struct net *net = sock_net(skb->sk);
struct tipc_net *tn = tipc_net(net);
int err;
if (!info->attrs[TIPC_NLA_NET])
return -EINVAL;
err = nla_parse_nested_deprecated(attrs, TIPC_NLA_NET_MAX,
info->attrs[TIPC_NLA_NET],
tipc_nl_net_policy, info->extack);
if (err)
return err;
/* Can't change net id once TIPC has joined a network */
if (tipc_own_addr(net))
return -EPERM;
if (attrs[TIPC_NLA_NET_ID]) {
u32 val;
val = nla_get_u32(attrs[TIPC_NLA_NET_ID]);
if (val < 1 || val > 9999)
return -EINVAL;
tn->net_id = val;
}
if (attrs[TIPC_NLA_NET_ADDR]) {
u32 addr;
addr = nla_get_u32(attrs[TIPC_NLA_NET_ADDR]);
if (!addr)
return -EINVAL;
tn->legacy_addr_format = true;
tipc_net_init(net, NULL, addr);
}
if (attrs[TIPC_NLA_NET_NODEID]) {
u8 node_id[NODE_ID_LEN];
u64 *w0 = (u64 *)&node_id[0];
u64 *w1 = (u64 *)&node_id[8];
if (!attrs[TIPC_NLA_NET_NODEID_W1])
return -EINVAL;
*w0 = nla_get_u64(attrs[TIPC_NLA_NET_NODEID]);
*w1 = nla_get_u64(attrs[TIPC_NLA_NET_NODEID_W1]);
tipc_net_init(net, node_id, 0);
}
return 0;
}
int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
{
int err;
rtnl_lock();
err = __tipc_nl_net_set(skb, info);
rtnl_unlock();
return err;
}
static int __tipc_nl_addr_legacy_get(struct net *net, struct tipc_nl_msg *msg)
{
struct tipc_net *tn = tipc_net(net);
struct nlattr *attrs;
void *hdr;
hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
0, TIPC_NL_ADDR_LEGACY_GET);
if (!hdr)
return -EMSGSIZE;
attrs = nla_nest_start(msg->skb, TIPC_NLA_NET);
if (!attrs)
goto msg_full;
if (tn->legacy_addr_format)
if (nla_put_flag(msg->skb, TIPC_NLA_NET_ADDR_LEGACY))
goto attr_msg_full;
nla_nest_end(msg->skb, attrs);
genlmsg_end(msg->skb, hdr);
return 0;
attr_msg_full:
nla_nest_cancel(msg->skb, attrs);
msg_full:
genlmsg_cancel(msg->skb, hdr);
return -EMSGSIZE;
}
int tipc_nl_net_addr_legacy_get(struct sk_buff *skb, struct genl_info *info)
{
struct net *net = sock_net(skb->sk);
struct tipc_nl_msg msg;
struct sk_buff *rep;
int err;
rep = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (!rep)
return -ENOMEM;
msg.skb = rep;
msg.portid = info->snd_portid;
msg.seq = info->snd_seq;
err = __tipc_nl_addr_legacy_get(net, &msg);
if (err) {
nlmsg_free(msg.skb);
return err;
}
return genlmsg_reply(msg.skb, info);
}
+52
View File
@@ -0,0 +1,52 @@
/*
* net/tipc/net.h: Include file for TIPC network routing code
*
* Copyright (c) 1995-2006, 2014, Ericsson AB
* Copyright (c) 2005, 2010-2011, Wind River Systems
* 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_NET_H
#define _TIPC_NET_H
#include <net/genetlink.h>
extern const struct nla_policy tipc_nl_net_policy[];
int tipc_net_init(struct net *net, u8 *node_id, u32 addr);
void tipc_net_finalize_work(struct work_struct *work);
void tipc_net_stop(struct net *net);
int tipc_nl_net_dump(struct sk_buff *skb, struct netlink_callback *cb);
int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info);
int __tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info);
int tipc_nl_net_addr_legacy_get(struct sk_buff *skb, struct genl_info *info);
#endif
+331
View File
@@ -0,0 +1,331 @@
/*
* net/tipc/netlink.c: TIPC configuration handling
*
* Copyright (c) 2005-2006, 2014, Ericsson AB
* Copyright (c) 2005-2007, Wind River Systems
* 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 "socket.h"
#include "name_table.h"
#include "bearer.h"
#include "link.h"
#include "node.h"
#include "net.h"
#include "udp_media.h"
#include <net/genetlink.h>
static const struct nla_policy tipc_nl_policy[TIPC_NLA_MAX + 1] = {
[TIPC_NLA_UNSPEC] = { .type = NLA_UNSPEC, },
[TIPC_NLA_BEARER] = { .type = NLA_NESTED, },
[TIPC_NLA_SOCK] = { .type = NLA_NESTED, },
[TIPC_NLA_PUBL] = { .type = NLA_NESTED, },
[TIPC_NLA_LINK] = { .type = NLA_NESTED, },
[TIPC_NLA_MEDIA] = { .type = NLA_NESTED, },
[TIPC_NLA_NODE] = { .type = NLA_NESTED, },
[TIPC_NLA_NET] = { .type = NLA_NESTED, },
[TIPC_NLA_NAME_TABLE] = { .type = NLA_NESTED, },
[TIPC_NLA_MON] = { .type = NLA_NESTED, },
};
const struct nla_policy
tipc_nl_name_table_policy[TIPC_NLA_NAME_TABLE_MAX + 1] = {
[TIPC_NLA_NAME_TABLE_UNSPEC] = { .type = NLA_UNSPEC },
[TIPC_NLA_NAME_TABLE_PUBL] = { .type = NLA_NESTED }
};
const struct nla_policy tipc_nl_monitor_policy[TIPC_NLA_MON_MAX + 1] = {
[TIPC_NLA_MON_UNSPEC] = { .type = NLA_UNSPEC },
[TIPC_NLA_MON_REF] = { .type = NLA_U32 },
[TIPC_NLA_MON_ACTIVATION_THRESHOLD] = { .type = NLA_U32 },
};
const struct nla_policy tipc_nl_sock_policy[TIPC_NLA_SOCK_MAX + 1] = {
[TIPC_NLA_SOCK_UNSPEC] = { .type = NLA_UNSPEC },
[TIPC_NLA_SOCK_ADDR] = { .type = NLA_U32 },
[TIPC_NLA_SOCK_REF] = { .type = NLA_U32 },
[TIPC_NLA_SOCK_CON] = { .type = NLA_NESTED },
[TIPC_NLA_SOCK_HAS_PUBL] = { .type = NLA_FLAG }
};
const struct nla_policy tipc_nl_net_policy[TIPC_NLA_NET_MAX + 1] = {
[TIPC_NLA_NET_UNSPEC] = { .type = NLA_UNSPEC },
[TIPC_NLA_NET_ID] = { .type = NLA_U32 },
[TIPC_NLA_NET_ADDR] = { .type = NLA_U32 },
[TIPC_NLA_NET_NODEID] = { .type = NLA_U64 },
[TIPC_NLA_NET_NODEID_W1] = { .type = NLA_U64 },
[TIPC_NLA_NET_ADDR_LEGACY] = { .type = NLA_FLAG }
};
const struct nla_policy tipc_nl_link_policy[TIPC_NLA_LINK_MAX + 1] = {
[TIPC_NLA_LINK_UNSPEC] = { .type = NLA_UNSPEC },
[TIPC_NLA_LINK_NAME] = { .type = NLA_NUL_STRING,
.len = TIPC_MAX_LINK_NAME },
[TIPC_NLA_LINK_MTU] = { .type = NLA_U32 },
[TIPC_NLA_LINK_BROADCAST] = { .type = NLA_FLAG },
[TIPC_NLA_LINK_UP] = { .type = NLA_FLAG },
[TIPC_NLA_LINK_ACTIVE] = { .type = NLA_FLAG },
[TIPC_NLA_LINK_PROP] = { .type = NLA_NESTED },
[TIPC_NLA_LINK_STATS] = { .type = NLA_NESTED },
[TIPC_NLA_LINK_RX] = { .type = NLA_U32 },
[TIPC_NLA_LINK_TX] = { .type = NLA_U32 }
};
const struct nla_policy tipc_nl_node_policy[TIPC_NLA_NODE_MAX + 1] = {
[TIPC_NLA_NODE_UNSPEC] = { .type = NLA_UNSPEC },
[TIPC_NLA_NODE_ADDR] = { .type = NLA_U32 },
[TIPC_NLA_NODE_UP] = { .type = NLA_FLAG },
[TIPC_NLA_NODE_ID] = { .type = NLA_BINARY,
.len = TIPC_NODEID_LEN},
[TIPC_NLA_NODE_KEY] = { .type = NLA_BINARY,
.len = TIPC_AEAD_KEY_SIZE_MAX},
[TIPC_NLA_NODE_KEY_MASTER] = { .type = NLA_FLAG },
[TIPC_NLA_NODE_REKEYING] = { .type = NLA_U32 },
};
/* Properties valid for media, bearer and link */
static const struct netlink_range_validation tipc_nl_mtu_range = {
.max = U16_MAX,
};
const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = {
[TIPC_NLA_PROP_UNSPEC] = { .type = NLA_UNSPEC },
[TIPC_NLA_PROP_PRIO] = { .type = NLA_U32 },
[TIPC_NLA_PROP_TOL] = { .type = NLA_U32 },
[TIPC_NLA_PROP_WIN] = { .type = NLA_U32 },
[TIPC_NLA_PROP_MTU] = NLA_POLICY_FULL_RANGE(NLA_U32, &tipc_nl_mtu_range),
[TIPC_NLA_PROP_BROADCAST] = { .type = NLA_U32 },
[TIPC_NLA_PROP_BROADCAST_RATIO] = { .type = NLA_U32 }
};
const struct nla_policy tipc_nl_bearer_policy[TIPC_NLA_BEARER_MAX + 1] = {
[TIPC_NLA_BEARER_UNSPEC] = { .type = NLA_UNSPEC },
[TIPC_NLA_BEARER_NAME] = { .type = NLA_NUL_STRING,
.len = TIPC_MAX_BEARER_NAME },
[TIPC_NLA_BEARER_PROP] = { .type = NLA_NESTED },
[TIPC_NLA_BEARER_DOMAIN] = { .type = NLA_U32 }
};
const struct nla_policy tipc_nl_media_policy[TIPC_NLA_MEDIA_MAX + 1] = {
[TIPC_NLA_MEDIA_UNSPEC] = { .type = NLA_UNSPEC },
[TIPC_NLA_MEDIA_NAME] = { .type = NLA_STRING },
[TIPC_NLA_MEDIA_PROP] = { .type = NLA_NESTED }
};
const struct nla_policy tipc_nl_udp_policy[TIPC_NLA_UDP_MAX + 1] = {
[TIPC_NLA_UDP_UNSPEC] = {.type = NLA_UNSPEC},
[TIPC_NLA_UDP_LOCAL] = {.type = NLA_BINARY,
.len = sizeof(struct sockaddr_storage)},
[TIPC_NLA_UDP_REMOTE] = {.type = NLA_BINARY,
.len = sizeof(struct sockaddr_storage)},
};
/* Users of the legacy API (tipc-config) can't handle that we add operations,
* so we have a separate genl handling for the new API.
*/
static const struct genl_ops tipc_genl_v2_ops[] = {
{
.cmd = TIPC_NL_BEARER_DISABLE,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_bearer_disable,
},
{
.cmd = TIPC_NL_BEARER_ENABLE,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_bearer_enable,
},
{
.cmd = TIPC_NL_BEARER_GET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = tipc_nl_bearer_get,
.dumpit = tipc_nl_bearer_dump,
},
{
.cmd = TIPC_NL_BEARER_ADD,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_bearer_add,
},
{
.cmd = TIPC_NL_BEARER_SET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_bearer_set,
},
{
.cmd = TIPC_NL_SOCK_GET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.start = tipc_dump_start,
.dumpit = tipc_nl_sk_dump,
.done = tipc_dump_done,
},
{
.cmd = TIPC_NL_PUBL_GET,
.validate = GENL_DONT_VALIDATE_STRICT |
GENL_DONT_VALIDATE_DUMP_STRICT,
.dumpit = tipc_nl_publ_dump,
},
{
.cmd = TIPC_NL_LINK_GET,
.validate = GENL_DONT_VALIDATE_STRICT,
.doit = tipc_nl_node_get_link,
.dumpit = tipc_nl_node_dump_link,
},
{
.cmd = TIPC_NL_LINK_SET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_node_set_link,
},
{
.cmd = TIPC_NL_LINK_RESET_STATS,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_node_reset_link_stats,
},
{
.cmd = TIPC_NL_MEDIA_GET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = tipc_nl_media_get,
.dumpit = tipc_nl_media_dump,
},
{
.cmd = TIPC_NL_MEDIA_SET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_media_set,
},
{
.cmd = TIPC_NL_NODE_GET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.dumpit = tipc_nl_node_dump,
},
{
.cmd = TIPC_NL_NET_GET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.dumpit = tipc_nl_net_dump,
},
{
.cmd = TIPC_NL_NET_SET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_net_set,
},
{
.cmd = TIPC_NL_NAME_TABLE_GET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.dumpit = tipc_nl_name_table_dump,
},
{
.cmd = TIPC_NL_MON_SET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_node_set_monitor,
},
{
.cmd = TIPC_NL_MON_GET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = tipc_nl_node_get_monitor,
.dumpit = tipc_nl_node_dump_monitor,
},
{
.cmd = TIPC_NL_MON_PEER_GET,
.validate = GENL_DONT_VALIDATE_STRICT |
GENL_DONT_VALIDATE_DUMP_STRICT,
.dumpit = tipc_nl_node_dump_monitor_peer,
},
{
.cmd = TIPC_NL_PEER_REMOVE,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_peer_rm,
},
#ifdef CONFIG_TIPC_MEDIA_UDP
{
.cmd = TIPC_NL_UDP_GET_REMOTEIP,
.validate = GENL_DONT_VALIDATE_STRICT |
GENL_DONT_VALIDATE_DUMP_STRICT,
.dumpit = tipc_udp_nl_dump_remoteip,
},
#endif
#ifdef CONFIG_TIPC_CRYPTO
{
.cmd = TIPC_NL_KEY_SET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_node_set_key,
},
{
.cmd = TIPC_NL_KEY_FLUSH,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.flags = GENL_UNS_ADMIN_PERM,
.doit = tipc_nl_node_flush_key,
},
#endif
{
.cmd = TIPC_NL_ADDR_LEGACY_GET,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
.doit = tipc_nl_net_addr_legacy_get,
},
};
struct genl_family tipc_genl_family __ro_after_init = {
.name = TIPC_GENL_V2_NAME,
.version = TIPC_GENL_V2_VERSION,
.hdrsize = 0,
.maxattr = TIPC_NLA_MAX,
.policy = tipc_nl_policy,
.netnsok = true,
.module = THIS_MODULE,
.ops = tipc_genl_v2_ops,
.n_ops = ARRAY_SIZE(tipc_genl_v2_ops),
.resv_start_op = TIPC_NL_ADDR_LEGACY_GET + 1,
};
int __init tipc_netlink_start(void)
{
int res;
res = genl_register_family(&tipc_genl_family);
if (res) {
pr_err("Failed to register netlink interface\n");
return res;
}
return 0;
}
void tipc_netlink_stop(void)
{
genl_unregister_family(&tipc_genl_family);
}
+64
View File
@@ -0,0 +1,64 @@
/*
* net/tipc/netlink.h: Include file for TIPC netlink code
*
* Copyright (c) 2014, 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_NETLINK_H
#define _TIPC_NETLINK_H
#include <net/netlink.h>
extern struct genl_family tipc_genl_family;
struct tipc_nl_msg {
struct sk_buff *skb;
u32 portid;
u32 seq;
};
extern const struct nla_policy tipc_nl_name_table_policy[];
extern const struct nla_policy tipc_nl_sock_policy[];
extern const struct nla_policy tipc_nl_net_policy[];
extern const struct nla_policy tipc_nl_link_policy[];
extern const struct nla_policy tipc_nl_node_policy[];
extern const struct nla_policy tipc_nl_prop_policy[];
extern const struct nla_policy tipc_nl_bearer_policy[];
extern const struct nla_policy tipc_nl_media_policy[];
extern const struct nla_policy tipc_nl_udp_policy[];
extern const struct nla_policy tipc_nl_monitor_policy[];
int tipc_netlink_start(void);
int tipc_netlink_compat_start(void);
void tipc_netlink_stop(void);
void tipc_netlink_compat_stop(void);
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+131
View File
@@ -0,0 +1,131 @@
/*
* net/tipc/node.h: Include file for TIPC node management routines
*
* Copyright (c) 2000-2006, 2014-2016, Ericsson AB
* Copyright (c) 2005, 2010-2014, Wind River Systems
* 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_NODE_H
#define _TIPC_NODE_H
#include "addr.h"
#include "net.h"
#include "bearer.h"
#include "msg.h"
/* Optional capabilities supported by this code version
*/
enum {
TIPC_SYN_BIT = (1),
TIPC_BCAST_SYNCH = (1 << 1),
TIPC_BCAST_STATE_NACK = (1 << 2),
TIPC_BLOCK_FLOWCTL = (1 << 3),
TIPC_BCAST_RCAST = (1 << 4),
TIPC_NODE_ID128 = (1 << 5),
TIPC_LINK_PROTO_SEQNO = (1 << 6),
TIPC_MCAST_RBCTL = (1 << 7),
TIPC_GAP_ACK_BLOCK = (1 << 8),
TIPC_TUNNEL_ENHANCED = (1 << 9),
TIPC_NAGLE = (1 << 10),
TIPC_NAMED_BCAST = (1 << 11)
};
#define TIPC_NODE_CAPABILITIES (TIPC_SYN_BIT | \
TIPC_BCAST_SYNCH | \
TIPC_BCAST_STATE_NACK | \
TIPC_BCAST_RCAST | \
TIPC_BLOCK_FLOWCTL | \
TIPC_NODE_ID128 | \
TIPC_LINK_PROTO_SEQNO | \
TIPC_MCAST_RBCTL | \
TIPC_GAP_ACK_BLOCK | \
TIPC_TUNNEL_ENHANCED | \
TIPC_NAGLE | \
TIPC_NAMED_BCAST)
#define INVALID_BEARER_ID -1
void tipc_node_stop(struct net *net);
bool tipc_node_get_id(struct net *net, u32 addr, u8 *id);
u32 tipc_node_get_addr(struct tipc_node *node);
char *tipc_node_get_id_str(struct tipc_node *node);
void tipc_node_put(struct tipc_node *node);
void tipc_node_get(struct tipc_node *node);
struct tipc_node *tipc_node_create(struct net *net, u32 addr, u8 *peer_id,
u16 capabilities, u32 hash_mixes,
bool preliminary);
#ifdef CONFIG_TIPC_CRYPTO
struct tipc_crypto *tipc_node_crypto_rx(struct tipc_node *__n);
struct tipc_crypto *tipc_node_crypto_rx_by_list(struct list_head *pos);
struct tipc_crypto *tipc_node_crypto_rx_by_addr(struct net *net, u32 addr);
#endif
u32 tipc_node_try_addr(struct net *net, u8 *id, u32 addr);
void tipc_node_check_dest(struct net *net, u32 onode, u8 *peer_id128,
struct tipc_bearer *bearer,
u16 capabilities, u32 signature, u32 hash_mixes,
struct tipc_media_addr *maddr,
bool *respond, bool *dupl_addr);
void tipc_node_delete_links(struct net *net, int bearer_id);
void tipc_node_apply_property(struct net *net, struct tipc_bearer *b, int prop);
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);
void tipc_node_unsubscribe(struct net *net, struct list_head *subscr, u32 addr);
void tipc_node_broadcast(struct net *net, struct sk_buff *skb, int rc_dests);
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 connected);
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);
int tipc_nl_node_reset_link_stats(struct sk_buff *skb, struct genl_info *info);
int tipc_nl_node_get_link(struct sk_buff *skb, struct genl_info *info);
int tipc_nl_node_set_link(struct sk_buff *skb, struct genl_info *info);
int tipc_nl_peer_rm(struct sk_buff *skb, struct genl_info *info);
int tipc_nl_node_set_monitor(struct sk_buff *skb, struct genl_info *info);
int tipc_nl_node_get_monitor(struct sk_buff *skb, struct genl_info *info);
int tipc_nl_node_dump_monitor(struct sk_buff *skb, struct netlink_callback *cb);
int tipc_nl_node_dump_monitor_peer(struct sk_buff *skb,
struct netlink_callback *cb);
#ifdef CONFIG_TIPC_CRYPTO
int tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info);
int tipc_nl_node_flush_key(struct sk_buff *skb, struct genl_info *info);
#endif
void tipc_node_pre_cleanup_net(struct net *exit_net);
#endif
File diff suppressed because it is too large Load Diff
+80
View File
@@ -0,0 +1,80 @@
/* net/tipc/socket.h: Include file for TIPC socket code
*
* Copyright (c) 2014-2016, 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_SOCK_H
#define _TIPC_SOCK_H
#include <net/sock.h>
#include <net/genetlink.h>
/* Compatibility values for deprecated message based flow control */
#define FLOWCTL_MSG_WIN 512
#define FLOWCTL_MSG_LIM ((FLOWCTL_MSG_WIN * 2 + 1) * SKB_TRUESIZE(MAX_MSG_SIZE))
#define FLOWCTL_BLK_SZ 1024
/* Socket receive buffer sizes */
#define RCVBUF_MIN (FLOWCTL_BLK_SZ * 512)
#define RCVBUF_DEF (FLOWCTL_BLK_SZ * 1024 * 2)
#define RCVBUF_MAX (FLOWCTL_BLK_SZ * 1024 * 16)
struct tipc_sock;
int tipc_socket_init(void);
void tipc_socket_stop(void);
void tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq);
void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq,
struct sk_buff_head *inputq);
void tipc_sk_reinit(struct net *net);
int tipc_sk_rht_init(struct net *net);
void tipc_sk_rht_destroy(struct net *net);
int tipc_nl_sk_dump(struct sk_buff *skb, struct netlink_callback *cb);
int tipc_nl_publ_dump(struct sk_buff *skb, struct netlink_callback *cb);
int tipc_sk_fill_sock_diag(struct sk_buff *skb, struct netlink_callback *cb,
struct tipc_sock *tsk, u32 sk_filter_state,
u64 (*tipc_diag_gen_cookie)(struct sock *sk));
int tipc_nl_sk_walk(struct sk_buff *skb, struct netlink_callback *cb,
int (*skb_handler)(struct sk_buff *skb,
struct netlink_callback *cb,
struct tipc_sock *tsk));
int tipc_dump_start(struct netlink_callback *cb);
int __tipc_dump_start(struct netlink_callback *cb, struct net *net);
int tipc_dump_done(struct netlink_callback *cb);
u32 tipc_sock_get_portid(struct sock *sk);
bool tipc_sk_overlimit1(struct sock *sk, struct sk_buff *skb);
bool tipc_sk_overlimit2(struct sock *sk, struct sk_buff *skb);
int tipc_sk_bind(struct socket *sock, struct sockaddr *skaddr, int alen);
int tsk_set_importance(struct sock *sk, int imp);
#endif
+183
View File
@@ -0,0 +1,183 @@
/*
* net/tipc/subscr.c: TIPC network topology service
*
* Copyright (c) 2000-2017, Ericsson AB
* Copyright (c) 2005-2007, 2010-2013, Wind River Systems
* Copyright (c) 2020-2021, Red Hat Inc
* 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 "name_table.h"
#include "subscr.h"
static void tipc_sub_send_event(struct tipc_subscription *sub,
struct publication *p,
u32 event)
{
struct tipc_subscr *s = &sub->evt.s;
struct tipc_event *evt = &sub->evt;
if (sub->inactive)
return;
tipc_evt_write(evt, event, event);
if (p) {
tipc_evt_write(evt, found_lower, p->sr.lower);
tipc_evt_write(evt, found_upper, p->sr.upper);
tipc_evt_write(evt, port.ref, p->sk.ref);
tipc_evt_write(evt, port.node, p->sk.node);
} else {
tipc_evt_write(evt, found_lower, s->seq.lower);
tipc_evt_write(evt, found_upper, s->seq.upper);
tipc_evt_write(evt, port.ref, 0);
tipc_evt_write(evt, port.node, 0);
}
tipc_topsrv_queue_evt(sub->net, sub->conid, event, evt);
}
/**
* tipc_sub_check_overlap - test for subscription overlap with the given values
* @subscribed: the service range subscribed for
* @found: the service range we are checking for match
*
* Returns true if there is overlap, otherwise false.
*/
static bool tipc_sub_check_overlap(struct tipc_service_range *subscribed,
struct tipc_service_range *found)
{
u32 found_lower = found->lower;
u32 found_upper = found->upper;
if (found_lower < subscribed->lower)
found_lower = subscribed->lower;
if (found_upper > subscribed->upper)
found_upper = subscribed->upper;
return found_lower <= found_upper;
}
void tipc_sub_report_overlap(struct tipc_subscription *sub,
struct publication *p,
u32 event, bool must)
{
struct tipc_service_range *sr = &sub->s.seq;
u32 filter = sub->s.filter;
if (!tipc_sub_check_overlap(sr, &p->sr))
return;
if (!must && !(filter & TIPC_SUB_PORTS))
return;
if (filter & TIPC_SUB_CLUSTER_SCOPE && p->scope == TIPC_NODE_SCOPE)
return;
if (filter & TIPC_SUB_NODE_SCOPE && p->scope != TIPC_NODE_SCOPE)
return;
spin_lock(&sub->lock);
tipc_sub_send_event(sub, p, event);
spin_unlock(&sub->lock);
}
static void tipc_sub_timeout(struct timer_list *t)
{
struct tipc_subscription *sub = timer_container_of(sub, t, timer);
spin_lock(&sub->lock);
tipc_sub_send_event(sub, NULL, TIPC_SUBSCR_TIMEOUT);
sub->inactive = true;
spin_unlock(&sub->lock);
}
static void tipc_sub_kref_release(struct kref *kref)
{
kfree(container_of(kref, struct tipc_subscription, kref));
}
void tipc_sub_put(struct tipc_subscription *subscription)
{
kref_put(&subscription->kref, tipc_sub_kref_release);
}
void tipc_sub_get(struct tipc_subscription *subscription)
{
kref_get(&subscription->kref);
}
struct tipc_subscription *tipc_sub_subscribe(struct net *net,
struct tipc_subscr *s,
int conid)
{
u32 lower = tipc_sub_read(s, seq.lower);
u32 upper = tipc_sub_read(s, seq.upper);
u32 filter = tipc_sub_read(s, filter);
struct tipc_subscription *sub;
u32 timeout;
if ((filter & TIPC_SUB_PORTS && filter & TIPC_SUB_SERVICE) ||
lower > upper) {
pr_warn("Subscription rejected, illegal request\n");
return NULL;
}
sub = kmalloc_obj(*sub, GFP_ATOMIC);
if (!sub) {
pr_warn("Subscription rejected, no memory\n");
return NULL;
}
INIT_LIST_HEAD(&sub->service_list);
INIT_LIST_HEAD(&sub->sub_list);
sub->net = net;
sub->conid = conid;
sub->inactive = false;
memcpy(&sub->evt.s, s, sizeof(*s));
sub->s.seq.type = tipc_sub_read(s, seq.type);
sub->s.seq.lower = lower;
sub->s.seq.upper = upper;
sub->s.filter = filter;
sub->s.timeout = tipc_sub_read(s, timeout);
memcpy(sub->s.usr_handle, s->usr_handle, 8);
spin_lock_init(&sub->lock);
kref_init(&sub->kref);
if (!tipc_nametbl_subscribe(sub)) {
kfree(sub);
return NULL;
}
timer_setup(&sub->timer, tipc_sub_timeout, 0);
timeout = tipc_sub_read(&sub->evt.s, timeout);
if (timeout != TIPC_WAIT_FOREVER)
mod_timer(&sub->timer, jiffies + msecs_to_jiffies(timeout));
return sub;
}
void tipc_sub_unsubscribe(struct tipc_subscription *sub)
{
tipc_nametbl_unsubscribe(sub);
if (sub->evt.s.timeout != TIPC_WAIT_FOREVER)
timer_delete_sync(&sub->timer);
list_del(&sub->sub_list);
tipc_sub_put(sub);
}
+122
View File
@@ -0,0 +1,122 @@
/*
* net/tipc/subscr.h: Include file for TIPC network topology service
*
* Copyright (c) 2003-2017, Ericsson AB
* Copyright (c) 2005-2007, 2012-2013, Wind River Systems
* Copyright (c) 2020-2021, Red Hat Inc
* 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_SUBSCR_H
#define _TIPC_SUBSCR_H
#include "topsrv.h"
#define TIPC_MAX_SUBSCR 65535
#define TIPC_MAX_PUBL 65535
struct publication;
struct tipc_subscription;
struct tipc_conn;
/**
* struct tipc_subscription - TIPC network topology subscription object
* @s: host-endian copy of the user subscription
* @evt: template for events generated by subscription
* @kref: reference count for this subscription
* @net: network namespace associated with subscription
* @timer: timer governing subscription duration (optional)
* @service_list: adjacent subscriptions in name sequence's subscription list
* @sub_list: adjacent subscriptions in subscriber's subscription list
* @conid: connection identifier of topology server
* @inactive: true if this subscription is inactive
* @lock: serialize up/down and timer events
*/
struct tipc_subscription {
struct tipc_subscr s;
struct tipc_event evt;
struct kref kref;
struct net *net;
struct timer_list timer;
struct list_head service_list;
struct list_head sub_list;
int conid;
bool inactive;
spinlock_t lock;
};
struct tipc_subscription *tipc_sub_subscribe(struct net *net,
struct tipc_subscr *s,
int conid);
void tipc_sub_unsubscribe(struct tipc_subscription *sub);
void tipc_sub_report_overlap(struct tipc_subscription *sub,
struct publication *p,
u32 event, bool must);
int __net_init tipc_topsrv_init_net(struct net *net);
void __net_exit tipc_topsrv_exit_net(struct net *net);
void tipc_sub_put(struct tipc_subscription *subscription);
void tipc_sub_get(struct tipc_subscription *subscription);
#define TIPC_FILTER_MASK (TIPC_SUB_PORTS | TIPC_SUB_SERVICE | TIPC_SUB_CANCEL)
/* tipc_sub_read - return field_ of struct sub_ in host endian format
*/
#define tipc_sub_read(sub_, field_) \
({ \
struct tipc_subscr *sub__ = sub_; \
u32 val__ = (sub__)->field_; \
int swap_ = !((sub__)->filter & TIPC_FILTER_MASK); \
(swap_ ? swab32(val__) : val__); \
})
/* tipc_sub_write - write val_ to field_ of struct sub_ in user endian format
*/
#define tipc_sub_write(sub_, field_, val_) \
({ \
struct tipc_subscr *sub__ = sub_; \
u32 val__ = val_; \
int swap_ = !((sub__)->filter & TIPC_FILTER_MASK); \
(sub__)->field_ = swap_ ? swab32(val__) : val__; \
})
/* tipc_evt_write - write val_ to field_ of struct evt_ in user endian format
*/
#define tipc_evt_write(evt_, field_, val_) \
({ \
struct tipc_event *evt__ = evt_; \
u32 val__ = val_; \
int swap_ = !((evt__)->s.filter & (TIPC_FILTER_MASK)); \
(evt__)->field_ = swap_ ? swab32(val__) : val__; \
})
#endif
+107
View File
@@ -0,0 +1,107 @@
/*
* net/tipc/sysctl.c: sysctl interface to TIPC subsystem
*
* Copyright (c) 2013, Wind River Systems
* 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 "trace.h"
#include "crypto.h"
#include "bcast.h"
#include <linux/sysctl.h>
static struct ctl_table_header *tipc_ctl_hdr;
static struct ctl_table tipc_table[] = {
{
.procname = "tipc_rmem",
.data = &sysctl_tipc_rmem,
.maxlen = sizeof(sysctl_tipc_rmem),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = SYSCTL_ONE,
},
{
.procname = "named_timeout",
.data = &sysctl_tipc_named_timeout,
.maxlen = sizeof(sysctl_tipc_named_timeout),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = SYSCTL_ZERO,
},
{
.procname = "sk_filter",
.data = &sysctl_tipc_sk_filter,
.maxlen = sizeof(sysctl_tipc_sk_filter),
.mode = 0644,
.proc_handler = proc_doulongvec_minmax,
},
#ifdef CONFIG_TIPC_CRYPTO
{
.procname = "max_tfms",
.data = &sysctl_tipc_max_tfms,
.maxlen = sizeof(sysctl_tipc_max_tfms),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = SYSCTL_ONE,
},
{
.procname = "key_exchange_enabled",
.data = &sysctl_tipc_key_exchange_enabled,
.maxlen = sizeof(sysctl_tipc_key_exchange_enabled),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = SYSCTL_ZERO,
.extra2 = SYSCTL_ONE,
},
#endif
{
.procname = "bc_retruni",
.data = &sysctl_tipc_bc_retruni,
.maxlen = sizeof(sysctl_tipc_bc_retruni),
.mode = 0644,
.proc_handler = proc_doulongvec_minmax,
},
};
int tipc_register_sysctl(void)
{
tipc_ctl_hdr = register_net_sysctl(&init_net, "net/tipc", tipc_table);
if (tipc_ctl_hdr == NULL)
return -ENOMEM;
return 0;
}
void tipc_unregister_sysctl(void)
{
unregister_net_sysctl_table(tipc_ctl_hdr);
}
+733
View File
@@ -0,0 +1,733 @@
/*
* net/tipc/server.c: TIPC server infrastructure
*
* Copyright (c) 2012-2013, Wind River Systems
* Copyright (c) 2017-2018, 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 "subscr.h"
#include "topsrv.h"
#include "core.h"
#include "socket.h"
#include "addr.h"
#include "msg.h"
#include "bearer.h"
#include <net/sock.h>
#include <linux/module.h>
#include <trace/events/sock.h>
/* Number of messages to send before rescheduling */
#define MAX_SEND_MSG_COUNT 25
#define MAX_RECV_MSG_COUNT 25
#define CF_CONNECTED 1
#define TIPC_SERVER_NAME_LEN 32
/**
* struct tipc_topsrv - TIPC server structure
* @conn_idr: identifier set of connection
* @idr_lock: protect the connection identifier set
* @idr_in_use: amount of allocated identifier entry
* @net: network namespace instance
* @awork: accept work item
* @rcv_wq: receive workqueue
* @send_wq: send workqueue
* @listener: topsrv listener socket
* @name: server name
*/
struct tipc_topsrv {
struct idr conn_idr;
spinlock_t idr_lock; /* for idr list */
int idr_in_use;
struct net *net;
struct work_struct awork;
struct workqueue_struct *rcv_wq;
struct workqueue_struct *send_wq;
struct socket *listener;
char name[TIPC_SERVER_NAME_LEN];
};
/**
* struct tipc_conn - TIPC connection structure
* @kref: reference counter to connection object
* @conid: connection identifier
* @sock: socket handler associated with connection
* @flags: indicates connection state
* @server: pointer to connected server
* @sub_list: list to all pertaining subscriptions
* @sub_lock: lock protecting the subscription list
* @rwork: receive work item
* @outqueue: pointer to first outbound message in queue
* @outqueue_lock: control access to the outqueue
* @swork: send work item
*/
struct tipc_conn {
struct kref kref;
int conid;
struct socket *sock;
unsigned long flags;
struct tipc_topsrv *server;
struct list_head sub_list;
spinlock_t sub_lock; /* for subscription list */
struct work_struct rwork;
struct list_head outqueue;
spinlock_t outqueue_lock; /* for outqueue */
struct work_struct swork;
};
/* An entry waiting to be sent */
struct outqueue_entry {
bool inactive;
struct tipc_event evt;
struct list_head list;
};
static void tipc_conn_recv_work(struct work_struct *work);
static void tipc_conn_send_work(struct work_struct *work);
static void tipc_topsrv_kern_evt(struct net *net, struct tipc_event *evt);
static void tipc_conn_delete_sub(struct tipc_conn *con, struct tipc_subscr *s);
static bool connected(struct tipc_conn *con)
{
return con && test_bit(CF_CONNECTED, &con->flags);
}
static void tipc_conn_kref_release(struct kref *kref)
{
struct tipc_conn *con = container_of(kref, struct tipc_conn, kref);
struct tipc_topsrv *s = con->server;
struct outqueue_entry *e, *safe;
spin_lock_bh(&s->idr_lock);
idr_remove(&s->conn_idr, con->conid);
s->idr_in_use--;
spin_unlock_bh(&s->idr_lock);
if (con->sock)
sock_release(con->sock);
spin_lock_bh(&con->outqueue_lock);
list_for_each_entry_safe(e, safe, &con->outqueue, list) {
list_del(&e->list);
kfree(e);
}
spin_unlock_bh(&con->outqueue_lock);
kfree(con);
}
static void conn_put(struct tipc_conn *con)
{
kref_put(&con->kref, tipc_conn_kref_release);
}
static void conn_get(struct tipc_conn *con)
{
kref_get(&con->kref);
}
static void tipc_conn_close(struct tipc_conn *con)
{
struct sock *sk = con->sock->sk;
bool disconnect = false;
write_lock_bh(&sk->sk_callback_lock);
disconnect = test_and_clear_bit(CF_CONNECTED, &con->flags);
if (disconnect) {
sk->sk_user_data = NULL;
tipc_conn_delete_sub(con, NULL);
}
write_unlock_bh(&sk->sk_callback_lock);
/* Handle concurrent calls from sending and receiving threads */
if (!disconnect)
return;
/* Don't flush pending works, -just let them expire */
kernel_sock_shutdown(con->sock, SHUT_RDWR);
conn_put(con);
}
static struct tipc_conn *tipc_conn_alloc(struct tipc_topsrv *s, struct socket *sock)
{
struct tipc_conn *con;
int ret;
con = kzalloc_obj(*con, GFP_ATOMIC);
if (!con)
return ERR_PTR(-ENOMEM);
kref_init(&con->kref);
INIT_LIST_HEAD(&con->outqueue);
INIT_LIST_HEAD(&con->sub_list);
spin_lock_init(&con->outqueue_lock);
spin_lock_init(&con->sub_lock);
INIT_WORK(&con->swork, tipc_conn_send_work);
INIT_WORK(&con->rwork, tipc_conn_recv_work);
spin_lock_bh(&s->idr_lock);
ret = idr_alloc(&s->conn_idr, con, 0, 0, GFP_ATOMIC);
if (ret < 0) {
kfree(con);
spin_unlock_bh(&s->idr_lock);
return ERR_PTR(-ENOMEM);
}
con->conid = ret;
s->idr_in_use++;
set_bit(CF_CONNECTED, &con->flags);
con->server = s;
con->sock = sock;
conn_get(con);
spin_unlock_bh(&s->idr_lock);
return con;
}
static struct tipc_conn *tipc_conn_lookup(struct tipc_topsrv *s, int conid)
{
struct tipc_conn *con;
spin_lock_bh(&s->idr_lock);
con = idr_find(&s->conn_idr, conid);
if (!connected(con) || !kref_get_unless_zero(&con->kref))
con = NULL;
spin_unlock_bh(&s->idr_lock);
return con;
}
/* tipc_conn_delete_sub - delete a specific or all subscriptions
* for a given subscriber
*/
static void tipc_conn_delete_sub(struct tipc_conn *con, struct tipc_subscr *s)
{
struct tipc_net *tn = tipc_net(con->server->net);
struct list_head *sub_list = &con->sub_list;
struct tipc_subscription *sub, *tmp;
spin_lock_bh(&con->sub_lock);
list_for_each_entry_safe(sub, tmp, sub_list, sub_list) {
if (!s || !memcmp(s, &sub->evt.s, sizeof(*s))) {
tipc_sub_unsubscribe(sub);
atomic_dec(&tn->subscription_count);
if (s)
break;
}
}
spin_unlock_bh(&con->sub_lock);
}
static void tipc_conn_send_to_sock(struct tipc_conn *con)
{
struct list_head *queue = &con->outqueue;
struct tipc_topsrv *srv = con->server;
struct outqueue_entry *e;
struct tipc_event *evt;
struct msghdr msg;
struct kvec iov;
int count = 0;
int ret;
spin_lock_bh(&con->outqueue_lock);
while (!list_empty(queue)) {
e = list_first_entry(queue, struct outqueue_entry, list);
evt = &e->evt;
spin_unlock_bh(&con->outqueue_lock);
if (e->inactive)
tipc_conn_delete_sub(con, &evt->s);
memset(&msg, 0, sizeof(msg));
msg.msg_flags = MSG_DONTWAIT;
iov.iov_base = evt;
iov.iov_len = sizeof(*evt);
msg.msg_name = NULL;
if (con->sock) {
ret = kernel_sendmsg(con->sock, &msg, &iov,
1, sizeof(*evt));
if (ret == -EWOULDBLOCK || ret == 0) {
cond_resched();
return;
} else if (ret < 0) {
return tipc_conn_close(con);
}
} else {
tipc_topsrv_kern_evt(srv->net, evt);
}
/* Don't starve users filling buffers */
if (++count >= MAX_SEND_MSG_COUNT) {
cond_resched();
count = 0;
}
spin_lock_bh(&con->outqueue_lock);
list_del(&e->list);
kfree(e);
}
spin_unlock_bh(&con->outqueue_lock);
}
static void tipc_conn_send_work(struct work_struct *work)
{
struct tipc_conn *con = container_of(work, struct tipc_conn, swork);
if (connected(con))
tipc_conn_send_to_sock(con);
conn_put(con);
}
/* tipc_topsrv_queue_evt() - interrupt level call from a subscription instance
* The queued work is launched into tipc_conn_send_work()->tipc_conn_send_to_sock()
*/
void tipc_topsrv_queue_evt(struct net *net, int conid,
u32 event, struct tipc_event *evt)
{
struct tipc_topsrv *srv = tipc_topsrv(net);
struct outqueue_entry *e;
struct tipc_conn *con;
con = tipc_conn_lookup(srv, conid);
if (!con)
return;
if (!connected(con))
goto err;
e = kmalloc_obj(*e, GFP_ATOMIC);
if (!e)
goto err;
e->inactive = (event == TIPC_SUBSCR_TIMEOUT);
memcpy(&e->evt, evt, sizeof(*evt));
spin_lock_bh(&con->outqueue_lock);
list_add_tail(&e->list, &con->outqueue);
spin_unlock_bh(&con->outqueue_lock);
if (queue_work(srv->send_wq, &con->swork))
return;
err:
conn_put(con);
}
/* tipc_conn_write_space - interrupt callback after a sendmsg EAGAIN
* Indicates that there now is more space in the send buffer
* The queued work is launched into tipc_send_work()->tipc_conn_send_to_sock()
*/
static void tipc_conn_write_space(struct sock *sk)
{
struct tipc_conn *con;
read_lock_bh(&sk->sk_callback_lock);
con = sk->sk_user_data;
if (connected(con)) {
conn_get(con);
if (!queue_work(con->server->send_wq, &con->swork))
conn_put(con);
}
read_unlock_bh(&sk->sk_callback_lock);
}
static int tipc_conn_rcv_sub(struct tipc_topsrv *srv,
struct tipc_conn *con,
struct tipc_subscr *s)
{
struct tipc_net *tn = tipc_net(srv->net);
struct tipc_subscription *sub;
u32 s_filter = tipc_sub_read(s, filter);
if (s_filter & TIPC_SUB_CANCEL) {
tipc_sub_write(s, filter, s_filter & ~TIPC_SUB_CANCEL);
tipc_conn_delete_sub(con, s);
return 0;
}
if (atomic_read(&tn->subscription_count) >= TIPC_MAX_SUBSCR) {
pr_warn("Subscription rejected, max (%u)\n", TIPC_MAX_SUBSCR);
return -1;
}
sub = tipc_sub_subscribe(srv->net, s, con->conid);
if (!sub)
return -1;
atomic_inc(&tn->subscription_count);
spin_lock_bh(&con->sub_lock);
list_add(&sub->sub_list, &con->sub_list);
spin_unlock_bh(&con->sub_lock);
return 0;
}
static int tipc_conn_rcv_from_sock(struct tipc_conn *con)
{
struct tipc_topsrv *srv = con->server;
struct sock *sk = con->sock->sk;
struct msghdr msg = {};
struct tipc_subscr s;
struct kvec iov;
int ret;
iov.iov_base = &s;
iov.iov_len = sizeof(s);
msg.msg_name = NULL;
iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, iov.iov_len);
ret = sock_recvmsg(con->sock, &msg, MSG_DONTWAIT);
if (ret == -EWOULDBLOCK)
return -EWOULDBLOCK;
if (ret == sizeof(s)) {
read_lock_bh(&sk->sk_callback_lock);
/* RACE: the connection can be closed in the meantime */
if (likely(connected(con)))
ret = tipc_conn_rcv_sub(srv, con, &s);
read_unlock_bh(&sk->sk_callback_lock);
if (!ret)
return 0;
}
tipc_conn_close(con);
return ret;
}
static void tipc_conn_recv_work(struct work_struct *work)
{
struct tipc_conn *con = container_of(work, struct tipc_conn, rwork);
int count = 0;
while (connected(con)) {
if (tipc_conn_rcv_from_sock(con))
break;
/* Don't flood Rx machine */
if (++count >= MAX_RECV_MSG_COUNT) {
cond_resched();
count = 0;
}
}
conn_put(con);
}
/* tipc_conn_data_ready - interrupt callback indicating the socket has data
* The queued work is launched into tipc_recv_work()->tipc_conn_rcv_from_sock()
*/
static void tipc_conn_data_ready(struct sock *sk)
{
struct tipc_conn *con;
trace_sk_data_ready(sk);
read_lock_bh(&sk->sk_callback_lock);
con = sk->sk_user_data;
if (connected(con)) {
conn_get(con);
if (!queue_work(con->server->rcv_wq, &con->rwork))
conn_put(con);
}
read_unlock_bh(&sk->sk_callback_lock);
}
static void tipc_topsrv_accept(struct work_struct *work)
{
struct tipc_topsrv *srv = container_of(work, struct tipc_topsrv, awork);
struct socket *newsock, *lsock;
struct tipc_conn *con;
struct sock *newsk;
int ret;
spin_lock_bh(&srv->idr_lock);
if (!srv->listener) {
spin_unlock_bh(&srv->idr_lock);
return;
}
lsock = srv->listener;
spin_unlock_bh(&srv->idr_lock);
while (1) {
ret = kernel_accept(lsock, &newsock, O_NONBLOCK);
if (ret < 0)
return;
con = tipc_conn_alloc(srv, newsock);
if (IS_ERR(con)) {
ret = PTR_ERR(con);
sock_release(newsock);
return;
}
/* Register callbacks */
newsk = newsock->sk;
write_lock_bh(&newsk->sk_callback_lock);
newsk->sk_data_ready = tipc_conn_data_ready;
newsk->sk_write_space = tipc_conn_write_space;
newsk->sk_user_data = con;
write_unlock_bh(&newsk->sk_callback_lock);
/* Wake up receive process in case of 'SYN+' message */
newsk->sk_data_ready(newsk);
conn_put(con);
}
}
/* tipc_topsrv_listener_data_ready - interrupt callback with connection request
* The queued job is launched into tipc_topsrv_accept()
*/
static void tipc_topsrv_listener_data_ready(struct sock *sk)
{
struct tipc_topsrv *srv;
trace_sk_data_ready(sk);
read_lock_bh(&sk->sk_callback_lock);
srv = sk->sk_user_data;
if (srv)
queue_work(srv->rcv_wq, &srv->awork);
read_unlock_bh(&sk->sk_callback_lock);
}
static int tipc_topsrv_create_listener(struct tipc_topsrv *srv)
{
struct socket *lsock = NULL;
struct sockaddr_tipc saddr;
struct sock *sk;
int rc;
rc = sock_create_kern(srv->net, AF_TIPC, SOCK_SEQPACKET, 0, &lsock);
if (rc < 0)
return rc;
srv->listener = lsock;
sk = lsock->sk;
write_lock_bh(&sk->sk_callback_lock);
sk->sk_data_ready = tipc_topsrv_listener_data_ready;
sk->sk_user_data = srv;
write_unlock_bh(&sk->sk_callback_lock);
lock_sock(sk);
rc = tsk_set_importance(sk, TIPC_CRITICAL_IMPORTANCE);
release_sock(sk);
if (rc < 0)
goto err;
saddr.family = AF_TIPC;
saddr.addrtype = TIPC_SERVICE_RANGE;
saddr.addr.nameseq.type = TIPC_TOP_SRV;
saddr.addr.nameseq.lower = TIPC_TOP_SRV;
saddr.addr.nameseq.upper = TIPC_TOP_SRV;
saddr.scope = TIPC_NODE_SCOPE;
rc = tipc_sk_bind(lsock, (struct sockaddr *)&saddr, sizeof(saddr));
if (rc < 0)
goto err;
rc = kernel_listen(lsock, 0);
if (rc < 0)
goto err;
/* As server's listening socket owner and creator is the same module,
* we have to decrease TIPC module reference count to guarantee that
* it remains zero after the server socket is created, otherwise,
* executing "rmmod" command is unable to make TIPC module deleted
* after TIPC module is inserted successfully.
*
* However, the reference count is ever increased twice in
* sock_create_kern(): one is to increase the reference count of owner
* of TIPC socket's proto_ops struct; another is to increment the
* reference count of owner of TIPC proto struct. Therefore, we must
* decrement the module reference count twice to ensure that it keeps
* zero after server's listening socket is created. Of course, we
* must bump the module reference count twice as well before the socket
* is closed.
*/
module_put(lsock->ops->owner);
module_put(sk->sk_prot_creator->owner);
return 0;
err:
sock_release(lsock);
return -EINVAL;
}
bool tipc_topsrv_kern_subscr(struct net *net, u32 port, u32 type, u32 lower,
u32 upper, u32 filter, int *conid)
{
struct tipc_subscr sub;
struct tipc_conn *con;
int rc;
sub.seq.type = type;
sub.seq.lower = lower;
sub.seq.upper = upper;
sub.timeout = TIPC_WAIT_FOREVER;
sub.filter = filter;
*(u64 *)&sub.usr_handle = (u64)port;
con = tipc_conn_alloc(tipc_topsrv(net), NULL);
if (IS_ERR(con))
return false;
*conid = con->conid;
rc = tipc_conn_rcv_sub(tipc_topsrv(net), con, &sub);
if (rc)
conn_put(con);
conn_put(con);
return !rc;
}
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;
test_and_clear_bit(CF_CONNECTED, &con->flags);
tipc_conn_delete_sub(con, NULL);
conn_put(con);
conn_put(con);
}
static void tipc_topsrv_kern_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_loopback_trace(net, &evtq);
tipc_sk_rcv(net, &evtq);
}
static int tipc_topsrv_work_start(struct tipc_topsrv *s)
{
s->rcv_wq = alloc_ordered_workqueue("tipc_rcv", 0);
if (!s->rcv_wq) {
pr_err("can't start tipc receive workqueue\n");
return -ENOMEM;
}
s->send_wq = alloc_ordered_workqueue("tipc_send", 0);
if (!s->send_wq) {
pr_err("can't start tipc send workqueue\n");
destroy_workqueue(s->rcv_wq);
return -ENOMEM;
}
return 0;
}
static void tipc_topsrv_work_stop(struct tipc_topsrv *s)
{
destroy_workqueue(s->rcv_wq);
destroy_workqueue(s->send_wq);
}
static int tipc_topsrv_start(struct net *net)
{
struct tipc_net *tn = tipc_net(net);
const char name[] = "topology_server";
struct tipc_topsrv *srv;
int ret;
srv = kzalloc_obj(*srv, GFP_ATOMIC);
if (!srv)
return -ENOMEM;
srv->net = net;
INIT_WORK(&srv->awork, tipc_topsrv_accept);
strscpy(srv->name, name, sizeof(srv->name));
tn->topsrv = srv;
atomic_set(&tn->subscription_count, 0);
spin_lock_init(&srv->idr_lock);
idr_init(&srv->conn_idr);
srv->idr_in_use = 0;
ret = tipc_topsrv_work_start(srv);
if (ret < 0)
goto err_start;
ret = tipc_topsrv_create_listener(srv);
if (ret < 0)
goto err_create;
return 0;
err_create:
tipc_topsrv_work_stop(srv);
err_start:
kfree(srv);
return ret;
}
static void tipc_topsrv_stop(struct net *net)
{
struct tipc_topsrv *srv = tipc_topsrv(net);
struct socket *lsock = srv->listener;
struct tipc_conn *con;
int id;
spin_lock_bh(&srv->idr_lock);
for (id = 0; srv->idr_in_use; id++) {
con = idr_find(&srv->conn_idr, id);
if (con) {
conn_get(con);
spin_unlock_bh(&srv->idr_lock);
tipc_conn_close(con);
conn_put(con);
spin_lock_bh(&srv->idr_lock);
}
}
__module_get(lsock->ops->owner);
__module_get(lsock->sk->sk_prot_creator->owner);
srv->listener = NULL;
spin_unlock_bh(&srv->idr_lock);
tipc_topsrv_work_stop(srv);
sock_release(lsock);
idr_destroy(&srv->conn_idr);
kfree(srv);
}
int __net_init tipc_topsrv_init_net(struct net *net)
{
return tipc_topsrv_start(net);
}
void __net_exit tipc_topsrv_exit_net(struct net *net)
{
tipc_topsrv_stop(net);
}
+54
View File
@@ -0,0 +1,54 @@
/*
* net/tipc/server.h: Include file for TIPC server code
*
* Copyright (c) 2012-2013, Wind River Systems
* 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_SERVER_H
#define _TIPC_SERVER_H
#include "core.h"
#define TIPC_SERVER_NAME_LEN 32
#define TIPC_SUB_CLUSTER_SCOPE 0x20
#define TIPC_SUB_NODE_SCOPE 0x40
#define TIPC_SUB_NO_STATUS 0x80
void tipc_topsrv_queue_evt(struct net *net, int conid,
u32 event, struct tipc_event *evt);
bool tipc_topsrv_kern_subscr(struct net *net, u32 port, u32 type, u32 lower,
u32 upper, u32 filter, int *conid);
void tipc_topsrv_kern_unsubscr(struct net *net, int conid);
#endif
+206
View File
@@ -0,0 +1,206 @@
/*
* net/tipc/trace.c: TIPC tracepoints code
*
* Copyright (c) 2018, 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 "ASIS"
* 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.
*/
#define CREATE_TRACE_POINTS
#include "trace.h"
/*
* socket tuples for filtering in socket traces:
* (portid, sock type, name type, name lower, name upper)
*/
unsigned long sysctl_tipc_sk_filter[5] __read_mostly = {0, };
/**
* tipc_skb_dump - dump TIPC skb data
* @skb: skb to be dumped
* @more: dump more?
* - false: dump only tipc msg data
* - true: dump kernel-related skb data and tipc cb[] array as well
* @buf: returned buffer of dump data in format
*/
int tipc_skb_dump(struct sk_buff *skb, bool more, char *buf)
{
int i = 0;
size_t sz = (more) ? SKB_LMAX : SKB_LMIN;
struct tipc_msg *hdr;
struct tipc_skb_cb *skbcb;
if (!skb) {
i += scnprintf(buf, sz, "msg: (null)\n");
return i;
}
hdr = buf_msg(skb);
skbcb = TIPC_SKB_CB(skb);
/* tipc msg data section */
i += scnprintf(buf, sz, "msg: %u", msg_user(hdr));
i += scnprintf(buf + i, sz - i, " %u", msg_type(hdr));
i += scnprintf(buf + i, sz - i, " %u", msg_hdr_sz(hdr));
i += scnprintf(buf + i, sz - i, " %u", msg_data_sz(hdr));
i += scnprintf(buf + i, sz - i, " %x", msg_orignode(hdr));
i += scnprintf(buf + i, sz - i, " %x", msg_destnode(hdr));
i += scnprintf(buf + i, sz - i, " %u", msg_seqno(hdr));
i += scnprintf(buf + i, sz - i, " %u", msg_ack(hdr));
i += scnprintf(buf + i, sz - i, " %u", msg_bcast_ack(hdr));
switch (msg_user(hdr)) {
case LINK_PROTOCOL:
i += scnprintf(buf + i, sz - i, " %c", msg_net_plane(hdr));
i += scnprintf(buf + i, sz - i, " %u", msg_probe(hdr));
i += scnprintf(buf + i, sz - i, " %u", msg_peer_stopping(hdr));
i += scnprintf(buf + i, sz - i, " %u", msg_session(hdr));
i += scnprintf(buf + i, sz - i, " %u", msg_next_sent(hdr));
i += scnprintf(buf + i, sz - i, " %u", msg_seq_gap(hdr));
i += scnprintf(buf + i, sz - i, " %u", msg_bc_snd_nxt(hdr));
i += scnprintf(buf + i, sz - i, " %u", msg_bc_gap(hdr));
break;
case TIPC_LOW_IMPORTANCE:
case TIPC_MEDIUM_IMPORTANCE:
case TIPC_HIGH_IMPORTANCE:
case TIPC_CRITICAL_IMPORTANCE:
case CONN_MANAGER:
case SOCK_WAKEUP:
i += scnprintf(buf + i, sz - i, " | %u", msg_origport(hdr));
i += scnprintf(buf + i, sz - i, " %u", msg_destport(hdr));
switch (msg_type(hdr)) {
case TIPC_NAMED_MSG:
i += scnprintf(buf + i, sz - i, " %u",
msg_nametype(hdr));
i += scnprintf(buf + i, sz - i, " %u",
msg_nameinst(hdr));
break;
case TIPC_MCAST_MSG:
i += scnprintf(buf + i, sz - i, " %u",
msg_nametype(hdr));
i += scnprintf(buf + i, sz - i, " %u",
msg_namelower(hdr));
i += scnprintf(buf + i, sz - i, " %u",
msg_nameupper(hdr));
break;
default:
break;
}
i += scnprintf(buf + i, sz - i, " | %u",
msg_src_droppable(hdr));
i += scnprintf(buf + i, sz - i, " %u",
msg_dest_droppable(hdr));
i += scnprintf(buf + i, sz - i, " %u", msg_errcode(hdr));
i += scnprintf(buf + i, sz - i, " %u", msg_reroute_cnt(hdr));
break;
default:
/* need more? */
break;
}
i += scnprintf(buf + i, sz - i, "\n");
if (!more)
return i;
/* kernel-related skb data section */
i += scnprintf(buf + i, sz - i, "skb: %s",
(skb->dev) ? skb->dev->name : "n/a");
i += scnprintf(buf + i, sz - i, " %u", skb->len);
i += scnprintf(buf + i, sz - i, " %u", skb->data_len);
i += scnprintf(buf + i, sz - i, " %u", skb->hdr_len);
i += scnprintf(buf + i, sz - i, " %u", skb->truesize);
i += scnprintf(buf + i, sz - i, " %u", skb_cloned(skb));
i += scnprintf(buf + i, sz - i, " %p", skb->sk);
i += scnprintf(buf + i, sz - i, " %u", skb_shinfo(skb)->nr_frags);
i += scnprintf(buf + i, sz - i, " %llx",
ktime_to_ms(skb_get_ktime(skb)));
i += scnprintf(buf + i, sz - i, " %llx\n",
ktime_to_ms(skb_hwtstamps(skb)->hwtstamp));
/* tipc skb cb[] data section */
i += scnprintf(buf + i, sz - i, "cb[]: %u", skbcb->bytes_read);
i += scnprintf(buf + i, sz - i, " %u", skbcb->orig_member);
i += scnprintf(buf + i, sz - i, " %u",
jiffies_to_msecs(skbcb->nxt_retr));
i += scnprintf(buf + i, sz - i, " %u", skbcb->validated);
i += scnprintf(buf + i, sz - i, " %u", skbcb->chain_imp);
i += scnprintf(buf + i, sz - i, " %u\n", skbcb->ackers);
return i;
}
/**
* tipc_list_dump - dump TIPC skb list/queue
* @list: list of skbs to be dumped
* @more: dump more?
* - false: dump only the head & tail skbs
* - true: dump the first & last 5 skbs
* @buf: returned buffer of dump data in format
*/
int tipc_list_dump(struct sk_buff_head *list, bool more, char *buf)
{
int i = 0;
size_t sz = (more) ? LIST_LMAX : LIST_LMIN;
u32 count, len;
struct sk_buff *hskb, *tskb, *skb, *tmp;
if (!list) {
i += scnprintf(buf, sz, "(null)\n");
return i;
}
len = skb_queue_len(list);
i += scnprintf(buf, sz, "len = %d\n", len);
if (!len)
return i;
if (!more) {
hskb = skb_peek(list);
i += scnprintf(buf + i, sz - i, " head ");
i += tipc_skb_dump(hskb, false, buf + i);
if (len > 1) {
tskb = skb_peek_tail(list);
i += scnprintf(buf + i, sz - i, " tail ");
i += tipc_skb_dump(tskb, false, buf + i);
}
} else {
count = 0;
skb_queue_walk_safe(list, skb, tmp) {
count++;
if (count == 6)
i += scnprintf(buf + i, sz - i, " .\n .\n");
if (count > 5 && count <= len - 5)
continue;
i += scnprintf(buf + i, sz - i, " #%d ", count);
i += tipc_skb_dump(skb, false, buf + i);
}
}
return i;
}
+434
View File
@@ -0,0 +1,434 @@
/*
* net/tipc/trace.h: TIPC tracepoints
*
* Copyright (c) 2018, 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 "ASIS"
* 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.
*/
#undef TRACE_SYSTEM
#define TRACE_SYSTEM tipc
#if !defined(_TIPC_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TIPC_TRACE_H
#include <linux/tracepoint.h>
#include "core.h"
#include "link.h"
#include "socket.h"
#include "node.h"
#define SKB_LMIN (100)
#define SKB_LMAX (SKB_LMIN * 2)
#define LIST_LMIN (SKB_LMIN * 3)
#define LIST_LMAX (SKB_LMIN * 11)
#define SK_LMIN (SKB_LMIN * 2)
#define SK_LMAX (SKB_LMIN * 11)
#define LINK_LMIN (SKB_LMIN)
#define LINK_LMAX (SKB_LMIN * 16)
#define NODE_LMIN (SKB_LMIN)
#define NODE_LMAX (SKB_LMIN * 11)
#ifndef __TIPC_TRACE_ENUM
#define __TIPC_TRACE_ENUM
enum {
TIPC_DUMP_NONE = 0,
TIPC_DUMP_TRANSMQ = 1,
TIPC_DUMP_BACKLOGQ = (1 << 1),
TIPC_DUMP_DEFERDQ = (1 << 2),
TIPC_DUMP_INPUTQ = (1 << 3),
TIPC_DUMP_WAKEUP = (1 << 4),
TIPC_DUMP_SK_SNDQ = (1 << 8),
TIPC_DUMP_SK_RCVQ = (1 << 9),
TIPC_DUMP_SK_BKLGQ = (1 << 10),
TIPC_DUMP_ALL = 0xffffu
};
#endif
/* Link & Node FSM states: */
#define state_sym(val) \
__print_symbolic(val, \
{(0xe), "ESTABLISHED" },\
{(0xe << 4), "ESTABLISHING" },\
{(0x1 << 8), "RESET" },\
{(0x2 << 12), "RESETTING" },\
{(0xd << 16), "PEER_RESET" },\
{(0xf << 20), "FAILINGOVER" },\
{(0xc << 24), "SYNCHING" },\
{(0xdd), "SELF_DOWN_PEER_DOWN" },\
{(0xaa), "SELF_UP_PEER_UP" },\
{(0xd1), "SELF_DOWN_PEER_LEAVING" },\
{(0xac), "SELF_UP_PEER_COMING" },\
{(0xca), "SELF_COMING_PEER_UP" },\
{(0x1d), "SELF_LEAVING_PEER_DOWN" },\
{(0xf0), "FAILINGOVER" },\
{(0xcc), "SYNCHING" })
/* Link & Node FSM events: */
#define evt_sym(val) \
__print_symbolic(val, \
{(0xec1ab1e), "ESTABLISH_EVT" },\
{(0x9eed0e), "PEER_RESET_EVT" },\
{(0xfa110e), "FAILURE_EVT" },\
{(0x10ca1d0e), "RESET_EVT" },\
{(0xfa110bee), "FAILOVER_BEGIN_EVT" },\
{(0xfa110ede), "FAILOVER_END_EVT" },\
{(0xc1ccbee), "SYNCH_BEGIN_EVT" },\
{(0xc1ccede), "SYNCH_END_EVT" },\
{(0xece), "SELF_ESTABL_CONTACT_EVT" },\
{(0x1ce), "SELF_LOST_CONTACT_EVT" },\
{(0x9ece), "PEER_ESTABL_CONTACT_EVT" },\
{(0x91ce), "PEER_LOST_CONTACT_EVT" },\
{(0xfbe), "FAILOVER_BEGIN_EVT" },\
{(0xfee), "FAILOVER_END_EVT" },\
{(0xcbe), "SYNCH_BEGIN_EVT" },\
{(0xcee), "SYNCH_END_EVT" })
/* Bearer, net device events: */
#define dev_evt_sym(val) \
__print_symbolic(val, \
{(NETDEV_CHANGE), "NETDEV_CHANGE" },\
{(NETDEV_GOING_DOWN), "NETDEV_GOING_DOWN" },\
{(NETDEV_UP), "NETDEV_UP" },\
{(NETDEV_CHANGEMTU), "NETDEV_CHANGEMTU" },\
{(NETDEV_CHANGEADDR), "NETDEV_CHANGEADDR" },\
{(NETDEV_UNREGISTER), "NETDEV_UNREGISTER" },\
{(NETDEV_CHANGENAME), "NETDEV_CHANGENAME" })
extern unsigned long sysctl_tipc_sk_filter[5] __read_mostly;
int tipc_skb_dump(struct sk_buff *skb, bool more, char *buf);
int tipc_list_dump(struct sk_buff_head *list, bool more, char *buf);
int tipc_sk_dump(struct sock *sk, u16 dqueues, char *buf);
int tipc_link_dump(struct tipc_link *l, u16 dqueues, char *buf);
int tipc_node_dump(struct tipc_node *n, bool more, char *buf);
bool tipc_sk_filtering(struct sock *sk);
DECLARE_EVENT_CLASS(tipc_skb_class,
TP_PROTO(struct sk_buff *skb, bool more, const char *header),
TP_ARGS(skb, more, header),
TP_STRUCT__entry(
__string(header, header)
__dynamic_array(char, buf, (more) ? SKB_LMAX : SKB_LMIN)
),
TP_fast_assign(
__assign_str(header);
tipc_skb_dump(skb, more, __get_str(buf));
),
TP_printk("%s\n%s", __get_str(header), __get_str(buf))
)
#define DEFINE_SKB_EVENT(name) \
DEFINE_EVENT(tipc_skb_class, name, \
TP_PROTO(struct sk_buff *skb, bool more, const char *header), \
TP_ARGS(skb, more, header))
DEFINE_SKB_EVENT(tipc_skb_dump);
DEFINE_SKB_EVENT(tipc_proto_build);
DEFINE_SKB_EVENT(tipc_proto_rcv);
DECLARE_EVENT_CLASS(tipc_list_class,
TP_PROTO(struct sk_buff_head *list, bool more, const char *header),
TP_ARGS(list, more, header),
TP_STRUCT__entry(
__string(header, header)
__dynamic_array(char, buf, (more) ? LIST_LMAX : LIST_LMIN)
),
TP_fast_assign(
__assign_str(header);
tipc_list_dump(list, more, __get_str(buf));
),
TP_printk("%s\n%s", __get_str(header), __get_str(buf))
);
#define DEFINE_LIST_EVENT(name) \
DEFINE_EVENT(tipc_list_class, name, \
TP_PROTO(struct sk_buff_head *list, bool more, const char *header), \
TP_ARGS(list, more, header))
DEFINE_LIST_EVENT(tipc_list_dump);
DECLARE_EVENT_CLASS(tipc_sk_class,
TP_PROTO(struct sock *sk, struct sk_buff *skb, u16 dqueues,
const char *header),
TP_ARGS(sk, skb, dqueues, header),
TP_STRUCT__entry(
__string(header, header)
__field(u32, portid)
__dynamic_array(char, buf, (dqueues) ? SK_LMAX : SK_LMIN)
__dynamic_array(char, skb_buf, (skb) ? SKB_LMIN : 1)
),
TP_fast_assign(
__assign_str(header);
__entry->portid = tipc_sock_get_portid(sk);
tipc_sk_dump(sk, dqueues, __get_str(buf));
if (skb)
tipc_skb_dump(skb, false, __get_str(skb_buf));
else
*(__get_str(skb_buf)) = '\0';
),
TP_printk("<%u> %s\n%s%s", __entry->portid, __get_str(header),
__get_str(skb_buf), __get_str(buf))
);
#define DEFINE_SK_EVENT_FILTER(name) \
DEFINE_EVENT_CONDITION(tipc_sk_class, name, \
TP_PROTO(struct sock *sk, struct sk_buff *skb, u16 dqueues, \
const char *header), \
TP_ARGS(sk, skb, dqueues, header), \
TP_CONDITION(tipc_sk_filtering(sk)))
DEFINE_SK_EVENT_FILTER(tipc_sk_dump);
DEFINE_SK_EVENT_FILTER(tipc_sk_create);
DEFINE_SK_EVENT_FILTER(tipc_sk_sendmcast);
DEFINE_SK_EVENT_FILTER(tipc_sk_sendmsg);
DEFINE_SK_EVENT_FILTER(tipc_sk_sendstream);
DEFINE_SK_EVENT_FILTER(tipc_sk_poll);
DEFINE_SK_EVENT_FILTER(tipc_sk_filter_rcv);
DEFINE_SK_EVENT_FILTER(tipc_sk_advance_rx);
DEFINE_SK_EVENT_FILTER(tipc_sk_rej_msg);
DEFINE_SK_EVENT_FILTER(tipc_sk_drop_msg);
DEFINE_SK_EVENT_FILTER(tipc_sk_release);
DEFINE_SK_EVENT_FILTER(tipc_sk_shutdown);
#define DEFINE_SK_EVENT_FILTER_COND(name, cond) \
DEFINE_EVENT_CONDITION(tipc_sk_class, name, \
TP_PROTO(struct sock *sk, struct sk_buff *skb, u16 dqueues, \
const char *header), \
TP_ARGS(sk, skb, dqueues, header), \
TP_CONDITION(tipc_sk_filtering(sk) && (cond)))
DEFINE_SK_EVENT_FILTER_COND(tipc_sk_overlimit1, tipc_sk_overlimit1(sk, skb));
DEFINE_SK_EVENT_FILTER_COND(tipc_sk_overlimit2, tipc_sk_overlimit2(sk, skb));
DECLARE_EVENT_CLASS(tipc_link_class,
TP_PROTO(struct tipc_link *l, u16 dqueues, const char *header),
TP_ARGS(l, dqueues, header),
TP_STRUCT__entry(
__string(header, header)
__array(char, name, TIPC_MAX_LINK_NAME)
__dynamic_array(char, buf, (dqueues) ? LINK_LMAX : LINK_LMIN)
),
TP_fast_assign(
__assign_str(header);
memcpy(__entry->name, tipc_link_name(l), TIPC_MAX_LINK_NAME);
tipc_link_dump(l, dqueues, __get_str(buf));
),
TP_printk("<%s> %s\n%s", __entry->name, __get_str(header),
__get_str(buf))
);
#define DEFINE_LINK_EVENT(name) \
DEFINE_EVENT(tipc_link_class, name, \
TP_PROTO(struct tipc_link *l, u16 dqueues, const char *header), \
TP_ARGS(l, dqueues, header))
DEFINE_LINK_EVENT(tipc_link_dump);
DEFINE_LINK_EVENT(tipc_link_conges);
DEFINE_LINK_EVENT(tipc_link_timeout);
DEFINE_LINK_EVENT(tipc_link_reset);
#define DEFINE_LINK_EVENT_COND(name, cond) \
DEFINE_EVENT_CONDITION(tipc_link_class, name, \
TP_PROTO(struct tipc_link *l, u16 dqueues, const char *header), \
TP_ARGS(l, dqueues, header), \
TP_CONDITION(cond))
DEFINE_LINK_EVENT_COND(tipc_link_too_silent, tipc_link_too_silent(l));
DECLARE_EVENT_CLASS(tipc_link_transmq_class,
TP_PROTO(struct tipc_link *r, u16 f, u16 t, struct sk_buff_head *tq),
TP_ARGS(r, f, t, tq),
TP_STRUCT__entry(
__array(char, name, TIPC_MAX_LINK_NAME)
__field(u16, from)
__field(u16, to)
__field(u32, len)
__field(u16, fseqno)
__field(u16, lseqno)
),
TP_fast_assign(
memcpy(__entry->name, tipc_link_name(r), TIPC_MAX_LINK_NAME);
__entry->from = f;
__entry->to = t;
__entry->len = skb_queue_len(tq);
__entry->fseqno = __entry->len ?
msg_seqno(buf_msg(skb_peek(tq))) : 0;
__entry->lseqno = __entry->len ?
msg_seqno(buf_msg(skb_peek_tail(tq))) : 0;
),
TP_printk("<%s> retrans req: [%u-%u] transmq: %u [%u-%u]\n",
__entry->name, __entry->from, __entry->to,
__entry->len, __entry->fseqno, __entry->lseqno)
);
DEFINE_EVENT_CONDITION(tipc_link_transmq_class, tipc_link_retrans,
TP_PROTO(struct tipc_link *r, u16 f, u16 t, struct sk_buff_head *tq),
TP_ARGS(r, f, t, tq),
TP_CONDITION(less_eq(f, t))
);
DEFINE_EVENT_PRINT(tipc_link_transmq_class, tipc_link_bc_ack,
TP_PROTO(struct tipc_link *r, u16 f, u16 t, struct sk_buff_head *tq),
TP_ARGS(r, f, t, tq),
TP_printk("<%s> acked: %u gap: %u transmq: %u [%u-%u]\n",
__entry->name, __entry->from, __entry->to,
__entry->len, __entry->fseqno, __entry->lseqno)
);
DECLARE_EVENT_CLASS(tipc_node_class,
TP_PROTO(struct tipc_node *n, bool more, const char *header),
TP_ARGS(n, more, header),
TP_STRUCT__entry(
__string(header, header)
__field(u32, addr)
__dynamic_array(char, buf, (more) ? NODE_LMAX : NODE_LMIN)
),
TP_fast_assign(
__assign_str(header);
__entry->addr = tipc_node_get_addr(n);
tipc_node_dump(n, more, __get_str(buf));
),
TP_printk("<%x> %s\n%s", __entry->addr, __get_str(header),
__get_str(buf))
);
#define DEFINE_NODE_EVENT(name) \
DEFINE_EVENT(tipc_node_class, name, \
TP_PROTO(struct tipc_node *n, bool more, const char *header), \
TP_ARGS(n, more, header))
DEFINE_NODE_EVENT(tipc_node_dump);
DEFINE_NODE_EVENT(tipc_node_create);
DEFINE_NODE_EVENT(tipc_node_delete);
DEFINE_NODE_EVENT(tipc_node_lost_contact);
DEFINE_NODE_EVENT(tipc_node_timeout);
DEFINE_NODE_EVENT(tipc_node_link_up);
DEFINE_NODE_EVENT(tipc_node_link_down);
DEFINE_NODE_EVENT(tipc_node_reset_links);
DEFINE_NODE_EVENT(tipc_node_check_state);
DECLARE_EVENT_CLASS(tipc_fsm_class,
TP_PROTO(const char *name, u32 os, u32 ns, int evt),
TP_ARGS(name, os, ns, evt),
TP_STRUCT__entry(
__string(name, name)
__field(u32, os)
__field(u32, ns)
__field(u32, evt)
),
TP_fast_assign(
__assign_str(name);
__entry->os = os;
__entry->ns = ns;
__entry->evt = evt;
),
TP_printk("<%s> %s--(%s)->%s\n", __get_str(name),
state_sym(__entry->os), evt_sym(__entry->evt),
state_sym(__entry->ns))
);
#define DEFINE_FSM_EVENT(fsm_name) \
DEFINE_EVENT(tipc_fsm_class, fsm_name, \
TP_PROTO(const char *name, u32 os, u32 ns, int evt), \
TP_ARGS(name, os, ns, evt))
DEFINE_FSM_EVENT(tipc_link_fsm);
DEFINE_FSM_EVENT(tipc_node_fsm);
TRACE_EVENT(tipc_l2_device_event,
TP_PROTO(struct net_device *dev, struct tipc_bearer *b,
unsigned long evt),
TP_ARGS(dev, b, evt),
TP_STRUCT__entry(
__string(dev_name, dev->name)
__string(b_name, b->name)
__field(unsigned long, evt)
__field(u8, b_up)
__field(u8, carrier)
__field(u8, oper)
),
TP_fast_assign(
__assign_str(dev_name);
__assign_str(b_name);
__entry->evt = evt;
__entry->b_up = test_bit(0, &b->up);
__entry->carrier = netif_carrier_ok(dev);
__entry->oper = netif_oper_up(dev);
),
TP_printk("%s on: <%s>/<%s> oper: %s carrier: %s bearer: %s\n",
dev_evt_sym(__entry->evt), __get_str(dev_name),
__get_str(b_name), (__entry->oper) ? "up" : "down",
(__entry->carrier) ? "ok" : "notok",
(__entry->b_up) ? "up" : "down")
);
#endif /* _TIPC_TRACE_H */
/* This part must be outside protection */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_FILE trace
#include <trace/define_trace.h>
+871
View File
@@ -0,0 +1,871 @@
/* net/tipc/udp_media.c: IP bearer support for TIPC
*
* Copyright (c) 2015, 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 <linux/socket.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/inet.h>
#include <linux/inetdevice.h>
#include <linux/igmp.h>
#include <linux/kernel.h>
#include <linux/workqueue.h>
#include <linux/wait_bit.h>
#include <linux/list.h>
#include <net/sock.h>
#include <net/ip.h>
#include <net/udp_tunnel.h>
#include <linux/tipc_netlink.h>
#include "core.h"
#include "addr.h"
#include "net.h"
#include "bearer.h"
#include "netlink.h"
#include "msg.h"
#include "udp_media.h"
/* IANA assigned UDP port */
#define UDP_PORT_DEFAULT 6118
#define UDP_MIN_HEADROOM 48
/**
* struct udp_media_addr - IP/UDP addressing information
*
* This is the bearer level originating address used in neighbor discovery
* messages, and all fields should be in network byte order
*
* @proto: Ethernet protocol in use
* @port: port being used
* @ipv4: IPv4 address of neighbor
* @ipv6: IPv6 address of neighbor
*/
struct udp_media_addr {
__be16 proto;
__be16 port;
union {
struct in_addr ipv4;
struct in6_addr ipv6;
};
};
/* struct udp_replicast - container for UDP remote addresses */
struct udp_replicast {
struct udp_media_addr addr;
struct dst_cache dst_cache;
struct rcu_head rcu;
struct list_head list;
};
/**
* struct udp_bearer - ip/udp bearer data structure
* @bearer: associated generic tipc bearer
* @sk: bearer associated socket
* @ifindex: local address scope
* @work: used to schedule deferred work on a bearer
* @rcast: associated udp_replicast container
* @rcast_lock: serialize updates to @rcast.list against concurrent updaters
* @disabled: bearer is being torn down; reject further @rcast.list additions
*/
struct udp_bearer {
struct tipc_bearer __rcu *bearer;
struct sock *sk;
u32 ifindex;
struct work_struct work;
struct udp_replicast rcast;
spinlock_t rcast_lock;
bool disabled;
};
static int tipc_udp_is_mcast_addr(struct udp_media_addr *addr)
{
if (ntohs(addr->proto) == ETH_P_IP)
return ipv4_is_multicast(addr->ipv4.s_addr);
#if IS_ENABLED(CONFIG_IPV6)
else
return ipv6_addr_is_multicast(&addr->ipv6);
#endif
return 0;
}
/* udp_media_addr_set - convert a ip/udp address to a TIPC media address */
static void tipc_udp_media_addr_set(struct tipc_media_addr *addr,
struct udp_media_addr *ua)
{
memset(addr, 0, sizeof(struct tipc_media_addr));
addr->media_id = TIPC_MEDIA_TYPE_UDP;
memcpy(addr->value, ua, sizeof(struct udp_media_addr));
if (tipc_udp_is_mcast_addr(ua))
addr->broadcast = TIPC_BROADCAST_SUPPORT;
}
/* tipc_udp_addr2str - convert ip/udp address to string */
static int tipc_udp_addr2str(struct tipc_media_addr *a, char *buf, int size)
{
struct udp_media_addr *ua = (struct udp_media_addr *)&a->value;
if (ntohs(ua->proto) == ETH_P_IP)
snprintf(buf, size, "%pI4:%u", &ua->ipv4, ntohs(ua->port));
else if (ntohs(ua->proto) == ETH_P_IPV6)
snprintf(buf, size, "%pI6:%u", &ua->ipv6, ntohs(ua->port));
else {
pr_err("Invalid UDP media address\n");
return 1;
}
return 0;
}
/* tipc_udp_msg2addr - extract an ip/udp address from a TIPC ndisc message */
static int tipc_udp_msg2addr(struct tipc_bearer *b, struct tipc_media_addr *a,
char *msg)
{
struct udp_media_addr *ua;
ua = (struct udp_media_addr *) (msg + TIPC_MEDIA_ADDR_OFFSET);
if (msg[TIPC_MEDIA_TYPE_OFFSET] != TIPC_MEDIA_TYPE_UDP)
return -EINVAL;
tipc_udp_media_addr_set(a, ua);
return 0;
}
/* tipc_udp_addr2msg - write an ip/udp address to a TIPC ndisc message */
static int tipc_udp_addr2msg(char *msg, struct tipc_media_addr *a)
{
memset(msg, 0, TIPC_MEDIA_INFO_SIZE);
msg[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_UDP;
memcpy(msg + TIPC_MEDIA_ADDR_OFFSET, a->value,
sizeof(struct udp_media_addr));
return 0;
}
/* tipc_send_msg - enqueue a send request */
static int tipc_udp_xmit(struct net *net, struct sk_buff *skb,
struct udp_bearer *ub, struct udp_media_addr *src,
struct udp_media_addr *dst, struct dst_cache *cache)
{
struct dst_entry *ndst;
int ttl, err;
local_bh_disable();
ndst = dst_cache_get(cache);
if (dst->proto == htons(ETH_P_IP)) {
struct rtable *rt = dst_rtable(ndst);
if (!rt) {
struct flowi4 fl = {
.daddr = dst->ipv4.s_addr,
.saddr = src->ipv4.s_addr,
.flowi4_mark = skb->mark,
.flowi4_proto = IPPROTO_UDP
};
rt = ip_route_output_key(net, &fl);
if (IS_ERR(rt)) {
err = PTR_ERR(rt);
goto tx_error;
}
dst_cache_set_ip4(cache, &rt->dst, fl.saddr);
}
ttl = ip4_dst_hoplimit(&rt->dst);
udp_tunnel_xmit_skb(rt, ub->sk, skb, src->ipv4.s_addr,
dst->ipv4.s_addr, 0, ttl, 0, src->port,
dst->port, false, true, 0);
#if IS_ENABLED(CONFIG_IPV6)
} else {
if (!ndst) {
struct flowi6 fl6 = {
.flowi6_oif = ub->ifindex,
.daddr = dst->ipv6,
.saddr = src->ipv6,
.flowi6_proto = IPPROTO_UDP
};
ndst = ip6_dst_lookup_flow(net, ub->sk,
&fl6, NULL);
if (IS_ERR(ndst)) {
err = PTR_ERR(ndst);
goto tx_error;
}
dst_cache_set_ip6(cache, ndst, &fl6.saddr);
}
ttl = ip6_dst_hoplimit(ndst);
udp_tunnel6_xmit_skb(ndst, ub->sk, skb, NULL,
&src->ipv6, &dst->ipv6, 0, ttl, 0,
src->port, dst->port, false, 0);
#endif
}
local_bh_enable();
return 0;
tx_error:
local_bh_enable();
kfree_skb(skb);
return err;
}
static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb,
struct tipc_bearer *b,
struct tipc_media_addr *addr)
{
struct udp_media_addr *src = (struct udp_media_addr *)&b->addr.value;
struct udp_media_addr *dst = (struct udp_media_addr *)&addr->value;
struct udp_replicast *rcast;
struct udp_bearer *ub;
int err = 0;
if (skb_headroom(skb) < UDP_MIN_HEADROOM) {
err = pskb_expand_head(skb, UDP_MIN_HEADROOM, 0, GFP_ATOMIC);
if (err)
goto out;
}
skb_set_inner_protocol(skb, htons(ETH_P_TIPC));
ub = rcu_dereference(b->media_ptr);
if (!ub) {
err = -ENODEV;
goto out;
}
if (addr->broadcast != TIPC_REPLICAST_SUPPORT)
return tipc_udp_xmit(net, skb, ub, src, dst,
&ub->rcast.dst_cache);
/* Replicast, send an skb to each configured IP address */
list_for_each_entry_rcu(rcast, &ub->rcast.list, list) {
struct sk_buff *_skb;
_skb = pskb_copy(skb, GFP_ATOMIC);
if (!_skb) {
err = -ENOMEM;
goto out;
}
err = tipc_udp_xmit(net, _skb, ub, src, &rcast->addr,
&rcast->dst_cache);
if (err)
goto out;
}
err = 0;
out:
kfree_skb(skb);
return err;
}
static int tipc_udp_rcast_add(struct tipc_bearer *b,
struct udp_media_addr *addr)
{
struct udp_replicast *rcast;
struct udp_bearer *ub;
ub = rcu_dereference_rtnl(b->media_ptr);
if (!ub)
return -ENODEV;
spin_lock_bh(&ub->rcast_lock);
if (ub->disabled) {
spin_unlock_bh(&ub->rcast_lock);
return 0;
}
list_for_each_entry(rcast, &ub->rcast.list, list) {
if (!memcmp(&rcast->addr, addr, sizeof(*addr))) {
spin_unlock_bh(&ub->rcast_lock);
return 0;
}
}
rcast = kmalloc_obj(*rcast, GFP_ATOMIC);
if (!rcast) {
spin_unlock_bh(&ub->rcast_lock);
return -ENOMEM;
}
if (dst_cache_init(&rcast->dst_cache, GFP_ATOMIC)) {
spin_unlock_bh(&ub->rcast_lock);
kfree(rcast);
return -ENOMEM;
}
memcpy(&rcast->addr, addr, sizeof(struct udp_media_addr));
list_add_rcu(&rcast->list, &ub->rcast.list);
b->bcast_addr.broadcast = TIPC_REPLICAST_SUPPORT;
spin_unlock_bh(&ub->rcast_lock);
if (ntohs(addr->proto) == ETH_P_IP)
pr_info("New replicast peer: %pI4\n", &rcast->addr.ipv4);
#if IS_ENABLED(CONFIG_IPV6)
else if (ntohs(addr->proto) == ETH_P_IPV6)
pr_info("New replicast peer: %pI6\n", &rcast->addr.ipv6);
#endif
return 0;
}
static int tipc_udp_rcast_disc(struct tipc_bearer *b, struct sk_buff *skb)
{
struct udp_media_addr src = {0};
struct udp_media_addr *dst;
dst = (struct udp_media_addr *)&b->bcast_addr.value;
if (tipc_udp_is_mcast_addr(dst))
return 0;
src.port = udp_hdr(skb)->source;
if (ip_hdr(skb)->version == 4) {
struct iphdr *iphdr = ip_hdr(skb);
src.proto = htons(ETH_P_IP);
src.ipv4.s_addr = iphdr->saddr;
if (ipv4_is_multicast(iphdr->daddr))
return 0;
#if IS_ENABLED(CONFIG_IPV6)
} else if (ip_hdr(skb)->version == 6) {
struct ipv6hdr *iphdr = ipv6_hdr(skb);
src.proto = htons(ETH_P_IPV6);
src.ipv6 = iphdr->saddr;
if (ipv6_addr_is_multicast(&iphdr->daddr))
return 0;
#endif
} else {
return 0;
}
return tipc_udp_rcast_add(b, &src);
}
/* tipc_udp_recv - read data from bearer socket */
static int tipc_udp_recv(struct sock *sk, struct sk_buff *skb)
{
struct udp_bearer *ub;
struct tipc_bearer *b;
struct tipc_msg *hdr;
int err;
ub = rcu_dereference_sk_user_data(sk);
if (!ub) {
pr_err_ratelimited("Failed to get UDP bearer reference");
goto out;
}
skb_pull(skb, sizeof(struct udphdr));
hdr = buf_msg(skb);
b = rcu_dereference(ub->bearer);
if (!b)
goto out;
if (b && test_bit(0, &b->up)) {
TIPC_SKB_CB(skb)->flags = 0;
tipc_rcv(sock_net(sk), skb, b);
return 0;
}
if (unlikely(msg_user(hdr) == LINK_CONFIG)) {
err = tipc_udp_rcast_disc(b, skb);
if (err)
goto out;
}
out:
kfree_skb(skb);
return 0;
}
static int enable_mcast(struct udp_bearer *ub, struct udp_media_addr *remote)
{
struct sock *sk = ub->sk;
struct ip_mreqn mreqn;
int err = 0;
if (ntohs(remote->proto) == ETH_P_IP) {
mreqn.imr_multiaddr = remote->ipv4;
mreqn.imr_ifindex = ub->ifindex;
err = ip_mc_join_group(sk, &mreqn);
#if IS_ENABLED(CONFIG_IPV6)
} else {
lock_sock(sk);
err = ipv6_sock_mc_join(sk, ub->ifindex, &remote->ipv6);
release_sock(sk);
#endif
}
return err;
}
static int __tipc_nl_add_udp_addr(struct sk_buff *skb,
struct udp_media_addr *addr, int nla_t)
{
if (ntohs(addr->proto) == ETH_P_IP) {
struct sockaddr_in ip4;
memset(&ip4, 0, sizeof(ip4));
ip4.sin_family = AF_INET;
ip4.sin_port = addr->port;
ip4.sin_addr.s_addr = addr->ipv4.s_addr;
if (nla_put(skb, nla_t, sizeof(ip4), &ip4))
return -EMSGSIZE;
#if IS_ENABLED(CONFIG_IPV6)
} else if (ntohs(addr->proto) == ETH_P_IPV6) {
struct sockaddr_in6 ip6;
memset(&ip6, 0, sizeof(ip6));
ip6.sin6_family = AF_INET6;
ip6.sin6_port = addr->port;
memcpy(&ip6.sin6_addr, &addr->ipv6, sizeof(struct in6_addr));
if (nla_put(skb, nla_t, sizeof(ip6), &ip6))
return -EMSGSIZE;
#endif
}
return 0;
}
int tipc_udp_nl_dump_remoteip(struct sk_buff *skb, struct netlink_callback *cb)
{
u32 bid = cb->args[0];
u32 skip_cnt = cb->args[1];
u32 portid = NETLINK_CB(cb->skb).portid;
struct udp_replicast *rcast, *tmp;
struct tipc_bearer *b;
struct udp_bearer *ub;
void *hdr;
int err;
int i;
if (!bid && !skip_cnt) {
struct nlattr **attrs = genl_dumpit_info(cb)->info.attrs;
struct net *net = sock_net(skb->sk);
struct nlattr *battrs[TIPC_NLA_BEARER_MAX + 1];
char *bname;
if (!attrs[TIPC_NLA_BEARER])
return -EINVAL;
err = nla_parse_nested_deprecated(battrs, TIPC_NLA_BEARER_MAX,
attrs[TIPC_NLA_BEARER],
tipc_nl_bearer_policy, NULL);
if (err)
return err;
if (!battrs[TIPC_NLA_BEARER_NAME])
return -EINVAL;
bname = nla_data(battrs[TIPC_NLA_BEARER_NAME]);
rtnl_lock();
b = tipc_bearer_find(net, bname);
if (!b || b->bcast_addr.media_id != TIPC_MEDIA_TYPE_UDP) {
rtnl_unlock();
return -EINVAL;
}
bid = b->identity;
} else {
struct net *net = sock_net(skb->sk);
struct tipc_net *tn = net_generic(net, tipc_net_id);
rtnl_lock();
b = rtnl_dereference(tn->bearer_list[bid]);
if (!b || b->bcast_addr.media_id != TIPC_MEDIA_TYPE_UDP) {
rtnl_unlock();
return -EINVAL;
}
}
ub = rtnl_dereference(b->media_ptr);
if (!ub) {
rtnl_unlock();
return -EINVAL;
}
i = 0;
list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
if (i < skip_cnt)
goto count;
hdr = genlmsg_put(skb, portid, cb->nlh->nlmsg_seq,
&tipc_genl_family, NLM_F_MULTI,
TIPC_NL_BEARER_GET);
if (!hdr)
goto done;
err = __tipc_nl_add_udp_addr(skb, &rcast->addr,
TIPC_NLA_UDP_REMOTE);
if (err) {
genlmsg_cancel(skb, hdr);
goto done;
}
genlmsg_end(skb, hdr);
count:
i++;
}
done:
rtnl_unlock();
cb->args[0] = bid;
cb->args[1] = i;
return skb->len;
}
int tipc_udp_nl_add_bearer_data(struct tipc_nl_msg *msg, struct tipc_bearer *b)
{
struct udp_media_addr *src = (struct udp_media_addr *)&b->addr.value;
struct udp_media_addr *dst;
struct udp_bearer *ub;
struct nlattr *nest;
ub = rtnl_dereference(b->media_ptr);
if (!ub)
return -ENODEV;
nest = nla_nest_start_noflag(msg->skb, TIPC_NLA_BEARER_UDP_OPTS);
if (!nest)
goto msg_full;
if (__tipc_nl_add_udp_addr(msg->skb, src, TIPC_NLA_UDP_LOCAL))
goto msg_full;
dst = (struct udp_media_addr *)&b->bcast_addr.value;
if (__tipc_nl_add_udp_addr(msg->skb, dst, TIPC_NLA_UDP_REMOTE))
goto msg_full;
if (!list_empty(&ub->rcast.list)) {
if (nla_put_flag(msg->skb, TIPC_NLA_UDP_MULTI_REMOTEIP))
goto msg_full;
}
nla_nest_end(msg->skb, nest);
return 0;
msg_full:
nla_nest_cancel(msg->skb, nest);
return -EMSGSIZE;
}
/**
* tipc_parse_udp_addr - build udp media address from netlink data
* @nla: netlink attribute containing sockaddr storage aligned address
* @addr: tipc media address to fill with address, port and protocol type
* @scope_id: IPv6 scope id pointer, not NULL indicates it's required
*/
static int tipc_parse_udp_addr(struct nlattr *nla, struct udp_media_addr *addr,
u32 *scope_id)
{
struct sockaddr_storage sa;
nla_memcpy(&sa, nla, sizeof(sa));
if (sa.ss_family == AF_INET) {
struct sockaddr_in *ip4 = (struct sockaddr_in *)&sa;
addr->proto = htons(ETH_P_IP);
addr->port = ip4->sin_port;
addr->ipv4.s_addr = ip4->sin_addr.s_addr;
return 0;
#if IS_ENABLED(CONFIG_IPV6)
} else if (sa.ss_family == AF_INET6) {
struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *)&sa;
addr->proto = htons(ETH_P_IPV6);
addr->port = ip6->sin6_port;
memcpy(&addr->ipv6, &ip6->sin6_addr, sizeof(struct in6_addr));
/* Scope ID is only interesting for local addresses */
if (scope_id) {
int atype;
atype = ipv6_addr_type(&ip6->sin6_addr);
if (__ipv6_addr_needs_scope_id(atype) &&
!ip6->sin6_scope_id) {
return -EINVAL;
}
*scope_id = ip6->sin6_scope_id ? : 0;
}
return 0;
#endif
}
return -EADDRNOTAVAIL;
}
int tipc_udp_nl_bearer_add(struct tipc_bearer *b, struct nlattr *attr)
{
int err;
struct udp_media_addr addr = {0};
struct nlattr *opts[TIPC_NLA_UDP_MAX + 1];
struct udp_media_addr *dst;
if (nla_parse_nested_deprecated(opts, TIPC_NLA_UDP_MAX, attr, tipc_nl_udp_policy, NULL))
return -EINVAL;
if (!opts[TIPC_NLA_UDP_REMOTE])
return -EINVAL;
err = tipc_parse_udp_addr(opts[TIPC_NLA_UDP_REMOTE], &addr, NULL);
if (err)
return err;
dst = (struct udp_media_addr *)&b->bcast_addr.value;
if (tipc_udp_is_mcast_addr(dst)) {
pr_err("Can't add remote ip to TIPC UDP multicast bearer\n");
return -EINVAL;
}
return tipc_udp_rcast_add(b, &addr);
}
/**
* tipc_udp_enable - callback to create a new udp bearer instance
* @net: network namespace
* @b: pointer to generic tipc_bearer
* @attrs: netlink bearer configuration
*
* validate the bearer parameters and initialize the udp bearer
* rtnl_lock should be held
*/
static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
struct nlattr *attrs[])
{
int err = -EINVAL;
struct udp_bearer *ub;
struct udp_media_addr remote = {0};
struct udp_media_addr local = {0};
struct udp_port_cfg udp_conf = {0};
struct udp_tunnel_sock_cfg tuncfg = {NULL};
struct nlattr *opts[TIPC_NLA_UDP_MAX + 1];
u8 node_id[NODE_ID_LEN] = {0,};
struct net_device *dev;
struct socket *sock;
int rmcast = 0;
ub = kzalloc_obj(*ub, GFP_ATOMIC);
if (!ub)
return -ENOMEM;
INIT_LIST_HEAD(&ub->rcast.list);
spin_lock_init(&ub->rcast_lock);
if (!attrs[TIPC_NLA_BEARER_UDP_OPTS])
goto err;
if (nla_parse_nested_deprecated(opts, TIPC_NLA_UDP_MAX, attrs[TIPC_NLA_BEARER_UDP_OPTS], tipc_nl_udp_policy, NULL))
goto err;
if (!opts[TIPC_NLA_UDP_LOCAL] || !opts[TIPC_NLA_UDP_REMOTE]) {
pr_err("Invalid UDP bearer configuration");
err = -EINVAL;
goto err;
}
err = tipc_parse_udp_addr(opts[TIPC_NLA_UDP_LOCAL], &local,
&ub->ifindex);
if (err)
goto err;
err = tipc_parse_udp_addr(opts[TIPC_NLA_UDP_REMOTE], &remote, NULL);
if (err)
goto err;
if (remote.proto != local.proto) {
err = -EINVAL;
goto err;
}
/* Checking remote ip address */
rmcast = tipc_udp_is_mcast_addr(&remote);
/* Autoconfigure own node identity if needed */
if (!tipc_own_id(net)) {
memcpy(node_id, local.ipv6.in6_u.u6_addr8, 16);
tipc_net_init(net, node_id, 0);
}
if (!tipc_own_id(net)) {
pr_warn("Failed to set node id, please configure manually\n");
err = -EINVAL;
goto err;
}
b->bcast_addr.media_id = TIPC_MEDIA_TYPE_UDP;
b->bcast_addr.broadcast = TIPC_BROADCAST_SUPPORT;
rcu_assign_pointer(b->media_ptr, ub);
rcu_assign_pointer(ub->bearer, b);
tipc_udp_media_addr_set(&b->addr, &local);
if (local.proto == htons(ETH_P_IP)) {
dev = __ip_dev_find(net, local.ipv4.s_addr, false);
if (!dev) {
err = -ENODEV;
goto err;
}
udp_conf.family = AF_INET;
/* Switch to use ANY to receive packets from group */
if (rmcast)
udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
else
udp_conf.local_ip.s_addr = local.ipv4.s_addr;
udp_conf.use_udp_checksums = false;
ub->ifindex = dev->ifindex;
b->encap_hlen = sizeof(struct iphdr) + sizeof(struct udphdr);
b->mtu = b->media->mtu;
#if IS_ENABLED(CONFIG_IPV6)
} else if (local.proto == htons(ETH_P_IPV6)) {
dev = ub->ifindex ? __dev_get_by_index(net, ub->ifindex) : NULL;
dev = ipv6_dev_find(net, &local.ipv6, dev);
if (!dev) {
err = -ENODEV;
goto err;
}
udp_conf.family = AF_INET6;
udp_conf.use_udp6_tx_checksums = true;
udp_conf.use_udp6_rx_checksums = true;
if (rmcast)
udp_conf.local_ip6 = in6addr_any;
else
udp_conf.local_ip6 = local.ipv6;
ub->ifindex = dev->ifindex;
b->encap_hlen = sizeof(struct ipv6hdr) + sizeof(struct udphdr);
b->mtu = 1280;
#endif
} else {
err = -EAFNOSUPPORT;
goto err;
}
udp_conf.local_udp_port = local.port;
err = udp_sock_create(net, &udp_conf, &sock);
if (err)
goto err;
ub->sk = sock->sk;
tuncfg.sk_user_data = ub;
tuncfg.encap_type = 1;
tuncfg.encap_rcv = tipc_udp_recv;
tuncfg.encap_destroy = NULL;
setup_udp_tunnel_sock(net, ub->sk, &tuncfg);
err = dst_cache_init(&ub->rcast.dst_cache, GFP_ATOMIC);
if (err)
goto free;
/*
* The bcast media address port is used for all peers and the ip
* is used if it's a multicast address.
*/
memcpy(&b->bcast_addr.value, &remote, sizeof(remote));
if (rmcast)
err = enable_mcast(ub, &remote);
else
err = tipc_udp_rcast_add(b, &remote);
if (err)
goto free;
return 0;
free:
dst_cache_destroy(&ub->rcast.dst_cache);
udp_tunnel_sock_release(ub->sk);
synchronize_rcu();
err:
kfree(ub);
return err;
}
static void rcast_free_rcu(struct rcu_head *rcu)
{
struct udp_replicast *rcast = container_of(rcu, struct udp_replicast, rcu);
dst_cache_destroy(&rcast->dst_cache);
kfree(rcast);
}
/* cleanup_bearer - break the socket/bearer association */
static void cleanup_bearer(struct work_struct *work)
{
struct udp_bearer *ub = container_of(work, struct udp_bearer, work);
struct udp_replicast *rcast, *tmp;
struct tipc_net *tn;
spin_lock_bh(&ub->rcast_lock);
list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
list_del_rcu(&rcast->list);
call_rcu_hurry(&rcast->rcu, rcast_free_rcu);
}
ub->disabled = true;
spin_unlock_bh(&ub->rcast_lock);
tn = tipc_net(sock_net(ub->sk));
udp_tunnel_sock_release(ub->sk);
synchronize_net();
dst_cache_destroy(&ub->rcast.dst_cache);
if (atomic_dec_and_test(&tn->wq_count))
wake_up_var(&tn->wq_count);
kfree(ub);
}
/* tipc_udp_disable - detach bearer from socket */
static void tipc_udp_disable(struct tipc_bearer *b)
{
struct udp_bearer *ub;
ub = rtnl_dereference(b->media_ptr);
if (!ub) {
pr_err("UDP bearer instance not found\n");
return;
}
sock_set_flag(ub->sk, SOCK_DEAD);
RCU_INIT_POINTER(ub->bearer, NULL);
/* sock_release need to be done outside of rtnl lock */
atomic_inc(&tipc_net(sock_net(ub->sk))->wq_count);
INIT_WORK(&ub->work, cleanup_bearer);
schedule_work(&ub->work);
}
struct tipc_media udp_media_info = {
.send_msg = tipc_udp_send_msg,
.enable_media = tipc_udp_enable,
.disable_media = tipc_udp_disable,
.addr2str = tipc_udp_addr2str,
.addr2msg = tipc_udp_addr2msg,
.msg2addr = tipc_udp_msg2addr,
.priority = TIPC_DEF_LINK_PRI,
.tolerance = TIPC_DEF_LINK_TOL,
.min_win = TIPC_DEF_LINK_WIN,
.max_win = TIPC_DEF_LINK_WIN,
.mtu = TIPC_DEF_LINK_UDP_MTU,
.type_id = TIPC_MEDIA_TYPE_UDP,
.hwaddr_len = 0,
.name = "udp"
};
+60
View File
@@ -0,0 +1,60 @@
/*
* net/tipc/udp_media.h: Include file for UDP bearer media
*
* Copyright (c) 1996-2006, 2013-2016, Ericsson AB
* Copyright (c) 2005, 2010-2011, Wind River Systems
* 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.
*/
#ifdef CONFIG_TIPC_MEDIA_UDP
#ifndef _TIPC_UDP_MEDIA_H
#define _TIPC_UDP_MEDIA_H
#include <linux/ip.h>
#include <linux/udp.h>
int tipc_udp_nl_bearer_add(struct tipc_bearer *b, struct nlattr *attr);
int tipc_udp_nl_add_bearer_data(struct tipc_nl_msg *msg, struct tipc_bearer *b);
int tipc_udp_nl_dump_remoteip(struct sk_buff *skb, struct netlink_callback *cb);
/* check if configured MTU is too low for tipc headers */
static inline bool tipc_udp_mtu_bad(u32 mtu)
{
if (mtu >= (TIPC_MIN_BEARER_MTU + sizeof(struct iphdr) +
sizeof(struct udphdr)))
return false;
pr_warn("MTU too low for tipc bearer\n");
return true;
}
#endif
#endif